switch_ivr/xml: Change the structure of the phrases/language system. Previously it was fxml->phrases->macros->language->macro. Changed it so fxml->languages->language->phrases->macros->macro

You can have sub macros <macros name="voicemail"><macro ...> and allow you to call it login@voicemail.
Change the sound-path to sound-prefix to make it constistant with the rest of freeswitch.
Also allow to set a sound-prefix to a macros, so you can override it for a specific file set.
You can set say-modules="en" or whatever in the <language section to define that say module to use.
This commit is contained in:
Marc Olivier Chouinard 2011-04-20 13:09:03 -04:00
parent 6dd1237445
commit 4137b360cf
13 changed files with 606 additions and 558 deletions

View File

@ -52,14 +52,12 @@
<X-PRE-PROCESS cmd="include" data="directory/*.xml"/> <X-PRE-PROCESS cmd="include" data="directory/*.xml"/>
</section> </section>
<!-- phrases section (under development still) --> <!-- languages section (under development still) -->
<section name="phrases" description="Speech Phrase Management"> <section name="languages" description="Language Management">
<macros> <X-PRE-PROCESS cmd="include" data="lang/de/*.xml"/>
<X-PRE-PROCESS cmd="include" data="lang/de/*.xml"/> <X-PRE-PROCESS cmd="include" data="lang/en/*.xml"/>
<X-PRE-PROCESS cmd="include" data="lang/en/*.xml"/> <X-PRE-PROCESS cmd="include" data="lang/fr/*.xml"/>
<X-PRE-PROCESS cmd="include" data="lang/fr/*.xml"/> <X-PRE-PROCESS cmd="include" data="lang/ru/*.xml"/>
<X-PRE-PROCESS cmd="include" data="lang/ru/*.xml"/> <X-PRE-PROCESS cmd="include" data="lang/he/*.xml"/>
<X-PRE-PROCESS cmd="include" data="lang/he/*.xml"/>
</macros>
</section> </section>
</document> </document>

View File

@ -1,7 +1,11 @@
<include> <include>
<language name="de" sound-path="/snds" tts-engine="cepstral" tts-voice="david"> <language name="de" sound-prefix="/snds" tts-engine="cepstral" tts-voice="david">
<X-PRE-PROCESS cmd="include" data="demo/demo.xml"/> <phrases>
<!--voicemail_de_tts is purely implemented with tts, we need a files based implementation too --> <macros>
<X-PRE-PROCESS cmd="include" data="vm/tts.xml"/> <X-PRE-PROCESS cmd="include" data="demo/demo.xml"/>
<!--voicemail_de_tts is purely implemented with tts, we need a files based implementation too -->
<X-PRE-PROCESS cmd="include" data="vm/tts.xml"/>
</macros>
</phrases>
</language> </language>
</include> </include>

View File

@ -1,8 +1,12 @@
<include> <include>
<language name="en" sound-path="$${sounds_dir}/en/us/callie" tts-engine="cepstral" tts-voice="callie"> <language name="en" say-module="en" sound-prefix="$${sounds_dir}/en/us/callie" tts-engine="cepstral" tts-voice="callie">
<X-PRE-PROCESS cmd="include" data="demo/*.xml"/> <!-- Note: this now grabs whole subdir, previously grabbed only demo.xml --> <phrases>
<!--voicemail_en_tts is purely implemented with tts, we have the files based one that is the default. --> <macros>
<X-PRE-PROCESS cmd="include" data="vm/sounds.xml"/> <!-- vm/tts.xml if you want to use tts and have cepstral --> <X-PRE-PROCESS cmd="include" data="demo/*.xml"/> <!-- Note: this now grabs whole subdir, previously grabbed only demo.xml -->
<X-PRE-PROCESS cmd="include" data="dir/sounds.xml"/> <!-- dir/tts.xml if you want to use tts and have cepstral --> <!--voicemail_en_tts is purely implemented with tts, we have the files based one that is the default. -->
<X-PRE-PROCESS cmd="include" data="vm/sounds.xml"/> <!-- vm/tts.xml if you want to use tts and have cepstral -->
<X-PRE-PROCESS cmd="include" data="dir/sounds.xml"/> <!-- dir/tts.xml if you want to use tts and have cepstral -->
</macros>
</phrases>
</language> </language>
</include> </include>

View File

@ -1,8 +1,12 @@
<include> <include>
<language name="fr" sound-path="/snds" tts-engine="cepstral" tts-voice="david"> <language name="fr" say-module="fr" sound-prefix="$${sounds_dir}/fr/ca/june" tts-engine="cepstral" tts-voice="david">
<X-PRE-PROCESS cmd="include" data="demo/demo.xml"/> <phrases>
<!--voicemail_fr_tts is purely implemented with tts, we need a files based implementation too --> <macros>
<X-PRE-PROCESS cmd="include" data="vm/sounds.xml"/> <X-PRE-PROCESS cmd="include" data="demo/demo.xml"/>
<X-PRE-PROCESS cmd="include" data="dir/sounds.xml"/> <!-- dir/tts.xml if you want to use tts and have cepstral --> <!--voicemail_fr_tts is purely implemented with tts, we need a files based implementation too -->
<X-PRE-PROCESS cmd="include" data="vm/sounds.xml"/>
<X-PRE-PROCESS cmd="include" data="dir/sounds.xml"/> <!-- dir/tts.xml if you want to use tts and have cepstral -->
</macros>
</phrases>
</language> </language>
</include> </include>

View File

@ -1,7 +1,11 @@
<include> <include>
<language name="he" sound-path="$${sounds_dir}/he/daniel" tts-engine="cepstral" tts-voice="daniel"> <language name="he" sound-prefix="$${sounds_dir}/he/daniel" tts-engine="cepstral" tts-voice="daniel">
<X-PRE-PROCESS cmd="include" data="demo/*.xml"/> <!-- Note: this now grabs whole subdir, previously grabbed only demo.xml --> <phrases>
<X-PRE-PROCESS cmd="include" data="vm/sounds.xml"/> <macros>
<X-PRE-PROCESS cmd="include" data="dir/sounds.xml"/> <X-PRE-PROCESS cmd="include" data="demo/*.xml"/> <!-- Note: this now grabs whole subdir, previously grabbed only demo.xml -->
<X-PRE-PROCESS cmd="include" data="vm/sounds.xml"/>
<X-PRE-PROCESS cmd="include" data="dir/sounds.xml"/>
</macros>
</phrases>
</language> </language>
</include> </include>

View File

