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 aHangupexception. If the call state is notIDLEbut also notANSWERED, this function will raise anErrorexception.If the play state is already
PLAYING, this function will raise anErrorexception.If the call channel already has an external audio source, e.g, it is connected to another call channel, this function will raise an
Errorexception.If the tone provided is not one of the pre-defined set, this function will raise an
Errorexception. 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 aHangupexception. If the call state is notIDLEbut also notANSWERED, this function will raise anErrorexception.If the play state is already
PLAYING, this function will raise anErrorexception.If the call channel already has an external audio source, e.g, it is connected to another call channel, this function will raise an
Errorexception.If the tone provided is not one of the pre-defined set, this function will raise an
Errorexception. 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 aHangupexception. If the call state is notIDLEbut also notANSWERED, this function will raise anErrorexception.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()
- 
class