Skip to main content

asyncio native asterisk client for python

Project description

ARI Client Library

A Python client library for Asterisk REST Interface (ARI) that provides an object-oriented approach to managing channels, bridges, and events.

Architecture

The library follows a clean architecture pattern with separation of concerns:

  • AriClient: Main client class that handles WebSocket connections and event dispatching
  • AriClientController: Separate controller class that handles all HTTP API operations
  • Model Objects: Bridge, Channel, and Event objects that encapsulate state and provide methods for actions

Key Design Principles

  1. All actions are performed via Bridge, Channel, and Event objects - This ensures that operations are context-aware and type-safe
  2. Controller is separate from client - The controller handles HTTP operations, while the client manages WebSocket connections
  3. Objects are self-contained - Each Bridge, Channel, and Event object has its own controller reference for performing actions

Installation

pip install -r requirements.txt
# or using uv
uv sync

Quick Start

import asyncio
from ari_client import AriClient, StasisStartEvent, StasisEndEvent
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Create client
client = AriClient(
    host="localhost",
    port=8088,
    ari_user="asterisk",
    ari_password="asterisk",
    tls_enabled=False
)

# Define event handlers
@client.on_stasis_start
async def on_stasis_start(event: StasisStartEvent):
    logger.info(f"Channel entered Stasis: {event.channel.id}")
    
    # Answer the channel using the channel object
    await event.channel.answer()
    
    # Create a bridge using the controller
    bridge = await client.ari.create_bridge(type="mixing")
    
    # Add channel to bridge using the bridge object
    await bridge.add_channel(event.channel.id)
    
    # Create external media using the controller
    external_media = await client.ari.create_external_media(
        external_host="192.168.1.100:10000",
        format="ulaw"
    )
    
    # Add external media to bridge
    await bridge.add_channel(external_media.id)
    await external_media.answer()

@client.on_stasis_end
async def on_stasis_end(event: StasisEndEvent):
    logger.info(f"Channel left Stasis: {event.channel.id}")

# Main function
async def main():
    await client.connect(app="myapp", subscribe_to_all=True)
    

    # Originate a call
    channel = await client.ari.originate(
        endpoint="PJSIP/1001",
        timeout=30
    )
    logger.info(f"Originated channel: {channel.id}")
    
    # Keep running
    try:
        await asyncio.sleep(3600)
    except KeyboardInterrupt:
        logger.info("Shutting down...")
    finally:
        await client.disconnect()

if __name__ == "__main__":
    asyncio.run(main())

Core Concepts

Event Objects

Event objects (StasisStartEvent, StasisEndEvent) are received when channels enter or leave your Stasis application. They contain channel information and can be used to access the channel object for performing actions.

Note: To create bridges, external media, or originate calls, use the controller via client.ari rather than event methods.

Channel Objects

Channel objects represent Asterisk channels and provide methods for channel operations:

  • channel.answer() - Answer the channel
  • channel.stop() - Hang up the channel

Bridge Objects

Bridge objects represent Asterisk bridges and provide methods for bridge operations:

  • bridge.add_channel(channel_id) - Add a channel to the bridge
  • bridge.stop() - Destroy the bridge

API Reference

AriClient

Main client class for connecting to Asterisk ARI.

Constructor

AriClient(
    host: str,
    port: int,
    ari_user: str,
    ari_password: str,
    tls_enabled: bool = False
)

Methods

  • async connect(app: str, subscribe_to_all: bool = False) - Connect to Asterisk and start listening for events
  • on_stasis_start(handler) - Register handler for StasisStart events (can be used as decorator)
  • on_stasis_end(handler) - Register handler for StasisEnd events (can be used as decorator)
  • ari - Get the ari controller instance for performing actions outside event handlers
  • async disconnect() - Disconnect from Asterisk

Event Handlers

Event handlers can be registered using decorators or method calls:

# As decorator
@client.on_stasis_start
async def handler(event: StasisStartEvent):
    pass

# As method call
async def handler(event: StasisStartEvent):
    pass

client.on_stasis_start(handler)

AriClientController

Controller class that handles all HTTP API operations. Typically accessed via client.ari or through event/channel/bridge objects.

Methods

  • async answer_channel(channel_id: str) - Answer a channel
  • async stop_channel(channel_id: str) - Hang up a channel
  • async create_bridge(type: str, bridge_id: Optional[str] = None, name: Optional[str] = None) -> Bridge - Create a bridge
  • async bridge_add_channel(bridge_id: str, channel_id: str) - Add channel to bridge
  • async stop_bridge(bridge_id: str) - Destroy a bridge
  • async create_external_media(...) -> Channel - Create external media channel
  • async originate(...) -> Channel - Originate a new channel

Event

Base event class for all ARI events.

StasisStartEvent

Event received when a channel enters your Stasis application.

Properties

  • type: EventType - Event type (STASIS_START)
  • timestamp: datetime - Event timestamp
  • args: List[str] - Arguments passed to the Stasis application
  • channel: Channel - The channel that entered Stasis
  • asterisk_id: str - Asterisk instance ID
  • application: str - Application name

StasisEndEvent

Event received when a channel leaves your Stasis application.

Properties

  • type: EventType - Event type (STASIS_END)
  • timestamp: datetime - Event timestamp
  • channel: Channel - The channel that left Stasis
  • application: str - Application name

Channel

Represents an Asterisk channel.

Properties

  • id: str - Channel unique identifier
  • name: str - Channel name
  • state: str - Channel state
  • caller: CallerID - Caller information
  • connected: CallerID - Connected party information
  • creationtime: datetime - Channel creation timestamp

Methods

  • async answer() - Answer the channel
  • async stop() - Hang up the channel
  • add_controller(controller: AriClientController) - Add controller for performing actions

Bridge

Represents an Asterisk bridge.

Properties

  • id: str - Bridge unique identifier
  • bridge_type: BridgeType - Type of bridge (MIXING, HOLDING)
  • name: str - Bridge name
  • channels: List[str] - List of channel IDs in the bridge
  • video_mode: Optional[VideoMode] - Video mode if applicable

Methods

  • async add_channel(channel_id: str) - Add a channel to the bridge
  • async stop() - Destroy the bridge

Best Practices

  1. Always use event/channel/bridge objects for actions - This ensures proper context and type safety
  2. Handle exceptions in event handlers - The library automatically logs exceptions, but you should handle them appropriately
  3. Use the controller for operations - Access the controller via client.ari to create bridges, external media, or originate calls
  4. Store bridge/channel references - If you need to reference bridges or channels later, store them in a dictionary or similar structure

Example: Call Bridging

bridge_map: dict[str, Bridge] = {}

@client.on_stasis_start
async def on_stasis_start(event: StasisStartEvent):
    # Skip external media channels
    if event.channel.name.startswith("UnicastRTP"):
        return
    
    # Answer the incoming channel
    await event.channel.answer()
    
    # Create a mixing bridge using the controller
    bridge = await client.ari.create_bridge(type="mixing,proxy_media")
    
    # Add the channel to the bridge
    await bridge.add_channel(event.channel.id)
    
    # Create external media for streaming using the controller
    external_media = await client.ari.create_external_media(
        external_host="192.168.1.100:10000",
        format="ulaw"
    )
    
    # Add external media to bridge and answer it
    await bridge.add_channel(external_media.id)
    await external_media.answer()
    
    # Store bridge reference for cleanup
    bridge_map[event.channel.id] = bridge

@client.on_stasis_end
async def on_stasis_end(event: StasisEndEvent):
    # Clean up bridge when channel leaves
    bridge = bridge_map.pop(event.channel.id, None)
    if bridge:
        await bridge.stop()

Error Handling

The library includes automatic error handling:

  • Event handler exceptions are automatically logged and don't crash the event listener
  • HTTP API errors raise exceptions with descriptive messages
  • WebSocket connection errors are logged and re-raised

Always wrap your operations in try-except blocks when appropriate:

@client.on_stasis_start
async def on_stasis_start(event: StasisStartEvent):
    try:
        await event.channel.answer()
    except Exception as e:
        logger.error(f"Failed to answer channel: {e}")

License

[Your License Here]

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ari_client-0.6.1.tar.gz (17.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ari_client-0.6.1-py3-none-any.whl (15.9 kB view details)

Uploaded Python 3

File details

Details for the file ari_client-0.6.1.tar.gz.

File metadata

  • Download URL: ari_client-0.6.1.tar.gz
  • Upload date:
  • Size: 17.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ari_client-0.6.1.tar.gz
Algorithm Hash digest
SHA256 698dca7eba4d97b42c200fe6cb7345e9354efab5793406cb21fa7bab2ec177d3
MD5 514049d2279285f15aa2affa3a15182b
BLAKE2b-256 1b6b4ddbe655243f8c86752130eff72571f50b7ed8a4c3b92df64b39244a91c0

See more details on using hashes here.

File details

Details for the file ari_client-0.6.1-py3-none-any.whl.

File metadata

  • Download URL: ari_client-0.6.1-py3-none-any.whl
  • Upload date:
  • Size: 15.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ari_client-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3b41306cafdc499a8820c0a9a7af1b7cfae3c8aa485cc464e3c6310c74cfbdb5
MD5 78d4053cbeade72ed296b2b4b8a65329
BLAKE2b-256 611a152ec3849a0ee4a01a424d68915aa114f82a8df2cdb215b1c0ed02c8a714

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page