Prosody Overview

This document provides a general overview of Prosody, and attempts to answer these questions:

What functionality does Prosody provide?

Prosody provides:

How do you use Prosody functionality?

Prosody provides telephony functionality in terms of channels. So what is a channel? It is an object used by the Prosody API to control processing. Just as an operating system might use file handles to allow you to refer to files and perform operations on the files, Prosody uses channels to refer to processing that you perform on telephony data.

How do channels relate to the hardware I have installed?

When you install a card that can be used by Prosody, it has one or more Prosody processors on it. These are advanced signal processing CPUs each with their own memory. Some may be on the card itself and some may be on daughter boards. Because each Prosody processor comes with its own private memory, they are often referred to as modules. This applies even to the ones which are fixed onto the card and which are not detachable modules.

Diagram of card containing modules

When you allocate a channel, it refers to processing resources on a single module. A channel is always associated with one module and can never be split between two or more modules, nor can it move from one module to another.

Diagram of card containing modules containing channels

Each module can support several channels. The maximum number it can support depends on what operations the channels are performing. You refer to a module in your program by using a tSMModuleId value.

How do the tSMModuleId values relate to my hardware?

With the introduction of the V6 API, tSMModuleId values must be obtained from sm_open_module().

Before the V6 API, tSMModuleId values were small integers, in a continuous range starting at zero. You can find out which card a module is on with sm_get_module_card_ix() which gives you the card index of the card that the module is on.

To make it as easy as possible for applications to handle both the pre-V6 API and the V6 API, Prosody TiNG allows sm_open_module() to be used even when using pre-V6 libraries, when it returns the appropriate module number. This allows an application to change only the tSMCardId values between V6 and pre-V6.

And how does a card index relate to the hardware?

With the introduction of the V6 API, cards must be opened before use, and when you do this you supply the serial number of the card to use. Obviously this means that when you need to refer to the same card through more than one Aculab API (such as when you want to connect a Prosody channel through the switch API) you use the same serial number to refer to the card through both APIs.

Using the pre-V6 API, the cards are numbered starting at zero in an arbitrary order. You can find out information about a card, including the serial number, with sm_get_card_info().

Note that the card numbering used by Prosody is not the same as the numbering used by other Aculab APIs. Each API may number cards differently (e.g. the call driver may consider a card to be card 2, while Prosody might consider it to be card 3). This is because Aculab produces a variety of products which provide different combinations of functionality. If Prosody were to number its cards the same way as every other Aculab API, it would have to allow for and support every type of card including cards with no Prosody hardware at all. In some systems all of the numbers will happen to be the same. This was particularly common with Prosody version 1. However the numbering used by each driver depends on which types of cards are present, so you should only rely on the numbering control provided by the installation documentation and the published API. This means your application is likely to work successfully with more combinations of hardware and with future Aculab products.

You can use sm_get_card_switch_ix() to discover the relationship between a Prosody card number and the switch driver's number for the card. Similarly, the call control API allows you to relate its objects to switch driver card numbers (for example with call_port_2_swdrvr()), which allows you to determine exactly how all the numbers correspond.

Are there different kinds of channels?

Yes. There are four kinds of channels:

An input-only channel cannot perform any operation that generates output (such as generating tones). An output-only channel cannot do anything that requires input (such as detecting tones). A half duplex channel can do anything, but cannot do input and output at the same time, while a full duplex channel can do input and output simultaneously.

Generally, it is a good idea to create channels which are either input-only or output-only as this protects you against some mistakes in which you use the wrong channel since the API functions will return an error if you try to do the wrong kind of operation on a channel. However, if you are using data communications, some protocols require that you do both the reception and transmission of data for a single connection on the same channel (for example, V.110).

When are resources actually allocated to channels?

Several different resources are used by a channel. The API library allocates some resources internally, such as memory to contain configuration information for the channel. These resources are allocated when the channel is allocated. Other resources are allocated on the Prosody processor that handles the channel. These resources are only allocated when an operation requires them, so for example, if you allocate a channel and play a file on the channel, when you finish playing the file, the channel is no longer using any resources on the Prosody processor.

How do I know when to check channel status?

When performing play, record and other tasks, you need to check the channel status so that you can find out when important changes to the status occur indicating things like when to supply or collect more data and when the task has finished. To make this checking efficient, a facility is available to indicate when it may be worth checking the status. This is provided using tSMEventId objects. You allocate one of these (with smd_ev_create()), associate it with a channel (with sm_channel_set_event()), and then you can wait on this event which will be signalled when you need to check the channel's status. You can either wait using smd_ev_wait() or wait for one of several events in a manner which varies between operating systems. See Prosody events for further details.

When are the various operations on a channel complete?

Some operations on a channel are started by one API call and do not complete before the API call returns. They are summarised in this table:

Operation
Started by Completed when
sm_replay_start() sm_replay_status() returns kSMReplayStatusComplete
sm_record_start() sm_record_status() returns kSMRecordStatusComplete
sm_play_tone() [see note 1] sm_play_tone_status() returns kSMPlayToneStatusComplete
sm_play_cptone() [see note 1] sm_play_cptone_status() returns kSMPlayCPToneStatusComplete
sm_play_digits() [see note 1] sm_play_digits_status() returns kSMPlayDigitsStatusComplete
sm_listen_for() enabling a detection sm_listen_for() enabling no detection
sm_asr_listen_for() enabling recognition sm_asr_listen_for() disabling recognition
sm_conf_prim_start() sm_conf_prim_abort() returns
sm_condition_input() enabling a conditioning type sm_condition_input() enabling no conditioning type
sm_catsig_listen_for() enabling a signal categorisation algorithm sm_catsig_listen_for() with non-zero abort_catsig_alg field
sm_replay_file_start() sm_replay_file_complete() returns
sm_record_file_start() sm_record_file_complete() returns
sm_replay_bfile_start() sm_replay_bfile_complete() returns
sm_record_bfile_start() sm_record_bfile_complete() returns
smdc_channel_config() smdc_line_status() returns kSMDCLinkStatusNotConnected in the link_status field

