Страница 1 из 1

Получить корректный CDR при attended transfer?

Добавлено: 30 янв 2022, 00:50
aclz
Смысл в следующем, обычная ситуация: приходит входящий звонок на оператора 1, он переводит звонок на оператора 2, после чего по завершении разговора кто-то из сторон (внешний клиент или оператор 2) кладет трубку, и звонок завершается.

Но при этом в CDR генерируются 4 записи:

src: Клиент, dst: Оператор 1 [начало звонка - начало перевода звонка]
src: Оператор 1, dst: Оператор 2 [начало перевода - оператор 1 кладет трубку]
src: Клиент, dst: Оператор 1 [время начала и конца соответствует предыдущей запси] <-- Видимо, соответствует каналу, где висит клиент на удержании, пока операторы разговаривают
src: Клиент, dst: Оператор 1 [оператор 1 кладет трубку, начало разговора оператора 2 с клиентом - конец разговора]

Вопрос по последней записи. По идее, там д.б. Оператор 2, вместо 1. В выводе консоли в этом simple_bridge операторы меняются местами, оператор 1 покидает, а оператор 2 помещается в него, и такое событие, судя по всему, не обновляет значения переменных об участниках канала.

Есть ли способы это пофиксить хотя бы костылями?

Что пробовал:
  • В диалплане какого-то отдельного обработчика, срабатываемого после attended transfer, когда операторы меняются местами, я не нашел (можно было бы установить из него свои переменные CDR).
  • Думал хотя бы по окончании разговора фиксировать последнего оператора: в hangup handler при завершении разговора делаю dumpchan, во всех переменных канала фигурирует оператор 1. В секции Info оператор 2 присутствует в поле ConnectedLineIDNum. Но проблема в том, что Info в dumpchan это не переменная канала, и непонятно, как это значение можно дёрнуть из диалплана. Можно было бы на худой конец распарсить вывод dumpchan, но само приложение не возвращает никакого значения, оно просто выводит текст в консоль, в диалплане он недоступен :?
  • Посмотрел в сырцах dumpchan, там юзается внутренняя функция

    Код: Выделить всё

    S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "(N/A)"),
    ведущая в chan_internal_api.c:

    Код: Выделить всё

    struct ast_party_connected_line *ast_channel_connected(struct ast_channel *chan)
    {
    	return &chan->connected;
    }
    В исходниках ни одного приложения или функции диалплана не нашел возврата chan->connected в диалплан (на то наверное оно и internal api).
В общем, куда копать пока непонятно :? :? :?

Re: Получить корректный CDR при attended transfer?

Добавлено: 30 янв 2022, 15:46
Zavr2008
Использовать CEL для этого, там всё объединяется по linkedid.

Re: Получить корректный CDR при attended transfer?

Добавлено: 30 янв 2022, 19:39
dimondack
https://www.npmjs.com/package/asterisk-ami-client
http://subnets.ru/forum/viewtopic.php?f=13&t=668

Ловится такое событие

1746 звонит на 1745, а 1745 переводит на 1701

Код: Выделить всё

