Добрый деньНесколько дней бьюсь над необходимым функционалом IVR как на 2801 так и 2821 (думал дело в железе, пробовал разные иосы). Остановился на c2800nm-adventerprisek9_ivs-mz.124-15.XZ2.bin
Схема такая: SIP провайдер - шлюз (2801 или 2801 - не суть важно) - ССМ 7. Транки везде сиповые, как от провайдера, так и между 2821 и ССМ.
Звонки ходят по сипу в обе стороны, dtmf работает, единственная загвоздка - IVR. Нужен функционал вроде: "Здравствуйте, вы позвонили в нашу компанию, наберите номер абонента или дождитесь ответа оператора". Скрипт срабатывает, и набрав 4 цифры номера в момент сообщения - звонок проходит на этот номер. Но если попытаться дождаться ответа оператора, - ответа нет. По окончании сообщения - длинные гудки в никуда (по всей видимости скрипт не тренсферит звонок и начинается какой-то таймаут). Данный скрипт сейчас работает на pots диалпирах, т.е. он рабочий. Видимо проблема именно в воиповых диалпирах. Со скриптами дела никогда не имел, потому мои попытки что-то в нём поправить ни к чему не привели - он либо переставал работать вообще, либо продолжал вести себя так, как я описал выше.
Вот собственно конфиг 2821:
voice call carrier capacity active
voice rtp send-recv
!
voice service pots
!
voice service voip
allow-connections h323 to h323
allow-connections h323 to sip
allow-connections sip to h323
allow-connections sip to sip
redirect ip2ip
h323
sip
registrar server
no call service stop
!
!
!
voice class codec 1
codec preference 1 g711ulaw
codec preference 2 g729r8
codec preference 3 g711alaw
codec preference 4 g729br8
!
!
application
service ivr_script flash:ivr.tcl
!
!
dial-peer voice 301 voip
description -=INCOMING IVR=-
huntstop
service ivr_script
incoming called-number 1234567
dtmf-relay rtp-nte
codec g711ulaw
no vad
!
dial-peer voice 302 voip
description -=TO CCM =-
service session
destination-pattern 66..
session protocol sipv2
session target ipv4:10.6.1.100
session transport udp
dtmf-relay rtp-nte
codec g711ulaw
no vad
!
dial-peer voice 200 voip
description -= TO SIP SERVER =-
service session
destination-pattern [37]......
session protocol sipv2
session target sip-server
session transport udp
dtmf-relay rtp-nte
codec g711ulaw
no vad
!
!
gateway
timer receive-rtp 1200
!
sip-ua
credentials username 123 password 7 12345 realm default
authentication username 123 password 7 12345
calling-info pstn-to-sip from name set 123
calling-info pstn-to-sip from number set 123
no remote-party-id
no redirection
retry invite 3
retry response 3
retry bye 3
retry cancel 3
timers trying 1000
timers connection aging 90
timers register 1000
registrar ipv4:10.102.10.54 expires 3600
sip-server ipv4:10.102.10.54
Вот сам скрипт:
proc init { } {
global param1
global selectCnt
global callInfo
global legConnected
set param1(interruptPrompt) true
set param1(abortKey) *
set param1(terminationKey) #
set selectCnt 0
set legConnected false
}
proc init_ConfigVars { } {
global destination
global aaPilot
global oprtr
set aaPilot 1234567
set oprtr 6624
}
proc init_perCallVars { } {
puts "\n*************************proc init_perCallvars"
global ani
global digit_enabled
global fcnt
global retrycnt
global dnis
set fcnt 0
set retrycnt 6
set ani ""
set dnis ""
set digit_enabled "FALSE"
set ani [infotag get leg_ani]
puts "\n***********************ANI $ani"
set dnis [infotag get leg_dnis]
puts "\n***********************DNIS $dnis"
}
proc act_Setup { } {
global param1
global selectCnt
global dest
global beep
global callInfo
global dnis
global fcnt
global aaPilot
global oprtr
global busyPrompt
global legConnected
puts "\n************************proc act_Setup"
set beep 0
init_perCallVars
infotag set med_language 1
if { ($dnis == "") || ($dnis == $aaPilot) } {
leg setupack leg_incoming
leg proceeding leg_incoming
leg connect leg_incoming
set legConnected true
puts "\n**************************No DNIS\n"
set param1(dialPlan) true
leg collectdigits leg_incoming param1
media play leg_incoming flash:ivr.au
} else {
set fcnt 6
leg setupack leg_incoming
handoff callappl leg_incoming default "DESTINATION=$dnis"
fsm setstate HANDOFF
}
}
proc act_GotDest { } {
global dest
global callInfo
global oprtr
global busyPrompt
puts "\n ******************************proc act_GotDest"
set status [infotag get evt_status]
set callInfo(alertTime) 30
if { ($status == "cd_004") } {
set dest [infotag get evt_dcdigits]
if { $dest == "0" } {
set dest $oprtr
}
handoff callappl leg_incoming default "DESTINATION=$dest"
} elseif { ($status == "cd_001") || ($status == "cd_002") } {
set dest $oprtr
handoff callappl leg_incoming default "DESTINATION=$dest"
} else {
puts "\n**************************Call [infotag get con_all] got event $status collecting destination"
set dest [infotag get evt_dcdigits]
if { $dest == "0" } {
set dest $oprtr
handoff callappl leg_incoming default "DESTINATION=$dest"
} else {
act_Select
}
}
}
proc act_CallSetupDone { } {
global busyPrompt
global legConnected
set status [infotag get evt_handoff_string]
if { [string length $status] != 0} {
regexp {([0-9][0-9][0-9])} $status StatusCode
puts "*****************************IP IVR Disconnect Status = $status"
switch $StatusCode {
"016" {
puts "\n **************************************Connection success"
fsm setstate CONTINUE
act_Cleanup
}
default {
if { $legConnected == "false" } {
leg proceeding leg_incoming
leg connect leg_incoming
set legConnected true
}
puts "\n ************************Call failed. Play prompt and collect digit"
act_Select
}
}
} else {
puts "\n *********************************Caller disconnected"
fsm setstate CALLDISCONNECT
act_Cleanup
}
}
proc act_Select { } {
global destination
global promptFlag2
global destBusy
global param1
global fcnt
global retrycnt
global busyPrompt
puts "\n **********************************proc act_Select"
set promptFlag2 0
set param1(interruptPrompt) true
set param1(abortKey) *
set param1(terminationKey) #
set param1(dialPlan) true
set param1(dialPlanTerm) true
leg collectdigits leg_incoming param1
}
puts "\n *********************************proc act_DestBusy"
proc act_playtone_ring { } {
puts "\n *********************************playtone ring begin"
playtone leg_incoming tn_ringback
puts "\n *********************************playtone ring end"
}
proc act_Cleanup { } {
call close
}
requiredversion 2.0
init
init_ConfigVars
#----------------------------------
# State Machine
#----------------------------------
set fsm(any_state,ev_disconnected) "act_Cleanup same_state"
set fsm(CALL_INIT,ev_setup_indication) "act_Setup GETDEST"
set fsm(GETDEST,ev_collectdigits_done) "act_GotDest HANDOFF"
set fsm(GETDEST,ev_media_done) "act_playtone_ring same_state"
set fsm(HANDOFF,ev_returned) "act_CallSetupDone CONTINUE"
set fsm(CALLDISCONNECT,ev_media_done) "act_Cleanup same_state"
fsm define fsm CALL_INIT
Как видно из скрипта, при звонке на номер 1234567 срабатывает IVR и после сообщения звонок автоматически должен попадать на оператора с номером 6624.
Дебажил, то это мне мало помогло. Все дебаги разобъю на 2 части - момент срабатывания IVR и момент начала длинных гудков.
debug voice application script:
1. 041583: .Sep 2 17:28:31: //-1//TCL :EE4BF4EC04000:/tcl_PutsObjCmd:
*********************************proc act_DestBusy
041584: .Sep 2 17:28:31:
041585: .Sep 2 17:28:31: //7091//TCL :/tcl_PutsObjCmd:
************************proc act_Setup
041586: .Sep 2 17:28:31:
041587: .Sep 2 17:28:31: //7091//TCL :/tcl_PutsObjCmd:
*************************proc init_perCallvars
041588: .Sep 2 17:28:31:
041589: .Sep 2 17:28:31: //7091//TCL :/tcl_PutsObjCmd:
***********************ANI 380575555555
041590: .Sep 2 17:28:31:
041591: .Sep 2 17:28:31: //7091//TCL :/tcl_PutsObjCmd:
***********************DNIS 1234567
041592: .Sep 2 17:28:31:
041593: .Sep 2 17:28:31: //7091//TCL :/tcl_PutsObjCmd:
**************************No DNIS
2. 041596: .Sep 2 17:28:45: //7091//TCL :/tcl_PutsObjCmd:
*********************************playtone ring begin
041597: .Sep 2 17:28:45:
041598: .Sep 2 17:28:45: //7091//TCL :/tcl_PutsObjCmd:
*********************************playtone ring end
debug voice application tclcommands
1. 041603: .Sep 2 17:30:29: //7097//TCL :/tcl_InfotagObjCmd: infotag get leg_ani
041604: .Sep 2 17:30:29: //7097//TCL :/tcl_InfotagGetObjCmd: infotag get leg_ani
041605: .Sep 2 17:30:29: //7097//AFW_:/vtr_lg_ani: argc 2 argindex 2
041606: .Sep 2 17:30:29: //7097//TCL :/tcl_InfotagObjCmd: infotag get leg_dnis
041607: .Sep 2 17:30:29: //7097//TCL :/tcl_InfotagGetObjCmd: infotag get leg_dnis
041608: .Sep 2 17:30:29: //7097//AFW_:/vtr_lg_dnis: argc 2 argindex 2
041609: .Sep 2 17:30:29: //7097//TCL :/tcl_InfotagObjCmd: infotag set med_language 1
041610: .Sep 2 17:30:29: //7097//TCL :/tcl_InfotagSetObjCmd: infotag set med_language 1
041611: .Sep 2 17:30:29: //7097//AFW_:/vtw_ms_language: argc 3 argindex 2
041612: .Sep 2 17:30:29: //7097//TCL :/tcl_LegObjCmd: leg setupack leg_incoming
041613: .Sep 2 17:30:29: //7097//TCL :/tcl_LegSetupAckObjCmd: setupack leg_incoming
041614: .Sep 2 17:30:29: //7097//AFW_:/vtd_lg_incoming: argc 2
041615: .Sep 2 17:30:29: //7097//AFW_:/vtd_lg_incoming: Legs [7097 ]
041616: .Sep 2 17:30:29: //7097//Tcl :/tcl_parseCallID_vartagObj: VARTAG Translation Leg Count=1
041617: .Sep 2 17:30:29: //7097//TCL :/tcl_LegObjCmd: leg proceeding leg_incoming
041618: .Sep 2 17:30:29: //7097//TCL :/tcl_LegProceedObjCmd: proceeding leg_incoming
041619: .Sep 2 17:30:29: //7097//AFW_:/vtd_lg_incoming: argc 2
041620: .Sep 2 17:30:29: //7097//AFW_:/vtd_lg_incoming: Legs [7097 ]
041621: .Sep 2 17:30:29: //7097//Tcl :/tcl_parseCallID_vartagObj: VARTAG Translation Leg Count=1
041622: .Sep 2 17:30:29: //7097//TCL :/tcl_LegObjCmd: leg connect leg_incoming
041623: .Sep 2 17:30:29: //7097//TCL :/tcl_LegConnectObjCmd: connect leg_incoming
041624: .Sep 2 17:30:29: //7097//AFW_:/vtd_lg_incoming: argc 2
041625: .Sep 2 17:30:29: //7097//AFW_:/vtd_lg_incoming: Legs [7097 ]
041626: .Sep 2 17:30:29: //7097//Tcl :/tcl_parseCallID_vartagObj: VARTAG Translation Leg Count=1
041627: .Sep 2 17:30:29: //7097//TCL :/tcl_LegObjCmd: leg collectdigits leg_incoming param1
041628: .Sep 2 17:30:29: //7097//AFW_:/vtd_lg_incoming: argc 3
041629: .Sep 2 17:30:29: //7097//AFW_:/vtd_lg_incoming: Legs [7097 ]
041630: .Sep 2 17:30:29: //7097//Tcl :/tcl_parseCallID_vartagObj: VARTAG Translation Leg Count=1
041631: .Sep 2 17:30:29: //7097//PACK:/tcl_MediaObjCmd: media play leg_incoming flash:ivr.au
041632: .Sep 2 17:30:29: //7097//PACK:/tcl_MediaPlayObjCmd: play leg_incoming flash:ivr.au
041633: .Sep 2 17:30:29: //7097//AFW_:/vtd_lg_incoming: argc 3
041634: .Sep 2 17:30:29: //7097//AFW_:/vtd_lg_incoming: Legs [7097 ]
041635: .Sep 2 17:30:29: //7097//Tcl :/tcl_parseCallID_vartagObj: VARTAG Translation Leg Count=1
041636: .Sep 2 17:30:29: //7097//PACK:/Media_Play_Start:
2. 041637: .Sep 2 17:30:42: //7097//TCL :/tcl_PlayToneObjCmd: playtone leg_incoming tn_ringback
041638: .Sep 2 17:30:42: //7097//AFW_:/vtd_lg_incoming: argc 3
041639: .Sep 2 17:30:42: //7097//AFW_:/vtd_lg_incoming: Legs [7097 ]
041640: .Sep 2 17:30:42: //7097//Tcl :/tcl_parseCallID_vartagObj: VARTAG Translation Leg Count=1
debug voice application media state
1. 041840: .Sep 2 17:35:15: //-1//DPM :DP90:/pc_mc_addToDynamicS: (1) flash:ivr.au
041841: .Sep 2 17:35:15: //-1//DPM :DP90:/pc_mc_addToDynamicS: Doing : flash:ivr.au
041842: .Sep 2 17:35:15: //-1//DPM :/mcTokenizerGetNext: savedcharptr=f endptrptr=flash:ivr.au
041843: .Sep 2 17:35:15: //-1//DPM :DP90:/pc_mc_addToDynamicS: Token : flash:ivr.au status 1
041844: .Sep 2 17:35:15: //-1//DPM :DP90:/pc_mc_addToDynamicS: du_IsNameURL() return TRUE
041845: .Sep 2 17:35:15: //-1//DPM :DP90:/dp_mcDQfromURL: file=flash:ivr.au
041846: .Sep 2 17:35:15: //-1//MCM :/mc_createFromFileUrl: Getting a media content: name=ivr.au
url=flash:ivr.au
load fast, fetchtimeout=-1
041847: .Sep 2 17:35:15: //-1//MCM :MC8:/mc_getFromUrlName: ivr.au on ram
041848: .Sep 2 17:35:15: //-1//MCM :/mc_createFromFileUrl: Found a good mc (0x4BD32204), RefCount(1)
041849: .Sep 2 17:35:15: //-1//DPM :DP90:/dp_mcDQfromURL: mc_createFromFileUrl OK
041850: .Sep 2 17:35:15: //-1//DPM :/mcTokenizerGetNext: savedcharptr= endptrptr=
041851: .Sep 2 17:35:15: //7110//MSW :/msw_create: cbf=0x42644A04
041852: .Sep 2 17:35:15: //-1//MSM :MS103:/ms_create: Iniz ply_timer
041853: .Sep 2 17:35:15: //7110//MSW :/msw_synth_open: mediaStream 0x4BCED720 created
041854: .Sep 2 17:35:15: //7110//MSW :/msw_synth_open: rtspStream 0x487F0F5C created,
status=RTSP_STATUS_SUCCESS, session_id=0x67 (103)
041855: .Sep 2 17:35:15: //7110//MSW :/msw_synth_open: AIS : Creating TTS AIS Backend record
041856: .Sep 2 17:35:15: //-1//MSM :MS104:/ms_create: Iniz ply_timer
041857: .Sep 2 17:35:15: //7110//MSW :/msw_recrd_open:
041858: .Sep 2 17:35:15: :msw_recrd_open mediaStream 0x4B16CB84 created
041859: .Sep 2 17:35:15: //7110//MSW :/msw_recrd_open: rtspStream 0x487F0F64 created,
status=RTSP_STATUS_SUCCESS, session_id=0x68 (104)
041860: .Sep 2 17:35:15: //7110//MSW :/msw_recog_open: AIS : Creating ASR AIS Backend record
041861: .Sep 2 17:35:15: //-1//MSW :/msw_associate_call:
041862: .Sep 2 17:35:15: msw_associate_call: callID=0x1BC6(7110),
genericStream=0x487DF2C8
041863: .Sep 2 17:35:15: //7110//MSW :/msw_synth_get_stream_state: genericStream 0x487DF2C8 is in state MSW_S_IDLE
041864: .Sep 2 17:35:15: //-1//MSW :/msw_synth_start:
041865: .Sep 2 17:35:15: msw_synth_start: Enter...
041866: .Sep 2 17:35:15: //7110//MSW :/msw_synth_start: current_stream_id=1, content 0x0, dynamicS 0x4BBFDA24, current_state=MSW_S_IDLE
041867: .Sep 2 17:35:15: //-1//MSW :/msw_synth_start: msw_synth_start: p_mcDynamicS, We've been given a list of URLs to play.
041868: .Sep 2 17:35:15: //-1//MSW :/msw_synth_start: p_mcDynamicQ is NOT empty
041869: .Sep 2 17:35:15: //7110//MSW :/msu_synth_partial_play: Media Stream URL
041870: .Sep 2 17:35:15: //7110//MSM :LP:MS103:/ms_associateDone:
041871: .Sep 2 17:35:15: //7110//MSM :/ms_asDone_buginf: callID=0x1BC6, pVdb=0x487C064C,
disposition=0, playFunc=0x43545E58,
codec=0x5=g711ulaw, vad=0,
mediaType=3, streamAssocID=7111
041872: .Sep 2 17:35:15: //7110//MSM :/ms_associateDone: Setting initial seqnum=7498 for the call
041873: .Sep 2 17:35:15: //-1//MCM :MR89:/mc_setup_reader_encaps: SSRC: 0x1 SeqNum: 0x1D4A
041874: .Sep 2 17:35:15: //7110//MSM :/ms_associateDone: First Buf Play at 4d10h of ivr.au
041875: .Sep 2 17:35:15: //7110//MSM :/ms_associateDone: 4d10h, Tstart(ply: iSndDly 0)
041876: .Sep 2 17:35:15: //7110//MSM :/ms_handle_stream_timer: >>ms_start_play()
041877: .Sep 2 17:35:15: //7110//MSM :/ms_start_play: 4d10h mgdTstop(ply)
2. 041878: .Sep 2 17:35:29: //7110//MSM :/ms_stop_play: mgdTstop at 4d10h (cause MS_STOP_COMPLETE)
041879: .Sep 2 17:35:29: //7110//MSM :/ms_stop_play: Play Stopped at 4d10h
041880: .Sep 2 17:35:29: //7110//MSM :/ms_stop_play: calling CBF for stream_id 1
041881: .Sep 2 17:35:29: //7110//MSW :/msu_synth_ms_play_complete: context=0x487DF2CC, use_dynamic=1, dynamicElement=0x0,
cause=MS_STOP_COMPLETE, stream_id=1, duration=13243, rate=0 proto_code=0
041882: .Sep 2 17:35:29: //7110//MSW :/msu_call_app: app_cbf=0x42644A04
Event = MSW_EV_SYNTHESIZER(1), Context 0x4BF7BB0C, Type MSW_SYNTH_TYPE_SYNTHESIZE(2), Reason MSW_SYNTH_REASON_GENERIC_SUCCESS(17)
041883: .Sep 2 17:35:29: //-1//MSW :/msw_mediadone_stats:
041884: .Sep 2 17:35:29: //-1//MCM :MC8:/mc_delete: mc=0x4BD32204
041885: .Sep 2 17:35:29: //-1//MCM :MC8:/mc_check_background_load: mc(0x4BD32204), mc->eof=1
041886: .Sep 2 17:35:29: //-1//MSW :/msw_synth_start:
041887: .Sep 2 17:35:29: msw_synth_start: Enter...
041888: .Sep 2 17:35:29: //7110//MSW :/msw_synth_start: current_stream_id=2, content 0x4BB0EC7C, dynamicS 0x0, current_state=MSW_S_IDLE
041889: .Sep 2 17:35:29: //7110//MSW :/msu_synth_partial_play: Media Stream URL
041890: .Sep 2 17:35:29: //7110//MSM :LP:MS103:/ms_associateDone:
041891: .Sep 2 17:35:29: //7110//MSM :/ms_asDone_buginf: callID=0x1BC6, pVdb=0x487C064C,
disposition=0, playFunc=0x43545E58,
codec=0x5=g711ulaw, vad=0,
mediaType=3, streamAssocID=7111
041892: .Sep 2 17:35:29: //-1//MCM :MR90:/mc_setup_reader_encaps: SSRC: 0x1 SeqNum: 0x1FE0
041893: .Sep 2 17:35:29: //7110//MSM :/ms_associateDone: First Buf Play at 4d10h of tone://US_g711u_tone_ringback
041894: .Sep 2 17:35:29: //7110//MSM :/ms_associateDone: 4d10h, Tstart(ply: iSndDly 0)
041895: .Sep 2 17:35:29: //7110//MSM :/ms_handle_stream_timer: >>ms_start_play()
041896: .Sep 2 17:35:29: //7110//MSM :/ms_start_play: 4d10h mgdTstop(ply)
debug voice application errors
041949: .Sep 2 17:39:29: //-1//PACK:/Media_LangCode_GetByIndex: Unable to retrieve language element with index 1
Но не думаю, что проблема с этим языком.
Быть может дело и не в скрипте (как я уже говорил - он сейчас работает на pots dial-peer)
Подскажите в чём может быть проблема и где смотреть.
Спасибо заранее!