Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

ProtocolPortTransportCrate
AMI5038TCPasterisk-rs-ami
AGI4573TCP (FastAGI)asterisk-rs-agi
ARI8088HTTP + WebSocketasterisk-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

VariantDescription
NotDefined = 0not defined (code 0)
Unallocated = 1unallocated number (code 1)
NoRouteTransitNet = 2no route to transit network (code 2)
NoRouteDestination = 3no route to destination (code 3)
MisdialledTrunkPrefix = 5misdialled trunk prefix (code 5)
ChannelUnacceptable = 6channel unacceptable (code 6)
CallAwardedDelivered = 7call awarded and being delivered (code 7)
PreEmpted = 8pre-empted (code 8)
NumberPortedNotHere = 14number ported but not found here (code 14)
NormalClearing = 16normal call clearing (code 16)
UserBusy = 17user busy (code 17)
NoUserResponse = 18no user response (code 18)
NoAnswer = 19no answer from user (code 19)
SubscriberAbsent = 20subscriber absent (code 20)
CallRejected = 21call rejected (code 21)
NumberChanged = 22number changed (code 22)
RedirectedToNewDestination = 23redirected to new destination (code 23)
AnsweredElsewhere = 26answered elsewhere (code 26)
DestinationOutOfOrder = 27destination out of order (code 27)
InvalidNumberFormat = 28invalid number format (code 28)
FacilityRejected = 29facility rejected (code 29)
ResponseToStatusEnquiry = 30response to status enquiry (code 30)
NormalUnspecified = 31normal unspecified (code 31)
NormalCircuitCongestion = 34normal circuit congestion (code 34)
NetworkOutOfOrder = 38network out of order (code 38)
NormalTemporaryFailure = 41normal temporary failure (code 41)
SwitchCongestion = 42switch congestion (code 42)
AccessInfoDiscarded = 43access information discarded (code 43)
RequestedChanUnavail = 44requested channel unavailable (code 44)
FacilityNotSubscribed = 50facility not subscribed (code 50)
OutgoingCallBarred = 52outgoing call barred (code 52)
IncomingCallBarred = 54incoming call barred (code 54)
BearerCapabilityNotAuth = 57bearer capability not authorized (code 57)
BearerCapabilityNotAvail = 58bearer capability not available (code 58)
BearerCapabilityNotImpl = 65bearer capability not implemented (code 65)
ChanNotImplemented = 66channel type not implemented (code 66)
FacilityNotImplemented = 69facility not implemented (code 69)
InvalidCallReference = 81invalid call reference (code 81)
IncompatibleDestination = 88incompatible destination (code 88)
InvalidMsgUnspecified = 95invalid message unspecified (code 95)
MandatoryIeMissing = 96mandatory information element missing (code 96)
MessageTypeNonexist = 97message type nonexistent (code 97)
WrongMessage = 98wrong message (code 98)
IeNonexist = 99information element nonexistent (code 99)
InvalidIeContents = 100invalid information element contents (code 100)
WrongCallState = 101wrong call state (code 101)
RecoveryOnTimerExpire = 102recovery on timer expiry (code 102)
MandatoryIeLengthError = 103mandatory information element length error (code 103)
ProtocolError = 111protocol error (code 111)
Interworking = 127interworking unspecified (code 127)

ChannelState

channel state as reported by Asterisk

VariantDescription
Down = 0channel is down and available
Reserved = 1channel is down, but reserved
OffHook = 2channel is off hook
Dialing = 3digits have been dialed
Ring = 4remote end is ringing
Ringing = 5local end is ringing
Up = 6channel is up (answered)
Busy = 7line is busy
DialingOffhook = 8dialing while offhook
PreRing = 9channel detected incoming call before ring

DeviceState

device state values used in device state events and queries

VariantDescription
Unknownstate is unknown
NotInUsedevice is not in use
InUsedevice is in use
Busydevice is busy
Invaliddevice is invalid
Unavailabledevice is unavailable
Ringingdevice is ringing
RingInUsedevice is ringing and in use
OnHolddevice is on hold

DialStatus

result of a dial attempt, set in the DIALSTATUS channel variable

VariantDescription
Answercall was answered
Busyremote end was busy
NoAnswerremote end did not answer
Cancelcall was cancelled
Congestioncongestion encountered
ChanUnavailchannel was unavailable
DontCallnumber on do-not-call list
Torturenumber routed to torture IVR
InvalidArgsinvalid arguments to Dial()
Unavailabletarget was unavailable

