Asterisk ari-request: Difference between revisions

From 탱이의 잡동사니
Jump to navigation Jump to search
(4 intermediate revisions by the same user not shown)
Line 20: Line 20:


[
[
    {
  {
        "bridge_ids": [
    "name": "test",
            "__AST_BRIDGE_ALL_TOPIC"
    "channel_ids": [
        ],
      "__AST_CHANNEL_ALL_TOPIC"
        "channel_ids": [
    ],
            "__AST_CHANNEL_ALL_TOPIC"
    "bridge_ids": [
        ],
      "__AST_BRIDGE_ALL_TOPIC"
        "device_names": [
    ],
            "__AST_DEVICE_STATE_ALL_TOPIC"
    "endpoint_ids": [
        ],
      "__AST_ENDPOINT_ALL_TOPIC"
        "endpoint_ids": [
    ],
            "__AST_ENDPOINT_ALL_TOPIC"
     "device_names": [
        ],
      "__AST_DEVICE_STATE_ALL_TOPIC"
        "name": "pchero-voip"
    ],
    },
    "events_allowed": [],
     {
    "events_disallowed": []
        "bridge_ids": [
  }
            "__AST_BRIDGE_ALL_TOPIC"
        ],
        "channel_ids": [
            "__AST_CHANNEL_ALL_TOPIC"
        ],
        "device_names": [
            "__AST_DEVICE_STATE_ALL_TOPIC"
        ],
        "endpoint_ids": [
            "__AST_ENDPOINT_ALL_TOPIC"
        ],
        "name": "pchero_voip"
    }
]
]
</pre>
</pre>


=== /applications/{applicationName} GET ===
=== /applications/{applicationName} GET ===
Line 65: Line 52:
Normal
Normal
<pre>
<pre>
$ curl -X GET -u asterisk:asterisk localhost:8088/ari/applications/pchero_voip
$ curl -X GET -u asterisk:asterisk http://192.168.30.10:8088/ari/applications/test
 
{
  "name": "test",
  "channel_ids": [
    "__AST_CHANNEL_ALL_TOPIC"
  ],
  "bridge_ids": [
    "__AST_BRIDGE_ALL_TOPIC"
  ],
  "endpoint_ids": [
    "__AST_ENDPOINT_ALL_TOPIC"
  ],
  "device_names": [
    "__AST_DEVICE_STATE_ALL_TOPIC"
  ],
  "events_allowed": [],
  "events_disallowed": []
}
</pre>
 
=== /applications/{applicationName}/subscription POST ===
Subscribe an application to a event source. Returns the state of the application after the subscriptions have changed.
 
'''Path parameters(parameters are case-sensitive)'''
* applicationName: string - Application's name
 
'''Query parameters'''
* eventSource: string - (required) URI for event source (channel: {channelId}, bridge: {bridgeId}, endpoint: {tech}[/{resource}], deviceState:{deviceName}
: Allows comma separated values.
 
'''Error responses'''
* 400: Missing parameter.
* 404: Application does not exist.
* 422: Event source does not exist.
 
==== Example ====
<pre>
$ curl -X POST -u asterisk:asterisk http://localhost:8088/ari/applications/test/subscription -H 'content-type: application/json' \
  -d '{"eventSource": "endpoint:PJSIP"}'


{
{
Line 80: Line 106:
         "__AST_ENDPOINT_ALL_TOPIC"
         "__AST_ENDPOINT_ALL_TOPIC"
     ],
     ],
     "name": "pchero_voip"
    "events_allowed": [],
    "events_disallowed": [],
     "name": "test"
}
}
</pre>
</pre>


=== /applications/{applicationName}/subscription POST ===
=== /applications/{applicationName}/subscription DELETE ===
Subscribe an application to a event source. Returns the state of the application after the subscriptions have changed.
Unsubscribe an application from an event source. Returns the state of the application after the subscription have changed.


'''Path parameters(parameters are case-sensitive)'''
'''Path parameters(parameters are case-sensitive)'''
Line 97: Line 125:
* 400: Missing parameter.
* 400: Missing parameter.
* 404: Application does not exist.
* 404: Application does not exist.
* 409: Application not subscribed to event source.
* 422: Event source does not exist.
* 422: Event source does not exist.


