I am going to implement my Asterisk CTI class using the Asterisk REST Interface (ARI). The CTI class has different class objects, for example, a reactor object for websocket event notification, a websocket event handler object for receiving of Asterisk telephony events, a thread with a circular buffer to handle the telephony events, also a thread pool to deliver each telephony event to the calling application.
To get telephony events notification from Asterisk, we need to subscribe endpoint eventsource first. For testing #1, I have setup two extensions 1000 and 1002 in FreePBX, I subscribed evens for the two extensions using my class. I dialed 1002 from 1000, answered the call then hangup the call. I found a lot of events were generated from Asterisk and it seems there is no way to filter the number events from Asterisk. So I wrote a function to filter some unwanted events and remained the following events that are useful in my class
- ChannelCreated
- ChannelConnectedLine
- ChannelDestroyed
- ChannelStateChange
- ChannelHold
- ChannelUnhold
- ChannelTalkingStarted
- ChannelTalkingFinished
- ChannelEnteredBridge
- ChannelLeftBridge
After the filtering applied, the following events in blue are for extension 1000, while the events in red are for extension 1002.
{ “type”: “ChannelCreated”, “timestamp”: “2015-11-02T22:28:38.776+0800”, “channel”: { “id”: “1446474518.30”, “name”: “PJSIP/1000-00000006”, “state”: “Ring”, “caller”: { “name”: “device”, “number”: “1000” }, “connected”: { “name”: “”, “number”: “” }, “accountcode”: “”, “dialplan”: { “context”: “from-internal”, “exten”: “1002”, “priority”: 1 }, “creationtime”: “2015-11-02T22:28:38.774+0800”, “language”: “en” }, “application”: “goanswer” }
{ “type”: “ChannelConnectedLine”, “timestamp”: “2015-11-02T22:28:38.862+0800”, “channel”: { “id”: “1446474518.30”, “name”: “PJSIP/1000-00000006”, “state”: “Ring”, “caller”: { “name”: “Kai”, “number”: “1000” }, “connected”: { “name”: “Ping”, “number”: “” }, “accountcode”: “”, “dialplan”: { “context”: “macro-dial-one”, “exten”: “s”, “priority”: 40 }, “creationtime”: “2015-11-02T22:28:38.774+0800”, “language”: “en” }, “application”: “goanswer” }
{ “type”: “ChannelCreated”, “timestamp”: “2015-11-02T22:28:38.864+0800”, “channel”: { “id”: “1446474518.32”, “name”: “PJSIP/1002-00000007”, “state”: “Down”, “caller”: { “name”: “device”, “number”: “1002” }, “connected”: { “name”: “”, “number”: “” }, “accountcode”: “”, “dialplan”: { “context”: “from-internal”, “exten”: “s”, “priority”: 1 }, “creationtime”: “2015-11-02T22:28:38.864+0800”, “language”: “en” }, “application”: “goanswer” }
{ “type”: “ChannelConnectedLine”, “timestamp”: “2015-11-02T22:28:38.862+0800”, “channel”: { “id”: “1446474518.30”, “name”: “PJSIP/1000-00000006”, “state”: “Ring”, “caller”: { “name”: “Kai”, “number”: “1000” }, “connected”: { “name”: “Ping”, “number”: “1002” }, “accountcode”: “”, “dialplan”: { “context”: “macro-dial-one”, “exten”: “s”, “priority”: 41 }, “creationtime”: “2015-11-02T22:28:38.774+0800”, “language”: “en” }, “application”: “goanswer” }
{ “type”: “ChannelConnectedLine”, “timestamp”: “2015-11-02T22:28:38.865+0800”, “channel”: { “id”: “1446474518.32”, “name”: “PJSIP/1002-00000007”, “state”: “Down”, “caller”: { “name”: “device”, “number”: “1002” }, “connected”: { “name”: “Kai”, “number”: “1000” }, “accountcode”: “”, “dialplan”: { “context”: “from-internal”, “exten”: “1002”, “priority”: 1 }, “creationtime”: “2015-11-02T22:28:38.864+0800”, “language”: “en” }, “application”: “goanswer” }
{ “type”: “ChannelStateChange”, “timestamp”: “2015-11-02T22:28:39.027+0800”, “channel”: { “id”: “1446474518.32”, “name”: “PJSIP/1002-00000007”, “state”: “Ringing”, “caller”: { “name”: “device”, “number”: “1002” }, “connected”: { “name”: “Kai”, “number”: “1000” }, “accountcode”: “”, “dialplan”: { “context”: “from-internal”, “exten”: “1002”, “priority”: 1 }, “creationtime”: “2015-11-02T22:28:38.864+0800”, “language”: “en” }, “application”: “goanswer” }
{ “type”: “ChannelStateChange”, “timestamp”: “2015-11-02T22:28:45.637+0800”, “channel”: { “id”: “1446474518.32”, “name”: “PJSIP/1002-00000007”, “state”: “Up”, “caller”: { “name”: “device”, “number”: “1002” }, “connected”: { “name”: “Kai”, “number”: “1000” }, “accountcode”: “”, “dialplan”: { “context”: “from-internal”, “exten”: “1002”, “priority”: 1 }, “creationtime”: “2015-11-02T22:28:38.864+0800”, “language”: “en” }, “application”: “goanswer” }
{ “type”: “ChannelStateChange”, “timestamp”: “2015-11-02T22:28:45.637+0800”, “channel”: { “id”: “1446474518.30”, “name”: “PJSIP/1000-00000006”, “state”: “Up”, “caller”: { “name”: “Kai”, “number”: “1000” }, “connected”: { “name”: “Ping”, “number”: “1002” }, “accountcode”: “”, “dialplan”: { “context”: “macro-dial-one”, “exten”: “s”, “priority”: 44 }, “creationtime”: “2015-11-02T22:28:38.774+0800”, “language”: “en” }, “application”: “goanswer” }
{ “type”: “ChannelDestroyed”, “timestamp”: “2015-11-02T22:28:50.080+0800”, “cause”: 16, “cause_txt”: “Normal Clearing”, “channel”: { “id”: “1446474518.30”, “name”: “PJSIP/1000-00000006”, “state”: “Up”, “caller”: { “name”: “Kai”, “number”: “1000” }, “connected”: { “name”: “Ping”, “number”: “1002” }, “accountcode”: “”, “dialplan”: { “context”: “from-internal”, “exten”: “h”, “priority”: 1 }, “creationtime”: “2015-11-02T22:28:38.774+0800”, “language”: “en” }, “application”: “goanswer” }
{ “type”: “ChannelDestroyed”, “timestamp”: “2015-11-02T22:28:50.082+0800”, “cause”: 16, “cause_txt”: “Normal Clearing”, “channel”: { “id”: “1446474518.32”, “name”: “PJSIP/1002-00000007”, “state”: “Up”, “caller”: { “name”: “device”, “number”: “1002” }, “connected”: { “name”: “Kai”, “number”: “1000” }, “accountcode”: “”, “dialplan”: { “context”: “from-internal”, “exten”: “”, “priority”: 1 }, “creationtime”: “2015-11-02T22:28:38.864+0800”, “language”: “en” }, “application”: “goanswer” }
For testing #2, I used three extensions, they are 1000, 1002 and 1006. I initiated a call from 1000 to 1002, answered the call by 1002, then initiated another from 1000 to 1006, answered the call by 1006, the last step transferred the call by 1000, leaving 1002 and 1006 in a call, then ended the call by 1002 finally. The text file is here.
For testing #3, I used three extensions, they are 1000, 1002 and 1006. I initiated a call from 1000 to 1002, answered the call by 1002, then initiated another from 1000 to 1006, answered the call by 1006, the last step conference the call by 1000, and finally hangup the call by 1002. The text file is here.
Next step I will add call control functions such as Originate, Hold, Retrieve, Transfer and Conference, etc. After the implementation of the CTI class, I will port my tools such as ScreenPop, ivrSVR to support Asterisk. Good luck to me.
hi, if we had 1000 extensions should we write each ext dial plan? so it should write 1000 dial plan?
No need to write any dial plan. The Asterisk CTI server now supports monitoring events only.
what event name should we subscribe to get monitoring event ?
by default AstCTI does not specify event, it monitors all events.
sorry i want build screen pop to CRM from asterisk
the issue is i’m confuse how to get all event from asterisk , i tried configured extensions.conf using Statis but i just got json event when direct call to extension but when using IVR goes to queue i didnt got anything
By default Queue App is not entered into Statis, so you can’t get the events.
so i should create my own ACD ?
Yes and you should create your ACD in the Statis application and it is very difficult.