YATE - External module

The work on this document is still in progress. Please do not use it as reference, the specifications are likely to change.

# External module command flow

## File handles used

The external user application or script comunicates with the module trough several file descriptors:
0 (stdin) - Carries commands and notifications from engine to application
1 (stdout) - Carries commands and answers from application to the engine
2 (stderr) - Has the usual meaning of reporting errors and is directed to the engine's stderr or logfile
3 (optional) - Transports audio data from the engine to the application
4 (optional) - Transports audio data from the application to the engine
File descriptors 3 and 4 are open only for audio capable applications.

## Socket operation

Yate can start one or more socket listeners and wait for external programs to connect to them. Depending on the platform, TCP and UNIX sockets may be available.
Once connected, an external program uses this single socket to send commands and receive answers from the engine.
For reporting errors it is recommended to use the %%>output keyword.
Each listener can have a single role or the connecting program will have to use the %%>connect command first to esablish a role.

## Format of commands and notifications

Words enclosed in <angle brackets> must be replaced with the proper value.
Elements in [square brackets] are optional. An ellipsis ... denotes optional repetition of the last element.
Every command is sent on its own newline (\n, ^J, decimal 10) delimited line.
Any value that contains special characters (ASCII code lower than 32) MUST have them converted to %<upcode> where <upcode> is the character with a numeric value equal with 64 + original ASCII code. The % character itself MUST be converted to a special %% representation. Characters with codes higher than 32 (except %) SHOULD not be escaped but may be so. A %-escaped code may be received instead of an unescaped character anywhere except in the initial keyword or the delimiting colon (:) characters. Anywhere in the line except the initial keyword a % character not followed by a character with a numeric value higher than 64 (40H, 0x40, '@') or another % is an error.

Special Keyword: Error in
Error in:<original>
Direction: Engine to application
The engine sends this notification as answer to a syntactically incorrect line it received from the application.
<original> - the original line exactly as received (not escaped or something)
The external module SHOULD NOT send anything back to Yate in response to such a notification as it can result in an infinite loop.

Keyword: %%>message
%%>message:<id>:<time>:<name>:<retvalue>[:<key>=<value>...]
Direction: Engine to application
This line is sent by the engine to the application) to ask it to process a message. The Yate thread that dispatches the message will block until an answer is received (see below).
<id> - obscure unique message ID string generated by Yate
<time> - time (in seconds) the message was initially created
<name> - name of the message
<retvalue> - default textual return value of the message
<key>=<value> - enumeration of the key-value pairs of the message

Keyword: %%<message
%%<message:<id>:<processed>:[<name>]:<retvalue>[:<key>=<value>...]
Direction: Application to engine
One such answer is required for every received message (%%>message). When the engine gets a line in this format it modifies the provided values back into the message and let it continue or stop dispatching.
<id> - same message ID string received trough %%>message
<processed> - boolean ("true" or "false") indication if the message has been processed or it should be passed to the next handler
<name> - new name of the message, if empty keep unchanged
<retvalue> - new textual return value of the message
<key>=<value> - new key-value pairs to set in the message; to delete the key-value pair provide just a key name with no equal sign or value

Keyword: %%>message
%%>message:<id>:<time>:<name>:<retvalue>[:<key>=<value>...]
Direction: Application to engine
This line is sent by the application to the engine to ask it to process a message. The answer to such a message is delivered asynchronously (see below).
<id> - obscure unique message ID string generated by the application
<time> - time (in seconds) the message was initially created
<name> - name of the message
<retvalue> - default textual return value of the message
<key>=<value> - enumeration of the key-value pairs of the message

Keyword: %%<message
%%<message:<id>:<processed>:[<name>]:<retvalue>[:<key>=<value>...]
Direction: Engine to application
One such answer is required for every message (%%>message) the application sent to the engine. It contains the message's return values and parameters.
<id> - same message ID string received trough %%>message
<processed> - boolean ("true" or "false") indication if the message has been declared processed by one of the handlers
<name> - name of the message, possibly changed
<retvalue> - textual return value of the message
<key>=<value> - key-value pairs of parameters to the message.

