Channel State¶
A channel's state reflects the current state of the path of communication between Asterisk and a device. What state a channel is in also affects what operations are allowed on it and/or how certain operations will affect a device.
While there are many states a channel can be in, the following are the most common:
- Down - a path of communication exists or used to exist between Asterisk and the device, but no media can flow between the two.
- Ringing - the device is ringing. Media may or may not be able to flow from Asterisk to the device.
- Up - the device has been answered. When in the up state, media can flow bidirectionally between Asterisk and the device.
Note
Certain channel technologies, such as DAHDI analog channels, may have additional channel states (such as "Pre-ring" or "Dialing Offhook"). When handling channel state, consult the Channel data model for all possible values.
Indicating Ringing¶
Asterisk can inform a device that it should start playing a ringing tone back to the caller using the POST /channels/{channel_id}/ring
operation. Likewise, ringing can be stopped using the DELETE /channels/{channel_id}/ring
operation. Note that indicating ringing typically does not actually transmit media from Asterisk to the device in question - Asterisk merely signals the device to ring. It is up to the device itself to actually play something back for the user.
Answering a Channel¶
When a channel isn't answered, Asterisk has typically not yet informed the device how it will communicate with it. Answering a channel will cause Asterisk to complete the path of communication, such that media flows bi-directionally between the device and Asterisk.
You can answer a channel using the POST /channels/{channel_id}/answer
operation.
Hanging up a channel¶
You can hang up a channel using the DELETE /channels/{channel_id}
operation. When this occurs, the path of communication between Asterisk and the device is terminated, and the channel will leave the Stasis application. Your application will be notified of this via a StasisEnd event.
The same is true if the device initiates the hang up. In the same fashion, the path of communication between Asterisk and the device is terminated, the channel is hung up, and your application is informed that the channel is leaving your application via a StasisEnd event.
Generally, once a channel leaves your application, you won't receive any more events about the channel. There are times, however, when you may be subscribed to all events coming from a channel - regardless if that channel is in your application or not. In that case, a ChannelDestroyed event will inform you when the channel is well and truly dead.
Example: Manipulating Channel State¶
For this example, we're going to write an ARI application that will do the following:
- Wait for a channel to enter its Stasis application.
- When a channel enters its Stasis application, it will indicate ringing to the channel. If the channel wasn't already ringing, it will now!
- After a few seconds, it will answer the channel.
- Once the channel is answered, we'll start silence on the channel so that the user feels a comfortable whishing noise. Then, after a few more seconds, we'll hangup the channel.
- If at any point in time the phone hangs up first, we'll gracefully handle that.
Dialplan¶
For this example, we need to just drop the channel into Stasis, specifying our application:
extensions.conf
Python¶
This example will use the ari-py library. The basic structure is very similar to the channel-dump Python example - see that example for more information on the basics of setting up an ARI connection using this library.
To start, once our ARI client has been set up, we will want to register handlers for three different events - StasisStart
, ChannelStateChange
, and StasisEnd
.
- The bulk of the work will be done in
StasisStart
, which is called when the channel enters our application. For the most part, this will involve setting up Python timers to initiate actions on the channel. - The
ChannelStateChange
handler will merely print out the channel state changes for us, which is informative as it will tell us when the channel is answered. - Finally, the
StasisEnd
event will clean up for us by cancelling any pending timers that we initiated. This will get called when the channel leaves our application - which will happen when the user hangs up the channel, or when we hang up the channel.
We can store the timers that we've set up for a channel using a dictionary of channel IDs to timer instances:
And we can register for our three events:
The StasisStart
event is the most interesting part.
- First, we tell the channel to ring, and after two seconds, to answer the channel:
If we didn't have that there, then the caller would probably just have dead space to listen to! Not very enjoyable. We store the timer in the channel_timers
dictionary so that our StasisEnd
event can cancel it for us if the user hangs up the phone. 2. Once we're in the answer_channel
handler, we answer the channel and start silence on the channel. That (hopefully) gives them a slightly more ambient silence noise. Note that we'll go ahead and declare answer_channel
as a nested function inside our StasisStart
handler, stasis_start_cb
:
hangup_channel
. This does the final action on the channel by hanging it up. Again, we'll declare hangup_channel
as a nested function inside our StasisStart
handler: channel_timers
dictionary. In our StasisEnd
event handler, we'll want to cancel any pending timers. Otherwise, our timers may fire and try to perform an action on channel that has already left our Stasis application, which is a good way to get an HTTP error response code. Finally, we want to print out the state of the channel in the ChannelStateChanged
handler. This will tell us exactly when our channel has been answered:
channel-state.py¶
The full source code for channel-state.py
is shown below:
channel-state.py in action¶
Here, we see the output from the channel-state.py
script when a PJSIP channel for endpoint 'alice' enters into the application:
Channel PJSIP/alice-00000001 has entered the application
Answering channel PJSIP/alice-00000001
Channel PJSIP/alice-00000001 is now: Up
Hanging up channel PJSIP/alice-00000001
Channel PJSIP/alice-00000001 just left our application
JavaScript (Node.js)¶
This example will use the ari-client library.
To start, once our ARI client has been set up, we will want to register callbakcs for three different events - StasisStart
, ChannelStateChange
, and StasisEnd
.
- The bulk of the work will be done in
StasisStart
, which is called when the channel enters our application. For the most part, this will involve setting up JavaScript timeouts to initiate actions on the channel. - The
ChannelStateChange
handler will merely print out the channel state changes for us, which is informative as it will tell us when the channel is answered. - Finally, the
StasisEnd
event will clean up for us by cancelling any pending timeouts that we initiated. This will get called when the channel leaves our application - which will happen when the user hangs up the channel, or when we hang up the channel.
We can store the timeouts that we've set up for a channel using an object of channel IDs to timer instances:
And we can register for our three events:
The StasisStart
event is the most interesting part.
- First, we tell the channel to ring, and after two seconds, to answer the channel:
If we didn't have that there, then the caller would probably just have dead space to listen to! Not very enjoyable. We store the timer in the timers
object so that our StasisEnd
event can cancel it for us if the user hangs up the phone. 2. Once we're in the answer
callback, we answer the channel and start silence on the channel. That (hopefully) gives them a slightly more ambient silence noise:
the hangup callback
. This does the final action on the channel by hanging it up: timers
object. In our StasisEnd
event handler, we'll want to cancel any pending timers. Otherwise, our timers may fire and try to perform an action on channel that has already left our Stasis application, which is a good way to get an HTTP error response code. Finally, we want to print out the state of the channel in the ChannelStateChanged
callback. This will tell us exactly when our channel has been answered:
channel-state.js¶
The full source code for channel-state.js
is shown below:
channel-state.js in action¶
Here, we see the output from the channel-state.js
script when a PJSIP channel for endpoint 'alice' enters into the application: