A modern JavaScript/TypeScript library for interacting with the Asterisk REST Interface (ARI).
- Complete Asterisk ARI support
- Written in TypeScript with full type support
- WebSocket support for real-time events
- Automatic reconnection management
- Simplified channel and playback handling
- ESM and CommonJS support
- Complete type documentation
npm install @ipcom/asterisk-ari
import { AriClient } from '@ipcom/asterisk-ari';
const client = new AriClient({
host: 'localhost', // Asterisk host
port: 8088, // ARI port
username: 'username', // ARI username
password: 'password', // ARI password
secure: false // Use true for HTTPS/WSS
});
// Connect to WebSocket to receive events
await client.connectWebSocket(['myApp']); // 'myApp' is your application name
// Listen for specific events
client.on('StasisStart', event => {
console.log('New channel started:', event.channel.id);
});
client.on('StasisEnd', event => {
console.log('Channel ended:', event.channel.id);
});
// Listen for DTMF events
client.on('ChannelDtmfReceived', event => {
console.log('DTMF received:', event.digit);
});
// Close WebSocket connection
client.closeWebSocket();
When working with WebSocket events, you get access to both the raw event data and convenient instance objects that allow direct interaction with the channel or playback:
client.on('StasisStart', async event => {
// event.channel contains the raw channel data
console.log('New channel started:', event.channel.id);
// event.instanceChannel provides a ready-to-use ChannelInstance
const channelInstance = event.instanceChannel;
// You can directly interact with the channel through the instance
await channelInstance.answer();
await channelInstance.play({ media: 'sound:welcome' });
});
// Similarly for playback events
client.on('PlaybackStarted', async event => {
// event.playback contains the raw playback data
console.log('Playback ID:', event.playback.id);
// event.instancePlayback provides a ready-to-use PlaybackInstance
const playbackInstance = event.instancePlayback;
// Direct control through the instance
await playbackInstance.control('pause');
});
This approach provides two key benefits:
- No need to manually create instances using
client.Channel()
orclient.Playback()
- Direct access to control methods without additional setup
Traditional approach:
client.on('StasisStart', async event => {
// Need to create channel instance manually
const channel = client.Channel(event.channel.id);
await channel.answer();
});
Using instance from event:
client.on('StasisStart', async event => {
// Instance is already available
await event.instanceChannel.answer();
});
This feature is particularly useful when handling multiple events and needing to perform actions on channels or playbacks immediately within event handlers.
// Create a channel instance
const channel = client.Channel();
// Originate a call
await channel.originate({
endpoint: 'PJSIP/1000',
extension: '1001',
context: 'default',
priority: 1
});
// Answer a call
await channel.answer();
// Play audio
const playback = await channel.play({
media: 'sound:welcome'
});
// Hangup the channel
await channel.hangup();
// Create a playback instance
const playback = client.Playback();
// Monitor playback events
playback.on('PlaybackStarted', event => {
console.log('Playback started:', event.playback.id);
});
playback.on('PlaybackFinished', event => {
console.log('Playback finished:', event.playback.id);
});
// Control playback
await playback.control('pause'); // Pause
await playback.control('unpause'); // Resume
await playback.control('restart'); // Restart
await playback.stop(); // Stop
// Create an instance for a specific channel
const channel = client.Channel('channel-id');
// Monitor specific channel events
channel.on('ChannelStateChange', event => {
console.log('Channel state changed:', event.channel.state);
});
channel.on('ChannelDtmfReceived', event => {
console.log('DTMF received on channel:', event.digit);
});
// Get channel details
const details = await channel.getDetails();
console.log('Channel details:', details);
// Handle channel variables
await channel.getVariable('CALLERID');
await channel.setVariable('CUSTOM_VAR', 'value');
// Play audio on a specific channel
const channel = client.Channel('channel-id');
const playback = await channel.play({
media: 'sound:welcome',
lang: 'en'
});
// Monitor specific playback
playback.on('PlaybackStarted', event => {
console.log('Playback started on channel');
});
// Control playback
await channel.stopPlayback(playback.id);
await channel.pausePlayback(playback.id);
await channel.resumePlayback(playback.id);
try {
await client.connectWebSocket(['myApp']);
} catch (error) {
console.error('Error connecting to WebSocket:', error);
}
// Using with async/await
try {
const channel = client.Channel();
await channel.originate({
endpoint: 'PJSIP/1000'
});
} catch (error) {
console.error('Error originating call:', error);
}
The library provides complete type definitions for all operations:
import type {
Channel,
ChannelEvent,
WebSocketEvent
} from '@ipcom/asterisk-ari';
// Types will be available for use
const handleChannelEvent = (event: ChannelEvent) => {
const channelId: string = event.channel.id;
};
The library provides access to many other ARI features:
- Bridge management
- Endpoint handling
- Sound manipulation
- Application control
- Asterisk system information
- And much more...
// Create and manage a bridge
const bridge = await client.bridges.createBridge({
type: 'mixing',
name: 'myBridge'
});
// Add channels to bridge
await client.bridges.addChannels(bridge.id, {
channel: ['channel-id-1', 'channel-id-2']
});
// Start recording on a channel
const channel = client.Channel('channel-id');
await channel.record({
name: 'recording-name',
format: 'wav',
maxDurationSeconds: 60,
beep: true
});
// Create external media channel
const channel = await client.channels.createExternalMedia({
app: 'myApp',
external_host: 'media-server:8088',
format: 'slin16'
});
For complete API documentation, please refer to the TypeScript types and interfaces exported by the package.
Contributions are welcome! Please feel free to submit a Pull Request.
Apache-2.0