CdrDisposition

CDR disposition values

VariantDescription
NoAnswercall was not answered
Answeredcall was answered
Busyremote end was busy
Failedcall attempt failed
Congestioncongestion encountered

PeerStatus

SIP/PJSIP peer registration status

VariantDescription
Registeredpeer is registered
Unregisteredpeer is unregistered
Reachablepeer is reachable
Unreachablepeer is unreachable
Laggedpeer response is lagged
Rejectedpeer registration was rejected
Unknownpeer status is unknown

QueueStrategy

queue member selection strategy

VariantDescription
RingAllring all available members simultaneously
LeastRecentring the member least recently called
FewestCallsring the member with the fewest completed calls
Randomring a random member
RoundRobinround-robin with memory
Linearring members in the order listed
WeightedRandomring a random member, weighted by penalty

ExtensionState

extension hint state values

VariantDescription
Removed = -2not found or removed
Idle = -1idle, no active calls
InUse = 1in use
Busy = 2busy
Unavailable = 4unavailable
Ringing = 8ringing
OnHold = 16on hold

AgiStatus

AGI response status codes

VariantDescription
Success = 200success
InvalidCommand = 510invalid or unknown command
DeadChannel = 511channel is dead
EndUsage = 520end 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 jitter
  • ReconnectPolicy::fixed(interval) — constant delay
  • ReconnectPolicy::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 string
  • channel() — the associated channel name, if any
  • unique_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)

