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.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -2
  4. data/CHANGELOG.md +17 -0
  5. data/Gemfile +1 -0
  6. data/Guardfile +4 -0
  7. data/README.markdown +6 -0
  8. data/Rakefile +16 -0
  9. data/benchmarks/ami_event_name_comparison.rb +14 -0
  10. data/benchmarks/channel.rb +27 -0
  11. data/lib/punchblock/client.rb +2 -6
  12. data/lib/punchblock/command/accept.rb +3 -24
  13. data/lib/punchblock/command/answer.rb +3 -24
  14. data/lib/punchblock/command/dial.rb +24 -76
  15. data/lib/punchblock/command/hangup.rb +3 -19
  16. data/lib/punchblock/command/join.rb +21 -70
  17. data/lib/punchblock/command/mute.rb +3 -3
  18. data/lib/punchblock/command/redirect.rb +6 -39
  19. data/lib/punchblock/command/reject.rb +14 -54
  20. data/lib/punchblock/command/unjoin.rb +8 -40
  21. data/lib/punchblock/command/unmute.rb +3 -3
  22. data/lib/punchblock/command_node.rb +0 -17
  23. data/lib/punchblock/component/asterisk/agi/command.rb +20 -127
  24. data/lib/punchblock/component/asterisk/ami/action.rb +30 -117
  25. data/lib/punchblock/component/component_node.rb +1 -1
  26. data/lib/punchblock/component/input.rb +89 -268
  27. data/lib/punchblock/component/output.rb +106 -154
  28. data/lib/punchblock/component/prompt.rb +51 -0
  29. data/lib/punchblock/component/record.rb +41 -130
  30. data/lib/punchblock/component.rb +1 -0
  31. data/lib/punchblock/connection/asterisk.rb +31 -4
  32. data/lib/punchblock/connection/xmpp.rb +6 -14
  33. data/lib/punchblock/core_ext/blather/stanza.rb +1 -1
  34. data/lib/punchblock/event/active_speaker.rb +2 -10
  35. data/lib/punchblock/event/answered.rb +3 -3
  36. data/lib/punchblock/event/asterisk/ami/event.rb +15 -47
  37. data/lib/punchblock/event/complete.rb +26 -48
  38. data/lib/punchblock/event/dtmf.rb +3 -13
  39. data/lib/punchblock/event/end.rb +10 -11
  40. data/lib/punchblock/event/joined.rb +5 -25
  41. data/lib/punchblock/event/offer.rb +4 -25
  42. data/lib/punchblock/event/ringing.rb +3 -3
  43. data/lib/punchblock/event/unjoined.rb +5 -25
  44. data/lib/punchblock/event.rb +0 -10
  45. data/lib/punchblock/has_headers.rb +20 -26
  46. data/lib/punchblock/rayo_node.rb +46 -23
  47. data/lib/punchblock/ref.rb +39 -18
  48. data/lib/punchblock/translator/asterisk/agi_app.rb +15 -0
  49. data/lib/punchblock/translator/asterisk/agi_command.rb +3 -1
  50. data/lib/punchblock/translator/asterisk/ami_error_converter.rb +20 -0
  51. data/lib/punchblock/translator/asterisk/call.rb +60 -39
  52. data/lib/punchblock/translator/asterisk/channel.rb +41 -0
  53. data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +4 -1
  54. data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +4 -4
  55. data/lib/punchblock/translator/asterisk/component/composed_prompt.rb +62 -0
  56. data/lib/punchblock/translator/asterisk/component/input.rb +1 -0
  57. data/lib/punchblock/translator/asterisk/component/mrcp_native_prompt.rb +56 -0
  58. data/lib/punchblock/translator/asterisk/component/mrcp_prompt.rb +53 -0
  59. data/lib/punchblock/translator/asterisk/component/mrcp_recog_prompt.rb +99 -0
  60. data/lib/punchblock/translator/asterisk/component/output.rb +30 -22
  61. data/lib/punchblock/translator/asterisk/component/record.rb +8 -6
  62. data/lib/punchblock/translator/asterisk/component.rb +6 -5
  63. data/lib/punchblock/translator/asterisk/unimrcp_app.rb +26 -0
  64. data/lib/punchblock/translator/asterisk.rb +24 -28
  65. data/lib/punchblock/translator/dtmf_recognizer.rb +39 -20
  66. data/lib/punchblock/translator/freeswitch/call.rb +15 -14
  67. data/lib/punchblock/translator/freeswitch/component/abstract_output.rb +5 -4
  68. data/lib/punchblock/translator/freeswitch/component/flite_output.rb +1 -1
  69. data/lib/punchblock/translator/freeswitch/component/input.rb +5 -0
  70. data/lib/punchblock/translator/freeswitch/component/output.rb +2 -2
  71. data/lib/punchblock/translator/freeswitch/component/record.rb +19 -13
  72. data/lib/punchblock/translator/freeswitch/component/tts_output.rb +2 -2
  73. data/lib/punchblock/translator/freeswitch/component.rb +2 -5
  74. data/lib/punchblock/translator/freeswitch.rb +2 -2
  75. data/lib/punchblock/translator/input_component.rb +33 -13
  76. data/lib/punchblock/uri_list.rb +21 -0
  77. data/lib/punchblock/version.rb +1 -1
  78. data/lib/punchblock.rb +4 -3
  79. data/punchblock.gemspec +7 -3
  80. data/spec/punchblock/client/component_registry_spec.rb +1 -1
  81. data/spec/punchblock/client_spec.rb +10 -26
  82. data/spec/punchblock/command/accept_spec.rb +41 -7
  83. data/spec/punchblock/command/answer_spec.rb +51 -7
  84. data/spec/punchblock/command/dial_spec.rb +56 -14
  85. data/spec/punchblock/command/hangup_spec.rb +41 -7
  86. data/spec/punchblock/command/join_spec.rb +53 -11
  87. data/spec/punchblock/command/mute_spec.rb +19 -4
  88. data/spec/punchblock/command/redirect_spec.rb +40 -10
  89. data/spec/punchblock/command/reject_spec.rb +43 -11
  90. data/spec/punchblock/command/unjoin_spec.rb +40 -9
  91. data/spec/punchblock/command/unmute_spec.rb +19 -4
  92. data/spec/punchblock/command_node_spec.rb +0 -4
  93. data/spec/punchblock/component/asterisk/agi/command_spec.rb +16 -39
  94. data/spec/punchblock/component/asterisk/ami/action_spec.rb +50 -53
  95. data/spec/punchblock/component/component_node_spec.rb +3 -5
  96. data/spec/punchblock/component/input_spec.rb +194 -61
  97. data/spec/punchblock/component/output_spec.rb +194 -62
  98. data/spec/punchblock/component/prompt_spec.rb +132 -0
  99. data/spec/punchblock/component/record_spec.rb +70 -32
  100. data/spec/punchblock/connection/asterisk_spec.rb +17 -3
  101. data/spec/punchblock/connection/freeswitch_spec.rb +4 -4
  102. data/spec/punchblock/connection/xmpp_spec.rb +20 -38
  103. data/spec/punchblock/event/answered_spec.rb +12 -10
  104. data/spec/punchblock/event/asterisk/ami/event_spec.rb +27 -22
  105. data/spec/punchblock/event/complete_spec.rb +15 -19
  106. data/spec/punchblock/event/dtmf_spec.rb +5 -6
  107. data/spec/punchblock/event/end_spec.rb +20 -10
  108. data/spec/punchblock/event/joined_spec.rb +8 -7
  109. data/spec/punchblock/event/offer_spec.rb +41 -12
  110. data/spec/punchblock/event/ringing_spec.rb +12 -10
  111. data/spec/punchblock/event/started_speaking_spec.rb +5 -6
  112. data/spec/punchblock/event/stopped_speaking_spec.rb +5 -6
  113. data/spec/punchblock/event/unjoined_spec.rb +7 -7
  114. data/spec/punchblock/ref_spec.rb +86 -9
  115. data/spec/punchblock/translator/asterisk/call_spec.rb +317 -154
  116. data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +28 -5
  117. data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +15 -13
  118. data/spec/punchblock/translator/asterisk/component/composed_prompt_spec.rb +237 -0
  119. data/spec/punchblock/translator/asterisk/component/input_spec.rb +171 -14
  120. data/spec/punchblock/translator/asterisk/component/mrcp_native_prompt_spec.rb +652 -0
  121. data/spec/punchblock/translator/asterisk/component/mrcp_prompt_spec.rb +646 -0
  122. data/spec/punchblock/translator/asterisk/component/output_spec.rb +127 -77
  123. data/spec/punchblock/translator/asterisk/component/record_spec.rb +17 -8
  124. data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +2 -2
  125. data/spec/punchblock/translator/asterisk/component_spec.rb +3 -7
  126. data/spec/punchblock/translator/asterisk_spec.rb +20 -24
  127. data/spec/punchblock/translator/freeswitch/call_spec.rb +103 -99
  128. data/spec/punchblock/translator/freeswitch/component/flite_output_spec.rb +17 -8
  129. data/spec/punchblock/translator/freeswitch/component/input_spec.rb +26 -14
  130. data/spec/punchblock/translator/freeswitch/component/output_spec.rb +30 -52
  131. data/spec/punchblock/translator/freeswitch/component/record_spec.rb +23 -19
  132. data/spec/punchblock/translator/freeswitch/component/tts_output_spec.rb +18 -8
  133. data/spec/punchblock/translator/freeswitch/component_spec.rb +4 -8
  134. data/spec/punchblock/translator/freeswitch_spec.rb +11 -14
  135. data/spec/punchblock/uri_list_spec.rb +49 -0
  136. data/spec/punchblock_spec.rb +11 -1
  137. data/spec/spec_helper.rb +7 -11
  138. data/spec/support/mock_connection_with_event_handler.rb +1 -1
  139. metadata +104 -24
  140. data/lib/punchblock/header.rb +0 -9
  141. data/lib/punchblock/key_value_pair_node.rb +0 -51
  142. 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) { stub('RubyFS::Stream').as_null_object }
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 stub('Connection::Freeswitch').as_null_object }
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
- :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"
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 = mock 'Translator::Freeswitch::Component', :id => component_id
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(subject)
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 :ssml => ssml_doc
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) { mock 'Punchblock::Component::Output' }
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) { mock '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.tap do |joined|
600
- joined.target_call_id = subject.id
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.tap do |joined|
641
- joined.target_call_id = subject.id
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 'NORMAL_CLEARING'
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
- mock 'Component', :id => component_id
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 :ssml => RubySpeech::SSML.draw
897
+ Punchblock::Component::Output.new :render_document => {:value => RubySpeech::SSML.draw}
892
898
  end
893
899
 
894
- let(:comp_id) { component_command.response.id }
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.tap do |e|
900
- e.target_call_id = subject.id
901
- e.component_id = comp_id
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 :call_id => other_call_id
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 :call_id => other_call_id
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
- { :ssml => ssml_doc }
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
- { :ssml => ssml_doc }.merge(command_opts)
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 'ssml' do
53
+ describe 'document' do
54
54
  context 'unset' do
55
- let(:command_opts) { { :ssml => nil } }
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::Success
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 :speech" do
219
- let(:command_opts) { { :interrupt_on => :speech } }
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 speech is unsupported.'
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) { mock('RubyFS::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::Success.new :mode => :dtmf,
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 :component_id => subject.id,
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 'speech' do
144
- let(:original_command_opts) { { :mode => :speech } }
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::Success
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::Success
233
+ reason.should be_a Punchblock::Component::Input::Complete::Match
222
234
  end
223
235
 
224
- it "should cause a NoMatch complete event to be sent after the timeout" do
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
- { :ssml => ssml_doc }
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
- { :ssml => ssml_doc }.merge(command_opts)
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 'ssml' do
55
+ describe 'document' do
56
56
  context 'unset' do
57
- let(:command_opts) { { :ssml => nil } }
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 :command_options do
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::Success
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 :command_options do
129
- {
130
- :ssml => RubySpeech::SSML.draw do
131
- audio :src => audio_filename1
132
- audio :src => audio_filename2
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::Success
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 :command_options do
152
- {
153
- :ssml => RubySpeech::SSML.draw do
154
- string "Foo Bar"
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 :speech" do
308
- let(:command_opts) { { :interrupt_on => :speech } }
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 speech is unsupported.'
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