Keyword: %%>install
%%>install:[<priority>]:<name>[:<filter-name>[:<filter-value>]]
Direction: Application to engine
Always from the application to the engine, requests the installing of a message handler for the application that requested it
The answer to the install request is delivered asynchronously (see below).
<priority> - priority in chain, use default (100) if missing
<name> - name of the messages for that a handler should be installed
<filter-name> - name of a variable the handler will filter
<filter-value> - matching value for the filtered variable

Keyword: %%<install
%%<install:<priority>:<name>:<success>
Direction: Engine to application
Confirmation from engine to the application that the handler has been installed properly or not.
<priority> - priority of the installed handler
<name> - name of the messages asked to handle
<success> - boolean ("true" or "false") success of operation

Keyword: %%>uninstall
%%>uninstall:<name>
Direction: Application to engine
Always from the application to the engine, requests uninstalling a previously installed message handler
The answer to the uninstall request is delivered asynchronously (see below).
<name> - name of the message handler thst should be uninstalled

Keyword: %%<uninstall
%%<uninstall:<priority>:<name>:<success>
Direction: Engine to application
Confirmation from engine to the application that the handler has been uninstalled properly or not.
<priority> - priority of the previously installed handler
<name> - name of the message handler asked to uninstall
<success> - boolean ("true" or "false") success of operation

Keyword: %%>watch
%%>watch:<name>
Direction: Application to engine
Always from the application to the engine, requests the installing of a message watcher (post-dispatching notifier) for the application that requested it
The answer to the watch request is delivered asynchronously (see below).
<name> - name of the messages for that a watcher should be installed

Keyword: %%<watch
%%<watch:<name>:<success>
Direction: Engine to application
Confirmation from engine to the application that the watcher has been installed properly or not.
<name> - name of the messages asked to watch
<success> - boolean ("true" or "false") success of operation

Keyword: %%>unwatch
%%>unwatch:<name>
Direction: Application to engine
Always from the application to the engine, requests uninstalling a previously installed message watcher
The answer to the unwatch request is delivered asynchronously (see below).
<name> - name of the message watcher thst should be uninstalled

Keyword: %%<unwatch
%%<unwatch:<name>:<success>
Direction: Engine to application
Confirmation from engine to the application that the watcher has been uninstalled properly or not.
<name> - name of the message watcher asked to uninstall
<success> - boolean ("true" or "false") success of operation

Keyword: %%>setlocal
%%>setlocal:<name>:<value>
Direction: Application to engine
Always from the application to the engine, requests the change of a local parameter
The answer to the change request is delivered asynchronously (see below).
<name> - name of the parameter to modify, must not be empty
<value> - new value to set in the local module instance, empty to just query
For read-only parameters you must provide an empty value.
Currently supported parameters:
id (string) - Identifier of the associated channel, if any
disconnected (bool) - Enable or disable sending "chan.disconnected" messages
trackparam (string) - Set the message handler tracking name, cannot be made empty
reason (string) - Set the disconnect reason that gets received by the peer channel
timeout (int) - Timeout in milliseconds for answering to messages
timebomb (bool) - Terminate this module instance if a timeout occured
setdata (bool) - Attach channel pointer as user data to generated messages
reenter (bool) - If this module is allowed to handle messages generated by itself
selfwatch (bool) - If this module is allowed to watch messages generated by itself
restart (bool) - Restart this global module if it terminates unexpectedly. Must be turned off to allow normal termination
Engine read-only run parameters:
engine.version (string,readonly) - Version of the engine, like "2.0.1"
engine.release (string,readonly) - Release type and number, like "beta2"
engine.nodename (string,readonly) - Server's node name as known by the engine
engine.runid (int,readonly) - Engine's run identifier
engine.configname (string,readonly) - Name of the master configuration
engine.sharedpath (string,readonly) - Path to the shared directory
engine.configpath (string,readonly) - Path to the program config files directory
engine.cfgsuffix (string,readonly) - Suffix of the config files names, normally ".conf"
engine.modulepath (string,readonly) - Path to the main modules directory
engine.modsuffix (string,readonly) - Suffix of the loadable modules, normally ".yate"
engine.logfile (string,readonly) - Name of the log file if in use, empty if not logging
engine.clientmode (bool,readonly) - Check if running as a client
engine.supervised (bool,readonly) - Check if running under supervisor
engine.maxworkers (int,readonly) - Maximum number of message worker threads
Engine configuration file parameters:
config.<section>.<key> (readonly) - Content of key= in [section] of main config file (yate.conf, yate-qt4.conf)