VariantDescription
NewChannelnew channel created
Hangupchannel hung up
Newstatechannel state changed
DialBegindial begin
DialEnddial end
DtmfBeginDTMF digit received
DtmfEndDTMF digit ended
FullyBootedasterisk has finished booting
PeerStatuspeer registration/status change
BridgeCreatebridge created
BridgeDestroybridge destroyed
BridgeEnterchannel entered bridge
BridgeLeavechannel left bridge
VarSetchannel variable set
Holdchannel placed on hold
Unholdchannel taken off hold
HangupRequesthangup requested
SoftHangupRequestsoft hangup requested
NewExtenchannel entered new dialplan extension
NewCalleridcaller id changed
NewConnectedLineconnected line info changed
NewAccountCodeaccount code changed
Renamechannel renamed
OriginateResponseoriginate result
DialStatedial state changed
Flashflash hook detected
Winkwink detected
UserEventuser-defined event
AttendedTransferattended transfer completed
BlindTransferblind transfer completed
BridgeMergetwo bridges merged
BridgeInfoChannelchannel info in bridge listing
BridgeInfoCompletebridge info listing complete
BridgeVideoSourceUpdatebridge video source changed
LocalBridgelocal channel bridged
LocalOptimizationBeginlocal optimization started
LocalOptimizationEndlocal optimization ended
Cdrcall detail record
Celchannel event logging
QueueCallerAbandoncaller abandoned queue
QueueCallerJoincaller joined queue
QueueCallerLeavecaller left queue
QueueMemberAddedmember added to queue
QueueMemberRemovedmember removed from queue
QueueMemberPausemember paused/unpaused
QueueMemberStatusmember status changed
QueueMemberPenaltymember penalty changed
QueueMemberRinginusemember ringinuse changed
QueueParamsqueue parameters
QueueEntryqueue entry
AgentCalledagent called from queue
AgentConnectagent connected
AgentCompleteagent completed call
AgentDumpagent dumped call
AgentLoginagent logged in
AgentLogoffagent logged off
AgentRingNoAnsweragent did not answer
Agentsagent list entry
AgentsCompleteagent list complete
ConfbridgeStartconfbridge started
ConfbridgeEndconfbridge ended
ConfbridgeJoinuser joined confbridge
ConfbridgeLeaveuser left confbridge
ConfbridgeListconfbridge list entry
ConfbridgeMuteconfbridge user muted
ConfbridgeUnmuteconfbridge user unmuted
ConfbridgeTalkingconfbridge talking status changed
ConfbridgeRecordconfbridge recording started
ConfbridgeStopRecordconfbridge recording stopped
ConfbridgeListRoomsconfbridge room list entry
MixMonitorStartmixmonitor started
MixMonitorStopmixmonitor stopped
MixMonitorMutemixmonitor mute state changed
MusicOnHoldStartmusic on hold started
MusicOnHoldStopmusic on hold stopped
ParkedCallcall parked
ParkedCallGiveUpparked caller gave up
ParkedCallTimeOutparked call timed out
ParkedCallSwapparked call swapped
UnParkedCallparked call retrieved
Pickupcall pickup
ChanSpyStartchannel spy started
ChanSpyStopchannel spy stopped
ChannelTalkingStartchannel started talking
ChannelTalkingStopchannel stopped talking
DeviceStateChangedevice state changed
ExtensionStatusextension status changed
PresenceStateChangepresence state changed
PresenceStatuspresence status
ContactStatuscontact status changed
Registryregistration status
MessageWaitingmessage waiting indication
VoicemailPasswordChangevoicemail password changed
RTCPReceivedrtcp packet received
RTCPSentrtcp packet sent
FailedACLacl check failed
InvalidAccountIDinvalid account id
InvalidPasswordinvalid password
ChallengeResponseFailedchallenge-response failed
ChallengeSentchallenge sent
SuccessfulAuthauthentication succeeded
SessionLimitsession limit reached
UnexpectedAddressunexpected source address
RequestBadFormatbad request format
RequestNotAllowedrequest not allowed
RequestNotSupportedrequest not supported
InvalidTransportinvalid transport
AuthMethodNotAllowedauth method not allowed
Shutdownasterisk shutting down
Reloadmodule reloaded
Loadmodule loaded
Unloadmodule unloaded
LogChannellog channel toggled
LoadAverageLimitload average exceeded limit
MemoryLimitmemory usage exceeded limit
AsyncAGIStartasync agi session started
AsyncAGIExecasync agi command executed
AsyncAGIEndasync agi session ended
AGIExecStartagi command execution started
AGIExecEndagi command execution ended
HangupHandlerPushhangup handler pushed
HangupHandlerPophangup handler popped
HangupHandlerRunhangup handler running
Statuschannel status entry
StatusCompletestatus listing complete
CoreShowChannelcore show channel entry
CoreShowChannelsCompletecore show channels complete
CoreShowChannelMapCompletecore show channel map complete
DAHDIChanneldahdi channel info
Alarmdahdi alarm
AlarmCleardahdi alarm cleared
SpanAlarmdahdi span alarm
SpanAlarmCleardahdi span alarm cleared
AocDadvice of charge — during call
AocEadvice of charge — end of call
AocSadvice of charge — setup
FAXStatusfax status update
ReceiveFAXfax received
SendFAXfax sent
MeetmeJoinmeetme user joined
MeetmeLeavemeetme user left
MeetmeEndmeetme conference ended
MeetmeMutemeetme user muted/unmuted
MeetmeTalkingmeetme user talking
MeetmeTalkRequestmeetme talk request
MeetmeListmeetme list entry
MeetmeListRoomsmeetme room list entry
DeviceStateListCompletedevice state list complete
ExtensionStateListCompleteextension state list complete
PresenceStateListCompletepresence state list complete
AorDetailaor detail
AorListaor list entry
AorListCompleteaor list complete
AuthDetailauth detail
AuthListauth list entry
AuthListCompleteauth list complete
ContactListcontact list entry
ContactListCompletecontact list complete
ContactStatusDetailcontact status detail
EndpointDetailendpoint detail
EndpointDetailCompleteendpoint detail complete
EndpointListendpoint list entry
EndpointListCompleteendpoint list complete
IdentifyDetailidentify detail
TransportDetailtransport detail
ResourceListDetailresource list detail
InboundRegistrationDetailinbound registration detail
OutboundRegistrationDetailoutbound registration detail
InboundSubscriptionDetailinbound subscription detail
OutboundSubscriptionDetailoutbound subscription detail
MWIGetmwi get response
MWIGetCompletemwi get complete
MiniVoiceMailminivm voicemail notification
FAXSessionfax session info
FAXSessionsEntryfax sessions list entry
FAXSessionsCompletefax sessions list complete
FAXStatsfax statistics
DNDStatedo not disturb state changed
DeadlockStartdeadlock detected
MCIDmalicious call id
Unknownunrecognized event — carries all raw headers

Actions (150 typed structs)

