punchblock 1.9.4 → 2.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -2
- data/CHANGELOG.md +17 -0
- data/Gemfile +1 -0
- data/Guardfile +4 -0
- data/README.markdown +6 -0
- data/Rakefile +16 -0
- data/benchmarks/ami_event_name_comparison.rb +14 -0
- data/benchmarks/channel.rb +27 -0
- data/lib/punchblock/client.rb +2 -6
- data/lib/punchblock/command/accept.rb +3 -24
- data/lib/punchblock/command/answer.rb +3 -24
- data/lib/punchblock/command/dial.rb +24 -76
- data/lib/punchblock/command/hangup.rb +3 -19
- data/lib/punchblock/command/join.rb +21 -70
- data/lib/punchblock/command/mute.rb +3 -3
- data/lib/punchblock/command/redirect.rb +6 -39
- data/lib/punchblock/command/reject.rb +14 -54
- data/lib/punchblock/command/unjoin.rb +8 -40
- data/lib/punchblock/command/unmute.rb +3 -3
- data/lib/punchblock/command_node.rb +0 -17
- data/lib/punchblock/component/asterisk/agi/command.rb +20 -127
- data/lib/punchblock/component/asterisk/ami/action.rb +30 -117
- data/lib/punchblock/component/component_node.rb +1 -1
- data/lib/punchblock/component/input.rb +89 -268
- data/lib/punchblock/component/output.rb +106 -154
- data/lib/punchblock/component/prompt.rb +51 -0
- data/lib/punchblock/component/record.rb +41 -130
- data/lib/punchblock/component.rb +1 -0
- data/lib/punchblock/connection/asterisk.rb +31 -4
- data/lib/punchblock/connection/xmpp.rb +6 -14
- data/lib/punchblock/core_ext/blather/stanza.rb +1 -1
- data/lib/punchblock/event/active_speaker.rb +2 -10
- data/lib/punchblock/event/answered.rb +3 -3
- data/lib/punchblock/event/asterisk/ami/event.rb +15 -47
- data/lib/punchblock/event/complete.rb +26 -48
- data/lib/punchblock/event/dtmf.rb +3 -13
- data/lib/punchblock/event/end.rb +10 -11
- data/lib/punchblock/event/joined.rb +5 -25
- data/lib/punchblock/event/offer.rb +4 -25
- data/lib/punchblock/event/ringing.rb +3 -3
- data/lib/punchblock/event/unjoined.rb +5 -25
- data/lib/punchblock/event.rb +0 -10
- data/lib/punchblock/has_headers.rb +20 -26
- data/lib/punchblock/rayo_node.rb +46 -23
- data/lib/punchblock/ref.rb +39 -18
- data/lib/punchblock/translator/asterisk/agi_app.rb +15 -0
- data/lib/punchblock/translator/asterisk/agi_command.rb +3 -1
- data/lib/punchblock/translator/asterisk/ami_error_converter.rb +20 -0
- data/lib/punchblock/translator/asterisk/call.rb +60 -39
- data/lib/punchblock/translator/asterisk/channel.rb +41 -0
- data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +4 -1
- data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +4 -4
- data/lib/punchblock/translator/asterisk/component/composed_prompt.rb +62 -0
- data/lib/punchblock/translator/asterisk/component/input.rb +1 -0
- data/lib/punchblock/translator/asterisk/component/mrcp_native_prompt.rb +56 -0
- data/lib/punchblock/translator/asterisk/component/mrcp_prompt.rb +53 -0
- data/lib/punchblock/translator/asterisk/component/mrcp_recog_prompt.rb +99 -0
- data/lib/punchblock/translator/asterisk/component/output.rb +30 -22
- data/lib/punchblock/translator/asterisk/component/record.rb +8 -6
- data/lib/punchblock/translator/asterisk/component.rb +6 -5
- data/lib/punchblock/translator/asterisk/unimrcp_app.rb +26 -0
- data/lib/punchblock/translator/asterisk.rb +24 -28
- data/lib/punchblock/translator/dtmf_recognizer.rb +39 -20
- data/lib/punchblock/translator/freeswitch/call.rb +15 -14
- data/lib/punchblock/translator/freeswitch/component/abstract_output.rb +5 -4
- data/lib/punchblock/translator/freeswitch/component/flite_output.rb +1 -1
- data/lib/punchblock/translator/freeswitch/component/input.rb +5 -0
- data/lib/punchblock/translator/freeswitch/component/output.rb +2 -2
- data/lib/punchblock/translator/freeswitch/component/record.rb +19 -13
- data/lib/punchblock/translator/freeswitch/component/tts_output.rb +2 -2
- data/lib/punchblock/translator/freeswitch/component.rb +2 -5
- data/lib/punchblock/translator/freeswitch.rb +2 -2
- data/lib/punchblock/translator/input_component.rb +33 -13
- data/lib/punchblock/uri_list.rb +21 -0
- data/lib/punchblock/version.rb +1 -1
- data/lib/punchblock.rb +4 -3
- data/punchblock.gemspec +7 -3
- data/spec/punchblock/client/component_registry_spec.rb +1 -1
- data/spec/punchblock/client_spec.rb +10 -26
- data/spec/punchblock/command/accept_spec.rb +41 -7
- data/spec/punchblock/command/answer_spec.rb +51 -7
- data/spec/punchblock/command/dial_spec.rb +56 -14
- data/spec/punchblock/command/hangup_spec.rb +41 -7
- data/spec/punchblock/command/join_spec.rb +53 -11
- data/spec/punchblock/command/mute_spec.rb +19 -4
- data/spec/punchblock/command/redirect_spec.rb +40 -10
- data/spec/punchblock/command/reject_spec.rb +43 -11
- data/spec/punchblock/command/unjoin_spec.rb +40 -9
- data/spec/punchblock/command/unmute_spec.rb +19 -4
- data/spec/punchblock/command_node_spec.rb +0 -4
- data/spec/punchblock/component/asterisk/agi/command_spec.rb +16 -39
- data/spec/punchblock/component/asterisk/ami/action_spec.rb +50 -53
- data/spec/punchblock/component/component_node_spec.rb +3 -5
- data/spec/punchblock/component/input_spec.rb +194 -61
- data/spec/punchblock/component/output_spec.rb +194 -62
- data/spec/punchblock/component/prompt_spec.rb +132 -0
- data/spec/punchblock/component/record_spec.rb +70 -32
- data/spec/punchblock/connection/asterisk_spec.rb +17 -3
- data/spec/punchblock/connection/freeswitch_spec.rb +4 -4
- data/spec/punchblock/connection/xmpp_spec.rb +20 -38
- data/spec/punchblock/event/answered_spec.rb +12 -10
- data/spec/punchblock/event/asterisk/ami/event_spec.rb +27 -22
- data/spec/punchblock/event/complete_spec.rb +15 -19
- data/spec/punchblock/event/dtmf_spec.rb +5 -6
- data/spec/punchblock/event/end_spec.rb +20 -10
- data/spec/punchblock/event/joined_spec.rb +8 -7
- data/spec/punchblock/event/offer_spec.rb +41 -12
- data/spec/punchblock/event/ringing_spec.rb +12 -10
- data/spec/punchblock/event/started_speaking_spec.rb +5 -6
- data/spec/punchblock/event/stopped_speaking_spec.rb +5 -6
- data/spec/punchblock/event/unjoined_spec.rb +7 -7
- data/spec/punchblock/ref_spec.rb +86 -9
- data/spec/punchblock/translator/asterisk/call_spec.rb +317 -154
- data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +28 -5
- data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +15 -13
- data/spec/punchblock/translator/asterisk/component/composed_prompt_spec.rb +237 -0
- data/spec/punchblock/translator/asterisk/component/input_spec.rb +171 -14
- data/spec/punchblock/translator/asterisk/component/mrcp_native_prompt_spec.rb +652 -0
- data/spec/punchblock/translator/asterisk/component/mrcp_prompt_spec.rb +646 -0
- data/spec/punchblock/translator/asterisk/component/output_spec.rb +127 -77
- data/spec/punchblock/translator/asterisk/component/record_spec.rb +17 -8
- data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +2 -2
- data/spec/punchblock/translator/asterisk/component_spec.rb +3 -7
- data/spec/punchblock/translator/asterisk_spec.rb +20 -24
- data/spec/punchblock/translator/freeswitch/call_spec.rb +103 -99
- data/spec/punchblock/translator/freeswitch/component/flite_output_spec.rb +17 -8
- data/spec/punchblock/translator/freeswitch/component/input_spec.rb +26 -14
- data/spec/punchblock/translator/freeswitch/component/output_spec.rb +30 -52
- data/spec/punchblock/translator/freeswitch/component/record_spec.rb +23 -19
- data/spec/punchblock/translator/freeswitch/component/tts_output_spec.rb +18 -8
- data/spec/punchblock/translator/freeswitch/component_spec.rb +4 -8
- data/spec/punchblock/translator/freeswitch_spec.rb +11 -14
- data/spec/punchblock/uri_list_spec.rb +49 -0
- data/spec/punchblock_spec.rb +11 -1
- data/spec/spec_helper.rb +7 -11
- data/spec/support/mock_connection_with_event_handler.rb +1 -1
- metadata +104 -24
- data/lib/punchblock/header.rb +0 -9
- data/lib/punchblock/key_value_pair_node.rb +0 -51
- data/spec/punchblock/header_spec.rb +0 -11
|
@@ -7,10 +7,10 @@ module Punchblock
|
|
|
7
7
|
class Freeswitch
|
|
8
8
|
describe Call do
|
|
9
9
|
let(:id) { Punchblock.new_uuid }
|
|
10
|
-
let(:stream) {
|
|
10
|
+
let(:stream) { double('RubyFS::Stream').as_null_object }
|
|
11
11
|
let(:media_engine) { 'freeswitch' }
|
|
12
12
|
let(:default_voice) { :hal }
|
|
13
|
-
let(:translator) { Freeswitch.new
|
|
13
|
+
let(:translator) { Freeswitch.new double('Connection::Freeswitch').as_null_object }
|
|
14
14
|
let(:es_env) do
|
|
15
15
|
{
|
|
16
16
|
:variable_direction => "inbound",
|
|
@@ -90,78 +90,78 @@ module Punchblock
|
|
|
90
90
|
|
|
91
91
|
let :headers do
|
|
92
92
|
{
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
93
|
+
'X-variable_direction' => "inbound",
|
|
94
|
+
'X-variable_uuid' => "3f0e1e18-c056-11e1-b099-fffeda3ce54f",
|
|
95
|
+
'X-variable_session_id' => "1",
|
|
96
|
+
'X-variable_sip_local_network_addr' => "109.148.160.137",
|
|
97
|
+
'X-variable_sip_network_ip' => "192.168.1.74",
|
|
98
|
+
'X-variable_sip_network_port' => "59253",
|
|
99
|
+
'X-variable_sip_received_ip' => "192.168.1.74",
|
|
100
|
+
'X-variable_sip_received_port' => "59253",
|
|
101
|
+
'X-variable_sip_via_protocol' => "udp",
|
|
102
|
+
'X-variable_sip_authorized' => "true",
|
|
103
|
+
'X-variable_sip_number_alias' => "1000",
|
|
104
|
+
'X-variable_sip_auth_username' => "1000",
|
|
105
|
+
'X-variable_sip_auth_realm' => "127.0.0.1",
|
|
106
|
+
'X-variable_number_alias' => "1000",
|
|
107
|
+
'X-variable_user_name' => "1000",
|
|
108
|
+
'X-variable_domain_name' => "127.0.0.1",
|
|
109
|
+
'X-variable_record_stereo' => "true",
|
|
110
|
+
'X-variable_default_gateway' => "example.com",
|
|
111
|
+
'X-variable_default_areacode' => "918",
|
|
112
|
+
'X-variable_transfer_fallback_extension' => "operator",
|
|
113
|
+
'X-variable_toll_allow' => "domestic,international,local",
|
|
114
|
+
'X-variable_accountcode' => "1000",
|
|
115
|
+
'X-variable_user_context' => "default",
|
|
116
|
+
'X-variable_effective_caller_id_name' => "Extension 1000",
|
|
117
|
+
'X-variable_effective_caller_id_number' => "1000",
|
|
118
|
+
'X-variable_outbound_caller_id_name' => "FreeSWITCH",
|
|
119
|
+
'X-variable_outbound_caller_id_number' => "0000000000",
|
|
120
|
+
'X-variable_callgroup' => "techsupport",
|
|
121
|
+
'X-variable_sip_from_user' => "1000",
|
|
122
|
+
'X-variable_sip_from_uri' => "1000@127.0.0.1",
|
|
123
|
+
'X-variable_sip_from_host' => "127.0.0.1",
|
|
124
|
+
'X-variable_sip_from_user_stripped' => "1000",
|
|
125
|
+
'X-variable_sip_from_tag' => "1248111553",
|
|
126
|
+
'X-variable_sofia_profile_name' => "internal",
|
|
127
|
+
'X-variable_sip_full_via' => "SIP/2.0/UDP 192.168.1.74:59253;rport=59253;branch=z9hG4bK2021947958",
|
|
128
|
+
'X-variable_sip_full_from' => "<sip:1000@127.0.0.1>;tag=1248111553",
|
|
129
|
+
'X-variable_sip_full_to' => "<sip:10@127.0.0.1>",
|
|
130
|
+
'X-variable_sip_req_user' => "10",
|
|
131
|
+
'X-variable_sip_req_uri' => "10@127.0.0.1",
|
|
132
|
+
'X-variable_sip_req_host' => "127.0.0.1",
|
|
133
|
+
'X-variable_sip_to_user' => "10",
|
|
134
|
+
'X-variable_sip_to_uri' => "10@127.0.0.1",
|
|
135
|
+
'X-variable_sip_to_host' => "127.0.0.1",
|
|
136
|
+
'X-variable_sip_contact_user' => "1000",
|
|
137
|
+
'X-variable_sip_contact_port' => "59253",
|
|
138
|
+
'X-variable_sip_contact_uri' => "1000@192.168.1.74:59253",
|
|
139
|
+
'X-variable_sip_contact_host' => "192.168.1.74",
|
|
140
|
+
'X-variable_channel_name' => "sofia/internal/1000@127.0.0.1",
|
|
141
|
+
'X-variable_sip_call_id' => "1251435211@127.0.0.1",
|
|
142
|
+
'X-variable_sip_user_agent' => "YATE/4.1.0",
|
|
143
|
+
'X-variable_sip_via_host' => "192.168.1.74",
|
|
144
|
+
'X-variable_sip_via_port' => "59253",
|
|
145
|
+
'X-variable_sip_via_rport' => "59253",
|
|
146
|
+
'X-variable_max_forwards' => "20",
|
|
147
|
+
'X-variable_presence_id' => "1000@127.0.0.1",
|
|
148
|
+
'X-variable_switch_r_sdp' => "v=0\r\no=yate 1340801245 1340801245 IN IP4 172.20.10.3\r\ns=SIP Call\r\nc=IN IP4 172.20.10.3\r\nt=0 0\r\nm=audio 25048 RTP/AVP 0 8 11 98 97 102 103 104 105 106 101\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:11 L16/8000\r\na=rtpmap:98 iLBC/8000\r\na=fmtp:98 mode=20\r\na=rtpmap:97 iLBC/8000\r\na=fmtp:97 mode=30\r\na=rtpmap:102 SPEEX/8000\r\na=rtpmap:103 SPEEX/16000\r\na=rtpmap:104 SPEEX/32000\r\na=rtpmap:105 iSAC/16000\r\na=rtpmap:106 iSAC/32000\r\na=rtpmap:101 telephone-event/8000\r\na=ptime:30\r\n",
|
|
149
|
+
'X-variable_remote_media_ip' => "172.20.10.3",
|
|
150
|
+
'X-variable_remote_media_port' => "25048",
|
|
151
|
+
'X-variable_sip_audio_recv_pt' => "0",
|
|
152
|
+
'X-variable_sip_use_codec_name' => "PCMU",
|
|
153
|
+
'X-variable_sip_use_codec_rate' => "8000",
|
|
154
|
+
'X-variable_sip_use_codec_ptime' => "30",
|
|
155
|
+
'X-variable_read_codec' => "PCMU",
|
|
156
|
+
'X-variable_read_rate' => "8000",
|
|
157
|
+
'X-variable_write_codec' => "PCMU",
|
|
158
|
+
'X-variable_write_rate' => "8000",
|
|
159
|
+
'X-variable_endpoint_disposition' => "RECEIVED",
|
|
160
|
+
'X-variable_call_uuid' => "3f0e1e18-c056-11e1-b099-fffeda3ce54f",
|
|
161
|
+
'X-variable_open' => "true",
|
|
162
|
+
'X-variable_rfc2822_date' => "Wed, 27 Jun 2012 13:47:25 +0100",
|
|
163
|
+
'X-variable_export_vars' => "RFC2822_DATE",
|
|
164
|
+
'X-variable_current_application' => "park"
|
|
165
165
|
}
|
|
166
166
|
end
|
|
167
167
|
|
|
@@ -176,7 +176,7 @@ module Punchblock
|
|
|
176
176
|
describe '#register_component' do
|
|
177
177
|
it 'should make the component accessible by ID' do
|
|
178
178
|
component_id = 'abc123'
|
|
179
|
-
component =
|
|
179
|
+
component = double 'Translator::Freeswitch::Component', :id => component_id
|
|
180
180
|
subject.register_component component
|
|
181
181
|
subject.component_with_id(component_id).should be component
|
|
182
182
|
end
|
|
@@ -350,13 +350,13 @@ module Punchblock
|
|
|
350
350
|
|
|
351
351
|
it "de-registers the call from the translator" do
|
|
352
352
|
translator.stub :handle_pb_event
|
|
353
|
-
translator.should_receive(:deregister_call).once.with(
|
|
353
|
+
translator.should_receive(:deregister_call).once.with(id)
|
|
354
354
|
subject.handle_es_event es_event
|
|
355
355
|
end
|
|
356
356
|
|
|
357
357
|
it "should cause all components to send complete events before sending end event" do
|
|
358
358
|
ssml_doc = RubySpeech::SSML.draw { audio { 'foo.wav' } }
|
|
359
|
-
comp_command = Punchblock::Component::Output.new :
|
|
359
|
+
comp_command = Punchblock::Component::Output.new :render_document => {:value => ssml_doc}
|
|
360
360
|
comp_command.request!
|
|
361
361
|
component = subject.execute_command comp_command
|
|
362
362
|
comp_command.response(0.1).should be_a Ref
|
|
@@ -374,7 +374,6 @@ module Punchblock
|
|
|
374
374
|
'NORMAL_CLEARING',
|
|
375
375
|
'ORIGINATOR_CANCEL',
|
|
376
376
|
'SYSTEM_SHUTDOWN',
|
|
377
|
-
'MANAGER_REQUEST',
|
|
378
377
|
'BLIND_TRANSFER',
|
|
379
378
|
'ATTENDED_TRANSFER',
|
|
380
379
|
'PICKED_OFF',
|
|
@@ -392,6 +391,17 @@ module Punchblock
|
|
|
392
391
|
end
|
|
393
392
|
end
|
|
394
393
|
|
|
394
|
+
context "with a MANAGER_REQUEST cause" do
|
|
395
|
+
let(:cause) { 'MANAGER_REQUEST' }
|
|
396
|
+
|
|
397
|
+
it 'should send an end (hangup-command) event to the translator' do
|
|
398
|
+
expected_end_event = Punchblock::Event::End.new :reason => :hangup_command,
|
|
399
|
+
:target_call_id => subject.id
|
|
400
|
+
translator.should_receive(:handle_pb_event).with expected_end_event
|
|
401
|
+
subject.handle_es_event es_event
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
|
|
395
405
|
context "with a user busy cause" do
|
|
396
406
|
let(:cause) { 'USER_BUSY' }
|
|
397
407
|
|
|
@@ -500,7 +510,7 @@ module Punchblock
|
|
|
500
510
|
end
|
|
501
511
|
|
|
502
512
|
context 'with an event for a known component' do
|
|
503
|
-
let(:mock_component_node) {
|
|
513
|
+
let(:mock_component_node) { double 'Punchblock::Component::Output' }
|
|
504
514
|
let :component do
|
|
505
515
|
Component::Output.new mock_component_node, subject
|
|
506
516
|
end
|
|
@@ -581,7 +591,7 @@ module Punchblock
|
|
|
581
591
|
RubyFS::Event.new nil, :event_name => 'DTMF'
|
|
582
592
|
end
|
|
583
593
|
|
|
584
|
-
let(:response) {
|
|
594
|
+
let(:response) { double 'Response' }
|
|
585
595
|
|
|
586
596
|
it 'should execute the handler' do
|
|
587
597
|
response.should_receive(:call).once.with es_event
|
|
@@ -596,10 +606,8 @@ module Punchblock
|
|
|
596
606
|
let(:other_call_id) { Punchblock.new_uuid }
|
|
597
607
|
|
|
598
608
|
let :expected_joined do
|
|
599
|
-
Punchblock::Event::Joined.new
|
|
600
|
-
|
|
601
|
-
joined.call_id = other_call_id
|
|
602
|
-
end
|
|
609
|
+
Punchblock::Event::Joined.new target_call_id: subject.id,
|
|
610
|
+
call_uri: other_call_id
|
|
603
611
|
end
|
|
604
612
|
|
|
605
613
|
context "where this is the joining call" do
|
|
@@ -637,10 +645,8 @@ module Punchblock
|
|
|
637
645
|
let(:other_call_id) { Punchblock.new_uuid }
|
|
638
646
|
|
|
639
647
|
let :expected_unjoined do
|
|
640
|
-
Punchblock::Event::Unjoined.new
|
|
641
|
-
|
|
642
|
-
joined.call_id = other_call_id
|
|
643
|
-
end
|
|
648
|
+
Punchblock::Event::Unjoined.new target_call_id: subject.id,
|
|
649
|
+
call_uri: other_call_id
|
|
644
650
|
end
|
|
645
651
|
|
|
646
652
|
context "where this is the unjoining call" do
|
|
@@ -738,7 +744,7 @@ module Punchblock
|
|
|
738
744
|
let(:command) { Command::Hangup.new }
|
|
739
745
|
|
|
740
746
|
it "should send a hangup message and set the command's response" do
|
|
741
|
-
expect_hangup_with_reason '
|
|
747
|
+
expect_hangup_with_reason 'MANAGER_REQUEST'
|
|
742
748
|
subject.execute_command command
|
|
743
749
|
command.response(0.5).should be true
|
|
744
750
|
end
|
|
@@ -874,7 +880,7 @@ module Punchblock
|
|
|
874
880
|
end
|
|
875
881
|
|
|
876
882
|
let :mock_component do
|
|
877
|
-
|
|
883
|
+
double 'Component', :id => component_id
|
|
878
884
|
end
|
|
879
885
|
|
|
880
886
|
context "for a known component ID" do
|
|
@@ -888,19 +894,17 @@ module Punchblock
|
|
|
888
894
|
|
|
889
895
|
context "for a component which began executing but crashed" do
|
|
890
896
|
let :component_command do
|
|
891
|
-
Punchblock::Component::Output.new :
|
|
897
|
+
Punchblock::Component::Output.new :render_document => {:value => RubySpeech::SSML.draw}
|
|
892
898
|
end
|
|
893
899
|
|
|
894
|
-
let(:comp_id) { component_command.response.
|
|
900
|
+
let(:comp_id) { component_command.response.component_id }
|
|
895
901
|
|
|
896
902
|
let(:subsequent_command) { Punchblock::Component::Stop.new :component_id => comp_id }
|
|
897
903
|
|
|
898
904
|
let :expected_event do
|
|
899
|
-
Punchblock::Event::Complete.new
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
e.reason = Punchblock::Event::Complete::Error.new
|
|
903
|
-
end
|
|
905
|
+
Punchblock::Event::Complete.new target_call_id: subject.id,
|
|
906
|
+
component_id: comp_id,
|
|
907
|
+
reason: Punchblock::Event::Complete::Error.new
|
|
904
908
|
end
|
|
905
909
|
|
|
906
910
|
before do
|
|
@@ -951,7 +955,7 @@ module Punchblock
|
|
|
951
955
|
let(:other_call_id) { Punchblock.new_uuid }
|
|
952
956
|
|
|
953
957
|
let :command do
|
|
954
|
-
Punchblock::Command::Join.new :
|
|
958
|
+
Punchblock::Command::Join.new :call_uri => other_call_id
|
|
955
959
|
end
|
|
956
960
|
|
|
957
961
|
it "executes the proper uuid_bridge command" do
|
|
@@ -983,7 +987,7 @@ module Punchblock
|
|
|
983
987
|
let(:other_call_id) { Punchblock.new_uuid }
|
|
984
988
|
|
|
985
989
|
let :command do
|
|
986
|
-
Punchblock::Command::Unjoin.new :
|
|
990
|
+
Punchblock::Command::Unjoin.new :call_uri => other_call_id
|
|
987
991
|
end
|
|
988
992
|
|
|
989
993
|
it "executes the unjoin via transfer to park" do
|
|
@@ -25,7 +25,7 @@ module Punchblock
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
let :command_options do
|
|
28
|
-
{ :
|
|
28
|
+
{ :render_document => {:value => ssml_doc} }
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def execute
|
|
@@ -43,16 +43,16 @@ module Punchblock
|
|
|
43
43
|
let(:command_opts) { {} }
|
|
44
44
|
|
|
45
45
|
let :command_options do
|
|
46
|
-
{ :
|
|
46
|
+
{ :render_document => {:value => ssml_doc} }.merge(command_opts)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
let :original_command do
|
|
50
50
|
Punchblock::Component::Output.new command_options
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
describe '
|
|
53
|
+
describe 'document' do
|
|
54
54
|
context 'unset' do
|
|
55
|
-
let(:
|
|
55
|
+
let(:ssml_doc) { nil }
|
|
56
56
|
it "should return an error and not execute any actions" do
|
|
57
57
|
execute
|
|
58
58
|
error = ProtocolError.new.setup 'option error', 'An SSML document is required.'
|
|
@@ -70,7 +70,16 @@ module Punchblock
|
|
|
70
70
|
expect_playback
|
|
71
71
|
execute
|
|
72
72
|
subject.handle_es_event RubyFS::Event.new(nil, :event_name => "CHANNEL_EXECUTE_COMPLETE")
|
|
73
|
-
original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::
|
|
73
|
+
original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Finish
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
context 'with multiple documents' do
|
|
78
|
+
let(:command_opts) { { :render_documents => [{:value => ssml_doc}, {:value => ssml_doc}] } }
|
|
79
|
+
it "should return an error and not execute any actions" do
|
|
80
|
+
subject.execute
|
|
81
|
+
error = ProtocolError.new.setup 'option error', 'Only a single document is supported.'
|
|
82
|
+
original_command.response(0.1).should be == error
|
|
74
83
|
end
|
|
75
84
|
end
|
|
76
85
|
end
|
|
@@ -215,11 +224,11 @@ module Punchblock
|
|
|
215
224
|
end
|
|
216
225
|
end
|
|
217
226
|
|
|
218
|
-
context "set to :
|
|
219
|
-
let(:command_opts) { { :interrupt_on => :
|
|
227
|
+
context "set to :voice" do
|
|
228
|
+
let(:command_opts) { { :interrupt_on => :voice } }
|
|
220
229
|
it "should return an error and not execute any actions" do
|
|
221
230
|
execute
|
|
222
|
-
error = ProtocolError.new.setup 'option error', 'An interrupt-on value of
|
|
231
|
+
error = ProtocolError.new.setup 'option error', 'An interrupt-on value of voice is unsupported.'
|
|
223
232
|
original_command.response(0.1).should be == error
|
|
224
233
|
end
|
|
225
234
|
end
|
|
@@ -11,7 +11,7 @@ module Punchblock
|
|
|
11
11
|
|
|
12
12
|
let(:id) { Punchblock.new_uuid }
|
|
13
13
|
let(:translator) { Punchblock::Translator::Freeswitch.new connection }
|
|
14
|
-
let(:mock_stream) {
|
|
14
|
+
let(:mock_stream) { double('RubyFS::Stream') }
|
|
15
15
|
let(:call) { Punchblock::Translator::Freeswitch::Call.new id, translator, nil, mock_stream }
|
|
16
16
|
|
|
17
17
|
let(:original_command_options) { {} }
|
|
@@ -74,13 +74,17 @@ module Punchblock
|
|
|
74
74
|
sleep 0.5
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
+
let :expected_nlsml do
|
|
78
|
+
RubySpeech::NLSML.draw do
|
|
79
|
+
interpretation confidence: 1 do
|
|
80
|
+
instance "dtmf-1 dtmf-2"
|
|
81
|
+
input "12", mode: :dtmf
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
77
86
|
let :expected_event do
|
|
78
|
-
Punchblock::Component::Input::Complete::
|
|
79
|
-
:confidence => 1,
|
|
80
|
-
:utterance => '12',
|
|
81
|
-
:interpretation => 'dtmf-1 dtmf-2',
|
|
82
|
-
:component_id => subject.id,
|
|
83
|
-
:target_call_id => call.id
|
|
87
|
+
Punchblock::Component::Input::Complete::Match.new nlsml: expected_nlsml
|
|
84
88
|
end
|
|
85
89
|
|
|
86
90
|
it "should send a success complete event with the relevant data" do
|
|
@@ -100,8 +104,7 @@ module Punchblock
|
|
|
100
104
|
end
|
|
101
105
|
|
|
102
106
|
let :expected_event do
|
|
103
|
-
Punchblock::Component::Input::Complete::NoMatch.new
|
|
104
|
-
:target_call_id => call.id
|
|
107
|
+
Punchblock::Component::Input::Complete::NoMatch.new
|
|
105
108
|
end
|
|
106
109
|
|
|
107
110
|
it "should send a nomatch complete event" do
|
|
@@ -119,6 +122,15 @@ module Punchblock
|
|
|
119
122
|
original_command.response(0.1).should be == error
|
|
120
123
|
end
|
|
121
124
|
end
|
|
125
|
+
|
|
126
|
+
context 'with multiple grammars' do
|
|
127
|
+
let(:original_command_opts) { { :grammars => [{:value => grammar}, {:value => grammar}] } }
|
|
128
|
+
it "should return an error and not execute any actions" do
|
|
129
|
+
subject.execute
|
|
130
|
+
error = ProtocolError.new.setup 'option error', 'Only a single grammar is supported.'
|
|
131
|
+
original_command.response(0.1).should be == error
|
|
132
|
+
end
|
|
133
|
+
end
|
|
122
134
|
end
|
|
123
135
|
|
|
124
136
|
describe 'mode' do
|
|
@@ -140,8 +152,8 @@ module Punchblock
|
|
|
140
152
|
end
|
|
141
153
|
end
|
|
142
154
|
|
|
143
|
-
context '
|
|
144
|
-
let(:original_command_opts) { { :mode => :
|
|
155
|
+
context 'voice' do
|
|
156
|
+
let(:original_command_opts) { { :mode => :voice } }
|
|
145
157
|
it "should return an error and not execute any actions" do
|
|
146
158
|
subject.execute
|
|
147
159
|
error = ProtocolError.new.setup 'option error', 'A mode value other than DTMF is unsupported.'
|
|
@@ -167,7 +179,7 @@ module Punchblock
|
|
|
167
179
|
send_dtmf 1
|
|
168
180
|
sleep 1.5
|
|
169
181
|
send_dtmf 2
|
|
170
|
-
reason.should be_a Punchblock::Component::Input::Complete::
|
|
182
|
+
reason.should be_a Punchblock::Component::Input::Complete::Match
|
|
171
183
|
end
|
|
172
184
|
|
|
173
185
|
it "should cause a NoInput complete event to be sent after the timeout" do
|
|
@@ -218,10 +230,10 @@ module Punchblock
|
|
|
218
230
|
send_dtmf 1
|
|
219
231
|
sleep 0.5
|
|
220
232
|
send_dtmf 2
|
|
221
|
-
reason.should be_a Punchblock::Component::Input::Complete::
|
|
233
|
+
reason.should be_a Punchblock::Component::Input::Complete::Match
|
|
222
234
|
end
|
|
223
235
|
|
|
224
|
-
it "should cause a
|
|
236
|
+
it "should cause a InterDigitTimeout complete event to be sent after the timeout" do
|
|
225
237
|
subject.execute
|
|
226
238
|
sleep 1.5
|
|
227
239
|
send_dtmf 1
|
|
@@ -23,7 +23,7 @@ module Punchblock
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
let :command_options do
|
|
26
|
-
{ :
|
|
26
|
+
{ :render_document => {:value => ssml_doc} }
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
subject { Output.new original_command, mock_call }
|
|
@@ -45,16 +45,17 @@ module Punchblock
|
|
|
45
45
|
let(:command_opts) { {} }
|
|
46
46
|
|
|
47
47
|
let :command_options do
|
|
48
|
-
{ :
|
|
48
|
+
{ :render_document => {:value => ssml_doc} }.merge(command_opts)
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
let :original_command do
|
|
52
52
|
Punchblock::Component::Output.new command_options
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
describe '
|
|
55
|
+
describe 'document' do
|
|
56
56
|
context 'unset' do
|
|
57
|
-
let(:
|
|
57
|
+
let(:ssml_doc) { nil }
|
|
58
|
+
|
|
58
59
|
it "should return an error and not execute any actions" do
|
|
59
60
|
subject.execute
|
|
60
61
|
error = ProtocolError.new.setup 'option error', 'An SSML document is required.'
|
|
@@ -62,38 +63,10 @@ module Punchblock
|
|
|
62
63
|
end
|
|
63
64
|
end
|
|
64
65
|
|
|
65
|
-
context 'with a string (not SSML)' do
|
|
66
|
-
let :command_options do
|
|
67
|
-
{ :text => 'Foo Bar' }
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it "should return an unrenderable document error" do
|
|
71
|
-
subject.execute
|
|
72
|
-
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.'
|
|
73
|
-
original_command.response(0.1).should be == error
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
context 'with a single text node without spaces' do
|
|
77
|
-
let(:audio_filename) { 'http://foo.com/bar.mp3' }
|
|
78
|
-
let :command_options do
|
|
79
|
-
{
|
|
80
|
-
:ssml => RubySpeech::SSML.draw { string audio_filename }
|
|
81
|
-
}
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
it 'should playback the audio file using the playback application' do
|
|
85
|
-
expect_playback
|
|
86
|
-
subject.execute
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
66
|
context 'with a single audio SSML node' do
|
|
92
67
|
let(:audio_filename) { 'http://foo.com/bar.mp3' }
|
|
93
|
-
let :
|
|
94
|
-
{
|
|
95
|
-
:ssml => RubySpeech::SSML.draw { audio :src => audio_filename }
|
|
96
|
-
}
|
|
68
|
+
let :ssml_doc do
|
|
69
|
+
RubySpeech::SSML.draw { audio :src => audio_filename }
|
|
97
70
|
end
|
|
98
71
|
|
|
99
72
|
it 'should playback the audio file using the playback application' do
|
|
@@ -105,7 +78,7 @@ module Punchblock
|
|
|
105
78
|
expect_playback
|
|
106
79
|
subject.execute
|
|
107
80
|
subject.handle_es_event RubyFS::Event.new(nil, :event_name => "CHANNEL_EXECUTE_COMPLETE", :application_response => 'FILE PLAYED')
|
|
108
|
-
original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::
|
|
81
|
+
original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Finish
|
|
109
82
|
end
|
|
110
83
|
|
|
111
84
|
context "when playback returns an error" do
|
|
@@ -125,13 +98,11 @@ module Punchblock
|
|
|
125
98
|
context 'with multiple audio SSML nodes' do
|
|
126
99
|
let(:audio_filename1) { 'http://foo.com/bar.mp3' }
|
|
127
100
|
let(:audio_filename2) { 'http://foo.com/baz.mp3' }
|
|
128
|
-
let :
|
|
129
|
-
|
|
130
|
-
:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
end
|
|
134
|
-
}
|
|
101
|
+
let :ssml_doc do
|
|
102
|
+
RubySpeech::SSML.draw do
|
|
103
|
+
audio :src => audio_filename1
|
|
104
|
+
audio :src => audio_filename2
|
|
105
|
+
end
|
|
135
106
|
end
|
|
136
107
|
|
|
137
108
|
it 'should playback all audio files using playback' do
|
|
@@ -143,17 +114,15 @@ module Punchblock
|
|
|
143
114
|
expect_playback([audio_filename1, audio_filename2].join('!'))
|
|
144
115
|
subject.execute
|
|
145
116
|
subject.handle_es_event RubyFS::Event.new(nil, :event_name => "CHANNEL_EXECUTE_COMPLETE", :application_response => "FILE PLAYED")
|
|
146
|
-
original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::
|
|
117
|
+
original_command.complete_event(0.1).reason.should be_a Punchblock::Component::Output::Complete::Finish
|
|
147
118
|
end
|
|
148
119
|
end
|
|
149
120
|
|
|
150
121
|
context "with an SSML document containing elements other than <audio/>" do
|
|
151
|
-
let :
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
end
|
|
156
|
-
}
|
|
122
|
+
let :ssml_doc do
|
|
123
|
+
RubySpeech::SSML.draw do
|
|
124
|
+
string "Foo Bar"
|
|
125
|
+
end
|
|
157
126
|
end
|
|
158
127
|
|
|
159
128
|
it "should return an unrenderable document error" do
|
|
@@ -162,6 +131,15 @@ module Punchblock
|
|
|
162
131
|
original_command.response(0.1).should be == error
|
|
163
132
|
end
|
|
164
133
|
end
|
|
134
|
+
|
|
135
|
+
context 'with multiple documents' do
|
|
136
|
+
let(:command_opts) { { :render_documents => [{:value => ssml_doc}, {:value => ssml_doc}] } }
|
|
137
|
+
it "should return an error and not execute any actions" do
|
|
138
|
+
subject.execute
|
|
139
|
+
error = ProtocolError.new.setup 'option error', 'Only a single document is supported.'
|
|
140
|
+
original_command.response(0.1).should be == error
|
|
141
|
+
end
|
|
142
|
+
end
|
|
165
143
|
end
|
|
166
144
|
|
|
167
145
|
describe 'start-offset' do
|
|
@@ -304,11 +282,11 @@ module Punchblock
|
|
|
304
282
|
end
|
|
305
283
|
end
|
|
306
284
|
|
|
307
|
-
context "set to :
|
|
308
|
-
let(:command_opts) { { :interrupt_on => :
|
|
285
|
+
context "set to :voice" do
|
|
286
|
+
let(:command_opts) { { :interrupt_on => :voice } }
|
|
309
287
|
it "should return an error and not execute any actions" do
|
|
310
288
|
subject.execute
|
|
311
|
-
error = ProtocolError.new.setup 'option error', 'An interrupt-on value of
|
|
289
|
+
error = ProtocolError.new.setup 'option error', 'An interrupt-on value of voice is unsupported.'
|
|
312
290
|
original_command.response(0.1).should be == error
|
|
313
291
|
end
|
|
314
292
|
end
|