From fc3d3a3ec1b5ee865cbc298dd7b1bc2c49fef9a2 Mon Sep 17 00:00:00 2001 From: ssether Date: Tue, 8 May 2018 13:30:07 -0500 Subject: [PATCH 01/19] initial version, adding spec tests --- .../translator/asterisk/component/output.rb | 129 +++++++++++------- .../asterisk/component/output_spec.rb | 45 +++++- 2 files changed, 121 insertions(+), 53 deletions(-) diff --git a/lib/punchblock/translator/asterisk/component/output.rb b/lib/punchblock/translator/asterisk/component/output.rb index a9525d7c..edf6886a 100644 --- a/lib/punchblock/translator/asterisk/component/output.rb +++ b/lib/punchblock/translator/asterisk/component/output.rb @@ -30,48 +30,48 @@ def execute repeat_times = 1000 if repeat_times.zero? case rendering_engine.to_sym - when :asterisk - validate_audio_only - setup_for_native + when :asterisk + validate_audio_number_only + setup_for_native - repeat_times.times do - render_docs.each do |doc| - playback(filenames(doc).values) || raise(PlaybackError) + repeat_times.times do + render_docs.each do |doc| + play_doc_asterisk(doc) + end end - end - when :native_or_unimrcp - setup_for_native - - repeat_times.times do - render_docs.each do |doc| - doc.value.children.each do |node| - case node - when RubySpeech::SSML::Audio - playback([path_for_audio_node(node)]) || render_with_unimrcp(fallback_doc(doc, node)) - when String - if node.include?(' ') - render_with_unimrcp(copied_doc(doc, node)) - else - playback([node]) || render_with_unimrcp(copied_doc(doc, node)) + when :native_or_unimrcp + setup_for_native + + repeat_times.times do + render_docs.each do |doc| + doc.value.children.each do |node| + case node + when RubySpeech::SSML::Audio + playback([path_for_audio_node(node)]) || render_with_unimrcp(fallback_doc(doc, node)) + when String + if node.include?(' ') + render_with_unimrcp(copied_doc(doc, node)) + else + playback([node]) || render_with_unimrcp(copied_doc(doc, node)) + end + else + render_with_unimrcp(copied_doc(doc, node.node)) end - else - render_with_unimrcp(copied_doc(doc, node.node)) end end end - end - when :unimrcp - send_progress_if_necessary - send_ref - repeat_times.times do - render_with_unimrcp(*render_docs) - end - when :swift - send_progress_if_necessary - send_ref - @call.execute_agi_command 'EXEC Swift', swift_doc - else - raise OptionError, "The renderer #{rendering_engine} is unsupported." + when :unimrcp + send_progress_if_necessary + send_ref + repeat_times.times do + render_with_unimrcp(*render_docs) + end + when :swift + send_progress_if_necessary + send_ref + @call.execute_agi_command 'EXEC Swift', swift_doc + else + raise OptionError, "The renderer #{rendering_engine} is unsupported." end send_finish rescue ChannelGoneError @@ -100,8 +100,8 @@ def setup_for_native raise OptionError, 'Interrupt digits are not allowed with early media.' if @early && @component_node.interrupt_on case @component_node.interrupt_on - when :any, :dtmf - interrupt = true + when :any, :dtmf + interrupt = true end send_progress_if_necessary @@ -119,9 +119,24 @@ def send_progress_if_necessary @call.send_progress if @early end - def validate_audio_only + def validate_audio_number_only render_docs.each do |doc| - filenames doc, -> { raise UnrenderableDocError, 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.' } + doc.value.children.each do |node| + case node + when RubySpeech::SSML::Audio + # Valid node, do nothing + when RubySpeech::SSML::SayAs + if all_numbers?(node.text) + #Valid node, do nothing. + else + raise UnrenderableDocError, 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.' + end + when String + raise UnrenderableDocError, 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.' if node.include?(' ') + else + raise UnrenderableDocError, 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.' + end + end end end @@ -136,20 +151,27 @@ def path_for_audio_node(node) end end - def filenames(doc, check_audio_only_policy = -> {}) - names = {} + def play_doc_asterisk(doc) doc.value.children.each do |node| case node - when RubySpeech::SSML::Audio - names[node] = path_for_audio_node node - when String - check_audio_only_policy.call if node.include?(' ') - names[nil] = node - else - check_audio_only_policy.call + when RubySpeech::SSML::Audio + playback([path_for_audio_node(node)]) || raise(PlaybackError) + when String + playback([node]) || raise(PlaybackError) + when RubySpeech::SSML::SayAs + if all_numbers?(node.text) + say_number(node.text) + else + raise UnrenderableDocError, 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.' + end + else + raise UnrenderableDocError, 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.' end end - names + end + + def all_numbers?(input) + !!(/^[0-9]+$/ =~ input) end def playback_options(paths) @@ -164,6 +186,11 @@ def playback(paths) @call.channel_var('PLAYBACKSTATUS') != 'FAILED' end + def say_number(number) + return true if @stopped + @call.execute_agi_command 'EXEC SayNumber', number + end + def fallback_doc(original, failed_audio_node) children = failed_audio_node.nokogiri_children copied_doc original, children @@ -229,4 +256,4 @@ def finish_reason end end end -end +end \ No newline at end of file diff --git a/spec/punchblock/translator/asterisk/component/output_spec.rb b/spec/punchblock/translator/asterisk/component/output_spec.rb index bb8507a1..6cd96493 100644 --- a/spec/punchblock/translator/asterisk/component/output_spec.rb +++ b/spec/punchblock/translator/asterisk/component/output_spec.rb @@ -503,6 +503,10 @@ def expect_playback_noanswer expect(mock_call).to receive(:execute_agi_command).once.with('EXEC Playback', audio_filename + ',noanswer').and_return code: 200 end + def expect_say_number(number) + expect(mock_call).to receive(:execute_agi_command).once.with('EXEC SayNumber', number).and_return code: 200 + end + let(:audio_filename) { 'tt-monkeys' } let :ssml_doc do @@ -703,7 +707,8 @@ def mock_call.answered? it 'should playback all audio files using Playback' do latch = CountDownLatch.new 2 - expect_playback [audio_filename1, audio_filename2].join('&') + expect_playback audio_filename1 + expect_playback audio_filename2 expect_answered subject.execute latch.wait 2 @@ -712,7 +717,8 @@ def mock_call.answered? it 'should send a complete event after the final file has finished playback' do expect_answered - expect_playback [audio_filename1, audio_filename2].join('&') + expect_playback audio_filename1 + expect_playback audio_filename2 latch = CountDownLatch.new 1 expect(original_command).to receive(:add_event).once { |e| expect(e.reason).to be_a Punchblock::Component::Output::Complete::Finish @@ -723,6 +729,41 @@ def mock_call.answered? end end + context 'with an audio file and a number' do + let(:audio_filename) { 'filename' } + let :ssml_doc do + RubySpeech::SSML.draw do + audio :src => audio_filename + say_as(:interpret_as => :cardinal) { '1234' } + end + end + + it 'should playback an audio file, and say a number' do + expect_answered + expect_playback audio_filename + expect_say_number '1234' + subject.execute + end + end + + context 'with an audio file and a number+text' do + let(:audio_filename) { 'filename' } + let :ssml_doc do + RubySpeech::SSML.draw do + audio :src => audio_filename + say_as(:interpret_as => :cardinal) { '1234X' } + end + end + + it "should return an unrenderable document error" do + subject.execute + error = ProtocolError.new.setup 'unrenderable document error', 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.' + expect(original_command.response(0.1)).to eq(error) + end + end + + + context "with an SSML document containing elements other than