@ -1,9 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--тестовые файлы Вы звуковые файлы можно взять тут svn co http://svn.freeswitch.ru/bbv/mod_say_ru/ru/ --> <!--тестовые файлы Вы звуковые файлы можно взять тут svn co http://svn.freeswitch.ru/bbv/mod_say_ru/ru/ -->
<include> <include>
<language name="ru" sound-path="$${sounds_dir}/ru/RU/elena" tts-engine="cepstral" tts-voice="elena"> <language name="ru" sound-prefix="$${sounds_dir}/ru/RU/elena" tts-engine="cepstral" tts-voice="elena">
<X-PRE-PROCESS cmd="include" data="demo/*.xml"/> <!-- Note: this now grabs whole subdir, previously grabbed only demo.xml --> <phrases>
<!--voicemail_en_tts is purely implemented with tts, we have the files based one that is the default. --> <macros>
<X-PRE-PROCESS cmd="include" data="vm/sounds.xml"/> <!-- vm/tts.xml if you want to use tts and have cepstral --> <X-PRE-PROCESS cmd="include" data="demo/*.xml"/> <!-- Note: this now grabs whole subdir, previously grabbed only demo.xml -->
<!--voicemail_en_tts is purely implemented with tts, we have the files based one that is the default. -->
<X-PRE-PROCESS cmd="include" data="vm/sounds.xml"/> <!-- vm/tts.xml if you want to use tts and have cepstral -->
</macros>
</phrases>
</language> </language>
</include> </include>

View File