ActionDescription
LogoffActionlogoff from AMI
PingActionping the server (keep-alive)
OriginateActionoriginate a call
HangupActionhangup a channel
RedirectActionredirect (transfer) a channel
CommandActionexecute a CLI command
GetVarActionget a channel variable
SetVarActionset a channel variable
StatusActionquery channel status
CoreStatusActionquery core system status
CoreSettingsActionquery core settings
CoreShowChannelsActionlist active channels
CoreShowChannelMapActionshow channel map for a given channel
ListCommandsActionlist available AMI commands
EventsActioncontrol event output
FilterActionmanage event filters
WaitEventActionwait for an event to occur
ReloadActionreload asterisk modules
LoggerRotateActionrotate logger files
ModuleCheckActioncheck if a module is loaded
ModuleLoadActionload, unload, or reload a module
UserEventActionsend a user-defined event
AbsoluteTimeoutActionset absolute timeout on a channel
MuteAudioActionmute or unmute audio on a channel
SendTextActionsend text to a channel
PlayDTMFActionplay a DTMF digit on a channel
AGIActionexecute an AGI command on a channel
DBGetActionget a value from the asterisk database
DBPutActionput a value into the asterisk database
DBDelActiondelete a key from the asterisk database
DBDelTreeActiondelete a family or subtree from the asterisk database
DBGetTreeActionget a tree of values from the asterisk database
AtxferActionattended transfer a channel
BlindTransferActionblind transfer a channel
CancelAtxferActioncancel an attended transfer
BridgeActionbridge two channels together
BridgeDestroyActiondestroy a bridge
BridgeInfoActionget information about a bridge
BridgeKickActionkick a channel from a bridge
BridgeListActionlist active bridges
QueueAddActionadd a member to a queue
QueueRemoveActionremove a member from a queue
QueuePauseActionpause or unpause a queue member
QueuePenaltyActionset penalty for a queue member
QueueStatusActionquery queue status
QueueSummaryActionquery queue summary
QueueReloadActionreload queue configuration
QueueResetActionreset queue statistics
QueueLogActionadd a custom entry to the queue log
MixMonitorActionstart recording a channel with mixmonitor
MixMonitorMuteActionmute or unmute a mixmonitor recording
StopMixMonitorActionstop recording a channel with mixmonitor
ControlPlaybackActioncontrol playback on a channel
ConfbridgeListActionlist participants in a conference
ConfbridgeListRoomsActionlist active conference rooms
ConfbridgeKickActionkick a participant from a conference
ConfbridgeMuteActionmute a participant in a conference
ConfbridgeUnmuteActionunmute a participant in a conference
ConfbridgeLockActionlock a conference
ConfbridgeUnlockActionunlock a conference
ConfbridgeStartRecordActionstart recording a conference
ConfbridgeStopRecordActionstop recording a conference
ParkActionpark a channel
ParkedCallsActionlist parked calls
ParkinglotsActionlist parking lots
GetConfigActionretrieve configuration file
GetConfigJSONActionretrieve configuration as JSON
UpdateConfigActionupdate a configuration file
CreateConfigActioncreate an empty configuration file
ListCategoriesActionlist categories in a configuration file
ShowDialPlanActionshow dialplan
PJSIPShowEndpointsActionlist all pjsip endpoints
PJSIPShowEndpointActionshow details for a pjsip endpoint
PJSIPQualifyActionqualify a pjsip endpoint
PJSIPRegisterActionregister a pjsip outbound registration
PJSIPUnregisterActionunregister a pjsip outbound registration
PJSIPShowRegistrationsInboundActionlist inbound pjsip registrations
PJSIPShowRegistrationsOutboundActionlist outbound pjsip registrations
PJSIPShowContactsActionlist pjsip contacts
PJSIPShowAorsActionlist pjsip address of records
PJSIPShowAuthsActionlist pjsip authentication objects
PJSIPNotifyActionsend a notify to a pjsip endpoint
PJSIPHangupActionhangup a pjsip channel
ExtensionStateActionquery extension state
ExtensionStateListActionlist all extension states
DeviceStateListActionlist all device states
PresenceStateActionquery presence state for a provider
PresenceStateListActionlist all presence states
DialplanExtensionAddActionadd an extension to the dialplan
DialplanExtensionRemoveActionremove an extension from the dialplan
LocalOptimizeAwayActionrequest local channel optimization
MailboxCountActionget mailbox message count
MailboxStatusActionget mailbox status
MWIGetActionget message waiting indicator state
MWIUpdateActionupdate message waiting indicator
MWIDeleteActiondelete message waiting indicator
MessageSendActionsend a text message
VoicemailUsersListActionlist voicemail users
VoicemailUserStatusActionget voicemail user status
VoicemailRefreshActionrefresh voicemail state
VoicemailBoxSummaryActionget voicemail box summary
MeetmeListActionlist meetme conference participants
MeetmeListRoomsActionlist active meetme rooms
MeetmeMuteActionmute a meetme participant
MeetmeUnmuteActionunmute a meetme participant
AgentLogoffActionlog off an agent
AgentsActionlist agents
FAXSessionActionget info about a fax session
FAXSessionsActionlist active fax sessions
FAXStatsActionget fax statistics
AOCMessageActionsend an advice of charge message
SendFlashActionsend a flash signal on a channel
PlayMFActionplay an MF digit on a channel
DAHDIDNDoffActiondisable do not disturb on a DAHDI channel
DAHDIDNDonActionenable do not disturb on a DAHDI channel
DAHDIDialOffhookActiondial a number on a DAHDI channel that is off hook
DAHDIHangupActionhangup a DAHDI channel
DAHDIRestartActionrestart the DAHDI channels
DAHDIShowChannelsActionshow DAHDI channel information
DAHDIShowStatusActionshow DAHDI status
DAHDITransferActiontransfer a DAHDI channel
IAXnetstatsActionshow IAX2 network statistics
IAXpeerlistActionlist IAX2 peers
IAXpeersActionlist IAX2 peers (compact)
IAXregistryActionlist IAX2 registrations
PRIDebugFileSetActionset the PRI debug log file
PRIDebugFileUnsetActionunset the PRI debug log file
PRIDebugSetActionset the PRI debug level for a span
PRIShowSpansActionshow PRI spans
BridgeTechnologyListActionlist available bridge technologies
BridgeTechnologySuspendActionsuspend a bridge technology
BridgeTechnologyUnsuspendActionunsuspend a bridge technology
PJSIPShowRegistrationInboundContactStatusesActionshow PJSIP inbound registration contact statuses
PJSIPShowResourceListsActionshow PJSIP resource lists
PJSIPShowSubscriptionsInboundActionshow PJSIP inbound subscriptions
PJSIPShowSubscriptionsOutboundActionshow PJSIP outbound subscriptions
QueueChangePriorityCallerActionchange priority of a caller in a queue
QueueMemberRingInUseActionset ring in use for a queue member
QueueRuleActionshow a queue rule
QueueWithdrawCallerActionwithdraw a caller from a queue
SorceryMemoryCacheExpireActionexpire all objects in a sorcery memory cache
SorceryMemoryCacheExpireObjectActionexpire a specific object in a sorcery memory cache
SorceryMemoryCachePopulateActionpopulate a sorcery memory cache
SorceryMemoryCacheStaleActionmark all objects in a sorcery memory cache as stale
SorceryMemoryCacheStaleObjectActionmark a specific object in a sorcery memory cache as stale
VoicemailForwardActionforward a voicemail message
VoicemailMoveActionmove a voicemail message
VoicemailRemoveActionremove a voicemail message
ConfbridgeSetSingleVideoSrcActionset the single video source in a conference bridge
JabberSendActionsend 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)