==== Example ====
==== Example ====
<pre>
$ curl -X DELETE -u asterisk:asterisk http://localhost:8088/ari/applications/test/subscription -H 'content-type: application/json' -d '{"eventSource": "endpoint:PJSIP"}'
{
    "bridge_ids": [
        "__AST_BRIDGE_ALL_TOPIC"
    ],
    "channel_ids": [
        "__AST_CHANNEL_ALL_TOPIC"
    ],
    "device_names": [
        "__AST_DEVICE_STATE_ALL_TOPIC"
    ],
    "endpoint_ids": [],
    "events_allowed": [],
    "events_disallowed": [],
    "name": "test"
}
</pre>


== Asterisk ==
== Asterisk ==

Revision as of 21:33, 11 April 2019

Overview

Asterisk ARI(Asterisk REST Interface) 내용 정리.

Basic

Asterisk-12 버전부터는 ARI(Asterisk REST Interface) 를 지원한다.

기본 사용포트 및 base uri 은 다음과 같다.

http://localhost:8088/ari

Applications

/applications GET

List all applications.

Example

Normal

$ curl -X GET -u asterisk:asterisk localhost:8088/ari/applications

[
  {
    "name": "test",
    "channel_ids": [
      "__AST_CHANNEL_ALL_TOPIC"
    ],
    "bridge_ids": [
      "__AST_BRIDGE_ALL_TOPIC"
    ],
    "endpoint_ids": [
      "__AST_ENDPOINT_ALL_TOPIC"
    ],
    "device_names": [
      "__AST_DEVICE_STATE_ALL_TOPIC"
    ],
    "events_allowed": [],
    "events_disallowed": []
  }
]

/applications/{applicationName} GET

Get detail of an application.

Path parameters

  • applicationName: string - Application's name.

Error responses

  • 404 : Application does not exist.

Example

Normal

$ curl -X GET -u asterisk:asterisk http://192.168.30.10:8088/ari/applications/test

{
  "name": "test",
  "channel_ids": [
    "__AST_CHANNEL_ALL_TOPIC"
  ],
  "bridge_ids": [
    "__AST_BRIDGE_ALL_TOPIC"
  ],
  "endpoint_ids": [
    "__AST_ENDPOINT_ALL_TOPIC"
  ],
  "device_names": [
    "__AST_DEVICE_STATE_ALL_TOPIC"
  ],
  "events_allowed": [],
  "events_disallowed": []
}

/applications/{applicationName}/subscription POST

Subscribe an application to a event source. Returns the state of the application after the subscriptions have changed.

Path parameters(parameters are case-sensitive)

  • applicationName: string - Application's name