Note 1
These functions take a wait_for_completion field. If this is non-zero, then the operation is already complete when the function returns and you should not attempt to check the status after this.
General Note
If a channel is released, any operations in progress on the channel are immediately stopped, no status information about such operations is reported or reccorded anywhere, and all resources being used by the channel are released.

How do I connect a channel to somewhere useful?

Data which is produced or received by a channel goes over timeslots. These are the only connections which leave the Prosody processor modules. Depending on the type of card, timeslots either are connected to a switch matrix controlled by the Aculab switch driver, or are connected directly to an industry standard bus. Each Prosody module has a limited number of available timeslots, specifically 64 input timeslots and 64 output timeslots, organised into streams (two input and two output) of 32 timeslots each. You explicitly connect a channel to a timeslot with sm_switch_channel_input() or sm_switch_channel_output() before starting an operation on the channel. The switch driver documentation explains the numbering of timeslots for all the cards on which the timeslots are connected to a switch matrix.

How do I use echo cancellation?

The function sm_condition_input() starts echo cancellation on a channel. You can either specify that the resulting signal is to be sent to a timeslot or simply use the channel for other operations, such as conferencing, which will then use the echo-cancelled signal. This channel is the primary and you must specify another channel to use as the reference.

What are the 'primary' and 'reference'?

The primary is the signal being received from which echo is to be removed. The reference is the signal which may appear in the primary as an echo. One typical scenario is that the reference is a prompt which is being played through Prosody to a user and the primary is the signal from that user which we are feeding into a speech recogniser. If we want to recognise the user's speech, it may be necessary to remove any echo of our prompt - otherwise the speech recogniser would think that the prompt was the user speaking and decode it. This problem does not normally arise when you are doing tone detection instead of speech recognition because prompts do not normally contain the tones being detected.

What is the best way for my application to handle different configurations?

It is not as easy to give a universal answer as it may first appear. One obvious way to handle a variety of possible configurations is for the application to use API functions to discover what resources are available and then to use them. This approach has two main disadvantages: it makes the application more complex and it makes testing difficult.

The application becomes complex because the consequences of the presence or absence of a resource can have a far-reaching effect. For example, if an additional Prosody processor module is found, this must not cause the application to allocate channels on that module which later need to be connected in a conference with channels on another module (which is not possible). Similarly, finding fewer modules must not mean that channels are allocated in a way which overloads one module when there is spare capacity elsewhere.

Testing is made difficult because you need to have each possible configuration available, which means lots of shutting down, exchanging cards, and rebooting. It also makes it difficult to test because parts of the application become interdependent, which produces more combinations to be tested.

There is another, less significant, disadvantage which is that if a system develops a fault and a resource is no longer available, the application will not realise that the resource is supposed to be present.

So if we do not let an application configure itself automatically, what would be a practical alternative? For many applications you can plan resource usage in advance. For example, in a voicemail application you can pre-determine which Prosody module will handle a call depending on which trunk and timeslot the call comes from. With the Prosody PCI card with four trunks fitted you might decide that calls from the first two trunks will be handled by the first Prosody module on that card and calls from the other two trunks will be handled by the second Prosody module. This makes it obvious that the two pairs of trunks are independent and cannot interfere with each other. It also makes it much easier to track down problems. For example, if there is a problem with one trunk which affects Prosody (such as distortion which prevents reliable tone detection) it is easier to see that it always happens in one place if the configuration is fixed.

In practice, the best way to configure an application is often some sort of configuration file which is read when the application starts. This allows the application to be adapted to a variety of configurations without having to worry about it doing anything unexpected in an unusual configuration.

Should I download firmware from within my application?

While it is possible for an application to download firmware, it is normally better to do so before starting the application. This makes testing and debugging much easier because when a special firmware module is needed to help with a test, you can simply download it and run your application. If the application downloaded the module, it would have to be modified to download the extra module. For example, if you want to determine what signal is being processed, you might run a recording using locrec from the test directory, which would allow you to make a recording while your application was running.

Can I copy files into my own projects?

Normally a project should refer to any necessary files rather than have local copies. This is the way libraries usually work (you wouldn't copy "stdio.h" into a project, would you?). If you reserve a particular location for Aculab software (e.g. /opt/aculab on Unix systems, or C:\Program Files\Aculab on Windows), then you can make several projects refer to this location, making it easier to see what versions you might be using. On Solaris and Linux, you can use a symbolic link if you want to have a location which always refers to the latest installed version. On Windows 2000/XP you can do the same with junctions but see the comment at the end of the page Prosody installation guide: unpacking.

If an external requirement (such as a version control standard) forces you to copy parts of a distribution into your project, be sure to do this in a way which avoids mixing files from different versions. Keep a record of which files you copied and when you upgrade to a later version, ensure that you remove all of them before copying in the files from the new version.

While it is not generally a good idea to copy Prosody files into your projects, the .h files in the include directory have been processed in a way which tries to make this as safe as possible. Each is self-contained, which reduces the possibilities for mixing arbitrary files from different versions. However this is not a complete protection. For example, you can still copy smdrvr.h from one version and smbesp.h from a different version and attempt to use both in a single application.

What other documentation is available?

All of the documentation for Prosody version 2 (TiNG) is listed on the Prosody main page. Some additional documentation which covers both Prosody version 1 and version 2 can be found on the Aculab web site.