__uas_identify__ = "application" __uas_version__ = "1.0b1" from prosody.uas import Hangup, Error """ An inbound application that answers the call and says a welcome message. The welcome message defaults to "Welcome to the voicemail server for " but can be changed. is obtained from the application_parameters and must be registered on the inbound services page of the CWP. The application uses to determine whether the caller owns the voicemail box. It does this by comparing with the property of the inbound call. If the caller owns the voicemail box, the top level options given are: 1. Play all existing messages with the option to delete each one individually 2. Delete all existing messages 3. Record a new welcome message If the caller does not own the voicemail box, he can leave a new message. The name of the .wav file to save to will be "samples/voicemail4//msg.wav". The is a variable, initialised to 1, which increments each time a message is successfully saved. This application is part of the Voice Mail tutorial at https://cloud.aculab.com/documents/voicemail. For this sample it is important that you also read about media files at https://cloud.aculab.com/apidocs/DOC_Python-1.0.100/applications.html#working-with-media-files, which describes some of the effects of Eventual Consistency. """ class VoiceMailFileFormat: def __init__(self, file_format, welcome_message): self.record_filename_format = file_format self.recorded_file_counter = 1 self.welcome_message_filename = welcome_message def main(channel, application_instance_id, file_man, my_log, application_parameters): return_code = 0 my_log.info("Started {0} :".format(application_parameters)) try: # The voicemail box name must have been configured at service registration if len(application_parameters) == 0: raise Error("Argument list is empty") rec_args = VoiceMailFileFormat("samples/voicemail4/" + application_parameters + "/msg{0}.wav", "samples/voicemail4/" + application_parameters + "/welcome.wav") # Obtain the next free counter while(file_man.exists(rec_args.record_filename_format.format(rec_args.recorded_file_counter))): my_log.info("{0} exists".format(rec_args.recorded_file_counter)) rec_args.recorded_file_counter += 1 my_log.info("Ring and answer") channel.ring(2) channel.answer() caller = get_caller(channel) my_log.info("Call from {0} to {1}'s Voicemail answered".format(caller, application_parameters)) if file_man.exists(rec_args.welcome_message_filename): play_file(channel, rec_args.welcome_message_filename) else: say_tts(channel, "Welcome to the voicemail server for {0}".format(application_parameters)) if caller == application_parameters: top_level_menu(channel, file_man, my_log, rec_args) else: record_new_message(channel, rec_args) say_tts(channel, "Goodbye.") channel.hang_up(); except Hangup as exc: my_log.info("Completed with Hangup") return_code = 100 except Error as exc: my_log.error("Completed with Error exception! {0}".format(exc)) return_code = -101 except Exception as exc: my_log.exception("Completed with exception! {0}".format(exc)) return_code = -100 finally: if channel.state() != channel.State.IDLE: channel.hang_up() my_log.info("Voicemail 4 example completed") return return_code def say_tts(channel, message, bargein=False): cause = channel.FilePlayer.say(message, barge_in=bargein) if cause != channel.FilePlayer.Cause.NORMAL and cause != channel.FilePlayer.Cause.BARGEIN: raise Error("Say '{0}' failed: cause is {1}".format(message, cause)) def play_file(channel, filename): cause = channel.FilePlayer.play(filename) if cause != channel.FilePlayer.Cause.NORMAL: raise Error("Play '{0}' failed: cause is {1}".format(filename, cause)) def record_file(channel, filename): cause = channel.FileRecorder.record(filename, milliseconds_max_silence=3000, seconds_timeout=60, barge_in=True) if cause != channel.FileRecorder.Cause.SILENCE and cause != channel.FileRecorder.Cause.BARGEIN: raise Error("Record message failed: cause is {0}".format(cause)) def get_caller(channel): caller = channel.Details.call_from # Extract the username from the SIP address if caller.startswith("sip:"): caller = caller[4:] return caller.split('@', 1)[0] def top_level_menu(channel, file_man, log_man, rec_args): key_selected = get_menu_select(channel, "Press 1 to listen to all messages. \ Press 2 to delete all messages. \ Press 3 to record a welcome message.", 20, "123") if key_selected == '1': play_all_messages(channel, file_man, log_man, rec_args) elif key_selected == '2': delete_all_messages(channel, file_man, log_man, rec_args) elif key_selected == '3': record_welcome_message(channel, rec_args) def record_welcome_message(channel, rec_args): filename = rec_args.welcome_message_filename while True: say_tts(channel, "Please record a welcome message after the tone. Press any digit to stop the recording.") cause = channel.DTMFPlayer.play("#"); if cause != channel.DTMFPlayer.Cause.NORMAL: raise Error("Play tone failed: caused is {0}".format(cause)) record_file(channel, filename) say_tts(channel, "The following message has been recorded") play_file(channel, filename) key_selected = get_menu_select(channel, "Please press 1 to keep this message or 2 to record an alternative message.", 20, "12") if key_selected == '1': say_tts(channel, "Message saved.") break def record_new_message(channel, rec_args): filename = rec_args.record_filename_format.format(rec_args.recorded_file_counter) rec_args.recorded_file_counter += 1 while True: say_tts(channel, "Please record a message after the tone. Press any digit to stop the recording.") cause = channel.DTMFPlayer.play("#"); if cause != channel.DTMFPlayer.Cause.NORMAL: raise Error("Play tone failed: caused is {0}".format(cause)) record_file(channel, filename) say_tts(channel, "The following message has been recorded") play_file(channel, filename) key_selected = get_menu_select(channel, "Please press 1 to keep this message or 2 to record an alternative message", 20, "12") if key_selected == '1': say_tts(channel, "Message saved.") break def play_all_messages(channel, file_man, log_man, rec_args): counter = 1 filename = rec_args.record_filename_format.format(counter) while file_man.exists(filename): say_tts(channel, "Message {0}".format(counter)) play_file(channel, filename) key_selected = get_menu_select(channel, "Please press 1 to keep this message. Press 2 to delete this message", 20, "12") if key_selected == '2': if file_man.delete_file(filename) is True: say_tts(channel, "Message deleted") move_files_down(channel, file_man, log_man, rec_args, counter) counter -= 1 counter += 1 filename = rec_args.record_filename_format.format(counter) if counter == 1: say_tts(channel, "You have no messages.") else: say_tts(channel, "End of messages.") def move_files_down(channel, file_man, log_man, rec_args, counter): next_file = rec_args.record_filename_format.format(counter + 1) while file_man.exists(next_file): this_file = rec_args.record_filename_format.format(counter) if file_man.rename(next_file, this_file) is True: counter += 1 next_file = rec_args.record_filename_format.format(counter + 1) else: break def delete_all_messages(channel, file_man, log_man, rec_args): counter = 1 filename = rec_args.record_filename_format.format(counter) while file_man.exists(filename): file_man.delete_file(filename) counter += 1 filename = rec_args.record_filename_format.format(counter) if counter == 1: say_tts(channel, "You have no messages.") else: say_tts(channel, "All messages deleted.") def get_menu_select(channel, prompt, seconds_repeat_prompt, valid_keys): channel.DTMFDetector.clear_digits() while True: say_tts(channel, prompt, True) digits = channel.DTMFDetector.get_digits(count=1, seconds_predigits_timeout=seconds_repeat_prompt) cause = channel.DTMFDetector.cause() if cause == channel.DTMFDetector.Cause.COUNT: if digits in valid_keys: return digits[0] else: say_tts(channel, "Invalid selection. Please try again.")