Query parameters

  • eventSource: string - (required) URI for event source (channel: {channelId}, bridge: {bridgeId}, endpoint: {tech}[/{resource}], deviceState:{deviceName}
Allows comma separated values.

Error responses

  • 400: Missing parameter.
  • 404: Application does not exist.
  • 422: Event source does not exist.

Example

$ curl -X POST -u asterisk:asterisk http://localhost:8088/ari/applications/test/subscription -H 'content-type: application/json' \
  -d '{"eventSource": "endpoint:PJSIP"}'

{
    "bridge_ids": [
        "__AST_BRIDGE_ALL_TOPIC"
    ],
    "channel_ids": [
        "__AST_CHANNEL_ALL_TOPIC"
    ],
    "device_names": [
        "__AST_DEVICE_STATE_ALL_TOPIC"
    ],
    "endpoint_ids": [
        "__AST_ENDPOINT_ALL_TOPIC"
    ],
    "events_allowed": [],
    "events_disallowed": [],
    "name": "test"
}

/applications/{applicationName}/subscription DELETE

Unsubscribe an application from an event source. Returns the state of the application after the subscription have changed.

Path parameters(parameters are case-sensitive)

  • applicationName: string - Application's name

Query parameters

  • eventSource: string - (required) URI for event source (channel: {channelId}, bridge: {bridgeId}, endpoint: {tech}[/{resource}], deviceState:{deviceName}
Allows comma separated values.

Error responses

  • 400: Missing parameter.
  • 404: Application does not exist.
  • 409: Application not subscribed to event source.
  • 422: Event source does not exist.

Example

$ curl -X DELETE -u asterisk:asterisk http://localhost:8088/ari/applications/test/subscription -H 'content-type: application/json' -d '{"eventSource": "endpoint:PJSIP"}'

{
    "bridge_ids": [
        "__AST_BRIDGE_ALL_TOPIC"
    ],
    "channel_ids": [
        "__AST_CHANNEL_ALL_TOPIC"
    ],
    "device_names": [
        "__AST_DEVICE_STATE_ALL_TOPIC"
    ],
    "endpoint_ids": [],
    "events_allowed": [],
    "events_disallowed": [],
    "name": "test"
}

Asterisk

/asterisk/info GET

Gets Asterisk system information.

Query parameters

  • only: string: Filter information returned.
Allowed values: build, system, config, status
Allows comma separated values.

Examples

$ curl -X GET -u asterisk:asterisk http://localhost:8088/ari/asterisk/info

{
    "build": {
        "date": "2019-01-08 14:16:26 UTC",
        "kernel": "4.9.0-8-amd64",
        "machine": "x86_64",
        "options": "OPTIONAL_API",
        "os": "Linux",
        "user": "pchero"
    },
    "config": {
        "default_language": "en",
        "name": "",
        "setid": {
            "group": "",
            "user": ""
        }
    },
    "status": {
        "last_reload_time": "2019-01-11T08:04:11.203+0000",
        "startup_time": "2019-01-11T08:04:11.203+0000"
    },
    "system": {
        "entity_id": "42:01:0a:84:00:12",
        "version": "GIT-master-cb214713c0M"
    }
}

/asterisk/modules GET

List Asterisk modules

Examples

$ curl -X GET -u asterisk:asterisk http://localhost:8088/ari/asterisk/modules

[
    {
        "description": "Named ACL system",
        "name": "acl",
        "status": "Running",
        "support_level": "core",
        "use_count": 2
    },
    {
        "description": "Asterisk ADSI Programming Application",
        "name": "app_adsiprog.so",
        "status": "Running",
        "support_level": "deprecated",
        "use_count": 0
    },
    ...
]

/asterisk/modules/{moduleName} GET

Get Asterisk module information.

Path parameters(Parameters are case-sensitive)

  • moduleName: string: Module's name

Error responses

  • 404: Module could not be found in running modules.
  • 409: Module information could not be retrieved.

Examples

$ curl -X GET -u asterisk:asterisk http://localhost:8088/ari/asterisk/modules/res_pjsip.so

{
    "description": "Basic SIP resource",
    "name": "res_pjsip.so",
    "status": "Running",
    "support_level": "core",
    "use_count": 46
}

Bridges

/bridges GET

List all active bridges in Asterisk.

Example

$ curl -s -X GET -u asterisk:asterisk localhost:8088/ari/bridges | python -m json.tool
[
    {
        "bridge_class": "stasis",
        "bridge_type": "mixing",
        "channels": [],
        "creator": "Stasis",
        "id": "3b925a5a-c464-4fc1-8fd9-8dc5dd330284",
        "name": "",
        "technology": "simple_bridge",
        "video_mode": "none"
    },
    {
        "bridge_class": "stasis",
        "bridge_type": "mixing",
        "channels": [],
        "creator": "Stasis",
        "id": "1beb554c-d752-4b16-b1d9-91b3f1375562",
        "name": "",
        "technology": "simple_bridge",
        "video_mode": "none"
    },
    {
        "bridge_class": "stasis",
        "bridge_type": "mixing",
        "channels": [],
        "creator": "Stasis",
        "id": "edfc58b1-1130-42c3-8117-0ca6d9e279f1",
        "name": "",
        "technology": "simple_bridge",
        "video_mode": "none"
    }
]

/bridges POST

Create a new bridge. This bridge persists until it has been shut down, or Asterisk has been shut down.

Query parameters

  • type: string : Comma separated list of bridge type attributes(mixing, holding, dtmf_events, proxy_media, video_sfu).
  • bridgeId: string : Unique ID to give to the bridge being created.
  • name: string : Name to give to the bridge being created.

Example

$ curl -s -X POST -u asterisk:asterisk localhost:8088/ari/bridges | python -m json.tool
{
    "bridge_class": "stasis",
    "bridge_type": "mixing",
    "channels": [],
    "creator": "Stasis",
    "id": "edfc58b1-1130-42c3-8117-0ca6d9e279f1",
    "name": "",
    "technology": "simple_bridge",
    "video_mode": "talker"
}

Channels

/channels GET

Example

$ curl localhost:8088/ari/channels

[
  {
    "id": "test_call",
    "name": "PJSIP/sipp-uac-00000000",
    "state": "Up",
    "caller": {
      "name": "",
      "number": ""
    },
    "connected": {
      "name": "",
      "number": ""
    },
    "accountcode": "",
    "dialplan": {
      "context": "sipp-uac",
      "exten": "s",
      "priority": 1
    },
    "creationtime": "2019-03-15T23:16:26.026+0100",
    "language": "en"
  }
]

/channels POST

Create a new channel(originate). The new channel is created immediately and a snapshot of it returned. If a Stasis application is provided it will be automatically subscribed to the originated for further events and updates.

Query parameters

  • endpoint: string - (required) Endpoint to call.
  • extension: string - The extension to dial after the endpoint answers. Mutually exclusive with 'app'.
  • context: string - The context to dial after the endpoint answers. If omitted, uses 'default'. Mutually exclusive with 'app'.
  • priority: long - The priority to dial after the endpoint answers. If omitted, uses 1. Mutually exclusive with 'app'.
  • label: string - The label to dial after the endpoint answers. Will supersede 'priority' if provided. Mutually exclusive with 'app'.
  • app: string - The application that is subscribed to the originated channel. When the channel is answered, it will be passed to this Stasis application. Mutually exclusive with 'context', 'extension', 'priority' and 'label'.
  • appArgs: string - The application arguments to pass to the Stasis application provided by 'app'. Mutually exclusive with 'context', 'extension', 'priority', and 'label'.
  • callerid: string - CallerID to use when dialing the endpoint or extension.
  • timeout: int - Timeout(in seconds) before giving up dialing, or -1 for no timeout.
Default: 30
  • channelId: string - The unique id to assign the channel on creation.
  • otherChannelId: string - The unique id to assign the second channel when using local channels.
  • originator: string - The unique id of the channel which is originating this one.
  • formats: string - The format name capability list to use if originator is not specified. Ex. "ulaw, slin16". Format names can be found with "core show codecs".

Body parameter

  • variables: containers - The "variables" key in the body object holds variable key/value pairs to set on the channel on creation. Other keys in the body object are interpreted as query parameters. Ex. { "endpoint": "SIP/Alice", "variables": {"CALLERID(name)": "Alice"}}

Error response

  • 400 : Invalid parameters for originating a channel.
  • 409 : Channel with given unique ID already exists.

Example

$ curl -X POST http://192.168.200.20:8088/ari/channels\?api_key=asterisk:asterisk\&endpoint=pjsip/test@sippuas\&app=test

{
	"id": "1543782963.26",
	"name": "PJSIP/sippuas-0000000d",
	"state": "Down",
	"caller": {
		"name": "",
		"number": ""
	},
	"connected": {
		"name": "",
		"number": ""
	},
	"accountcode": "",
	"dialplan": {
		"context": "sippuas",
		"exten": "s",
		"priority": 1
	},
	"creationtime": "2018-12-02T21:36:03.239+0100",
	"language": "en"
}

/channels/{channelId} GET

Example

$ curl localhost:8088/ari/channels/test_call
{
  "id": "test_call",
  "name": "PJSIP/sipp-uac-00000000",
  "state": "Up",
  "caller": {
    "name": "",
    "number": ""
  },
  "connected": {
    "name": "",
    "number": ""
  },
  "accountcode": "",
  "dialplan": {
    "context": "sipp-uac",
    "exten": "s",
    "priority": 1
  },
  "creationtime": "2019-03-15T23:16:26.026+0100",
  "language": "en"
}

/channels/{channelId}/answer POST

Example

$ curl -X POST -u asterisk:asterisk localhost:8088/ari/channels/1548886670.0/answer

/channels/{channelId}/continue POST

Exit application; continue execution in the dialplan.

Path parameters(Parameters are case-sensitive)

  • channelId: string - Channel's Id

Query parameters

  • context: string - The context to continue to.
  • extension: string - The extension to continue to.
  • priority: int - The priority to continue to.
  • label: string - The label to continue to - will supersede 'priority' if both are provided.

Error responses

  • 404: Channel not found
  • 409: Channel not in a Stasis application.
  • 412: Channel in invalid state.

Example

Normal

$ curl -X POST http://192.168.200.20:8088/ari/channels/1543782963.26/continue\?api_key=asterisk:asterisk

No channel info

~$ curl -X POST http://192.168.200.20:8088/ari/channels/1543782963.26/continue\?api_key=asterisk:asterisk

{"message":"Channel not in Stasis application"}

/channels/{channelId}/create POST

Create channel.

Query parameters

  • endpoint: string - (required) Endpoint for channel communication.
  • app: string - (required) Stasis Application to place channel into.
  • appArgs: string - The application arguments to pass to the Stasis application provided by 'app'. Mutually exclusive with 'context', 'extension', 'priority', and 'label'.
  • channelId: string - The unique id to assign the channel on creation.
  • otherChannelId: string - The unique id to assign the second channel when using local channels.
  • originator: string - Unique ID of the calling channel.
  • formats: string - The format name capability list to use if originator is not specified. Ex. "ulaw,slin16". Format names can be found with "core show codecs".

Error responses

  • 409: Channel with given unique ID already exists.

Example

Normal

## Asterisk - test_call2: create channel only
curl -X "POST" "http://localhost:8088/ari/channels/create" \
     -H 'Content-Type: application/json; charset=utf-8' \
     -u 'asterisk:asterisk' \
     -d $'{
  "appArgs": "pchero_dialed=1",
  "channelId": "test_call2",
  "app": "pchero_voip",
  "endpoint": "PJSIP/pchero-voip/sip:test@127.0.0.1",
  "callerId": "pchero"
}'

{
    "accountcode": "",
    "caller": {
        "name": "",
        "number": ""
    },
    "connected": {
        "name": "",
        "number": ""
    },
    "creationtime": "2019-02-25T13:37:26.509+0000",
    "dialplan": {
        "context": "pchero-voip",
        "exten": "s",
        "priority": 1
    },
    "id": "test_call2",
    "language": "en",
    "name": "PJSIP/pchero-voip-00000049",
    "state": "Down"
}

/channels/{channelId}/dial POST

Dial a created channel.

Path parameters(Parameters are case-sensitive)

  • ChannelId: string - Channel's id.

Query parameters

  • caller: string - Channel ID of caller.
  • timeout: int - Dial timeout.
Allowed range: Min: 0, Max: None

Example

Normal

## Asterisk - test_call: dial to test_call2
curl -X "POST" "http://localhost:8088/ari/channels/test_call/dial" \
     -H 'Content-Type: application/json; charset=utf-8' \
     -u 'asterisk:asterisk' \
     -d $'{
  "channelId": "test_call2"
}'