ConstantAGI CommandDescription
ANSWERANSWER
HANGUPHANGUP
STREAM_FILESTREAM FILE
GET_DATAGET DATA
SAY_DIGITSSAY DIGITS
SAY_NUMBERSAY NUMBER
SET_VARIABLESET VARIABLE
GET_VARIABLEGET VARIABLE
EXECEXEC
WAIT_FOR_DIGITWAIT FOR DIGIT
CHANNEL_STATUSCHANNEL STATUS
VERBOSEVERBOSE
SET_CALLERIDSET CALLERID
DATABASE_GETDATABASE GET
DATABASE_PUTDATABASE PUT
DATABASE_DELDATABASE DEL
CONTROL_STREAM_FILECONTROL STREAM FILE
DATABASE_DELTREEDATABASE DELTREE
GET_FULL_VARIABLEGET FULL VARIABLE
GET_OPTIONGET OPTION
GOSUBGOSUB
NOOPNOOP
RECEIVE_CHARRECEIVE CHAR
RECEIVE_TEXTRECEIVE TEXT
RECORD_FILERECORD FILE
SAY_ALPHASAY ALPHA
SAY_DATESAY DATE
SAY_DATETIMESAY DATETIME
SAY_PHONETICSAY PHONETIC
SAY_TIMESAY TIME
SEND_IMAGESEND IMAGE
SEND_TEXTSEND TEXT
SET_AUTOHANGUPSET AUTOHANGUP
SET_CONTEXTSET CONTEXT
SET_EXTENSIONSET EXTENSION
SET_MUSICSET MUSIC
SET_PRIORITYSET PRIORITY
SPEECH_ACTIVATE_GRAMMARSPEECH ACTIVATE GRAMMAR
SPEECH_CREATESPEECH CREATE
SPEECH_DEACTIVATE_GRAMMARSPEECH DEACTIVATE GRAMMAR
SPEECH_DESTROYSPEECH DESTROY
SPEECH_LOAD_GRAMMARSPEECH LOAD GRAMMAR
SPEECH_RECOGNIZESPEECH RECOGNIZE
SPEECH_SETSPEECH SET
SPEECH_UNLOAD_GRAMMARSPEECH UNLOAD GRAMMAR
TDD_MODETDD MODE
ASYNCAGI_BREAKASYNCAGI BREAK