Keyword: %%<setlocal
%%<setlocal:<name>:<value>:<success>
Direction: Engine to application
Confirmation from engine to the application that the local parameter has been changed successfully or not.
<name> - name of the modified parameter
<value> - new value of the local parameter
<success> - boolean ("true" or "false") success of operation

Keyword: %%>output
%%>output:arbitrary unescaped string
Direction: Application to engine
The "output" keyword is used to relay arbitrary output messages to engine's logging output.
This is the proper way of logging messages for programs that connect to the socket interface as they may not have the standard error redirected.

Keyword: %%>connect
%%>connect:<role>[:<id>][:<type>]
Direction: Application to engine
The "connect" keyword is used only by external modules that attach to the socket interface. As the conection is initiated from the external module the engine must be informed on the role of the connection.
This must be the first request sent over a newly established socket connection. The role and direction of the connection is established and then this keyword cannot be used again on the same connection.
There is no answer to this request - if it fails the engine will slam the connection shut.
Connections with a role of play, record or playrec are data connections and must be attached to a valid control channel. Any existing data endpoint with the same type and direction is closed.
<role> - role of this connection: global, channel, play, record, playrec
<id> - channel id to connect this socket to
<type> - type of data channel, assuming audio if missing

## Example

In the example below the lines sent from application to engine are prefixed with A: while lines sent from engine to application are prefixed with E:
Comments are indented

        Application installs a handler for a "test" handler with priority 50
    A: %%>install:50:test

        Engine installs the handler and acknowledges it
    E: %%<install:50:test:true

        Application installs a handler for the "engine.timer" handler with default priority
    A: %%>install::engine.timer

        Engine installs the handler and acknowledges it
    E: %%<install:100:engine.timer:true

        Application emits a private "app.job" message; notice how the '%' and ':' characters were escaped
    A: %%>message:myapp55251:1095112794:app.job::job=cleanup:done=75%%:path=/bin%Z/usr/bin

        Engine just dispatched an "engine.timer" message
    E: %%>message:234479208:1095112795:engine.timer::time=1095112795

        Engine gets back the answer to the "app.job" message with a "Restart required" returned text value
    E: %%<message:myapp55251:true:app.job:Restart required:path=/bin%Z/usr/bin%Z/usr/local/bin

        Application ignores the timer message
    A: %%<message:234479208:false:engine.timer::time=1095112795

        Application uninstalls the "test" handler
    A: %%>uninstall:test

        Engine removes the handler and acknowledges it
    E: %%<uninstall:50:test:true

        Engine just dispatched another "engine.timer" message
    E: %%>message:234479288:1095112796:engine.timer::time=1095112796

        Application modifies the timer message but lets it flow further
    A: %%<message:234479288:false:engine.timer::time=1095112796:extra=yes

        Engine just dispatched another "engine.timer" message
    E: %%>message:234479244:1095112797:engine.timer::time=1095112797

        Application suddenly exits without acknowledging previous message.
        The engine releases the message 234479244 (as if "false" was returned) and
        uninstalls the remaining "engine.timer" handler