/channells/{channelId}/record POST

Start a recording. Record audio from a channel. Note that this will not capture audio sent to the channel. The bridge itself has a record feature if that's what you want.

Path parameters(Parameters are case-sensitive)

  • chanelId: string: Channel's Id.

Query parameters

  • name: string: (required)Recording's filename.
  • format: string: (required)Format to encode audio in.
  • maxDurationSeconds: int: Maximum duration of the recording, in seconds. 0 for no limit.
Allowed range: Min: 0, Max: None
  • maxSilenceSeconds: int: Maximum duration of silence, in seconds, 0 for no limit
Allowed range: Min: 0, Max: None
  • ifExists: string: Action to take if a recording with the same name already exists.
Default: fail
Allowed values: fail, overwrite, append
  • beep: boolean: Play beep when recording begins.
  • terminateOn: string: DTMF input to terminate recording.
Default: none
Allowed value: non, any, *, #

Error responses

  • 400: Invalid parameters.
  • 404: Channel not found.
  • 409: Channel is not in a Stasis application; the channel is currently bridged with other channels; A recording with the same name already exists on the system and can not be overwritten because it is in progess or ifExists=fail.
  • 422: The format specified is unknown on this system.


/channells/{channelId}/play POST

Example

curl -X POST -u asterisk:asterisk -H 'Content-Type: application/json; charset=utf-8' localhost:8088/ari/channels/1548886670.0/play -d \
'{"media": ["sound:https://github.com/pchero/asterisk-medias/raw/master/samples_codec/pcm_samples/example-mono_16bit_8khz_pcm.wav"]}'