@ -417,6 +417,8 @@ SWITCH_DECLARE(switch_xml_section_t) switch_xml_parse_section_string(_In_opt_z_
SWITCH_DECLARE(int) switch_xml_std_datetime_check(switch_xml_t xcond); SWITCH_DECLARE(int) switch_xml_std_datetime_check(switch_xml_t xcond);
SWITCH_DECLARE(switch_status_t) switch_xml_locate_language(switch_xml_t *root, switch_xml_t *node, switch_event_t *params, switch_xml_t *language, switch_xml_t *phrases, switch_xml_t *macros, const char *str_language);
SWITCH_END_EXTERN_C SWITCH_END_EXTERN_C
///\} ///\}
#endif // _SWITCH_XML_H #endif // _SWITCH_XML_H

View File

@ -17,7 +17,7 @@
<menus> <menus>
<menu name="std_authenticate"> <menu name="std_authenticate">
<phrases> <phrases>
<phrase name="fail_auth" value="protovm_fail_auth" /> <phrase name="fail_auth" value="fail_auth@protovm" />
</phrases> </phrases>
<keys> <keys>
</keys> </keys>
@ -25,7 +25,7 @@
<menu name="std_authenticate_ask_user"> <menu name="std_authenticate_ask_user">
<phrases> <phrases>
<phrase name="instructions" value="protovm_enter_id" /> <phrase name="instructions" value="enter_id@protovm" />
</phrases> </phrases>
<keys> <keys>
<key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" /> <!-- TODO Make the ivrengine: parsed and the key configurable --> <key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" /> <!-- TODO Make the ivrengine: parsed and the key configurable -->
@ -34,7 +34,7 @@
<menu name="std_authenticate_ask_password"> <menu name="std_authenticate_ask_password">
<phrases> <phrases>
<phrase name="instructions" value="protovm_enter_pass" /> <phrase name="instructions" value="enter_pass@protovm" />
</phrases> </phrases>
<keys> <keys>
<key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" /> <!-- TODO Make the ivrengine: parsed and the key configurable --> <key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" /> <!-- TODO Make the ivrengine: parsed and the key configurable -->
@ -43,12 +43,12 @@
<menu name="std_navigator"> <menu name="std_navigator">
<phrases> <phrases>
<phrase name="msg_count" value="protovm_message_count" /> <phrase name="msg_count" value="message_count@protovm" />
<phrase name="say_date" value="protovm_say_date_event" /> <phrase name="say_date" value="say_date_event@protovm" />
<phrase name="say_msg_number" value="protovm_say_message_number" /> <phrase name="say_msg_number" value="say_message_number@protovm" />
<phrase name="menu_options" value="protovm_listen_file_check" /> <phrase name="menu_options" value="listen_file_check@protovm" />
<phrase name="ack" value="protovm_ack" /> <phrase name="ack" value="ack@protovm" />
<phrase name="play_message" value="protovm_play_message" /> <phrase name="play_message" value="play_message@protovm" />
</phrases> </phrases>
<keys> <keys>
<key dtmf="1" action="skip_intro" variable="VM-Key-Main-Listen-File" /> <key dtmf="1" action="skip_intro" variable="VM-Key-Main-Listen-File" />
@ -62,7 +62,7 @@
<menu name="std_preference"> <menu name="std_preference">
<phrases> <phrases>
<phrase name="menu_options" value="protovm_config_menu" /> <phrase name="menu_options" value="config_menu@protovm" />
</phrases> </phrases>
<keys> <keys>
<key dtmf="1" action="menu:std_record_greeting_with_slot" variable="VM-Key-Record-Greeting" /> <key dtmf="1" action="menu:std_record_greeting_with_slot" variable="VM-Key-Record-Greeting" />
@ -75,9 +75,9 @@
<menu name="std_record_greeting"> <menu name="std_record_greeting">
<phrases> <phrases>
<phrase name="instructions" value="voicemail_record_greeting" /> <phrase name="instructions" value="record_greeting@protovm" />
<phrase name="play_recording" value="protovm_play_recording" /> <phrase name="play_recording" value="play_recording@protovm" />
<phrase name="menu_options" value="protovm_record_file_check" /> <phrase name="menu_options" value="record_file_check@protovm" />
</phrases> </phrases>
<keys> <keys>
<key dtmf="1" action="listen" variable="VM-Key-Listen-File" /> <key dtmf="1" action="listen" variable="VM-Key-Listen-File" />
@ -90,9 +90,9 @@
<menu name="std_record_name"> <menu name="std_record_name">
<phrases> <phrases>
<phrase name="instructions" value="protovm_record_name" /> <phrase name="instructions" value="record_name@protovm" />
<phrase name="play_recording" value="protovm_play_recording" /> <phrase name="play_recording" value="play_recording@protovm" />
<phrase name="menu_options" value="protovm_record_file_check" /> <phrase name="menu_options" value="record_file_check@protovm" />
</phrases> </phrases>
<keys> <keys>
<key dtmf="1" action="listen" variable="VM-Key-Listen-File" /> <key dtmf="1" action="listen" variable="VM-Key-Listen-File" />
@ -106,9 +106,9 @@
<menu name="std_select_greeting_slot"> <menu name="std_select_greeting_slot">
<phrases> <phrases>
<phrase name="instructions" value="protovm_choose_greeting" /> <phrase name="instructions" value="choose_greeting@protovm" />
<phrase name="invalid_slot" value="protovm_choose_greeting_fail" /> <phrase name="invalid_slot" value="choose_greeting_fail@protovm" />
<phrase name="selected_slot" value="protovm_greeting_selected" /> <phrase name="selected_slot" value="greeting_selected@protovm" />
</phrases> </phrases>
<keys> <keys>
</keys> </keys>
@ -116,7 +116,7 @@
<menu name="std_record_greeting_with_slot"> <menu name="std_record_greeting_with_slot">
<phrases> <phrases>
<phrase name="instructions" value="protovm_choose_greeting" /> <phrase name="instructions" value="choose_greeting@protovm" />
</phrases> </phrases>
<keys> <keys>
</keys> </keys>
@ -124,7 +124,7 @@
<menu name="std_set_password"> <menu name="std_set_password">
<phrases> <phrases>
<phrase name="instructions" value="protovm_enter_pass" /> <phrase name="instructions" value="enter_pass@protovm" />
</phrases> </phrases>
<keys> <keys>
</keys> </keys>

View File

@ -1,375 +1,376 @@
<include><!--This line will be ignored it's here to validate the xml and is optional --> <include><!--This line will be ignored it's here to validate the xml and is optional -->
<macro name="protovm_press_key"> <macros name="protovm" sound-prefix="$${sounds_dir}/fr/ca/june">
<input pattern="^(.*):(.*)$"> <macro name="press_key">
<match> <input pattern="^(.*):(.*)$">
<action function="play-file" data="$2"/> <match>
<action function="play-file" data="voicemail/vm-press.wav"/> <action function="play-file" data="$2"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/> <action function="play-file" data="voicemail/vm-press.wav"/>
</match> <action function="say" data="$1" method="pronounced" type="name_spelled"/>
</input> </match>
</macro> </input>
</macro>
<macro name="protovm_plurial_msg">
<input pattern="^[01]:(.*):(.*)$" break_on_match="true">
<match>
<action function="play-file" data="$1"/>
</match>
</input>
<input pattern="^.*:(.*):(.*)$" break_on_match="true">
<match>
<action function="play-file" data="$2"/>
</match>
</input>
</macro>
<macro name="protovm_enter_id">
<input pattern="(.+)">
<match>
<action function="play-file" data="voicemail/vm-enter_id.wav"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
<nomatch>
<action function="play-file" data="voicemail/vm-enter_id.wav"/>
<action function="say" data="${VM-Key-Terminator}" method="pronounced" type="name_spelled"/>
</nomatch>
</input>
</macro>
<macro name="plurial_msg">
<macro name="protovm_enter_pass"> <input pattern="^[01]:(.*):(.*)$" break_on_match="true">
<input pattern="(.+)"> <match>
<match> <action function="play-file" data="$1"/>
<action function="play-file" data="voicemail/vm-enter_pass.wav"/> </match>
<action function="say" data="$1" method="pronounced" type="name_spelled"/> </input>
</match> <input pattern="^.*:(.*):(.*)$" break_on_match="true">
<nomatch> <match>
<action function="play-file" data="voicemail/vm-enter_pass.wav"/> <action function="play-file" data="$2"/>
<action function="say" data="${VM-Key-Terminator}" method="pronounced" type="name_spelled"/> </match>
</nomatch> </input>
</macro>
</input>
</macro>
<macro name="protovm_fail_auth">
<input>
<match>
<action function="play-file" data="voicemail/vm-fail_auth.wav"/>
</match>
</input>
</macro>
<macro name="protovm_hello">
<input>
<match>
<!--<action function="play-file" data="voicemail/vm-hello.wav"/> -->
</match>
</input>
</macro>
<macro name="protovm_goodbye">
<input>
<match>
<action function="play-file" data="voicemail/vm-goodbye.wav"/>
</match>
</input>
</macro>
<macro name="protovm_abort">
<input>
<match>
<action function="play-file" data="voicemail/vm-abort.wav"/>
</match>
</input>
</macro>
<macro name="protovm_message_count">
<input field="${VM-Total-New-Urgent-Messages}" pattern="^(0)$">
<nomatch>
<action function="play-file" data="voicemail/vm-you_have.wav"/>
<action function="say" data="${VM-Total-New-Urgent-Messages}" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-urgent-new.wav"/>
<action function="phrase" phrase="voicemail_plurial_msg" data="${VM-Total-New-Urgent-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
</nomatch>
</input>
<input field="${VM-Total-New-Messages}" pattern="^(\d+)$">
<match>
<action function="play-file" data="voicemail/vm-you_have.wav"/>
<action function="say" data="${VM-Total-New-Messages}" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-new.wav"/>
<action function="phrase" phrase="voicemail_plurial_msg" data="${VM-Total-New-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
</match>
</input>
<input field="${VM-Total-Saved-Messages}" pattern="^(0)$">
<nomatch>
<action function="play-file" data="currency/and.wav"/>
<action function="say" data="${VM-Total-Saved-Messages}" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-saved.wav"/>
<action function="phrase" phrase="voicemail_plurial_msg" data="${VM-Total-Saved-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
</nomatch>
</input>
</macro>
<macro name="protovm_menu">
<input>
<match>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Play-New-Messages}:voicemail/vm-listen_new.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Play-Saved-Messages}:voicemail/vm-listen_saved.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Config-Menu}:voicemail/vm-advanced.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Terminator}:voicemail/vm-to_exit.wav"/>
</match>
</input>
</macro>
<macro name="protovm_config_menu">
<input>
<match>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Record-Greeting}:voicemail/vm-to_record_greeting.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Choose-Greeting}:voicemail/vm-choose_greeting.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Record-Name}:voicemail/vm-record_name2.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Change-Password}:voicemail/vm-change_password.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Main-Menu}:voicemail/vm-main_menu.wav"/>
</match>
</input>
</macro>
<macro name="protovm_record_name">
<input>
<match>
<action function="play-file" data="voicemail/vm-record_name1.wav"/>
</match>
</input>
</macro>
<macro name="protovm_record_file_check">
<input>
<match>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Listen-File}:voicemail/vm-listen_to_recording.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Save-File}:voicemail/vm-save_recording.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Record-File}:voicemail/vm-rerecord.wav"/>
</match>
</input>
</macro>
<macro name="protovm_record_urgent_check">
<input>
<match>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Urgent}:voicemail/vm-mark-urgent.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Terminator}:voicemail/vm-continue.wav"/>
</match>
</input>
</macro>
<macro name="protovm_forward_prepend">
<input>
<match>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Prepend}:voicemail/vm-forward_add_intro.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Forward}:voicemail/vm-send_message_now.wav"/>
</match>
</input>
</macro>
<macro name="protovm_forward_message_enter_extension">
<input pattern="^([0-9#*])$">
<match>
<action function="play-file" data="voicemail/vm-forward_enter_ext.wav"/>
<action function="play-file" data="voicemail/vm-followed_by.wav"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
</input>
</macro>
<macro name="protovm_invalid_extension">
<input>
<match>
<action function="play-file" data="voicemail/vm-that_was_an_invalid_ext.wav"/>
</match>
</input>
</macro>
<macro name="protovm_listen_file_check">
<input>
<match>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Main-Next-Msg}:voicemail/vm-for_next_msg.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Main-Listen-File}:voicemail/vm-listen_to_recording.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Main-Save-File}:voicemail/vm-save_recording.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Main-Delete-File}:voicemail/vm-delete_recording.wav"/>
</match>
</input>
<input field="${VM-Message-Email}" pattern="^$">
<nomatch>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Main-Email}:voicemail/vm-forward_to_email.wav"/>
</nomatch>
</input>
<input>
<match>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Main-Callback}:voicemail/vm-return_call.wav"/>
<action function="phrase" phrase="voicemail_press_key" data="${VM-Key-Main-Forward}:voicemail/vm-to_forward.wav"/>
</match>
</input>
</macro>
<macro name="protovm_choose_greeting">
<input>
<match>
<action function="play-file" data="voicemail/vm-choose_greeting_choose.wav"/>
</match>
</input>
</macro>
<macro name="protovm_choose_greeting_fail">
<input>
<match>
<action function="play-file" data="voicemail/vm-choose_greeting_fail.wav"/>
</match>
</input>
</macro>
<macro name="protovm_record_greeting">
<input>
<match>
<action function="play-file" data="voicemail/vm-record_greeting.wav"/>
</match>
</input>
</macro>
<macro name="protovm_record_message">
<input>
<match>
<action function="play-file" data="voicemail/vm-record_message.wav"/>
</match>
</input>
</macro>
<macro name="protovm_greeting_selected">
<input pattern="^(\d+)$">
<match>
<action function="play-file" data="voicemail/vm-greeting.wav"/>
<action function="say" data="$1" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-selected.wav"/>
</match>
</input>
</macro>
<macro name="protovm_play_greeting">
<input pattern="^(.*)$">
<match>
<action function="play-file" data="voicemail/vm-person.wav"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
<action function="play-file" data="voicemail/vm-not_available.wav"/>
</match>
</input>
</macro>
<macro name="protovm_say_number">
<input pattern="^(\d+)$">
<match>
<action function="say" data="$1" method="pronounced" type="items"/>
</match>
</input>
</macro>
<macro name="protovm_say_message_number">
<input>
<match>
<action function="play-file" data="voicemail/vm-${VM-Message-Type}.wav"/>
<action function="play-file" data="voicemail/vm-message_number.wav"/>
<action function="say" data="${VM-Message-Number}" method="pronounced" type="items"/>
</match>
</input>
</macro>
<macro name="protovm_say_phone_number">
<input pattern="^(.*)$">
<match>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
</input>
</macro>
<macro name="protovm_say_name">
<input pattern="^(.*)$">
<match>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
</input>
</macro>
<!-- Note: Update this to marked-urgent,emailed and saved once new sound files are recorded -->
<macro name="protovm_ack">
<input pattern="^(too-small)$">
<match>
<action function="play-file" data="voicemail/vm-too-small.wav"/>
</match>
</input>
<input pattern="^(undeleted)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(deleted)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(saved)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(emailed)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(marked-urgent)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
</macro>
<macro name="protovm_say_date">
<input pattern="^(.*)$">
<match>
<action function="say" data="$1" method="pronounced" type="short_date_time"/>
</match>
</input>
</macro>
<macro name="protovm_say_date_event">
<input>
<match>
<action function="say" data="${VM-Message-Received-Epoch}" method="pronounced" type="short_date_time"/>
</match>
</input>
</macro>
<macro name="protovm_play_message">
<input>
<match>
<action function="play-file" data="${VM-Message-File-Path}"/>
</match>
</input>
</macro>
<macro name="protovm_play_recording">
<input>
<match>
<action function="play-file" data="${VM-Record-File-Path}"/>
</match>
</input>
</macro>
<macro name="protovm_disk_quota_exceeded"> <macro name="enter_id">
<input> <input pattern="(.+)">
<match> <match>
<action function="play-file" data="voicemail/vm-mailbox_full.wav"/> <action function="play-file" data="voicemail/vm-enter_id.wav"/>
</match> <action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
<nomatch>
<action function="play-file" data="voicemail/vm-enter_id.wav"/>
<action function="say" data="${VM-Key-Terminator}" method="pronounced" type="name_spelled"/>
</nomatch>
</input> </input>
</macro> </macro>
<macro name="enter_pass">
<input pattern="(.+)">
<match>
<action function="play-file" data="voicemail/vm-enter_pass.wav"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
<nomatch>
<action function="play-file" data="voicemail/vm-enter_pass.wav"/>
<action function="say" data="${VM-Key-Terminator}" method="pronounced" type="name_spelled"/>
</nomatch>
</input>
</macro>
<macro name="fail_auth">
<input>
<match>
<action function="play-file" data="voicemail/vm-fail_auth.wav"/>
</match>
</input>
</macro>
<macro name="hello">
<input>
<match>
<!--<action function="play-file" data="voicemail/vm-hello.wav"/> -->
</match>
</input>
</macro>
<macro name="goodbye">
<input>
<match>
<action function="play-file" data="voicemail/vm-goodbye.wav"/>
</match>
</input>
</macro>
<macro name="abort">
<input>
<match>
<action function="play-file" data="voicemail/vm-abort.wav"/>
</match>
</input>
</macro>
<macro name="message_count">
<input field="${VM-Total-New-Urgent-Messages}" pattern="^(0)$">
<nomatch>
<action function="play-file" data="voicemail/vm-you_have.wav"/>
<action function="say" data="${VM-Total-New-Urgent-Messages}" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-urgent-new.wav"/>
<action function="phrase" phrase="plurial_msg@protovm" data="${VM-Total-New-Urgent-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
</nomatch>
</input>
<input field="${VM-Total-New-Messages}" pattern="^(\d+)$">
<match>
<action function="play-file" data="voicemail/vm-you_have.wav"/>
<action function="say" data="${VM-Total-New-Messages}" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-new.wav"/>
<action function="phrase" phrase="plurial_msg@protovm" data="${VM-Total-New-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
</match>
</input>
<input field="${VM-Total-Saved-Messages}" pattern="^(0)$">
<nomatch>
<action function="play-file" data="currency/and.wav"/>
<action function="say" data="${VM-Total-Saved-Messages}" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-saved.wav"/>
<action function="phrase" phrase="plurial_msg@protovm" data="${VM-Total-Saved-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
</nomatch>
</input>
</macro>
<macro name="menu">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Play-New-Messages}:voicemail/vm-listen_new.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Play-Saved-Messages}:voicemail/vm-listen_saved.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Config-Menu}:voicemail/vm-advanced.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Terminator}:voicemail/vm-to_exit.wav"/>
</match>
</input>
</macro>
<macro name="config_menu">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Record-Greeting}:voicemail/vm-to_record_greeting.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Choose-Greeting}:voicemail/vm-choose_greeting.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Record-Name}:voicemail/vm-record_name2.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Change-Password}:voicemail/vm-change_password.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Menu}:voicemail/vm-main_menu.wav"/>
</match>
</input>
</macro>
<macro name="record_name">
<input>
<match>
<action function="play-file" data="voicemail/vm-record_name1.wav"/>
</match>
</input>
</macro>
<macro name="record_file_check">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Listen-File}:voicemail/vm-listen_to_recording.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Save-File}:voicemail/vm-save_recording.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Record-File}:voicemail/vm-rerecord.wav"/>
</match>
</input>
</macro>
<macro name="record_urgent_check">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Urgent}:voicemail/vm-mark-urgent.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Terminator}:voicemail/vm-continue.wav"/>
</match>
</input>
</macro>
<macro name="forward_prepend">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Prepend}:voicemail/vm-forward_add_intro.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Forward}:voicemail/vm-send_message_now.wav"/>
</match>
</input>
</macro>
<macro name="forward_message_enter_extension">
<input pattern="^([0-9#*])$">
<match>
<action function="play-file" data="voicemail/vm-forward_enter_ext.wav"/>
<action function="play-file" data="voicemail/vm-followed_by.wav"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
</input>
</macro>
<macro name="invalid_extension">
<input>
<match>
<action function="play-file" data="voicemail/vm-that_was_an_invalid_ext.wav"/>
</match>
</input>
</macro>
<macro name="listen_file_check">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Next-Msg}:voicemail/vm-for_next_msg.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Listen-File}:voicemail/vm-listen_to_recording.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Save-File}:voicemail/vm-save_recording.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Delete-File}:voicemail/vm-delete_recording.wav"/>
</match>
</input>
<input field="${VM-Message-Email}" pattern="^$">
<nomatch>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Email}:voicemail/vm-forward_to_email.wav"/>
</nomatch>
</input>
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Callback}:voicemail/vm-return_call.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Forward}:voicemail/vm-to_forward.wav"/>
</match>
</input>
</macro>
<macro name="choose_greeting">
<input>
<match>
<action function="play-file" data="voicemail/vm-choose_greeting_choose.wav"/>
</match>
</input>
</macro>
<macro name="choose_greeting_fail">
<input>
<match>
<action function="play-file" data="voicemail/vm-choose_greeting_fail.wav"/>
</match>
</input>
</macro>
<macro name="record_greeting">
<input>
<match>
<action function="play-file" data="voicemail/vm-record_greeting.wav"/>
</match>
</input>
</macro>
<macro name="record_message">
<input>
<match>
<action function="play-file" data="voicemail/vm-record_message.wav"/>
</match>
</input>
</macro>
<macro name="greeting_selected">
<input pattern="^(\d+)$">
<match>
<action function="play-file" data="voicemail/vm-greeting.wav"/>
<action function="say" data="$1" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-selected.wav"/>
</match>
</input>
</macro>
<macro name="play_greeting">
<input pattern="^(.*)$">
<match>
<action function="play-file" data="voicemail/vm-person.wav"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
<action function="play-file" data="voicemail/vm-not_available.wav"/>
</match>
</input>
</macro>
<macro name="say_number">
<input pattern="^(\d+)$">
<match>
<action function="say" data="$1" method="pronounced" type="items"/>
</match>
</input>
</macro>
<macro name="say_message_number">
<input>
<match>
<action function="play-file" data="voicemail/vm-${VM-Message-Type}.wav"/>
<action function="play-file" data="voicemail/vm-message_number.wav"/>
<action function="say" data="${VM-Message-Number}" method="pronounced" type="items"/>
</match>
</input>
</macro>
<macro name="say_phone_number">
<input pattern="^(.*)$">
<match>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
</input>
</macro>
<macro name="say_name">
<input pattern="^(.*)$">
<match>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
</input>
</macro>
<!-- Note: Update this to marked-urgent,emailed and saved once new sound files are recorded -->
<macro name="ack">
<input pattern="^(too-small)$">
<match>
<action function="play-file" data="voicemail/vm-too-small.wav"/>
</match>
</input>
<input pattern="^(undeleted)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(deleted)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(saved)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(emailed)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(marked-urgent)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
</macro>
<macro name="say_date">
<input pattern="^(.*)$">
<match>
<action function="say" data="$1" method="pronounced" type="short_date_time"/>
</match>
</input>
</macro>
<macro name="say_date_event">
<input>
<match>
<action function="say" data="${VM-Message-Received-Epoch}" method="pronounced" type="short_date_time"/>
</match>
</input>
</macro>
<macro name="play_message">
<input>
<match>
<action function="play-file" data="${VM-Message-File-Path}"/>
</match>
</input>
</macro>
<macro name="play_recording">
<input>
<match>
<action function="play-file" data="${VM-Record-File-Path}"/>
</match>
</input>
</macro>
<macro name="disk_quota_exceeded">
<input>
<match>
<action function="play-file" data="voicemail/vm-mailbox_full.wav"/>
</match>
</input>
</macro>
</macros>
</include><!--This line will be ignored it's here to validate the xml and is optional --> </include><!--This line will be ignored it's here to validate the xml and is optional -->