{
  Event: 'AttendedTransfer',
  Privilege: 'call,all',
  Result: 'Success',
  OrigTransfererChannel: 'SIP/1745-00000004',
  OrigTransfererChannelState: '6',
  OrigTransfererChannelStateDesc: 'Up',
  OrigTransfererCallerIDNum: '1745',
  OrigTransfererCallerIDName: '1745',
  OrigTransfererConnectedLineNum: '1701',
  OrigTransfererConnectedLineName: 'Dimondack',
  OrigTransfererLanguage: 'ru',
  OrigTransfererAccountCode: '',
  OrigTransfererContext: 'users',
  OrigTransfererExten: '',
  OrigTransfererPriority: '1',
  OrigTransfererUniqueid: '1643559559.48',
  OrigTransfererLinkedid: '1643559559.46',
  OrigBridgeUniqueid: '5a8890a2-229f-48af-a63f-998770f9dab3',
  OrigBridgeType: 'basic',
  OrigBridgeTechnology: 'simple_bridge',
  OrigBridgeCreator: '<unknown>',
  OrigBridgeName: '<unknown>',
  OrigBridgeNumChannels: '2',
  OrigBridgeVideoSourceMode: 'none',
  SecondTransfererChannel: 'SIP/1745-00000004',
  SecondTransfererChannelState: '6',
  SecondTransfererChannelStateDesc: 'Up',
  SecondTransfererCallerIDNum: '1745',
  SecondTransfererCallerIDName: '1745',
  SecondTransfererConnectedLineNum: '1701',
  SecondTransfererConnectedLineName: 'Dimondack',
  SecondTransfererLanguage: 'ru',
  SecondTransfererAccountCode: '',
  SecondTransfererContext: 'users',
  SecondTransfererExten: '',
  SecondTransfererPriority: '1',
  SecondTransfererUniqueid: '1643559559.48',
  SecondTransfererLinkedid: '1643559559.46',
  SecondBridgeUniqueid: '43918afc-8937-4010-889c-2e8a7fbb7114',
  SecondBridgeType: 'basic',
  SecondBridgeTechnology: 'simple_bridge',
  SecondBridgeCreator: '<unknown>',
  SecondBridgeName: '<unknown>',
  SecondBridgeNumChannels: '0',
  SecondBridgeVideoSourceMode: 'none',
  TransfereeChannel: 'SIP/1746-00000003',
  TransfereeChannelState: '6',
  TransfereeChannelStateDesc: 'Up',
  TransfereeCallerIDNum: '1746',
  TransfereeCallerIDName: '1746',
  TransfereeConnectedLineNum: '1745',
  TransfereeConnectedLineName: '1745',
  TransfereeLanguage: 'ru',
  TransfereeAccountCode: '',
  TransfereeContext: 'users',
  TransfereeExten: '1745',
  TransfereePriority: '10',
  TransfereeUniqueid: '1643559559.46',
  TransfereeLinkedid: '1643559559.46',
  TransferTargetChannel: 'Local/1701@users-00000001;1',
  TransferTargetChannelState: '6',
  TransferTargetChannelStateDesc: 'Up',
  TransferTargetCallerIDNum: '1701',
  TransferTargetCallerIDName: 'Dimondack',
  TransferTargetConnectedLineNum: '1745',
  TransferTargetConnectedLineName: '1745',
  TransferTargetLanguage: 'ru',
  TransferTargetAccountCode: '',
  TransferTargetContext: 'users',
  TransferTargetExten: '1701',
  TransferTargetPriority: '1',
  TransferTargetUniqueid: '1643559567.54',
  TransferTargetLinkedid: '1643559559.46',
  IsExternal: 'No',
  DestType: 'Bridge',
  DestBridgeUniqueid: '5a8890a2-229f-48af-a63f-998770f9dab3'

Код: Выделить всё

const AmiClient = require('asterisk-ami-client');
const dateFormat = require('dateformat') 
const fs = require('fs')

let client = new AmiClient({
    reconnect: true,
    keepAlive: true,
    emitEventsByTypes: true,
    emitResponsesById: true
});

client.connect('admin', '123', {host: 'localhost', port: 5038})
    .then(() => {
        client
            .on('AttendedTransfer', event => ev(event)  )
	    .on('BlindTransfer', event => ev(event)  )

.on('internalError', error => logger('internalError',error));


})
      .catch(error => logger('catch',error));

function ev(ev){

//logger('attend_transfer',ev)
console.log(ev)
let dt = dateFormat(new Date(), "yyyymmddHHMMss")
//console.log('Exten =',ev.Extension)
//if(ev.Extension == group_num){
//logger('hangup',s)


console.log('Channel= ',ev.TransfereeChannel)

    client.action({
            Action: 'SetVar',
            ActionID: 777759,
            Channel: ev.TransfereeChannel,
            Variable: 'MyVar',
            Value: ev.TransferTargetCallerIDNum
                         });
}

function logger(type,log){
let dt = dateFormat( new Date(), "yyyy-mm-dd HH:MM:ss" )
let str  = dt + "  " + type  + '\n\r'
let str2 = dt + "  " + log   + '\n\r' 
fs.appendFileSync("logger.log",str)
fs.appendFileSync("logger.log",str2)
}


Далее выполняется SetVar см. выше
Action: 'SetVar',
ActionID: 777759,
Channel: ev.TransfereeChannel,
Variable: 'MyVar',
Value: ev.TransferTargetCallerIDNum
оператор 2 - это (1701)
присутствует в поле
ConnectedLineIDNum - это (TransferTargetCallerIDNum)
непонятно, как это значение можно дёрнуть из диалплана.
Ну а далее проверяем переменную MyVar в диалплане.


:) :) :)

Re: Получить корректный CDR при attended transfer?

Добавлено: 30 янв 2022, 21:31
aclz
Спасибо, тоже прихожу к выводу, что CEL это те же яйца (CDR), вид сбоку, только разгребать больше, а на выходе всё равно полуфабрикат будет, и если уж пилить нормальный биллинг, то на чем-то типа AMI events, событиях stasis итп...
А свою маленькую проблемку я решил через функцию диалплана CONNECTEDLINE(num), которую почему-то не заметил ранее.

Re: Получить корректный CDR при attended transfer?

Добавлено: 30 янв 2022, 22:15
Zavr2008
AMi да, там приходит всё, но и разгребать самому.
в CEL прилетает всё что нужно, только поменьше возни и сразу в БД есть все данные. Обычно в последнее время писатели коннекторов с CRM любят юзать - записи те же чтобы не склеивать вручную итп.