{
    "id": "bbd2b76c-091d-4b13-bb9d-982ddeec53d5",
    "language": "en",
    "media_uri": "sound:https://github.com/pchero/asterisk-medias/raw/master/samples_codec/pcm_samples/example-mono_16bit_8khz_pcm.wav",
    "state": "queued",
    "target_uri": "channel:1548886670.0"
}

/channels/{channelId}/variable GET

Get the value of a channel variable or function.

You can see the more available channel variables are here

Path Parameters

  • channelId : string : Channel's id.

Query parameters

  • variable : string : (required) The channel variable or function to get.

Example

$ curl -s -u asterisk:asterisk localhost:8088/ari/channels/test_call/variable\?variable=CHANNEL\(rtcp,all_loss\) | python -m json.tool

{
    "value": "minrxlost=0.000000;maxrxlost=8.000000;avgrxlost=0.024691;stdevrxlost=inf;reported_minlost=0.000000;reported_maxlost=0.000000;reported_avglost=0.000000;reported_stdevlost=0.000000;"
}
$ curl -s -u asterisk:asterisk localhost:8088/ari/channels/test_call/variable\?variable=CHANNEL\(rtcp,all\) | python -m json.tool

{
    "value":"ssrc=528427381;themssrc=487275306;lp=8;rxjitter=0.000000;rxcount=96231;txjitter=0.001051;txcount=900;rlp=0;rtt=0.000000"
}
$ curl -s -u asterisk:asterisk localhost:8088/ari/channels/test_call/variable\?variable=CHANNEL\(pjsip,call-id\) | python -m json.tool