Channel Methods (48 total)

MethodDescription
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 event
  • timestamp — ISO 8601 when the event was created
  • asterisk_id — unique Asterisk instance ID (for clusters)
  • event — the typed AriEvent payload

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, &params).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

HandleResourceKey Operations
ChannelHandleChannelanswer, hangup, play, record, hold, mute, dtmf, dial, snoop
BridgeHandleBridgeadd/remove channel, play, record, moh, video source
PlaybackHandlePlaybackcontrol, stop
RecordingHandleRecordingstop, 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)

VariantDescription
StasisStartchannel entered a Stasis application
StasisEndchannel left a Stasis application
ChannelCreatedchannel was created
ChannelDestroyedchannel was destroyed
ChannelStateChangechannel state changed
ChannelDtmfReceivedDTMF digit received on channel
ChannelHangupRequesthangup requested on channel
ChannelVarsetchannel variable set
BridgeCreatedbridge was created
BridgeDestroyedbridge was destroyed
ChannelEnteredBridgechannel entered a bridge
ChannelLeftBridgechannel left a bridge
PlaybackStartedmedia playback started
PlaybackFinishedmedia playback finished
RecordingStartedrecording started
RecordingFinishedrecording finished
ChannelCallerIdchannel caller id changed
ChannelConnectedLinechannel connected line changed
ChannelDialplanchannel dialplan location changed
ChannelHoldchannel placed on hold
ChannelUnholdchannel removed from hold
ChannelTalkingStartedchannel talking started
ChannelTalkingFinishedchannel talking finished
ChannelToneDetectedtone detected on channel
ChannelTransferchannel transfer via REFER
ChannelUsereventuser-defined event from the dialplan
Dialdial event with caller and peer channels
BridgeAttendedTransferbridge attended transfer completed
BridgeBlindTransferbridge blind transfer completed
BridgeMergedtwo bridges merged
BridgeVideoSourceChangedbridge video source changed
ContactStatusChangecontact status changed
DeviceStateChangeddevice state changed
EndpointStateChangeendpoint state changed
PeerStatusChangepeer status changed
PlaybackContinuingplayback continuing to next media uri
RecordingFailedrecording failed
ApplicationMoveFailedapplication move failed
ApplicationRegisteredapplication registered
ApplicationReplacedapplication replaced by another websocket connection
ApplicationUnregisteredapplication unregistered
TextMessageReceivedtext message received
RESTResponseREST API response over websocket
Unknowncatch-all for event types not yet modeled

Resources (10 modules)

Application (5 operations)

MethodDescription
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)

MethodDescription
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)

MethodDescription
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)

MethodDescription
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)

MethodDescription
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)

MethodDescription
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)

MethodDescription
list()list all mailboxes
get()get a specific mailbox
update()also accepts POST for compatibility
delete()delete a mailbox

Playback (PlaybackHandle, 3 operations)

MethodDescription
control()control the playback (pause, unpause, restart, reverse, forward)
stop()stop the playback
get()get current playback state

Recording (RecordingHandle, 8 operations)

MethodDescription
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)

MethodDescription
list()list all sounds
get()get a specific sound