The tone manager¶
The tone manager module provides some tone management functionality. Specifically,
it can be used to create custom tones, for example a custom ringback
tone.
The tone manager is also necessary for some types of call transfer.
To use the tone manager module in an application import it as follows:
from prosody.uas import ToneManager
Create a tone manager and pass it a reference to the logger, for example:
tone_manager = ToneManager(my_log)
The ToneManager
can be used to create new tones and add them to the
list of known tones. It can also be used to set a new default ringtone.
To set a new default ringtone use the set_default
function. It takes a pre-defined
tone as the argument:
ToneManager.set_default(ToneManager.PredefinedTones.RINGBACK_EU)
The tone manager has three pre-defined tones RINGBACK_EU
, RINGBACK_UK
and RINGBACK
(which is the US ringtone).
To add to the list of pre-defined tones use the create_tone
function. This function
allows the user to create a custom tone sequence and add it to the tone manager. The
function takes two arguments:
- tone_info
a list of tone descriptions.
- tone_name
a name to give the new tone sequence
The argument tone_info
is a list of tones to play. Each
tone in the list is actually a pair of tones that will be
combined by either summation or modulation. The pair of tones
is described in a tuple that contains the definition for two
tones, the duration and the way they are to be added together.
And each tone definition is a dictionary containing the
information for that tone. See below for an illustration of
tone_info
:
[
(
{
'frequency' : value, # frequency in Hz, 0 to 9999
'amplitude' : value # negative amplitude in dBm0, 0 to 99
},
{
'frequency' : value,
'amplitude' : value
},
{
'duration' : value, # duration in milliseconds, 0 to 9999
'add' : method # the method used to add the tones, 'summation' or 'modulation'
}
),
(
.. next tone pair
)
]
The following will play a single 400 Hz tone at -10 dBm0 for 1.65 seconds followed by silence for 3.35 seconds:
# create the tone
new_tone_sequence = [ ( { 'frequency' : 400,
'amplitude' : 10 },
{ 'frequency' : 0,
'amplitude' : 0 },
{ 'duration' : 1650,
'add' : 'summation' } ),
( { 'frequency' : 0,
'amplitude' : 0 },
{ 'frequency' : 0,
'amplitude' : 0 },
{ 'duration' : 3350,
'add' : 'modulation' } ) ]
# add the tone to the list of known tones
ToneManager.create_tone(new_tone_sequence, 'MY_RINGBACK')
# set the new tone to be the default tone
ToneManager.set_default('MY_RINGBACK')
The tone player¶
For a channel to be able to use the tones that are configured on the tone manager, it must create a tone player.
The create_tone_player function on the call channel will take a reference to the tone
manager and create a tone player. This will create the public property TonePlayer
on the channel object.
The tone player is used automatically for certain types of call transfer.
- class TonePlayer¶
A class that provides an API for playing tones.
- class Cause¶
Once a play job has ended and the play state has returned to idle or error, the cause will be one of these.
Play termination causes are:
- ERROR
play has stopped due to an error.
- NORMAL
play has stopped normally.
- ABORTED
play has been aborted (probably because stop was called).
- HANGUP
play ended due to a call hangup.
- TIMEOUT
play failed because a timer has expired.
- NONE
play is in progress, or no play has occurred.
Usage example:
state = channel.TonePlayer.state() if state != channel.TonePlayer.State.PLAYING: cause = channel.TonePlayer.cause() if cause == channel.TonePlayer.Cause.NORMAL: # Tone replay finished normally pass
- class State¶
The play state can be checked to determine whether a tone play job is in progress. When a play job ends, the play termination cause can be checked to find the reason why.
Play states are:
- PLAYING
a play job is in progress.
- IDLE
no play job is in progress.
- ERROR
a play job failed.
Usage example:
state = channel.TonePlayer.state() if state == channel.TonePlayer.State.ERROR: # a tone replay job failed due to an error. pass
- play(tone)¶
This function will play a tone.
- Required argument:
- tone
the tone to play.
This function will play a tone, the tone is one of a pre-defined set.
If the call state is
IDLE
, this function will raise aHangup
exception. If the call state is notIDLE
but also notANSWERED
, this function will raise anError
exception.If the play state is already
PLAYING
, this function will raise anError
exception.If the call channel already has an external audio source, e.g, it is connected to another call channel, this function will raise an
Error
exception.If the tone provided is not one of the pre-defined set, this function will raise an
Error
exception. Additional pre-defined tones can be created using the ToneManager API.The function will block until the tone has finished playing, or a timeout occurs.
This function will return True on success, otherwise False.
Usage example:
cause = channel.TonePlayer.play("RINGBACK_UK")
- start(tone, loop=True)¶
This function will start the playing of a tone.
- Required argument:
- tone
the tone to play.
- loop
if true the tone sequence will loop until told to stop.
This function will start playing a tone, the tone is one of a pre-defined set.
If the call state is
IDLE
, this function will raise aHangup
exception. If the call state is notIDLE
but also notANSWERED
, this function will raise anError
exception.If the play state is already
PLAYING
, this function will raise anError
exception.If the call channel already has an external audio source, e.g, it is connected to another call channel, this function will raise an
Error
exception.If the tone provided is not one of the pre-defined set, this function will raise an
Error
exception. Additional pre-defined tones can be created using the ToneManager API.The function will block until confirmation has been received that the tone has begun to play, or a timeout occurs.
This function will return True on success, otherwise False.
Usage example:
if channel.TonePlayer.start("RINGBACK_UK") == True: # tone playing has begun pass
- stop()¶
Stop playback of a tone to the current channel.
Calling this method will abort any current tone playback. However, it is unnecessary to stop any media operation upon call hang-up, as that is done automatically.
If the call state is
IDLE
, this function will raise aHangup
exception. If the call state is notIDLE
but also notANSWERED
, this function will raise anError
exception.If the play state is not
PLAYING
, this function will simply return True. Otherwise, this call will block until the playback has stopped or a timeout has expired.Upon return, this method will return True for success, otherwise False.
Usage example:
# Start playing a tone and then stop it. if channel.TonePlayer.start("RINGBACK_UK") == True: # while the tone is playing, we can do something else # ... # then stop it. channel.TonePlayer.stop()