{
    "value":"7486de53-1305-42a3-abc5-97a34626fe8e"
}

Devicestates

Endpoints

Events

/events GET

Websocket connection for events.

Query parameters

  • app: string - (required) Applications to subscribe to.
Allows comma separated values.
  • subscribeAll: boolean - Subscribe to all Asterisk events. If provided, the applications listed will be subscribed to all events, effectively disabling the application specific subscriptions.
Default: false

Example

ws://192.168.200.20:8088/ari/events?api_key=asterisk:asterisk&app=test
ws://192.168.200.20:8088/ari/events?api_key=asterisk:asterisk&app=test&subscribeAll=true

Mailboxes

Playbacks

Recordings

/recordings/stored GET

List recordings that are complete.

Examples

$ curl -X GET -u asterisk:asterisk http://localhost:8088/ari/recordings/stored

[
    {
        "format": "wav",
        "name": "test_call"
    }
]

/recordings/stored/{recordingName} DELETE

Delete a stored recording.

Path parameters

  • recordingName: string: The name of the recording.

Error responses

  • 404: Recording not found.

Examples

Normal

$ curl -X DELETE -u asterisk:asterisk http://localhost:8088/ari/recordings/stored/test_call

Not found

$ curl -X DELETE -u asterisk:asterisk http://localhost:8088/ari/recordings/stored/test_call
{"message":"Recording not found"}

/recordings/stored/{recording name} GET

Get a stored recording's details.

Path parameters

  • recording name: string: The name of the recording.

Error response

  • 404: Recording not found

Examples

$ curl -X GET -u asterisk:asterisk http://localhost:8088/ari/recordings/stored/test_call

{
    "format": "wav",
    "name": "test_call"
}

Sounds

/sounds GET

List all sounds.

Query parameters

  • lang: string: Lookup sound for specific language.
  • format: string: Lookup sound in a specific format.

Examples

$ curl -X GET -u asterisk:asterisk http://localhost:8088/ari/sounds

[
    {
        "formats": [
            {
                "format": "gsm",
                "language": "en"
            }
        ],
        "id": "conf-now-unmuted",
        "text": "The conference is now unmuted."
    },
    {
        "formats": [
            {
                "format": "gsm",
                "language": "en"
            }
        ],
        "id": "queue-minutes",
        "text": "minutes"
    },
    ...
]

/sounds/{soundId} GET

Get a sound's details.

Path parameters(case-sensitive)

  • sound: string: Sound's id.

Examples

$ curl -X GET -u asterisk:asterisk http://localhost:8088/ari/sounds/demo-thanks

{
    "formats": [
        {
            "format": "gsm",
            "language": "en"
        }
    ],
    "id": "demo-thanks",
    "text": "Goodbye.  Thank you for trying out the Asterisk Open Source PBX."
}

See also