Команда Asterisk: MixMonitor
Приложение Asterisk записи разговора и микширования аудио двух каналов (приемника и передатчика).
Описание
Записывает аудио текущего соединения в указанный файл.
Это приложение не отвечает само на вызов и требует предварительного выполнения answerили progress
Используйте также приложение StopMixMonitor, чтобы получить доступ к записанному файлу, пока обработка диалплана записываемого вызова не завершена.
примечание: MixMonitor запускается как audiohook.
${MIXMONITOR_FILENAME}: Содержит имя созданного файла.
Синтаксис
MixMonitor(filename.extension[,options[,command]])
Аргументыfilename - Имя записываемого файла. Если не содержит абсолютный путь, то помещается в директорию, определенную по умолчанию в конфиге asterisk.conf
options
- a: Добавить файл, а не перезаписывать, если существует.
- b: Сохранять аудио, только если установлено соединение. Если эта опция используется для канала Local, используйте опцию '/n', чтобы обеспечить корректную работу. Например:Dial(Local/start@mycontext/n)
- v(x): Регулировать «слух» по значению <x> (диапазон от '-4' до '4')
- V(x): Регулировать «речь» по значению <x> (диапазон от '-4' до '4')
- W(x): Регулировать «слух и речь» по значению <x> (диапазон от '-4' до '4')
«heard and spoke» - имеются ввиду входящий и исходящий медиа(аудио) потоки по отношению к инициатору вызова.
- r(file): Записать принимаемыйаудио поток в указанный файл. Как и для основного файла, директория определяется в либо абсолютным путем к файлу, либо по умолчанию, в директорию monitorсм. asterisk.conf
- t(file): Записать передаваемый аудио поток в указанный файл.
- i(chanvar): Сохранить MixMonitorsID в указанной переменной (chanvar) .
- m(mailbox): Создать копию файла, как файл голосовой почты для заданных голосовых ящиков, перечисленных через запятую, вида:m(1111@default,2222@default,…). Директория, необязательный параметр, может быть задана как: m(mailbox@context/folder).
command - Будет выполнена по завершению записи. Любая строка вида '^{X}' будет рассматриваться как ${X}. Все переменные будут установлены в момент вызова MixMonitor.
См. Также
<spoiler>
[sub-record-check] exten => s,1,GotoIf($[${LEN(${FROMEXTEN})}]?initialized) exten => s,n,Set(__REC_STATUS=INITIALIZED) ;exten => s,n,Set(NOW=${EPOCH}) ;exten => s,n,Set(__DAY=${STRFTIME(${NOW},,%d)}) ;exten => s,n,Set(__MONTH=${STRFTIME(${NOW},,%m)}) ;exten => s,n,Set(__YEAR=${STRFTIME(${NOW},,%Y)}) ;exten => s,n,Set(__TIMESTR=${YEAR}${MONTH}${DAY}-${STRFTIME(${NOW},,%H%M%S)}) ;exten => s,n,Set(__FROMEXTEN=${IF($[${LEN(${AMPUSER})}]?${AMPUSER}:${IF($[${LEN(${REALCALLERIDNUM})}]?${REALCALLERIDNUM}:unknown)})}) ;exten => s,n,Set(__MON_FMT=${IF($["${MIXMON_FORMAT}"="wav49"]?WAV:${MIXMON_FORMAT})}) exten => s,n(initialized),Noop(Recordings initialized) exten => s,n,ExecIf($[!${LEN(${ARG3})}]?Set(ARG3=dontcare)) exten => s,n,Set(REC_POLICY_MODE_SAVE=${REC_POLICY_MODE}) exten => s,n,ExecIf($["${BLINDTRANSFER}${ATTENDEDTRANSFER}" != ""]?Set(REC_STATUS=NO)) exten => s,n(next),GotoIf($[${LEN(${ARG1})}]?checkaction) exten => s,n(recorderror),Playback(something-terribly-wrong,error) exten => s,n,Hangup exten => s,n(checkaction),GotoIf($[${DIALPLAN_EXISTS(sub-record-check,${ARG1})}]?sub-record-check,${ARG1},1) exten => s,n,Noop(Generic ${ARG1} Recording Check - ${FROMEXTEN} ${ARG2}) exten => s,n,Gosub(recordcheck,1(${ARG3},${ARG1},${ARG2})) exten => s,n,Return() exten => recordcheck,1,Goto(${ARG1}) exten => recordcheck,n(dontcare),return exten => recordcheck,n(no),return exten => recordcheck,n(never),return exten => recordcheck,n(always),goto(reccc) exten => recordcheck,n(force),goto(reccc) exten => recordcheck,n(yes),goto(reccc) exten => recordcheck,n(reccc),Set(WAV=/var/spool/asterisk/monitor/${UNIQUEID}) exten => recordcheck,n,Set(MP3=/var/spool/asterisk/monitor/mp3/${UNIQUEID}) exten => recordcheck,n,Set(monopt=nice -n 19 /usr/local/bin/lame -b 32 --silent "${WAV}.wav" "${MP3}.mp3" && rm -f "${WAV}.wav" && chmod o+r "${MP3}.mp3") exten => recordcheck,n,Set(CDR(recordingfile)=${UNIQUEID}.mp3) exten => recordcheck,n,MixMonitor(${WAV}.wav,b,${monopt}) exten => recordcheck,n,return exten => out,1,Noop(Outbound Recording Check from ${FROMEXTEN} to ${ARG2}) exten => out,n,Set(RECMODE=${DB(AMPUSER/${FROMEXTEN}/recording/out/external)}) exten => out,n,ExecIf($[!${LEN(${RECMODE})} | "${RECMODE}" = "dontcare"]?Goto(routewins)) exten => out,n,ExecIf($["${ARG3}" = "never" | "${ARG3}" = "force"]?Goto(routewins)) exten => out,n(extenwins),Gosub(recordcheck,1(${RECMODE},out,${ARG2})) exten => out,n,Return() exten => out,n(routewins),Gosub(recordcheck,1(${ARG3},out,${ARG2})) exten => out,n,Return() exten => in,1,Noop(Inbound Recording Check to ${ARG2}) exten => in,n,Set(FROMEXTEN=unknown) exten => in,n,ExecIf($[${LEN(${CALLERID(num)})}]?Set(FROMEXTEN=${CALLERID(num)})) exten => in,n,Gosub(recordcheck,1(${ARG3},in,${ARG2})) exten => in,n,Return() exten => exten,1,Noop(Exten Recording Check between ${FROMEXTEN} and ${ARG2}) exten => exten,n,Set(CALLTYPE=${IF($[${LEN(${FROM_DID})}]?external:internal)}) exten => exten,n,ExecIf(${LEN(${CALLTYPE_OVERRIDE})}?Set(CALLTYPE=${CALLTYPE_OVERRIDE})) exten => exten,n,Set(CALLEE=${DB(AMPUSER/${ARG2}/recording/in/${CALLTYPE})}) exten => exten,n,ExecIf($[!${LEN(${CALLEE})}]?Set(CALLEE=dontcare)) exten => exten,n,GotoIf($["${CALLTYPE}"="external"]?callee) exten => exten,n,GotoIf($["${CALLEE}"="dontcare"]?caller) exten => exten,n,ExecIf($[${LEN(${DB(AMPUSER/${FROMEXTEN}/recording/priority)})}]?Set(CALLER_PRI=${DB(AMPUSER/${FROMEXTEN}/recording/priority)}):Set(CALLER_$ exten => exten,n,ExecIf($[${LEN(${DB(AMPUSER/${ARG2}/recording/priority)})}]?Set(CALLEE_PRI=${DB(AMPUSER/${ARG2}/recording/priority)}):Set(CALLEE_PRI=0)) exten => exten,n,GotoIf($["${CALLER_PRI}"="${CALLEE_PRI}"]?${REC_POLICY}:${IF($[${CALLER_PRI}>${CALLEE_PRI}]?caller:callee)}) exten => exten,n(callee),Gosub(recordcheck,1(${CALLEE},${CALLTYPE},${ARG2})) exten => exten,n,Return() exten => exten,n(caller),Set(RECMODE=${DB(AMPUSER/${FROMEXTEN}/recording/out/internal)}) exten => exten,n,ExecIf($[!${LEN(${RECMODE})}]?Set(RECMODE=dontcare)) exten => exten,n,ExecIf($["${RECMODE}"="dontcare"]?Set(RECMODE=${CALLEE})) exten => exten,n,Gosub(recordcheck,1(${RECMODE},${CALLTYPE},${ARG2})) exten => exten,n,Return() exten => conf,1,Noop(Conference Recording Check ${FROMEXTEN} to ${ARG2}) exten => conf,n,Gosub(recconf,1(${ARG2},${ARG2},${ARG3})) exten => conf,n,Return() exten => page,1,Noop(Paging Recording Check ${FROMEXTEN} to ${ARG2}) exten => page,n,GosubIf($["${REC_POLICY_MODE}"="always"]?recconf,1(${ARG2},${FROMEXTEN},${ARG3})) exten => page,n,Return() exten => recconf,1,Noop(Setting up recording: ${ARG1}, ${ARG2}, ${ARG3}) exten => recconf,n,Set(__CALLFILENAME=${IF($[${CONFBRIDGE_INFO(parties,${ARG2})}]?${DB(RECCONF/${ARG2})}:${ARG1}-${ARG2}-${ARG3}-${TIMESTR}-${UNIQUEID})}) exten => recconf,n,ExecIf($[!${CONFBRIDGE_INFO(parties,${ARG2})}]?Set(DB(RECCONF/${ARG2})=${CALLFILENAME})) exten => recconf,n,Set(CONFBRIDGE(bridge,record_file)=${MIXMON_DIR}${YEAR}/${MONTH}/${DAY}/${CALLFILENAME}.${MON_FMT}) exten => recconf,n,ExecIf($["${ARG3}"!="always"]?Return()) exten => recconf,n,Set(CONFBRIDGE(bridge,record_conference)=yes) exten => recconf,n,Set(__REC_STATUS=RECORDING) exten => recconf,n,Set(CDR(recordingfile)=${CALLFILENAME}.${MON_FMT}) exten => recconf,n,Return() exten => recq,1,Noop(Setting up recording: ${ARG1}, ${ARG2}, ${ARG3}) exten => recq,n,Set(AUDIOHOOK_INHERIT(MixMonitor)=yes) exten => recq,n,Set(MONITOR_FILENAME=${MIXMON_DIR}${YEAR}/${MONTH}/${DAY}/${CALLFILENAME}) exten => recq,n,MixMonitor(${MONITOR_FILENAME}.${MON_FMT},${MONITOR_OPTIONS},${MIXMON_POST}) exten => recq,n,Set(__REC_STATUS=RECORDING) exten => recq,n,Set(CDR(recordingfile)=${CALLFILENAME}.${MON_FMT}) exten => recq,n,Return() exten => parking,1,Noop(User ${ARG2} picked up a parked call) exten => parking,n,Set(USER=${ARG2}) exten => parking,n,ExecIf($[!${LEN(${ARG2})}]?Set(USER=unknown)) exten => parking,n,Set(RECMODE=${DB(AMPUSER/${ARG2}/recording/out/internal)}) exten => parking,n,ExecIf($[!${LEN(${RECMODE})}]?Set(RECMODE=dontcare)) exten => parking,n,Gosub(recordcheck,1(${RECMODE},parked,${USER})) exten => parking,n,Return()
</spoiler>