View File

@ -50,7 +50,8 @@ typedef enum {
XML_LDAP_CONFIG = 0, XML_LDAP_CONFIG = 0,
XML_LDAP_DIRECTORY, XML_LDAP_DIRECTORY,
XML_LDAP_DIALPLAN, XML_LDAP_DIALPLAN,
XML_LDAP_PHRASE XML_LDAP_PHRASE,
XML_LDAP_LANGUAGE
} xml_ldap_query_type_t; } xml_ldap_query_type_t;
SWITCH_MODULE_LOAD_FUNCTION(mod_xml_ldap_load); SWITCH_MODULE_LOAD_FUNCTION(mod_xml_ldap_load);
@ -247,6 +248,8 @@ static switch_xml_t xml_ldap_search(const char *section, const char *tag_name, c
query_type = XML_LDAP_DIALPLAN; query_type = XML_LDAP_DIALPLAN;
} else if (!strcmp(section, "phrases")) { } else if (!strcmp(section, "phrases")) {
query_type = XML_LDAP_PHRASE; query_type = XML_LDAP_PHRASE;
} else if (!strcmp(section, "languages")) {
query_type = XML_LDAP_LANGUAGE;
} else { } else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid section\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid section\n");
return NULL; return NULL;
@ -269,6 +272,7 @@ static switch_xml_t xml_ldap_search(const char *section, const char *tag_name, c
case XML_LDAP_DIALPLAN: case XML_LDAP_DIALPLAN:
case XML_LDAP_PHRASE: case XML_LDAP_PHRASE:
case XML_LDAP_LANGUAGE:
break; break;
} }
} }
@ -326,6 +330,7 @@ static switch_xml_t xml_ldap_search(const char *section, const char *tag_name, c
break; break;
case XML_LDAP_PHRASE: case XML_LDAP_PHRASE:
case XML_LDAP_LANGUAGE:
break; break;
} }
} else { } else {

View File

@ -29,6 +29,7 @@
* Matt Klein <mklein@nmedia.net> * Matt Klein <mklein@nmedia.net>
* Michael Jerris <mike@jerris.com> * Michael Jerris <mike@jerris.com>
* Ken Rice <krice at suspicious dot org> * Ken Rice <krice at suspicious dot org>
* Marc Olivier Chouinard <mochouinard@moctel.com>
* *
* switch_ivr.c -- IVR Library * switch_ivr.c -- IVR Library
* *
@ -2327,9 +2328,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say(switch_core_session_t *session,
switch_say_interface_t *si; switch_say_interface_t *si;
switch_channel_t *channel; switch_channel_t *channel;
switch_status_t status = SWITCH_STATUS_FALSE; switch_status_t status = SWITCH_STATUS_FALSE;
const char *save_path = NULL, *chan_lang = NULL, *lang = NULL, *lname = NULL, *sound_path = NULL; const char *save_path = NULL, *chan_lang = NULL, *lang = NULL, *sound_path = NULL;
switch_event_t *hint_data; switch_event_t *hint_data;
switch_xml_t cfg, xml = NULL, language, macros; switch_xml_t cfg, xml = NULL, language = NULL, macros = NULL, phrases = NULL;
char *p; char *p;
switch_assert(session); switch_assert(session);
@ -2341,6 +2342,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say(switch_core_session_t *session,
} }
if (module_name) { if (module_name) {
char *p;
p = switch_core_session_strdup(session, module_name); p = switch_core_session_strdup(session, module_name);
module_name = p; module_name = p;
@ -2371,58 +2373,35 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say(switch_core_session_t *session,
switch_event_add_header_string(hint_data, SWITCH_STACK_BOTTOM, "lang", chan_lang); switch_event_add_header_string(hint_data, SWITCH_STACK_BOTTOM, "lang", chan_lang);
switch_channel_event_set_data(channel, hint_data); switch_channel_event_set_data(channel, hint_data);
if (switch_xml_locate("phrases", NULL, NULL, NULL, &xml, &cfg, hint_data, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) { if (switch_xml_locate_language(&xml, &cfg, hint_data, &language, &phrases, &macros, chan_lang) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Open of phrases failed.\n");
goto done; goto done;
} }
if (!(macros = switch_xml_child(cfg, "macros"))) { if ((p = (char *) switch_xml_attr(language, "say-module"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find macros tag.\n"); module_name = switch_core_session_strdup(session, p);
goto done; } else if ((p = (char *) switch_xml_attr(language, "module"))) {
} module_name = switch_core_session_strdup(session, p);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Deprecated usage of module attribute\n");
if (!(language = switch_xml_child(macros, "language"))) { } else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find language tag.\n");
goto done;
}
while (language) {
if ((lname = (char *) switch_xml_attr(language, "name")) && !strcasecmp(lname, chan_lang)) {
const char *tmp;
if ((tmp = switch_xml_attr(language, "module"))) {
module_name = tmp;
}
break;
}
language = language->next;
}
if (!language) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find language %s.\n", chan_lang);
goto done;
}
if (!module_name) {
module_name = chan_lang; module_name = chan_lang;
} }
if (!(sound_path = (char *) switch_xml_attr(language, "sound-path"))) { if (!(sound_path = (char *) switch_xml_attr(language, "sound-prefix"))) {
sound_path = (char *) switch_xml_attr(language, "sound_path"); if (!(sound_path = (char *) switch_xml_attr(language, "sound-path"))) {
sound_path = (char *) switch_xml_attr(language, "sound_path");
}
} }
save_path = switch_channel_get_variable(channel, "sound_prefix"); if (channel) {
const char *p = switch_channel_get_variable(channel, "sound_prefix_enforced");
if (sound_path) { if (!switch_true(p)) {
switch_channel_set_variable(channel, "sound_prefix", sound_path); save_path = switch_channel_get_variable(channel, "sound_prefix");
p = switch_core_session_strdup(session, sound_path); if (sound_path) {
sound_path = p; switch_channel_set_variable(channel, "sound_prefix", sound_path);
}
}
} }
if (xml) {
switch_xml_free(xml);
}
if ((si = switch_loadable_module_get_say_interface(module_name))) { if ((si = switch_loadable_module_get_say_interface(module_name))) {
/* should go back and proto all the say mods to const.... */ /* should go back and proto all the say mods to const.... */
switch_say_args_t say_args = {0}; switch_say_args_t say_args = {0};
@ -2446,7 +2425,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say(switch_core_session_t *session,
if (save_path) { if (save_path) {
switch_channel_set_variable(channel, "sound_prefix", save_path); switch_channel_set_variable(channel, "sound_prefix", save_path);
} }
if (xml) {
switch_xml_free(xml);
}
return status; return status;
} }
@ -2463,9 +2446,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say_string(switch_core_session_t *ses
switch_say_interface_t *si; switch_say_interface_t *si;
switch_channel_t *channel = NULL; switch_channel_t *channel = NULL;
switch_status_t status = SWITCH_STATUS_FALSE; switch_status_t status = SWITCH_STATUS_FALSE;
const char *save_path = NULL, *chan_lang = NULL, *lname = NULL, *sound_path = NULL; const char *save_path = NULL, *chan_lang = NULL, *sound_path = NULL;
switch_event_t *hint_data; switch_event_t *hint_data;
switch_xml_t cfg, xml = NULL, language, macros; switch_xml_t cfg, xml = NULL, language = NULL, macros = NULL, phrases = NULL;
if (session) { if (session) {
channel = switch_core_session_get_channel(session); channel = switch_core_session_get_channel(session);
@ -2498,52 +2481,31 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say_string(switch_core_session_t *ses
switch_channel_event_set_data(channel, hint_data); switch_channel_event_set_data(channel, hint_data);
} }
if (switch_xml_locate("phrases", NULL, NULL, NULL, &xml, &cfg, hint_data, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) { if (switch_xml_locate_language(&xml, &cfg, hint_data, &language, &phrases, &macros, chan_lang) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Open of phrases failed.\n");
goto done; goto done;
} }
if (!(macros = switch_xml_child(cfg, "macros"))) { if ((module_name = switch_xml_attr(language, "say-module"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find macros tag.\n"); } else if ((module_name = switch_xml_attr(language, "module"))) {
goto done; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Deprecated usage of module attribute\n");
} } else {
if (!(language = switch_xml_child(macros, "language"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find language tag.\n");
goto done;
}
while (language) {
if ((lname = (char *) switch_xml_attr(language, "name")) && !strcasecmp(lname, chan_lang)) {
const char *tmp;
if ((tmp = switch_xml_attr(language, "module"))) {
module_name = tmp;
}
break;
}
language = language->next;
}
if (!language) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find language %s.\n", chan_lang);
goto done;
}
if (!module_name) {
module_name = chan_lang; module_name = chan_lang;
} }
if (!(sound_path = (char *) switch_xml_attr(language, "sound-path"))) { if (!(sound_path = (char *) switch_xml_attr(language, "sound-prefix"))) {
sound_path = (char *) switch_xml_attr(language, "sound_path"); if (!(sound_path = (char *) switch_xml_attr(language, "sound-path"))) {
sound_path = (char *) switch_xml_attr(language, "sound_path");
}
} }
if (channel) { if (channel) {
save_path = switch_channel_get_variable(channel, "sound_prefix"); const char *p = switch_channel_get_variable(channel, "sound_prefix_enforced");
} if (!switch_true(p)) {
save_path = switch_channel_get_variable(channel, "sound_prefix");
if (sound_path && channel) { if (sound_path) {
switch_channel_set_variable(channel, "sound_prefix", sound_path); switch_channel_set_variable(channel, "sound_prefix", sound_path);
}
}
} }
if ((si = switch_loadable_module_get_say_interface(module_name))) { if ((si = switch_loadable_module_get_say_interface(module_name))) {

View File

@ -28,6 +28,7 @@
* Neal Horman <neal at wanlink dot com> * Neal Horman <neal at wanlink dot com>
* Matt Klein <mklein@nmedia.net> * Matt Klein <mklein@nmedia.net>
* Michael Jerris <mike@jerris.com> * Michael Jerris <mike@jerris.com>
* Marc Olivier Chouinard <mochouinard@moctel.com>
* *
* switch_ivr_play_say.c -- IVR Library (functions to play or say audio) * switch_ivr_play_say.c -- IVR Library (functions to play or say audio)
* *
@ -39,8 +40,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro_event(switch_core_sessio
switch_input_args_t *args) switch_input_args_t *args)
{ {
switch_event_t *hint_data; switch_event_t *hint_data;
switch_xml_t cfg, xml = NULL, language, macros, macro, input, action; switch_xml_t cfg, xml = NULL, language = NULL, macros = NULL, phrases = NULL, macro, input, action;
char *lname = NULL, *mname = NULL;
switch_status_t status = SWITCH_STATUS_GENERR; switch_status_t status = SWITCH_STATUS_GENERR;
const char *old_sound_prefix = NULL, *sound_path = NULL, *tts_engine = NULL, *tts_voice = NULL; const char *old_sound_prefix = NULL, *sound_path = NULL, *tts_engine = NULL, *tts_voice = NULL;
const char *module_name = NULL, *chan_lang = NULL; const char *module_name = NULL, *chan_lang = NULL;
@ -49,6 +49,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro_event(switch_core_sessio
int matches = 0; int matches = 0;
const char *pause_val; const char *pause_val;
int pause = 100; int pause = 100;
const char *group_macro_name = NULL;
const char *local_macro_name = macro_name;
switch_bool_t sound_prefix_enforced = switch_true(switch_channel_get_variable(channel, "sound_prefix_enforced"));
switch_bool_t local_sound_prefix_enforced = SWITCH_FALSE;
if (!macro_name) { if (!macro_name) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No phrase macro specified.\n"); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No phrase macro specified.\n");
@ -65,8 +69,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro_event(switch_core_sessio
chan_lang = lang; chan_lang = lang;
} }
module_name = chan_lang;
switch_event_create(&hint_data, SWITCH_EVENT_REQUEST_PARAMS); switch_event_create(&hint_data, SWITCH_EVENT_REQUEST_PARAMS);
switch_assert(hint_data); switch_assert(hint_data);
@ -82,40 +84,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro_event(switch_core_sessio
} }
switch_channel_event_set_data(channel, hint_data); switch_channel_event_set_data(channel, hint_data);
if (switch_xml_locate("phrases", NULL, NULL, NULL, &xml, &cfg, hint_data, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) { if (switch_xml_locate_language(&xml, &cfg, hint_data, &language, &phrases, &macros, chan_lang) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Open of phrases failed.\n");
goto done; goto done;
} }
if (!(macros = switch_xml_child(cfg, "macros"))) { if ((module_name = switch_xml_attr(language, "say-module"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find macros tag.\n"); } else if ((module_name = switch_xml_attr(language, "module"))) {
goto done; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Deprecated usage of module attribute. Use say-module instead\n");
} else {
module_name = chan_lang;
} }
if (!(language = switch_xml_child(macros, "language"))) { if (!(sound_path = (char *) switch_xml_attr(language, "sound-prefix"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find language tag.\n"); if (!(sound_path = (char *) switch_xml_attr(language, "sound-path"))) {
goto done; sound_path = (char *) switch_xml_attr(language, "sound_path");
}
while (language) {
if ((lname = (char *) switch_xml_attr(language, "name")) && !strcasecmp(lname, chan_lang)) {
const char *tmp;
if ((tmp = switch_xml_attr(language, "module"))) {
module_name = tmp;
}
break;
} }
language = language->next;
}
if (!language) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find language %s.\n", chan_lang);
goto done;
}
if (!(sound_path = (char *) switch_xml_attr(language, "sound-path"))) {
sound_path = (char *) switch_xml_attr(language, "sound_path");
} }
if (!(tts_engine = (char *) switch_xml_attr(language, "tts-engine"))) { if (!(tts_engine = (char *) switch_xml_attr(language, "tts-engine"))) {
@ -126,7 +109,41 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro_event(switch_core_sessio
tts_voice = (char *) switch_xml_attr(language, "tts_voice"); tts_voice = (char *) switch_xml_attr(language, "tts_voice");
} }
if (sound_path) { /* If we use the new structure, check for a group name */
if (language != macros) {
char *p;
char *macro_name_dup = switch_core_session_strdup(session, macro_name);
const char *group_sound_path;
const char *sound_prefix_enforced_str;
if ((p = strchr(macro_name_dup, '@'))) {
*p++ = '\0';
local_macro_name = macro_name_dup;
group_macro_name = p;
if (!(macros = switch_xml_find_child(phrases, "macros", "name", group_macro_name))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find macros group %s.\n", group_macro_name);
goto done;
}
}
/* Support override of certain language attribute */
if ((group_sound_path = (char *) switch_xml_attr(macros, "sound-prefix")) || (group_sound_path = (char *) switch_xml_attr(macros, "sound-path")) || (group_sound_path = (char *) switch_xml_attr(macros, "sound_path"))) {
sound_path = group_sound_path;
}
if (sound_prefix_enforced == SWITCH_FALSE && (sound_prefix_enforced_str = switch_xml_attr(macros, "sound-prefix-enforced"))
&& (local_sound_prefix_enforced = switch_true(sound_prefix_enforced_str)) == SWITCH_TRUE) {
switch_channel_set_variable(channel, "sound_prefix_enforced", sound_prefix_enforced_str);
}
}
if (!(macro = switch_xml_find_child(macros, "macro", "name", local_macro_name))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find macro %s.\n", macro_name);
goto done;
}
if (sound_path && sound_prefix_enforced == SWITCH_FALSE) {
char *p; char *p;
old_sound_prefix = switch_str_nil(switch_channel_get_variable(channel, "sound_prefix")); old_sound_prefix = switch_str_nil(switch_channel_get_variable(channel, "sound_prefix"));
p = switch_core_session_strdup(session, old_sound_prefix); p = switch_core_session_strdup(session, old_sound_prefix);
@ -134,23 +151,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro_event(switch_core_sessio
switch_channel_set_variable(channel, "sound_prefix", sound_path); switch_channel_set_variable(channel, "sound_prefix", sound_path);
} }
if (!(macro = switch_xml_child(language, "macro"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find any macro tags.\n");
goto done;
}
while (macro) {
if ((mname = (char *) switch_xml_attr(macro, "name")) && !strcasecmp(mname, macro_name)) {
break;
}
macro = macro->next;
}
if (!macro) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't find macro %s.\n", macro_name);
goto done;
}
if ((pause_val = switch_xml_attr(macro, "pause"))) { if ((pause_val = switch_xml_attr(macro, "pause"))) {
int tmp = atoi(pause_val); int tmp = atoi(pause_val);
if (tmp >= 0) { if (tmp >= 0) {
@ -342,6 +342,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro_event(switch_core_sessio
if (old_sound_prefix) { if (old_sound_prefix) {
switch_channel_set_variable(channel, "sound_prefix", old_sound_prefix); switch_channel_set_variable(channel, "sound_prefix", old_sound_prefix);
} }
if (local_sound_prefix_enforced == SWITCH_TRUE) {
switch_channel_set_variable(channel, "sound_prefix_enforced", NULL);
}
if (xml) { if (xml) {
switch_xml_free(xml); switch_xml_free(xml);
} }

View File

@ -25,7 +25,7 @@
* *
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Simon Capper <skyjunky@sbcglobal.net> * Simon Capper <skyjunky@sbcglobal.net>
* * Marc Olivier Chouinard <mochouinard@moctel.com>
* *
* switch_xml.c -- XML PARSER * switch_xml.c -- XML PARSER
* *
@ -2785,6 +2785,62 @@ SWITCH_DECLARE(int) switch_xml_std_datetime_check(switch_xml_t xcond) {
return time_match; return time_match;
} }
SWITCH_DECLARE(switch_status_t) switch_xml_locate_language(switch_xml_t *root, switch_xml_t *node, switch_event_t *params, switch_xml_t *language, switch_xml_t *phrases, switch_xml_t *macros, const char *str_language) {
switch_status_t status = SWITCH_STATUS_FALSE;
if (switch_xml_locate("languages", NULL, NULL, NULL, root, node, params, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) {
switch_xml_t sub_macros;
if (switch_xml_locate("phrases", NULL, NULL, NULL, root, node, params, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of languages and phrases failed.\n");
goto done;
}
if (!(sub_macros = switch_xml_child(*node, "macros"))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find macros tag.\n");
switch_xml_free(*root);
*root = NULL;
*node = NULL;
goto done;
}
if (!(*language = switch_xml_find_child(sub_macros, "language", "name", str_language))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find language %s.\n", str_language);
switch_xml_free(*root);
*root = NULL;
*node = NULL;
goto done;
}
*macros = *language;
} else {
if (!(*language = switch_xml_find_child(*node, "language", "name", str_language))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find language %s.\n", str_language);
switch_xml_free(*root);
*root = NULL;
goto done;
}
if (!(*phrases = switch_xml_child(*language, "phrases"))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find phrases tag.\n");
switch_xml_free(*root);
*root = NULL;
*node = NULL;
*language = NULL;
goto done;
}
if (!(*macros = switch_xml_child(*phrases, "macros"))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find macros tag.\n");
switch_xml_free(*root);
*root = NULL;
*node = NULL;
*language = NULL;
*phrases = NULL;
goto done;
}
}
status = SWITCH_STATUS_SUCCESS;
done:
return status;
}
#ifdef WIN32 #ifdef WIN32
/* /*