Getting Started
Add asterisk-rs to your project:
[dependencies]
asterisk-rs = "0.2"
Or pick individual protocols:
[dependencies]
asterisk-rs = { version = "0.2", default-features = false, features = ["ami"] }
Or use crates directly:
[dependencies]
asterisk-rs-ami = "0.2"
Protocols
| Protocol | Port | Transport | Crate |
|---|---|---|---|
| AMI | 5038 | TCP | asterisk-rs-ami |
| AGI | 4573 | TCP (FastAGI) | asterisk-rs-agi |
| ARI | 8088 | HTTP + WebSocket | asterisk-rs-ari |
Domain Types
Common Asterisk constants are available as typed enums in asterisk_rs_core::types:
hangup causes, channel states, device states, dial statuses, and more.
See Domain Types for the full list.
Requirements
- Rust 1.83+ (for async fn in trait / RPITIT)
- tokio runtime
- A running Asterisk instance for integration
Domain Types
Typed enums for Asterisk domain constants, available in asterisk_rs_core::types.
HangupCause
Q.931/Q.850 hangup cause codes used across AMI and ARI
| Variant | Description |
|---|---|
NotDefined = 0 | not defined (code 0) |
Unallocated = 1 | unallocated number (code 1) |
NoRouteTransitNet = 2 | no route to transit network (code 2) |
NoRouteDestination = 3 | no route to destination (code 3) |
MisdialledTrunkPrefix = 5 | misdialled trunk prefix (code 5) |
ChannelUnacceptable = 6 | channel unacceptable (code 6) |
CallAwardedDelivered = 7 | call awarded and being delivered (code 7) |
PreEmpted = 8 | pre-empted (code 8) |
NumberPortedNotHere = 14 | number ported but not found here (code 14) |
NormalClearing = 16 | normal call clearing (code 16) |
UserBusy = 17 | user busy (code 17) |
NoUserResponse = 18 | no user response (code 18) |
NoAnswer = 19 | no answer from user (code 19) |
SubscriberAbsent = 20 | subscriber absent (code 20) |
CallRejected = 21 | call rejected (code 21) |
NumberChanged = 22 | number changed (code 22) |
RedirectedToNewDestination = 23 | redirected to new destination (code 23) |
AnsweredElsewhere = 26 | answered elsewhere (code 26) |
DestinationOutOfOrder = 27 | destination out of order (code 27) |
InvalidNumberFormat = 28 | invalid number format (code 28) |
FacilityRejected = 29 | facility rejected (code 29) |
ResponseToStatusEnquiry = 30 | response to status enquiry (code 30) |
NormalUnspecified = 31 | normal unspecified (code 31) |
NormalCircuitCongestion = 34 | normal circuit congestion (code 34) |
NetworkOutOfOrder = 38 | network out of order (code 38) |
NormalTemporaryFailure = 41 | normal temporary failure (code 41) |
SwitchCongestion = 42 | switch congestion (code 42) |
AccessInfoDiscarded = 43 | access information discarded (code 43) |
RequestedChanUnavail = 44 | requested channel unavailable (code 44) |
FacilityNotSubscribed = 50 | facility not subscribed (code 50) |
OutgoingCallBarred = 52 | outgoing call barred (code 52) |
IncomingCallBarred = 54 | incoming call barred (code 54) |
BearerCapabilityNotAuth = 57 | bearer capability not authorized (code 57) |
BearerCapabilityNotAvail = 58 | bearer capability not available (code 58) |
BearerCapabilityNotImpl = 65 | bearer capability not implemented (code 65) |
ChanNotImplemented = 66 | channel type not implemented (code 66) |
FacilityNotImplemented = 69 | facility not implemented (code 69) |
InvalidCallReference = 81 | invalid call reference (code 81) |
IncompatibleDestination = 88 | incompatible destination (code 88) |
InvalidMsgUnspecified = 95 | invalid message unspecified (code 95) |
MandatoryIeMissing = 96 | mandatory information element missing (code 96) |
MessageTypeNonexist = 97 | message type nonexistent (code 97) |
WrongMessage = 98 | wrong message (code 98) |
IeNonexist = 99 | information element nonexistent (code 99) |
InvalidIeContents = 100 | invalid information element contents (code 100) |
WrongCallState = 101 | wrong call state (code 101) |
RecoveryOnTimerExpire = 102 | recovery on timer expiry (code 102) |
MandatoryIeLengthError = 103 | mandatory information element length error (code 103) |
ProtocolError = 111 | protocol error (code 111) |
Interworking = 127 | interworking unspecified (code 127) |
ChannelState
channel state as reported by Asterisk
| Variant | Description |
|---|---|
Down = 0 | channel is down and available |
Reserved = 1 | channel is down, but reserved |
OffHook = 2 | channel is off hook |
Dialing = 3 | digits have been dialed |
Ring = 4 | remote end is ringing |
Ringing = 5 | local end is ringing |
Up = 6 | channel is up (answered) |
Busy = 7 | line is busy |
DialingOffhook = 8 | dialing while offhook |
PreRing = 9 | channel detected incoming call before ring |
DeviceState
device state values used in device state events and queries
| Variant | Description |
|---|---|
Unknown | state is unknown |
NotInUse | device is not in use |
InUse | device is in use |
Busy | device is busy |
Invalid | device is invalid |
Unavailable | device is unavailable |
Ringing | device is ringing |
RingInUse | device is ringing and in use |
OnHold | device is on hold |
DialStatus
result of a dial attempt, set in the DIALSTATUS channel variable
| Variant | Description |
|---|---|
Answer | call was answered |
Busy | remote end was busy |
NoAnswer | remote end did not answer |
Cancel | call was cancelled |
Congestion | congestion encountered |
ChanUnavail | channel was unavailable |
DontCall | number on do-not-call list |
Torture | number routed to torture IVR |
InvalidArgs | invalid arguments to Dial() |
Unavailable | target was unavailable |
CdrDisposition
CDR disposition values
| Variant | Description |
|---|---|
NoAnswer | call was not answered |
Answered | call was answered |
Busy | remote end was busy |
Failed | call attempt failed |
Congestion | congestion encountered |
PeerStatus
SIP/PJSIP peer registration status
| Variant | Description |
|---|---|
Registered | peer is registered |
Unregistered | peer is unregistered |
Reachable | peer is reachable |
Unreachable | peer is unreachable |
Lagged | peer response is lagged |
Rejected | peer registration was rejected |
Unknown | peer status is unknown |
QueueStrategy
queue member selection strategy
| Variant | Description |
|---|---|
RingAll | ring all available members simultaneously |
LeastRecent | ring the member least recently called |
FewestCalls | ring the member with the fewest completed calls |
Random | ring a random member |
RoundRobin | round-robin with memory |
Linear | ring members in the order listed |
WeightedRandom | ring a random member, weighted by penalty |
ExtensionState
extension hint state values
| Variant | Description |
|---|---|
Removed = -2 | not found or removed |
Idle = -1 | idle, no active calls |
InUse = 1 | in use |
Busy = 2 | busy |
Unavailable = 4 | unavailable |
Ringing = 8 | ringing |
OnHold = 16 | on hold |
AgiStatus
AGI response status codes
| Variant | Description |
|---|---|
Success = 200 | success |
InvalidCommand = 510 | invalid or unknown command |
DeadChannel = 511 | channel is dead |
EndUsage = 520 | end of proper usage for command |
AMI (Asterisk Manager Interface)
AMI is a TCP protocol on port 5038 for monitoring and controlling Asterisk. The client handles authentication, reconnection, and event dispatch automatically.
Quick Start
use asterisk_rs_ami::AmiClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = AmiClient::builder()
.host("10.0.0.1")
.credentials("admin", "secret")
.build()
.await?;
let resp = client.ping().await?;
println!("{resp:?}");
client.disconnect().await?;
Ok(())
}
Capabilities
- Typed events and actions covering the full Asterisk 23 AMI surface
- MD5 challenge-response and plaintext authentication
- Automatic reconnection with re-authentication
- Filtered subscriptions – receive only events you care about
- Event-collecting actions –
send_collecting()gathers multi-event responses - Command output capture for
Response: Follows - Configurable timeouts, backoff, and event buffer size
See Connection & Authentication for setup details, Events for the event system, and Reference for complete event/action lists.
Connection & Authentication
Builder
use asterisk_rs_ami::AmiClient;
use asterisk_rs_core::config::ReconnectPolicy;
use std::time::Duration;
let client = AmiClient::builder()
.host("10.0.0.1")
.port(5038)
.credentials("admin", "secret")
.timeout(Duration::from_secs(10))
.reconnect(ReconnectPolicy::exponential(
Duration::from_secs(1),
Duration::from_secs(30),
))
.event_capacity(2048)
.build()
.await?;
Authentication
The client tries MD5 challenge-response first, falling back to plaintext.
Authentication happens automatically during build() and after every reconnect.
Reconnection
When the TCP connection drops, the background task reconnects with exponential
backoff and re-authenticates before setting the connection state to Connected.
Policies:
ReconnectPolicy::exponential(initial, max)— doubling delay with jitterReconnectPolicy::fixed(interval)— constant delayReconnectPolicy::none()— no retry.with_max_retries(n)— cap attempts
Connection State
Monitor connection health:
use asterisk_rs_core::config::ConnectionState;
let state = client.connection_state();
match state {
ConnectionState::Connected => { /* ready */ }
ConnectionState::Reconnecting => { /* waiting */ }
_ => { /* down */ }
}
Disconnect
client.disconnect().await?;
Sends a Logoff action before closing the TCP connection.
Events
AMI delivers real-time events as things happen in Asterisk. Events are parsed
into typed AmiEvent variants. See Reference for the
complete list.
Subscribing
let mut sub = client.subscribe();
while let Some(event) = sub.recv().await {
println!("{}: {}", event.event_name(), event.channel().unwrap_or("n/a"));
}
Filtered Subscriptions
Subscribe to specific event types without processing every event:
let mut hangups = client.subscribe_filtered(|e| {
e.event_name() == "Hangup"
});
while let Some(event) = hangups.recv().await {
if let AmiEvent::Hangup { channel, cause, cause_txt, .. } = event {
println!("hangup on {channel}: {cause} ({cause_txt})");
}
}
Event-Generating Actions
Actions like Status, CoreShowChannels, and QueueStatus return results
as a sequence of events. Use send_collecting to gather them:
use asterisk_rs_ami::action::StatusAction;
let result = client.send_collecting(&StatusAction { channel: None }).await?;
println!("got {} channel status events", result.events.len());
for event in &result.events {
println!(" {}", event.event_name());
}
Common Accessors
Every AmiEvent has:
event_name()— the raw event name stringchannel()— the associated channel name, if anyunique_id()— the unique channel identifier, if any
Unknown Events
Events not covered by typed variants arrive as AmiEvent::Unknown:
if let AmiEvent::Unknown { event_name, headers } = event {
println!("unhandled: {event_name}");
for (k, v) in &headers {
println!(" {k}: {v}");
}
}
AMI Reference
Events (181 typed variants)
| Variant | Description |
|---|---|
NewChannel | new channel created |
Hangup | channel hung up |
Newstate | channel state changed |
DialBegin | dial begin |
DialEnd | dial end |
DtmfBegin | DTMF digit received |
DtmfEnd | DTMF digit ended |
FullyBooted | asterisk has finished booting |
PeerStatus | peer registration/status change |
BridgeCreate | bridge created |
BridgeDestroy | bridge destroyed |
BridgeEnter | channel entered bridge |
BridgeLeave | channel left bridge |
VarSet | channel variable set |
Hold | channel placed on hold |
Unhold | channel taken off hold |
HangupRequest | hangup requested |
SoftHangupRequest | soft hangup requested |
NewExten | channel entered new dialplan extension |
NewCallerid | caller id changed |
NewConnectedLine | connected line info changed |
NewAccountCode | account code changed |
Rename | channel renamed |
OriginateResponse | originate result |
DialState | dial state changed |
Flash | flash hook detected |
Wink | wink detected |
UserEvent | user-defined event |
AttendedTransfer | attended transfer completed |
BlindTransfer | blind transfer completed |
BridgeMerge | two bridges merged |
BridgeInfoChannel | channel info in bridge listing |
BridgeInfoComplete | bridge info listing complete |
BridgeVideoSourceUpdate | bridge video source changed |
LocalBridge | local channel bridged |
LocalOptimizationBegin | local optimization started |
LocalOptimizationEnd | local optimization ended |
Cdr | call detail record |
Cel | channel event logging |
QueueCallerAbandon | caller abandoned queue |
QueueCallerJoin | caller joined queue |
QueueCallerLeave | caller left queue |
QueueMemberAdded | member added to queue |
QueueMemberRemoved | member removed from queue |
QueueMemberPause | member paused/unpaused |
QueueMemberStatus | member status changed |
QueueMemberPenalty | member penalty changed |
QueueMemberRinginuse | member ringinuse changed |
QueueParams | queue parameters |
QueueEntry | queue entry |
AgentCalled | agent called from queue |
AgentConnect | agent connected |
AgentComplete | agent completed call |
AgentDump | agent dumped call |
AgentLogin | agent logged in |
AgentLogoff | agent logged off |
AgentRingNoAnswer | agent did not answer |
Agents | agent list entry |
AgentsComplete | agent list complete |
ConfbridgeStart | confbridge started |
ConfbridgeEnd | confbridge ended |
ConfbridgeJoin | user joined confbridge |
ConfbridgeLeave | user left confbridge |
ConfbridgeList | confbridge list entry |
ConfbridgeMute | confbridge user muted |
ConfbridgeUnmute | confbridge user unmuted |
ConfbridgeTalking | confbridge talking status changed |
ConfbridgeRecord | confbridge recording started |
ConfbridgeStopRecord | confbridge recording stopped |
ConfbridgeListRooms | confbridge room list entry |
MixMonitorStart | mixmonitor started |
MixMonitorStop | mixmonitor stopped |
MixMonitorMute | mixmonitor mute state changed |
MusicOnHoldStart | music on hold started |
MusicOnHoldStop | music on hold stopped |
ParkedCall | call parked |
ParkedCallGiveUp | parked caller gave up |
ParkedCallTimeOut | parked call timed out |
ParkedCallSwap | parked call swapped |
UnParkedCall | parked call retrieved |
Pickup | call pickup |
ChanSpyStart | channel spy started |
ChanSpyStop | channel spy stopped |
ChannelTalkingStart | channel started talking |
ChannelTalkingStop | channel stopped talking |
DeviceStateChange | device state changed |
ExtensionStatus | extension status changed |
PresenceStateChange | presence state changed |
PresenceStatus | presence status |
ContactStatus | contact status changed |
Registry | registration status |
MessageWaiting | message waiting indication |
VoicemailPasswordChange | voicemail password changed |
RTCPReceived | rtcp packet received |
RTCPSent | rtcp packet sent |
FailedACL | acl check failed |
InvalidAccountID | invalid account id |
InvalidPassword | invalid password |
ChallengeResponseFailed | challenge-response failed |
ChallengeSent | challenge sent |
SuccessfulAuth | authentication succeeded |
SessionLimit | session limit reached |
UnexpectedAddress | unexpected source address |
RequestBadFormat | bad request format |
RequestNotAllowed | request not allowed |
RequestNotSupported | request not supported |
InvalidTransport | invalid transport |
AuthMethodNotAllowed | auth method not allowed |
Shutdown | asterisk shutting down |
Reload | module reloaded |
Load | module loaded |
Unload | module unloaded |
LogChannel | log channel toggled |
LoadAverageLimit | load average exceeded limit |
MemoryLimit | memory usage exceeded limit |
AsyncAGIStart | async agi session started |
AsyncAGIExec | async agi command executed |
AsyncAGIEnd | async agi session ended |
AGIExecStart | agi command execution started |
AGIExecEnd | agi command execution ended |
HangupHandlerPush | hangup handler pushed |
HangupHandlerPop | hangup handler popped |
HangupHandlerRun | hangup handler running |
Status | channel status entry |
StatusComplete | status listing complete |
CoreShowChannel | core show channel entry |
CoreShowChannelsComplete | core show channels complete |
CoreShowChannelMapComplete | core show channel map complete |
DAHDIChannel | dahdi channel info |
Alarm | dahdi alarm |
AlarmClear | dahdi alarm cleared |
SpanAlarm | dahdi span alarm |
SpanAlarmClear | dahdi span alarm cleared |
AocD | advice of charge — during call |
AocE | advice of charge — end of call |
AocS | advice of charge — setup |
FAXStatus | fax status update |
ReceiveFAX | fax received |
SendFAX | fax sent |
MeetmeJoin | meetme user joined |
MeetmeLeave | meetme user left |
MeetmeEnd | meetme conference ended |
MeetmeMute | meetme user muted/unmuted |
MeetmeTalking | meetme user talking |
MeetmeTalkRequest | meetme talk request |
MeetmeList | meetme list entry |
MeetmeListRooms | meetme room list entry |
DeviceStateListComplete | device state list complete |
ExtensionStateListComplete | extension state list complete |
PresenceStateListComplete | presence state list complete |
AorDetail | aor detail |
AorList | aor list entry |
AorListComplete | aor list complete |
AuthDetail | auth detail |
AuthList | auth list entry |
AuthListComplete | auth list complete |
ContactList | contact list entry |
ContactListComplete | contact list complete |
ContactStatusDetail | contact status detail |
EndpointDetail | endpoint detail |
EndpointDetailComplete | endpoint detail complete |
EndpointList | endpoint list entry |
EndpointListComplete | endpoint list complete |
IdentifyDetail | identify detail |
TransportDetail | transport detail |
ResourceListDetail | resource list detail |
InboundRegistrationDetail | inbound registration detail |
OutboundRegistrationDetail | outbound registration detail |
InboundSubscriptionDetail | inbound subscription detail |
OutboundSubscriptionDetail | outbound subscription detail |
MWIGet | mwi get response |
MWIGetComplete | mwi get complete |
MiniVoiceMail | minivm voicemail notification |
FAXSession | fax session info |
FAXSessionsEntry | fax sessions list entry |
FAXSessionsComplete | fax sessions list complete |
FAXStats | fax statistics |
DNDState | do not disturb state changed |
DeadlockStart | deadlock detected |
MCID | malicious call id |
Unknown | unrecognized event — carries all raw headers |
Actions (150 typed structs)
| Action | Description |
|---|---|
LogoffAction | logoff from AMI |
PingAction | ping the server (keep-alive) |
OriginateAction | originate a call |
HangupAction | hangup a channel |
RedirectAction | redirect (transfer) a channel |
CommandAction | execute a CLI command |
GetVarAction | get a channel variable |
SetVarAction | set a channel variable |
StatusAction | query channel status |
CoreStatusAction | query core system status |
CoreSettingsAction | query core settings |
CoreShowChannelsAction | list active channels |
CoreShowChannelMapAction | show channel map for a given channel |
ListCommandsAction | list available AMI commands |
EventsAction | control event output |
FilterAction | manage event filters |
WaitEventAction | wait for an event to occur |
ReloadAction | reload asterisk modules |
LoggerRotateAction | rotate logger files |
ModuleCheckAction | check if a module is loaded |
ModuleLoadAction | load, unload, or reload a module |
UserEventAction | send a user-defined event |
AbsoluteTimeoutAction | set absolute timeout on a channel |
MuteAudioAction | mute or unmute audio on a channel |
SendTextAction | send text to a channel |
PlayDTMFAction | play a DTMF digit on a channel |
AGIAction | execute an AGI command on a channel |
DBGetAction | get a value from the asterisk database |
DBPutAction | put a value into the asterisk database |
DBDelAction | delete a key from the asterisk database |
DBDelTreeAction | delete a family or subtree from the asterisk database |
DBGetTreeAction | get a tree of values from the asterisk database |
AtxferAction | attended transfer a channel |
BlindTransferAction | blind transfer a channel |
CancelAtxferAction | cancel an attended transfer |
BridgeAction | bridge two channels together |
BridgeDestroyAction | destroy a bridge |
BridgeInfoAction | get information about a bridge |
BridgeKickAction | kick a channel from a bridge |
BridgeListAction | list active bridges |
QueueAddAction | add a member to a queue |
QueueRemoveAction | remove a member from a queue |
QueuePauseAction | pause or unpause a queue member |
QueuePenaltyAction | set penalty for a queue member |
QueueStatusAction | query queue status |
QueueSummaryAction | query queue summary |
QueueReloadAction | reload queue configuration |
QueueResetAction | reset queue statistics |
QueueLogAction | add a custom entry to the queue log |
MixMonitorAction | start recording a channel with mixmonitor |
MixMonitorMuteAction | mute or unmute a mixmonitor recording |
StopMixMonitorAction | stop recording a channel with mixmonitor |
ControlPlaybackAction | control playback on a channel |
ConfbridgeListAction | list participants in a conference |
ConfbridgeListRoomsAction | list active conference rooms |
ConfbridgeKickAction | kick a participant from a conference |
ConfbridgeMuteAction | mute a participant in a conference |
ConfbridgeUnmuteAction | unmute a participant in a conference |
ConfbridgeLockAction | lock a conference |
ConfbridgeUnlockAction | unlock a conference |
ConfbridgeStartRecordAction | start recording a conference |
ConfbridgeStopRecordAction | stop recording a conference |
ParkAction | park a channel |
ParkedCallsAction | list parked calls |
ParkinglotsAction | list parking lots |
GetConfigAction | retrieve configuration file |
GetConfigJSONAction | retrieve configuration as JSON |
UpdateConfigAction | update a configuration file |
CreateConfigAction | create an empty configuration file |
ListCategoriesAction | list categories in a configuration file |
ShowDialPlanAction | show dialplan |
PJSIPShowEndpointsAction | list all pjsip endpoints |
PJSIPShowEndpointAction | show details for a pjsip endpoint |
PJSIPQualifyAction | qualify a pjsip endpoint |
PJSIPRegisterAction | register a pjsip outbound registration |
PJSIPUnregisterAction | unregister a pjsip outbound registration |
PJSIPShowRegistrationsInboundAction | list inbound pjsip registrations |
PJSIPShowRegistrationsOutboundAction | list outbound pjsip registrations |
PJSIPShowContactsAction | list pjsip contacts |
PJSIPShowAorsAction | list pjsip address of records |
PJSIPShowAuthsAction | list pjsip authentication objects |
PJSIPNotifyAction | send a notify to a pjsip endpoint |
PJSIPHangupAction | hangup a pjsip channel |
ExtensionStateAction | query extension state |
ExtensionStateListAction | list all extension states |
DeviceStateListAction | list all device states |
PresenceStateAction | query presence state for a provider |
PresenceStateListAction | list all presence states |
DialplanExtensionAddAction | add an extension to the dialplan |
DialplanExtensionRemoveAction | remove an extension from the dialplan |
LocalOptimizeAwayAction | request local channel optimization |
MailboxCountAction | get mailbox message count |
MailboxStatusAction | get mailbox status |
MWIGetAction | get message waiting indicator state |
MWIUpdateAction | update message waiting indicator |
MWIDeleteAction | delete message waiting indicator |
MessageSendAction | send a text message |
VoicemailUsersListAction | list voicemail users |
VoicemailUserStatusAction | get voicemail user status |
VoicemailRefreshAction | refresh voicemail state |
VoicemailBoxSummaryAction | get voicemail box summary |
MeetmeListAction | list meetme conference participants |
MeetmeListRoomsAction | list active meetme rooms |
MeetmeMuteAction | mute a meetme participant |
MeetmeUnmuteAction | unmute a meetme participant |
AgentLogoffAction | log off an agent |
AgentsAction | list agents |
FAXSessionAction | get info about a fax session |
FAXSessionsAction | list active fax sessions |
FAXStatsAction | get fax statistics |
AOCMessageAction | send an advice of charge message |
SendFlashAction | send a flash signal on a channel |
PlayMFAction | play an MF digit on a channel |
DAHDIDNDoffAction | disable do not disturb on a DAHDI channel |
DAHDIDNDonAction | enable do not disturb on a DAHDI channel |
DAHDIDialOffhookAction | dial a number on a DAHDI channel that is off hook |
DAHDIHangupAction | hangup a DAHDI channel |
DAHDIRestartAction | restart the DAHDI channels |
DAHDIShowChannelsAction | show DAHDI channel information |
DAHDIShowStatusAction | show DAHDI status |
DAHDITransferAction | transfer a DAHDI channel |
IAXnetstatsAction | show IAX2 network statistics |
IAXpeerlistAction | list IAX2 peers |
IAXpeersAction | list IAX2 peers (compact) |
IAXregistryAction | list IAX2 registrations |
PRIDebugFileSetAction | set the PRI debug log file |
PRIDebugFileUnsetAction | unset the PRI debug log file |
PRIDebugSetAction | set the PRI debug level for a span |
PRIShowSpansAction | show PRI spans |
BridgeTechnologyListAction | list available bridge technologies |
BridgeTechnologySuspendAction | suspend a bridge technology |
BridgeTechnologyUnsuspendAction | unsuspend a bridge technology |
PJSIPShowRegistrationInboundContactStatusesAction | show PJSIP inbound registration contact statuses |
PJSIPShowResourceListsAction | show PJSIP resource lists |
PJSIPShowSubscriptionsInboundAction | show PJSIP inbound subscriptions |
PJSIPShowSubscriptionsOutboundAction | show PJSIP outbound subscriptions |
QueueChangePriorityCallerAction | change priority of a caller in a queue |
QueueMemberRingInUseAction | set ring in use for a queue member |
QueueRuleAction | show a queue rule |
QueueWithdrawCallerAction | withdraw a caller from a queue |
SorceryMemoryCacheExpireAction | expire all objects in a sorcery memory cache |
SorceryMemoryCacheExpireObjectAction | expire a specific object in a sorcery memory cache |
SorceryMemoryCachePopulateAction | populate a sorcery memory cache |
SorceryMemoryCacheStaleAction | mark all objects in a sorcery memory cache as stale |
SorceryMemoryCacheStaleObjectAction | mark a specific object in a sorcery memory cache as stale |
VoicemailForwardAction | forward a voicemail message |
VoicemailMoveAction | move a voicemail message |
VoicemailRemoveAction | remove a voicemail message |
ConfbridgeSetSingleVideoSrcAction | set the single video source in a conference bridge |
JabberSendAction | send a jabber (XMPP) message |
AGI (Asterisk Gateway Interface)
AGI allows external programs to control Asterisk dialplan execution. This crate implements a FastAGI TCP server that accepts connections from Asterisk and dispatches them to a handler.
Quick Start
use asterisk_rs_agi::{AgiServer, AgiHandler, AgiRequest, AgiChannel};
struct MyHandler;
impl AgiHandler for MyHandler {
async fn handle(&self, request: AgiRequest, mut channel: AgiChannel)
-> asterisk_rs_agi::error::Result<()>
{
channel.answer().await?;
channel.stream_file("hello-world", "").await?;
channel.hangup(None).await?;
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (server, _shutdown) = AgiServer::builder()
.bind("0.0.0.0:4573")
.handler(MyHandler)
.max_connections(100)
.build()
.await?;
server.run().await?;
Ok(())
}
Capabilities
- Every AGI command with typed async methods
- Handler trait using native async fn (RPITIT, no macro needed)
- Request environment parsing from Asterisk
- Configurable concurrency limits
- Graceful shutdown via
ShutdownHandle
See FastAGI Server for server details and Reference for the complete command list.
FastAGI Server
Binding
The server binds a TCP listener and dispatches each connection to your handler.
Asterisk connects via the AGI() dialplan application:
exten => 100,1,AGI(agi://your-server:4573)
Handler Trait
pub trait AgiHandler: Send + Sync + 'static {
fn handle(&self, request: AgiRequest, channel: AgiChannel)
-> impl Future<Output = Result<()>> + Send;
}
The handler receives the AGI request (parsed environment variables from Asterisk) and a channel for sending commands back.
Request Environment
AgiRequest contains the agi_* variables sent by Asterisk at connection start:
channel name, caller ID, called extension, context, language, etc.
Channel Commands
AgiChannel provides typed async methods for every AGI command: answer, hangup,
stream_file, get_data, say_digits, record_file, database_get,
speech_create, and more. See Reference.
Concurrency
Limit concurrent connections with max_connections:
let (server, _shutdown) = AgiServer::builder()
.bind("0.0.0.0:4573")
.handler(MyHandler)
.max_connections(50)
.build()
.await?;
Graceful Shutdown
build() returns a ShutdownHandle that stops the accept loop:
let (server, shutdown) = AgiServer::builder()
.bind("0.0.0.0:4573")
.handler(MyHandler)
.build()
.await?;
// stop accepting after ctrl-c
tokio::spawn(async move {
tokio::signal::ctrl_c().await.ok();
shutdown.shutdown();
});
server.run().await?;
AGI Reference
Commands (47 total)
| Constant | AGI Command | Description |
|---|---|---|
ANSWER | ANSWER | |
HANGUP | HANGUP | |
STREAM_FILE | STREAM FILE | |
GET_DATA | GET DATA | |
SAY_DIGITS | SAY DIGITS | |
SAY_NUMBER | SAY NUMBER | |
SET_VARIABLE | SET VARIABLE | |
GET_VARIABLE | GET VARIABLE | |
EXEC | EXEC | |
WAIT_FOR_DIGIT | WAIT FOR DIGIT | |
CHANNEL_STATUS | CHANNEL STATUS | |
VERBOSE | VERBOSE | |
SET_CALLERID | SET CALLERID | |
DATABASE_GET | DATABASE GET | |
DATABASE_PUT | DATABASE PUT | |
DATABASE_DEL | DATABASE DEL | |
CONTROL_STREAM_FILE | CONTROL STREAM FILE | |
DATABASE_DELTREE | DATABASE DELTREE | |
GET_FULL_VARIABLE | GET FULL VARIABLE | |
GET_OPTION | GET OPTION | |
GOSUB | GOSUB | |
NOOP | NOOP | |
RECEIVE_CHAR | RECEIVE CHAR | |
RECEIVE_TEXT | RECEIVE TEXT | |
RECORD_FILE | RECORD FILE | |
SAY_ALPHA | SAY ALPHA | |
SAY_DATE | SAY DATE | |
SAY_DATETIME | SAY DATETIME | |
SAY_PHONETIC | SAY PHONETIC | |
SAY_TIME | SAY TIME | |
SEND_IMAGE | SEND IMAGE | |
SEND_TEXT | SEND TEXT | |
SET_AUTOHANGUP | SET AUTOHANGUP | |
SET_CONTEXT | SET CONTEXT | |
SET_EXTENSION | SET EXTENSION | |
SET_MUSIC | SET MUSIC | |
SET_PRIORITY | SET PRIORITY | |
SPEECH_ACTIVATE_GRAMMAR | SPEECH ACTIVATE GRAMMAR | |
SPEECH_CREATE | SPEECH CREATE | |
SPEECH_DEACTIVATE_GRAMMAR | SPEECH DEACTIVATE GRAMMAR | |
SPEECH_DESTROY | SPEECH DESTROY | |
SPEECH_LOAD_GRAMMAR | SPEECH LOAD GRAMMAR | |
SPEECH_RECOGNIZE | SPEECH RECOGNIZE | |
SPEECH_SET | SPEECH SET | |
SPEECH_UNLOAD_GRAMMAR | SPEECH UNLOAD GRAMMAR | |
TDD_MODE | TDD MODE | |
ASYNCAGI_BREAK | ASYNCAGI BREAK |
Channel Methods (48 total)
| Method | Description |
|---|---|
send_command() | send a raw command string and parse the response the command should already be formatted with a trailing newline. checks the hung_up flag before sending to avoid writing to a dead channel. |
answer() | answer the channel |
hangup() | hang up the channel, optionally specifying which channel to hang up |
stream_file() | stream a sound file, allowing the caller to interrupt with escape digits |
get_data() | play a prompt and collect DTMF digits |
say_digits() | say a digit string with escape digits |
say_number() | say a number with escape digits |
set_variable() | set a channel variable |
get_variable() | get a channel variable |
exec() | execute an asterisk application |
wait_for_digit() | wait for a DTMF digit, -1 for infinite timeout |
channel_status() | get the status of a channel |
verbose() | send a verbose message to the asterisk console |
set_callerid() | set the caller id for the current channel |
database_get() | get a value from the asterisk database |
database_put() | set a value in the asterisk database |
database_del() | delete a key from the asterisk database |
database_deltree() | delete a family or key tree from the asterisk database |
control_stream_file() | stream file with ability to control (pause, rewind, fast forward) |
get_full_variable() | get a full variable expression, evaluating functions and expressions |
get_option() | stream file with playback offset, allowing the caller to interrupt with escape digits |
gosub() | execute a dialplan subroutine |
noop() | do nothing, used for testing |
receive_char() | receive a character from the connected channel |
receive_text() | receive a text message from the connected channel |
record_file() | record audio to a file |
say_alpha() | say an alphabetic string with escape digits |
say_date() | say a date (unix timestamp) with escape digits |
say_datetime() | say a date and time (unix timestamp) with escape digits |
say_phonetic() | say a string phonetically with escape digits |
say_time() | say a time (unix timestamp) with escape digits |
send_image() | send an image to the connected channel |
send_text() | send text to the connected channel |
set_autohangup() | set the auto-hangup timer in seconds (0 to disable) |
set_context() | set the dialplan context for continuation after agi completes |
set_extension() | set the dialplan extension for continuation after agi completes |
set_music() | enable or disable music on hold |
set_priority() | set the dialplan priority for continuation after agi completes |
speech_create() | create a speech recognition object |
speech_destroy() | destroy the current speech recognition object |
speech_activate_grammar() | activate a loaded grammar for recognition |
speech_deactivate_grammar() | deactivate a grammar |
speech_load_grammar() | load a grammar from a file |
speech_unload_grammar() | unload a previously loaded grammar |
speech_recognize() | play a prompt and perform speech recognition |
speech_set() | set a speech engine setting |
tdd_mode() | enable or disable tdd mode on the channel |
asyncagi_break() | break out of async agi |
ARI (Asterisk REST Interface)
ARI provides full call control through a REST API combined with a WebSocket event stream for Stasis applications.
Quick Start
use asterisk_rs_ari::{AriClient, AriConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = AriConfig::builder("my-app")
.host("10.0.0.1")
.username("asterisk")
.password("secret")
.build()?;
let client = AriClient::connect(config).await?;
let mut events = client.subscribe();
while let Some(msg) = events.recv().await {
println!("[{}] {:?}", msg.application, msg.event);
}
Ok(())
}
Capabilities
- REST client and WebSocket listener covering the full Asterisk 23 ARI surface
- Typed events with metadata (application, timestamp, asterisk_id)
- Filtered subscriptions – receive only events you care about
- Resource handles for channels, bridges, playbacks, recordings
- System management – modules, logging, config, global variables
- URL-safe query encoding, HTTP timeouts, WebSocket lifecycle management
See Stasis Applications for the event model, Resources for the handle pattern, and Reference for complete endpoint lists.
Stasis Applications
ARI routes calls to your application via the Stasis() dialplan application:
exten => 100,1,Stasis(my-app,arg1,arg2)
Event Stream
Events arrive via WebSocket as AriMessage structs containing metadata
and a typed AriEvent:
use asterisk_rs_ari::event::{AriEvent, AriMessage};
let mut events = client.subscribe();
while let Some(msg) = events.recv().await {
println!("app={} time={}", msg.application, msg.timestamp);
match msg.event {
AriEvent::StasisStart { channel, args, .. } => {
println!("call from {} with args {:?}", channel.name, args);
}
AriEvent::StasisEnd { channel } => {
println!("call ended: {}", channel.name);
}
_ => {}
}
}
Filtered Subscriptions
let mut calls = client.subscribe_filtered(|msg| {
matches!(msg.event, AriEvent::StasisStart { .. } | AriEvent::StasisEnd { .. })
});
Event Metadata
Every AriMessage carries:
application— the Stasis app that received the eventtimestamp— ISO 8601 when the event was createdasterisk_id— unique Asterisk instance ID (for clusters)event— the typedAriEventpayload
See Reference for the complete event list.
Resources
ARI resources are managed through handle objects that bundle a resource ID with a client reference.
Handle Pattern
use asterisk_rs_ari::resources::channel::{ChannelHandle, originate, OriginateParams};
// originate a channel
let params = OriginateParams {
endpoint: "PJSIP/100".into(),
app: Some("my-app".into()),
..Default::default()
};
let channel = originate(&client, ¶ms).await?;
// wrap in a handle for operations
let handle = ChannelHandle::new(channel.id, client.clone());
handle.answer().await?;
handle.play("sound:hello-world").await?;
handle.hangup(None).await?;
Available Handles
| Handle | Resource | Key Operations |
|---|---|---|
ChannelHandle | Channel | answer, hangup, play, record, hold, mute, dtmf, dial, snoop |
BridgeHandle | Bridge | add/remove channel, play, record, moh, video source |
PlaybackHandle | Playback | control, stop |
RecordingHandle | Recording | stop, pause, mute |
Module Functions
Each resource module also provides free functions for list/get/create:
use asterisk_rs_ari::resources::channel;
use asterisk_rs_ari::resources::bridge;
let channels = channel::list(&client).await?;
let bridges = bridge::list(&client).await?;
Asterisk System
The asterisk resource module provides system management:
use asterisk_rs_ari::resources::asterisk;
let info = asterisk::info(&client, None).await?;
let pong = asterisk::ping(&client).await?;
asterisk::reload_module(&client, "res_pjsip.so").await?;
See Reference for all operations per resource.
ARI Reference
Events (44 typed variants)
| Variant | Description |
|---|---|
StasisStart | channel entered a Stasis application |
StasisEnd | channel left a Stasis application |
ChannelCreated | channel was created |
ChannelDestroyed | channel was destroyed |
ChannelStateChange | channel state changed |
ChannelDtmfReceived | DTMF digit received on channel |
ChannelHangupRequest | hangup requested on channel |
ChannelVarset | channel variable set |
BridgeCreated | bridge was created |
BridgeDestroyed | bridge was destroyed |
ChannelEnteredBridge | channel entered a bridge |
ChannelLeftBridge | channel left a bridge |
PlaybackStarted | media playback started |
PlaybackFinished | media playback finished |
RecordingStarted | recording started |
RecordingFinished | recording finished |
ChannelCallerId | channel caller id changed |
ChannelConnectedLine | channel connected line changed |
ChannelDialplan | channel dialplan location changed |
ChannelHold | channel placed on hold |
ChannelUnhold | channel removed from hold |
ChannelTalkingStarted | channel talking started |
ChannelTalkingFinished | channel talking finished |
ChannelToneDetected | tone detected on channel |
ChannelTransfer | channel transfer via REFER |
ChannelUserevent | user-defined event from the dialplan |
Dial | dial event with caller and peer channels |
BridgeAttendedTransfer | bridge attended transfer completed |
BridgeBlindTransfer | bridge blind transfer completed |
BridgeMerged | two bridges merged |
BridgeVideoSourceChanged | bridge video source changed |
ContactStatusChange | contact status changed |
DeviceStateChanged | device state changed |
EndpointStateChange | endpoint state changed |
PeerStatusChange | peer status changed |
PlaybackContinuing | playback continuing to next media uri |
RecordingFailed | recording failed |
ApplicationMoveFailed | application move failed |
ApplicationRegistered | application registered |
ApplicationReplaced | application replaced by another websocket connection |
ApplicationUnregistered | application unregistered |
TextMessageReceived | text message received |
RESTResponse | REST API response over websocket |
Unknown | catch-all for event types not yet modeled |
Resources (10 modules)
Application (5 operations)
| Method | Description |
|---|---|
list() | list all stasis applications |
get() | get a specific stasis application |
subscribe() | subscribe an application to an event source |
unsubscribe() | unsubscribe an application from an event source |
set_event_filter() | set the event filter for an application |
Asterisk (16 operations)
| Method | Description |
|---|---|
info() | get asterisk system information |
ping() | ping asterisk |
list_modules() | list all loaded modules |
get_module() | get details for a specific module |
load_module() | load a module |
unload_module() | unload a module |
reload_module() | reload a module |
list_log_channels() | list log channels |
add_log_channel() | add a log channel |
remove_log_channel() | remove a log channel |
rotate_log_channel() | rotate a log channel |
get_variable() | get a global variable |
set_variable() | set a global variable |
get_config() | get dynamic configuration object |
update_config() | update dynamic configuration object |
delete_config() | delete dynamic configuration object |
Bridge (BridgeHandle, 16 operations)
| Method | Description |
|---|---|
add_channel() | add a channel to this bridge |
remove_channel() | remove a channel from this bridge |
play() | play media on the bridge |
record() | start recording on the bridge |
destroy() | destroy this bridge |
start_moh() | start music on hold for the bridge |
stop_moh() | stop music on hold for the bridge |
play_with_id() | play media with a specific playback id |
set_video_source() | set the video source for the bridge |
clear_video_source() | clear the video source for the bridge |
create() | create a new bridge |
list() | list all bridges |
get() | get details for a specific bridge |
create() | create a new bridge |
list() | list all bridges |
get() | get details for a specific bridge |
Channel (ChannelHandle, 32 operations)
| Method | Description |
|---|---|
answer() | answer the channel |
hangup() | hang up the channel with an optional reason |
play() | play media on the channel |
record() | start recording on the channel |
mute() | mute the channel, optionally specifying direction (both, in, out) |
unmute() | unmute the channel, optionally specifying direction |
hold() | place the channel on hold |
unhold() | remove the channel from hold |
send_dtmf() | send dtmf digits to the channel |
get_variable() | get a channel variable |
set_variable() | set a channel variable |
continue_in_dialplan() | continue the channel in the dialplan |
snoop() | snoop on the channel — spy and/or whisper |
redirect() | redirect the channel to a different dialplan location |
ring() | start ringing on the channel |
ring_stop() | stop ringing on the channel |
start_silence() | start silence on the channel |
stop_silence() | stop silence on the channel |
play_with_id() | play media on the channel with additional options |
dial() | dial a created channel |
rtp_statistics() | get rtp statistics for the channel |
external_media() | start an external media session |
list() | list all active channels |
get() | get details for a specific channel |
originate() | originate a new channel |
create() | create a channel without dialing it |
external_media() | start an external media session |
list() | list all active channels |
get() | get details for a specific channel |
originate() | originate a new channel |
create() | create a channel without dialing it |
external_media() | start an external media session |
Device State (4 operations)
| Method | Description |
|---|---|
list() | list all device states |
get() | get a specific device state |
update() | also accepts POST for compatibility |
delete() | delete a device state |
Endpoint (7 operations)
| Method | Description |
|---|---|
list() | list all endpoints |
list_by_tech() | list endpoints for a specific technology |
get() | get a specific endpoint |
send_message() | send a message to some technology uri or endpoint |
refer() | refer an endpoint or technology uri to some technology uri or endpoint |
send_message_to_endpoint() | send a message to an endpoint |
refer_to_endpoint() | refer an endpoint to some technology uri or endpoint |
Mailbox (4 operations)
| Method | Description |
|---|---|
list() | list all mailboxes |
get() | get a specific mailbox |
update() | also accepts POST for compatibility |
delete() | delete a mailbox |
Playback (PlaybackHandle, 3 operations)
| Method | Description |
|---|---|
control() | control the playback (pause, unpause, restart, reverse, forward) |
stop() | stop the playback |
get() | get current playback state |
Recording (RecordingHandle, 8 operations)
| Method | Description |
|---|---|
stop() | stop the live recording |
pause() | pause the live recording |
unpause() | unpause the live recording |
mute() | mute the live recording |
unmute() | unmute the live recording |
get() | get current live recording state |
list_stored() | list all stored recordings |
list_stored() | list all stored recordings |
Sound (2 operations)
| Method | Description |
|---|---|
list() | list all sounds |
get() | get a specific sound |