| CCXML Voxeo 1.0 Development Guide | Home | Frameset Home |
| duplex | Data Type: STRING | Default: full |
| This attribute denotes whether parties in the conference will be able to hear the joining party. This attribute is useful for implementing an 'eavesdropping' functionality in a conferenced call. If 'half' is specified as the value, then the joined party will not be able to be heard by the rest of the parties in the conference. If set to 'full' then all parties will be able to hear the joined party. If not specified, this attribute defaults to 'full'. | ||
| id1 | Data Type: (ECMAScript Expression) | Default: none - attribute is required |
| This attribute indicates the first of the call leg identifiers or conference objects to <join> together in a conference. | ||
| id2 | Data Type: (ECMAScript Expression) | Default: none - attribute is required |
| This attribute indicates the second of two call leg identifiers or conference objects to <join> together in a conference. If both audio endpoints are call legs, then the interpreter will inherently be bridged together. However, if we have a call leg attempting to connect to a conference, (or vice-versa), then the call leg will be added into the conference automatically. Note that in the Voxeo implementation, two separate conferences maynot join together. | ||
| voxeo-entertone | Data Type: (true|false) | Default: Optional |
The voxeo-entertone is used to play a tone or custom wav file to the conference particapents when another caller joins. Setting this to 'true' will play the default system beep, while setting it to 'false' will result in no alerting sound being played at all. The developer may also specfy a URL value that points to a user-defined wav file to be played instead of the default system beep. Note that this URL has a limitation of 250 characters maximum. | ||
| voxeo-exittone | Data Type: (true|false) | Default: Optional |
The voxeo-exittone is used to play a tone or custom wav file to the conference particapents when another caller exits. Setting this to 'true' will play the default system beep, while setting it to 'false' will result in no alerting sound being played at all. The developer may also specfy a URL value that points to a user-defined wav file to be played instead of the default system beep. Note that this URL has a limitation of 250 characters maximum. | ||
| voxeo-termdigits | Data Type: CDATA | Default: Optional |
The voxeo-termdigits attribute extension has been added to allow a user a method of disconnecting from a conference without hanging up the call. The value of this attribute specifies which DTMF key will disconnect the caller and return to the CCXML application:Note that specifying a value of '@' will allow any dtmf key to be pressed to exit from the conference. | ||
| <?xml version="1.0" encoding="UTF-8"?> <ccxml version="1.0"> <eventhandler statevariable="state0"> <transition state="'init'" event="connection.CONNECTION_ALERTING" name="evt"> <var name="line_0" expr="evt.callid"/> <createconference name="smallConf"/> </transition> <transition state="'init'" event="ccxml.conference.created"> <assign name="state0" expr="'docalls'"/> <accept callid="line_0"/> <createcall dest="'4078351111'" name="line_1"/> <createcall dest="'4078351112'" name="line_2"/> <createcall dest="'4078351113'" name="line_3"/> </transition> <transition event="connection.CONNECTION_CONNECTED" name="evt"> <join sessionid1="evt.callid" sessionid2="smallConf"/> </transition> <transition event="ccxml.conference.joined" name="evt"> <log expr="'---- call leg ' + evt.callid + ' has joined the conference ----'"/> </transition> <transition event="ccxml.conference.unjoined" name="evt"> <log expr="'---- call leg ' + evt.callid + ' has unjoined the conference ----'"/> </transition> <transition event="call.CALL_INVALID" name="evt"> <if cond="evt.callid == line_0"> <destroyconference conferenceid="smallConf"/> <assign name="state0" expr="'conferencedestroyed'"/> </if> </transition> <transition event="ccxml.conference.destroyed"> <exit/> </transition> <transition state="'docalls'" event="error.*" name="evt"> <destroyconference conferenceid="smallConf"/> <exit/> </transition> <transition event="error.*" name="evt"> <log expr="'---- an error has occurred (' + evt.error + ') ----'"/> <exit/> </transition> </eventhandler> </ccxml> |
| <?xml version="1.0" encoding="UTF-8"?> <ccxml version="1.0"> <eventhandler statevariable="state0"> <transition state="'init'" event="connection.CONNECTION_ALERTING" name="evt"> <var name="line_0" expr="evt.callid"/> <createconference name="smallConf"/> </transition> <transition state="'init'" event="ccxml.conference.created"> <assign name="state0" expr="'docalls'"/> <accept callid="line_0"/> <createcall dest="'4078351111'" name="line_1"/> <createcall dest="'4078351112'" name="line_2"/> <createcall dest="'4078351113'" name="line_3"/> </transition> <transition event="connection.CONNECTION_CONNECTED" name="evt"> <join sessionid1="evt.callid" sessionid2="smallConf" voxeo-termdigits="'#'" voxeo-entertone="true" voxeo-exittone="true"/> </transition> <transition event="ccxml.conference.joined" name="evt"> <log expr="'---- call leg ' + evt.callid + ' has joined the conference ----'"/> </transition> <transition event="ccxml.conference.unjoined" name="evt"> <log expr="'---- call leg ' + evt.callid + ' has unjoined the conference ----'"/> <log expr="'---- TERMDIGIT PRESSED WAS: ' + evt.termdigit + ' ----'" /> </transition> <transition event="call.CALL_INVALID" name="evt"> <if cond="evt.callid == line_0"> <destroyconference conferenceid="smallConf"/> <assign name="state0" expr="'conferencedestroyed'"/> </if> </transition> <transition event="ccxml.conference.destroyed"> <exit/> </transition> <transition state="'docalls'" event="error.*" name="evt"> <destroyconference conferenceid="smallConf"/> <exit/> </transition> <transition event="error.*" name="evt"> <log expr="'---- an error has occurred (' + evt.error + ') ----'"/> <exit/> </transition> </eventhandler> </ccxml> |
| ANNOTATIONS: EXISTING POSTS |
bpcamac
|
|
| The voxeo extensions (termdigit, etc) of this command only work when a call leg is joined to a conference, and not when two call legs are joined together directly.
Is this the intended behavior for the extensions? To work only with conference objects? I know I can workaround this problem by creating a conference object and joining the calls to it, but that complicates the control state of my app. So I thought I would ask here first to see if this situation might be rectified in the future. Thx. |
|
mikethompson
|
|
| Hey there,
This is currently intended behavior. What exactly are you trying to accomplish with these legs? What is the reason for the un-joining of these legs? With a bit more information, we may be able to help you out in this regard. Regards, Mike Thompson Voxeo Extreme Support |
|
bpcamac
|
|
| Specifically, I was hoping to use the voxeo-termdigit extension to allow a call participant (on a two party call) to disconnect from the call without hanging up. The application would then present them a menu via a dialog (VXML), and the possibility of rejoining the call. This is conceptually the same as if they were involved in a conference, but in this case the conference has only two participants. And that is why I was surprised when I discovered that the extensions didn't work under this special case.
As I mentioned, I can simulate the behavior I'm looking for by creating a conference of two participants, but this seems to be overkill which is why I thought I would ask. rgds, Brenton |
|
Michael.Book
|
|
| Hi Brenton,
I might be able to add some insight here... A straight two party <join> is really intended for the most basic of bridged call situations - userA wants to call userB. In these situations, it would not be uncommon that userA be required to enter an extension number and/or navigate an office PBX system via DTMF tones. Thus, DTMF tones must be passed through. Disallowing or reserving one or more DTMF key presses for special functions, like terminating the bridge, would effectively cripple userA and/or produce unexpected results. For example, let's say your CCXML application reserves DTMF-pound to terminate the two party bridge: - userA initiates a call to userB's work phone. - userB's office PBX answers and prompts userA to enter an extension number or press the pound key for the employee directory. - userA presses pound and is seemingly disconnected from the call. - userA, confused by the apparent disconnect, tries the call two more time with the same result. - userA curses your shiny new CCXML application, hangs up, and promptly calls your tech-support team unleashing his/her furry on the poor, unlucky sap that answers. It's easy to see the possible problems associated with this type of application logic; unless, of course, you hate your tech-support employees. :-p Now let's consider n-party conference bridging situations. In general, these solutions do not pass DTMF tones through, as the whole conference doesn't need to hear a key press by any one user, whether it be to activate a feature/funtion (e.g. unjoining, muting, etc.) or if it was simply by mistake. We also don't generally see situations whereas an in-progress conference of "n" participants needs the ability to enter an extension number or navigate a PBX system. So, understanding now why the <join> works the way it does is fine and all, but what if your application needs are simply outside of the norm? - Ah, yes... It is at these moments, as angel trumpets begin to play, you will fall in love with CCXML for the first time, or all over again... Check out this little gem: **Link to this CCXML file with all needed .wav files: http://docs.voxeo.com/opensource/ccxml_conf_passing_DTMF.zip _________________________ <?xml version="1.0" encoding="UTF-8" ?> <ccxml version="1.0"> <!-- *** Be sure to set your 'audioPath' and 'num2call' vars *** --> <var name="audioPath" expr="'http://myserver.com/audio/'"/> <var name="num2call" expr="'1234567890'"/> <!-- Declare call-leg and dialog name vars... --> <var name="call_0"/> <var name="call_1"/> <var name="myConf"/> <var name="getCtrlChar_Dlg"/> <var name="finished_Dlg"/> <!-- Declare app vars... --> <var name="toneVar"/> <var name="call2join"/> <var name="state0" expr="'init'"/> <eventhandler statevariable="state0"> <transition state="'init'" event="connection.CONNECTION_ALERTING" name="evt"> <assign name="state0" expr="'inProgress'"/> <log expr="' *** INCOMING CALL *** '"/> <assign name="call_0" expr="evt.callid"/> <log expr="' *** CREATE LOCAL CONF *** '"/> <createconference id="myConf"/> </transition> <transition event="ccxml.conference.created" name="evt"> <log expr="' *** CONFERENCE CREATED - CONF ID: [' + myConf + ']'" /> <log expr="' *** MAKE OUTBOUND CALL *** '"/> <createcall dest="'tel:+1' + num2call" name="call_1"/> <log expr="' *** ACCEPT INCOMING CALL *** '"/> <accept callid="call_0"/> </transition> <transition event="connection.CONNECTION_FAILED" name="evt"> <log expr="' *** OUTBOUND CALL FAILED - ERROR: [' + evt.error + '] *** '"/> <exit/> </transition> <transition event="connection.CONNECTION_CONNECTED" name="evt"> <log expr="' *** CALL CONNECTED - CALL ID: [' + evt.callid + '] *** '"/> <assign name="toneVar" expr="'false'"/> <assign name="call2join" expr="evt.callid"/> <!-- We will send 'call2join' and 'toneVar', as they are at this moment, in the <send> namelist. This will prevent a race condition when working with muliple call legs. --> <send target="session.id" event="'joinConf'" namelist="toneVar call2join"/> </transition> <transition event="user.joinConf" name="evt"> <log expr="' *** JOIN CONF - ALLOW ANY TERMDIGIT *** '"/> <log expr="' *** CALL TO JOIN: [' + evt.call2join + '] *** '"/> <log expr="' *** ENTERTONE: [' + evt.toneVar + '] ***'"/> <!-- Here we use the 'evt.call2join' and 'evt.toneVar' to assure we are joining the call associated with this specific joinConf event, NOT the current value of 'call2join' and 'toneVar'. This will prevent a race condition when working with muliple call legs. --> <join id1="evt.call2join" id2="myConf" voxeo-termdigits="'@'" voxeo-entertone="evt.toneVar" voxeo-exittone="false"/> </transition> <transition event="ccxml.conference.unjoined" name="evt"> <log expr="' *** CALL UNJOINED THE CONF - CALL ID: [' + evt.callid + '] *** '"/> <log expr="' *** TERMDIGIT PRESSED WAS: [' + evt.termdigit + '] *** '" /> <if cond="evt.termdigit == '#'"> <log expr="' *** CONTROL KEY ENTERED - ALLOW 1s TO ENTER ADDITIONAL INSTRUCTION KEY *** '"/> <dialogstart src="audioPath + 'silence.wav?termdigits=0123456789#*&maxtime=1000'" type="'application/x-fetchdigits'" dialogid="getCtrlChar_Dlg" callid="evt.callid"/> <elseif cond="evt.termdigit == '*'"/> <assign name="toneVar" expr="audioPath + 'dtmf-star.wav'"/> <send target="session.id" event="'joinConf.params_' + evt.callid + ',' + toneVar"/> <else/> <assign name="toneVar" expr="audioPath + 'dtmf-' + evt.termdigit + '.wav'"/> <assign name="call2join" expr="evt.callid"/> <send target="session.id" event="'joinConf'" namelist="toneVar call2join"/> </if> </transition> <transition event="error.dialog.notstarted" name="evt"> <log expr="' *** USER DID NOT ENTER ADDITIONAL INSTRUCTION KEY *** '"/> <assign name="toneVar" expr="audioPath + 'dtmf-pound.wav'"/> <assign name="call2join" expr="evt.callid"/> <send target="session.id" event="'joinConf'" namelist="toneVar call2join"/> </transition> <transition state="'inProgress'" event="dialog.exit" name="evt"> <log expr="' *** USER ENTERED ADDITIONAL INSTRUCTION KEY ENTERED: [' + evt.termdigit + '] *** '"/> <assign name="state0" expr="'finished'"/> <dialogstart src="'null://?text=You pressed pound followed by the ' + evt.termdigit + ' key.'" type="'audio/wav'" dialogid="finished_Dlg" callid="call_0"/> </transition> <transition state="'finished'" event="dialog.exit" name="evt"> <log expr="'*** POINT PROVEN - EXITING ***'"/> <exit/> </transition> <transition event="call.CALL_INVALID" name="evt"> <!-- For this test I will just exit. --> <exit/> </transition> <transition event="error.*" name="evt"> <log expr="' *** AN ERROR HAS OCCURRED: [' + evt.error + '] *** '"/> <exit/> </transition> <!-- I like to include a kill event in all my CCXML applications. If I accidentally start a looping application, I can kill it via CCXML's external send function: http://session.voxeo.net/CCXML.send?sessionid=[sessionID]&eventname=[event] --> <transition event="user.kill" name="evt"> <log expr="' *** KILL EVENT - EXITING *** '"/> <exit/> </transition> </eventhandler> </ccxml> _________________________ Here we are creating a local conference bridge, joining both parties to that bridge with the option to terminate using any DTMF key entry. We have chosen the DTMF-pound key as our special "control" key. If a user presses any key, besides the control key (DTMF-pound), we immediately rejoin the call-leg back to the conference playing a .wav file of the corresponding DTMF tone as the 'voxeo-entertone'. This effectively passes the DTMF tone through to the other call-leg(s) in that conference. If a user presses the control key ("#"), the user will then have one second to enter a second "instruction" key-press. If the user does not enter an instruction key within one second, the call-leg will be rejoined to the conference playing 'Dtmf-pound.wav' as the 'voxeo-entertone'. Viola! And all of the conf join/unjoin actions will happen so fast, it will be seamless to the endusers... I hope this helps. Let me know if you have any questions... Have Fun, ~ Michael |
|
bpcamac
|
|
| I take your point that in some situations a 2-party call may not want dtmf tones to be interpreted by the CC platform. And consequently that the CC platform has been designed the way it is in order to prevent such situations.
However there are other examples, equally plausable, where a CC-application would desire the CC platform to be able to recognize dtmf tones, and where this behaviour wouldn't be confusing to the caller. (viz. the example I described above). Given this duality I think it would be better if the platform supported dtmf recognition in all types of calls and left it to the application developer to decide whether it is a good design decision to use it or not based upon the particular application setting it is to be used in. That said, I see this more as a convienience than anything else since I can work around the restriction as it now stands. But in either case, I applaude Voxeo for introducing this extension to the platform. Its an incredibly important peice of functionality for real world apps, and if it weren't present (in conferencing) then that would be a real deficiency. Also, thanks for the code snippet. |
|
MattHenry
|
|
|
Hiya Brendan, Glad we could help out! ~Matthew Henry |
|
Michael.Book
|
|
| >> "Given this duality I think it would be better if the platform supported dtmf recognition in all types of calls and left it to the application developer to decide whether it is a good design decision to use it or not based upon the particular application setting it is to be used in."
Hmmmm... Ya' know, that's a good point, Brenton. I think I would probably agree with you here. I have kicked this up to my Platform Engineering team as a feature request. Let us see where this takes us. :-) And thank you for the thoughts and feed-back... Very valuable! Best, ~ Michael |
|
moshe
|
|
| I can get "conference.unjoin" because of a termdigit or possibly for other reasons (e.g., some other CCXML instance unjoins the connection or destroys the conference). If the script tests for evt.termdigit when no termdigit was present, won't I get an error.semantic?
What is the proper way to distinguish between possible events that lead to conference.unjoin? |
|
voxeojeff
|
|
| Hello Moshe,
As I understand it, you are inquiring about whether or not a script testing for evt.termdigit, when no termdigit is present, would return an error.semantic. Also, you wish to know a sufficient way to distinguish between possible events leading to a conference.unjoin. Per my research, if a script is testing for evt.termdigit when no termdigit is present, it would not throw an error.semantic, but instead it would just return "undefined." Also, it is perfectly acceptable to test for the presence of evt.termdigit as a means to distinguish between possible events. If you have any other questions or comments regarding this matter, please do not hesitate to ask. Hope this helps! :-) Regards, Jeff |
| login |