punchblock 1.8.2 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +8 -0
  4. data/lib/punchblock/component/asterisk/agi/command.rb +0 -11
  5. data/lib/punchblock/connection/asterisk.rb +3 -3
  6. data/lib/punchblock/translator/asterisk/agi_command.rb +40 -0
  7. data/lib/punchblock/translator/asterisk/call.rb +56 -47
  8. data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +13 -37
  9. data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +24 -41
  10. data/lib/punchblock/translator/asterisk/component/input.rb +2 -1
  11. data/lib/punchblock/translator/asterisk/component/output.rb +16 -21
  12. data/lib/punchblock/translator/asterisk/component/record.rb +11 -19
  13. data/lib/punchblock/translator/asterisk/component.rb +12 -9
  14. data/lib/punchblock/translator/asterisk.rb +16 -22
  15. data/lib/punchblock/translator/dtmf_recognizer.rb +4 -4
  16. data/lib/punchblock/translator/freeswitch/component/input.rb +2 -1
  17. data/lib/punchblock/translator/input_component.rb +2 -2
  18. data/lib/punchblock/version.rb +1 -1
  19. data/punchblock.gemspec +1 -1
  20. data/spec/punchblock/connection/asterisk_spec.rb +8 -7
  21. data/spec/punchblock/translator/asterisk/call_spec.rb +262 -229
  22. data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +57 -29
  23. data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +40 -46
  24. data/spec/punchblock/translator/asterisk/component/input_spec.rb +7 -7
  25. data/spec/punchblock/translator/asterisk/component/output_spec.rb +84 -53
  26. data/spec/punchblock/translator/asterisk/component/record_spec.rb +55 -83
  27. data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +5 -1
  28. data/spec/punchblock/translator/asterisk/component_spec.rb +2 -10
  29. data/spec/punchblock/translator/asterisk_spec.rb +73 -100
  30. metadata +5 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 90ceeeef84eac2fec034a32edbc3fdd387c8d1f2
4
- data.tar.gz: ca82c8ffbfa67c81369eb3146b5c4f333d443613
3
+ metadata.gz: 64729c9456c13c6897d13dbac65657a51951f67a
4
+ data.tar.gz: aa7522da6cf77ebfbbb044865e7c43b79a1939d3
5
5
  SHA512:
6
- metadata.gz: 333ac7e2473e30d84f38f23493dba4c33d4422cb4725e7c5da3fd98c468ab170156922ad5f540936e871653a34993bf57dd9e227ebcf6b9091335ab27d5a1445
7
- data.tar.gz: bb079007e70f4e27552354c8327c5d602961b7335c6a102ef51d106c2ca847d972bec2852a99f5623381c88e1c377ce88d74e93cba5b49ec4cc88719e1f24041
6
+ metadata.gz: d39f61aaa9ffb224dfa32e9bd898fadc359a9ec6881682e709ee3d0df36afff2c26854baa30e0fc99794a73c18309e8f4922c17d065cb2f5402573947dfabba1
7
+ data.tar.gz: 5c93e10769dbbd141b71732f163783bf7ff653faa30d3886f382a87c5a3402c5e6bcd8784701d7b55adbfdf1a728f3841a0093d455c1a16e10e94e161473b902
data/.travis.yml CHANGED
@@ -2,6 +2,7 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.2
4
4
  - 1.9.3
5
+ - 2.0.0
5
6
  - jruby-19mode
6
7
  - rbx-19mode
7
8
  - ruby-head
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # [develop](https://github.com/adhearsion/punchblock)
2
2
 
3
+ # [v1.9.0](https://github.com/adhearsion/punchblock/compare/v1.8.2...v1.9.0) - [2013-05-03](https://rubygems.org/gems/punchblock/versions/1.9.0)
4
+ * Feature: Use RubyAMI 2.0 with a single AMI connection.
5
+ * Feature: Cache channel variables on Asterisk calls.
6
+ * Feature: Allow optional sending of end event when breaking from AsyncAGI on Asterisk. This enables dialplan handback. Only triggers if the channel variable 'PUNCHBLOCK_END_ON_ASYNCAGI_BREAK' is set.
7
+ * Bugfix: Avoid DTMF recognizer failures and race conditions by bringing DTMFRecognizer back into the Input component actor.
8
+ * Bugfix: Catch Asterisk AMI errors in all cases and fail accordingly, instead of ploughing ahead in the face of adversity.
9
+ * Bugfix: Improve performance of Asterisk implementation by no longer spinning up a component actor for AGI command execution.
10
+
3
11
  # [v1.8.2](https://github.com/adhearsion/punchblock/compare/v1.8.1...v1.8.2) - [2013-04-19](https://rubygems.org/gems/punchblock/versions/1.8.2)
4
12
  * Bugfix: Input initial timeout was being set as a float rather than an integer
5
13
 
@@ -86,17 +86,6 @@ module Punchblock
86
86
  class Success < Event::Complete::Reason
87
87
  register :success, :agi_complete
88
88
 
89
- def self.new(options = {})
90
- super().tap do |new_node|
91
- case options
92
- when Nokogiri::XML::Node
93
- new_node.inherit options
94
- else
95
- options.each_pair { |k,v| new_node.send :"#{k}=", v }
96
- end
97
- end
98
- end
99
-
100
89
  def node_with_name(name)
101
90
  n = if self.class.registered_ns
102
91
  find_first "ns:#{name}", :ns => self.class.registered_ns
@@ -9,19 +9,19 @@ module Punchblock
9
9
  attr_accessor :event_handler
10
10
 
11
11
  def initialize(options = {})
12
- @ami_client = RubyAMI::Client.new options.merge(:event_handler => lambda { |event| translator.async.handle_ami_event event }, :logger => pb_logger)
12
+ @ami_client = RubyAMI::Stream.new options[:host], options[:port], options[:username], options[:password], ->(event) { translator.async.handle_ami_event event }, pb_logger
13
13
  @translator = Translator::Asterisk.new @ami_client, self, options[:media_engine]
14
14
  super()
15
15
  end
16
16
 
17
17
  def run
18
- ami_client.start
18
+ ami_client.run
19
19
  raise DisconnectedError
20
20
  end
21
21
 
22
22
  def stop
23
23
  translator.async.shutdown
24
- ami_client.stop
24
+ ami_client.terminate
25
25
  end
26
26
 
27
27
  def write(command, options)
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ require 'active_support/core_ext/string/filters'
4
+
5
+ module Punchblock
6
+ module Translator
7
+ class Asterisk
8
+ class AGICommand
9
+ ARG_QUOTER = /["\\]/.freeze
10
+
11
+ attr_reader :id
12
+
13
+ def initialize(id, channel, command, *params)
14
+ @id, @channel, @command, @params = id, channel, command, params
15
+ end
16
+
17
+ def execute(ami_client)
18
+ ami_client.send_action 'AGI', 'Channel' => @channel, 'Command' => agi_command, 'CommandID' => id
19
+ end
20
+
21
+ def parse_result(event)
22
+ parser = RubyAMI::AGIResultParser.new event['Result']
23
+ {code: parser.code, result: parser.result, data: parser.data}
24
+ end
25
+
26
+ private
27
+
28
+ def agi_command
29
+ "#{@command} #{@params.map { |arg| quote_arg(arg) }.join(' ')}".squish
30
+ end
31
+
32
+ # Arguments surrounded by quotes; quotes backslash-escaped.
33
+ # See parse_args in asterisk/res/res_agi.c (Asterisk 1.4.21.1)
34
+ def quote_arg(arg)
35
+ '"' + arg.to_s.gsub(ARG_QUOTER) { |m| "\\#{m}" } + '"'
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -22,14 +22,15 @@ module Punchblock
22
22
 
23
23
  trap_exit :actor_died
24
24
 
25
- def initialize(channel, translator, agi_env = nil)
26
- @channel, @translator = channel, translator
25
+ def initialize(channel, translator, ami_client, connection, agi_env = nil)
26
+ @channel, @translator, @ami_client, @connection = channel, translator, ami_client, connection
27
27
  @agi_env = agi_env || {}
28
28
  @id, @components = Punchblock.new_uuid, {}
29
29
  @answered = false
30
30
  @pending_joins = {}
31
31
  @progress_sent = false
32
32
  @block_commands = false
33
+ @channel_variables = {}
33
34
  end
34
35
 
35
36
  def register_component(component)
@@ -49,6 +50,10 @@ module Punchblock
49
50
  terminate
50
51
  end
51
52
 
53
+ def channel_var(variable)
54
+ @channel_variables[variable] || fetch_channel_var(variable)
55
+ end
56
+
52
57
  def to_s
53
58
  "#<#{self.class}:#{id} Channel: #{channel.inspect}>"
54
59
  end
@@ -89,7 +94,7 @@ module Punchblock
89
94
  def send_progress
90
95
  return if answered? || outbound? || @progress_sent
91
96
  @progress_sent = true
92
- send_agi_action "EXEC Progress"
97
+ execute_agi_command "EXEC Progress"
93
98
  end
94
99
 
95
100
  def channel=(other)
@@ -101,13 +106,7 @@ module Punchblock
101
106
 
102
107
  case ami_event.name
103
108
  when 'Hangup'
104
- @block_commands = true
105
- @components.dup.each_pair do |id, component|
106
- safe_from_dead_actors do
107
- component.call_ended if component.alive?
108
- end
109
- end
110
- send_end_event HANGUP_CAUSE_TO_END_REASON[ami_event['Cause'].to_i]
109
+ handle_hangup_event HANGUP_CAUSE_TO_END_REASON[ami_event['Cause'].to_i]
111
110
  when 'AsyncAGI'
112
111
  if component = component_with_id(ami_event['CommandID'])
113
112
  component.handle_ami_event ami_event
@@ -151,6 +150,8 @@ module Punchblock
151
150
  end
152
151
  send_pb_event event
153
152
  end
153
+ when 'VarSet'
154
+ @channel_variables[ami_event['Variable']] = ami_event['Value']
154
155
  end
155
156
  trigger_handler :ami, ami_event
156
157
  end
@@ -172,32 +173,23 @@ module Punchblock
172
173
  if outbound?
173
174
  command.response = true
174
175
  else
175
- send_agi_action 'EXEC RINGING' do |response|
176
- command.response = true
177
- end
178
- end
179
- when Command::Answer
180
- send_agi_action 'ANSWER' do |response|
176
+ execute_agi_command 'EXEC RINGING'
181
177
  command.response = true
182
178
  end
179
+ when Command::Answer
180
+ execute_agi_command 'ANSWER'
181
+ command.response = true
183
182
  when Command::Hangup
184
- send_ami_action 'Hangup', 'Channel' => channel, 'Cause' => 16 do |response|
185
- command.response = true
186
- end
183
+ send_ami_action 'Hangup', 'Channel' => channel, 'Cause' => 16
184
+ command.response = true
187
185
  when Command::Join
188
186
  other_call = translator.call_with_id command.call_id
189
187
  @pending_joins[other_call.channel] = command
190
- send_agi_action 'EXEC Bridge', other_call.channel
188
+ execute_agi_command 'EXEC Bridge', other_call.channel
191
189
  when Command::Unjoin
192
190
  other_call = translator.call_with_id command.call_id
193
- redirect_back other_call do |response|
194
- case response
195
- when RubyAMI::Error
196
- command.response = ProtocolError.new.setup 'error', response.message
197
- else
198
- command.response = true
199
- end
200
- end
191
+ redirect_back other_call
192
+ command.response = true
201
193
  when Command::Reject
202
194
  rejection = case command.reason
203
195
  when :busy
@@ -209,9 +201,8 @@ module Punchblock
209
201
  else
210
202
  'EXEC Congestion'
211
203
  end
212
- send_agi_action rejection do |response|
213
- command.response = true
214
- end
204
+ execute_agi_command rejection
205
+ command.response = true
215
206
  when Punchblock::Component::Asterisk::AGI::Command
216
207
  execute_component Component::Asterisk::AGICommand, command
217
208
  when Punchblock::Component::Output
@@ -223,31 +214,31 @@ module Punchblock
223
214
  else
224
215
  command.response = ProtocolError.new.setup 'command-not-acceptable', "Did not understand command for call #{id}", id
225
216
  end
217
+ rescue RubyAMI::Error => e
218
+ command.response = ProtocolError.new.setup 'error', e.message
226
219
  rescue Celluloid::DeadActorError
227
220
  command.response = ProtocolError.new.setup :item_not_found, "Could not find a component with ID #{command.component_id} for call #{id}", id, command.component_id
228
221
  end
229
222
 
230
- def send_agi_action(command, *params, &block)
231
- @current_agi_command = Punchblock::Component::Asterisk::AGI::Command.new :name => command, :params => params, :target_call_id => id
232
- @current_agi_command.request!
233
- @current_agi_command.register_handler :internal, Punchblock::Event::Complete do |e|
234
- block.call e if block
235
- end
236
- execute_component Component::Asterisk::AGICommand, @current_agi_command, :internal => true
237
- end
238
-
239
- def send_ami_action(name, headers = {}, &block)
240
- (name.is_a?(RubyAMI::Action) ? name : RubyAMI::Action.new(name, headers, &block)).tap do |action|
241
- @current_ami_action = action
242
- translator.send_ami_action action
223
+ def execute_agi_command(command, *params)
224
+ agi = AGICommand.new Punchblock.new_uuid, channel, command, *params
225
+ condition = Celluloid::Condition.new
226
+ register_tmp_handler :ami, name: 'AsyncAGI', [:[], 'SubEvent'] => 'Exec', [:[], 'CommandID'] => agi.id do |event|
227
+ condition.signal event
243
228
  end
229
+ agi.execute @ami_client
230
+ event = condition.wait
231
+ return unless event
232
+ agi.parse_result event
233
+ rescue RubyAMI::Error => e
234
+ abort e
244
235
  end
245
236
 
246
237
  def logger_id
247
238
  "#{self.class}: #{id}"
248
239
  end
249
240
 
250
- def redirect_back(other_call = nil, &block)
241
+ def redirect_back(other_call = nil)
251
242
  redirect_options = {
252
243
  'Channel' => channel,
253
244
  'Exten' => Asterisk::REDIRECT_EXTENSION,
@@ -260,7 +251,17 @@ module Punchblock
260
251
  'ExtraPriority' => Asterisk::REDIRECT_PRIORITY,
261
252
  'ExtraContext' => Asterisk::REDIRECT_CONTEXT
262
253
  }) if other_call
263
- send_ami_action 'Redirect', redirect_options, &block
254
+ send_ami_action 'Redirect', redirect_options
255
+ end
256
+
257
+ def handle_hangup_event(reason = :hangup)
258
+ @block_commands = true
259
+ @components.dup.each_pair do |id, component|
260
+ safe_from_dead_actors do
261
+ component.call_ended if component.alive?
262
+ end
263
+ end
264
+ send_end_event reason
264
265
  end
265
266
 
266
267
  def actor_died(actor, reason)
@@ -274,6 +275,15 @@ module Punchblock
274
275
 
275
276
  private
276
277
 
278
+ def fetch_channel_var(variable)
279
+ result = @ami_client.send_action 'GetVar', 'Channel' => channel, 'Variable' => variable
280
+ result['Value'] == '(null)' ? nil : result['Value']
281
+ end
282
+
283
+ def send_ami_action(name, headers = {})
284
+ @ami_client.send_action name, headers
285
+ end
286
+
277
287
  def send_end_event(reason)
278
288
  send_pb_event Event::End.new(:reason => reason)
279
289
  translator.deregister_call current_actor
@@ -283,7 +293,6 @@ module Punchblock
283
293
  def execute_component(type, command, options = {})
284
294
  type.new_link(command, current_actor).tap do |component|
285
295
  register_component component
286
- component.internal = true if options[:internal]
287
296
  component.async.execute
288
297
  end
289
298
  end
@@ -1,63 +1,39 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'active_support/core_ext/string/filters'
4
-
5
3
  module Punchblock
6
4
  module Translator
7
5
  class Asterisk
8
6
  module Component
9
7
  module Asterisk
10
8
  class AGICommand < Component
11
- attr_reader :action
12
-
13
9
  def setup
14
- @action = create_action
10
+ @agi = Punchblock::Translator::Asterisk::AGICommand.new id, @call.channel, @component_node.name, *@component_node.params_array
15
11
  end
16
12
 
17
13
  def execute
14
+ @agi.execute ami_client
18
15
  send_ref
19
- @call.send_ami_action @action
16
+ rescue RubyAMI::Error
17
+ set_node_response false
18
+ terminate
20
19
  end
20
+ exclusive :execute
21
21
 
22
22
  def handle_ami_event(event)
23
- if event.name == 'AsyncAGI'
24
- if event['SubEvent'] == 'Exec'
25
- send_complete_event success_reason(event)
23
+ if event.name == 'AsyncAGI' && event['SubEvent'] == 'Exec'
24
+ send_complete_event success_reason(event), nil, false
25
+ if @component_node.name == 'ASYNCAGI BREAK' && @call.channel_var('PUNCHBLOCK_END_ON_ASYNCAGI_BREAK')
26
+ @call.handle_hangup_event
26
27
  end
27
- end
28
- end
29
-
30
- def handle_response(response)
31
- case response
32
- when RubyAMI::Error
33
- set_node_response false
34
- when RubyAMI::Response
35
- send_ref
28
+ terminate
36
29
  end
37
30
  end
38
31
 
39
32
  private
40
33
 
41
- def create_action
42
- command = current_actor
43
- RubyAMI::Action.new 'AGI', 'Channel' => @call.channel, 'Command' => agi_command, 'CommandID' => id do |response|
44
- command.handle_response response
45
- end
46
- end
47
-
48
- def agi_command
49
- "#{@component_node.name} #{@component_node.params_array.map { |arg| quote_arg(arg) }.join(' ')}".squish
50
- end
51
-
52
- # Arguments surrounded by quotes; quotes backslash-escaped.
53
- # See parse_args in asterisk/res/res_agi.c (Asterisk 1.4.21.1)
54
- def quote_arg(arg)
55
- '"' + arg.to_s.gsub(/["\\]/) { |m| "\\#{m}" } + '"'
56
- end
57
-
58
34
  def success_reason(event)
59
- parser = RubyAMI::AGIResultParser.new event['Result']
60
- Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new :code => parser.code, :result => parser.result, :data => parser.data
35
+ result = @agi.parse_result event
36
+ Punchblock::Component::Asterisk::AGI::Command::Complete::Success.new result
61
37
  end
62
38
  end
63
39
  end
@@ -6,70 +6,45 @@ module Punchblock
6
6
  module Component
7
7
  module Asterisk
8
8
  class AMIAction < Component
9
- attr_reader :action, :translator
9
+ attr_reader :translator
10
10
 
11
- def initialize(component_node, translator)
11
+ def initialize(component_node, translator, ami_client)
12
12
  super component_node, nil
13
- @translator = translator
14
- end
15
-
16
- def setup
17
- @action = create_action
18
- @id = @action.action_id
13
+ @translator, @ami_client = translator, ami_client
19
14
  end
20
15
 
21
16
  def execute
22
- send_action
23
17
  send_ref
24
- end
25
-
26
- def handle_response(response)
27
- case response
28
- when RubyAMI::Error
29
- send_complete_event error_reason(response)
30
- when RubyAMI::Response
31
- send_events
32
- send_complete_event success_reason(response)
33
- end
18
+ response = send_action
19
+ final_event = send_events response
20
+ send_complete_event success_reason(response, final_event)
21
+ rescue RubyAMI::Error => e
22
+ send_complete_event error_reason(e)
34
23
  end
35
24
 
36
25
  private
37
26
 
38
- def create_action
39
- headers = {}
40
- @component_node.params_hash.each_pair do |key, value|
41
- headers[key.to_s.capitalize] = value
42
- end
43
- component = current_actor
44
- RubyAMI::Action.new @component_node.name, headers do |response|
45
- component.async.handle_response response
46
- end
47
- end
48
-
49
27
  def send_action
50
- @translator.send_ami_action @action
28
+ @ami_client.send_action @component_node.name, action_headers
51
29
  end
52
30
 
53
31
  def error_reason(response)
54
32
  Punchblock::Event::Complete::Error.new :details => response.message
55
33
  end
56
34
 
57
- def success_reason(response)
35
+ def success_reason(response, final_event = nil)
58
36
  headers = response.headers
59
- headers.merge! @extra_complete_attributes if instance_variable_defined?(:@extra_complete_attributes)
37
+ headers.merge! final_event.headers if final_event
60
38
  headers.delete 'ActionID'
61
39
  Punchblock::Component::Asterisk::AMI::Action::Complete::Success.new :message => headers.delete('Message'), :attributes => headers
62
40
  end
63
41
 
64
- def send_events
65
- return unless @action.has_causal_events?
66
- @action.events.each do |e|
67
- if e.name.downcase == @action.causal_event_terminator_name
68
- @extra_complete_attributes = e.headers
69
- else
70
- send_event pb_event_from_ami_event(e)
71
- end
42
+ def send_events(response)
43
+ final_event = response.events.pop
44
+ response.events.each do |e|
45
+ send_event pb_event_from_ami_event(e)
72
46
  end
47
+ final_event
73
48
  end
74
49
 
75
50
  def pb_event_from_ami_event(ami_event)
@@ -77,6 +52,14 @@ module Punchblock
77
52
  headers.delete 'ActionID'
78
53
  Event::Asterisk::AMI::Event.new :name => ami_event.name, :attributes => headers
79
54
  end
55
+
56
+ def action_headers
57
+ headers = {}
58
+ @component_node.params_hash.each_pair do |key, value|
59
+ headers[key.to_s.capitalize] = value
60
+ end
61
+ headers
62
+ end
80
63
  end
81
64
  end
82
65
  end
@@ -16,8 +16,9 @@ module Punchblock
16
16
  private
17
17
 
18
18
  def register_dtmf_event_handler
19
+ component = current_actor
19
20
  call.register_handler :ami, :name => 'DTMF', [:[], 'End'] => 'Yes' do |event|
20
- @recognizer << event['Digit']
21
+ component.process_dtmf event['Digit']
21
22
  end
22
23
  end
23
24
 
@@ -9,7 +9,7 @@ module Punchblock
9
9
  class Output < Component
10
10
  include StopByRedirect
11
11
 
12
- UnrenderableDocError = Class.new OptionError
12
+ UnrenderableDocError = Class.new OptionError
13
13
 
14
14
  def setup
15
15
  @media_engine = @call.translator.media_engine
@@ -25,8 +25,6 @@ module Punchblock
25
25
 
26
26
  early = !@call.answered?
27
27
 
28
- output_component = current_actor
29
-
30
28
  rendering_engine = @component_node.renderer || @media_engine || :asterisk
31
29
 
32
30
  case rendering_engine.to_sym
@@ -46,26 +44,26 @@ module Punchblock
46
44
  @call.send_progress if early
47
45
 
48
46
  if interrupt
49
- call.register_handler :ami, :name => 'DTMF' do |event|
50
- output_component.stop_by_redirect Punchblock::Component::Output::Complete::Success.new if event['End'] == 'Yes'
47
+ output_component = current_actor
48
+ call.register_handler :ami, :name => 'DTMF', [:[], 'End'] => 'Yes' do |event|
49
+ output_component.stop_by_redirect Punchblock::Component::Output::Complete::Success.new
51
50
  end
52
51
  end
53
52
 
54
53
  opts = early ? "#{path},noanswer" : path
55
- playback opts
54
+ @call.execute_agi_command 'EXEC Playback', opts
56
55
  when :unimrcp
57
56
  send_ref
58
- @call.async.send_agi_action 'EXEC MRCPSynth', escape_commas(escaped_doc), mrcpsynth_options do |complete_event|
59
- output_component.async.send_complete_event success_reason
60
- end
57
+ @call.execute_agi_command 'EXEC MRCPSynth', escape_commas(escaped_doc), mrcpsynth_options
61
58
  when :swift
62
59
  send_ref
63
- @call.async.send_agi_action 'EXEC Swift', swift_doc do |complete_event|
64
- output_component.async.send_complete_event success_reason
65
- end
60
+ @call.execute_agi_command 'EXEC Swift', swift_doc
66
61
  else
67
- raise OptionError, 'The renderer foobar is unsupported.'
62
+ raise OptionError, "The renderer #{rendering_engine} is unsupported."
68
63
  end
64
+ send_success
65
+ rescue RubyAMI::Error => e
66
+ complete_with_error "Terminated due to AMI error '#{e.message}'"
69
67
  rescue UnrenderableDocError => e
70
68
  with_error 'unrenderable document error', e.message
71
69
  rescue OptionError => e
@@ -90,19 +88,12 @@ module Punchblock
90
88
  raise UnrenderableDocError, 'The provided document could not be rendered. See http://adhearsion.com/docs/common_problems#unrenderable-document-error for details.'
91
89
  end
92
90
 
93
- def playback(path)
94
- op = current_actor
95
- @call.async.send_agi_action 'EXEC Playback', path do |complete_event|
96
- op.async.send_complete_event success_reason
97
- end
98
- end
99
-
100
91
  def escaped_doc
101
92
  @component_node.ssml.to_s.squish.gsub(/["\\]/) { |m| "\\#{m}" }
102
93
  end
103
94
 
104
95
  def escape_commas(text)
105
- text.gsub(/,/, '\\,')
96
+ text.gsub(',', '\\,')
106
97
  end
107
98
 
108
99
  def mrcpsynth_options
@@ -119,6 +110,10 @@ module Punchblock
119
110
  doc
120
111
  end
121
112
 
113
+ def send_success
114
+ send_complete_event success_reason
115
+ end
116
+
122
117
  def success_reason
123
118
  Punchblock::Component::Output::Complete::Success.new
124
119
  end
@@ -22,7 +22,6 @@ module Punchblock
22
22
 
23
23
  @format = @component_node.format || 'wav'
24
24
 
25
-
26
25
  component = current_actor
27
26
  call.register_tmp_handler :ami, :name => 'MonitorStop' do |event|
28
27
  component.finished
@@ -31,18 +30,17 @@ module Punchblock
31
30
  send_ref
32
31
 
33
32
  if @component_node.start_beep
34
- @call.async.send_agi_action 'STREAM FILE', 'beep', '""' do
35
- component.async.signal :beep_finished
36
- end
37
- wait :beep_finished
33
+ @call.execute_agi_command 'STREAM FILE', 'beep', '""'
38
34
  end
39
35
 
40
- call.async.send_ami_action 'Monitor', 'Channel' => call.channel, 'File' => filename, 'Format' => @format, 'Mix' => true
36
+ ami_client.send_action 'Monitor', 'Channel' => call.channel, 'File' => filename, 'Format' => @format, 'Mix' => true
41
37
  unless max_duration == -1
42
38
  after max_duration/1000 do
43
- call.async.send_ami_action 'StopMonitor', 'Channel' => call.channel
39
+ ami_client.send_action 'StopMonitor', 'Channel' => call.channel
44
40
  end
45
41
  end
42
+ rescue RubyAMI::Error => e
43
+ complete_with_error "Terminated due to AMI error '#{e.message}'"
46
44
  rescue OptionError => e
47
45
  with_error 'option error', e.message
48
46
  end
@@ -51,20 +49,14 @@ module Punchblock
51
49
  case command
52
50
  when Punchblock::Component::Stop
53
51
  command.response = true
54
- a = current_actor
55
- call.async.send_ami_action 'StopMonitor', 'Channel' => call.channel do |complete_event|
56
- @complete_reason = stop_reason
57
- end
52
+ ami_client.send_action 'StopMonitor', 'Channel' => call.channel
53
+ @complete_reason = stop_reason
58
54
  when Punchblock::Component::Record::Pause
59
- a = current_actor
60
- call.async.send_ami_action 'PauseMonitor', 'Channel' => call.channel do |complete_event|
61
- command.response = true
62
- end
55
+ ami_client.send_action 'PauseMonitor', 'Channel' => call.channel
56
+ command.response = true
63
57
  when Punchblock::Component::Record::Resume
64
- a = current_actor
65
- call.async.send_ami_action 'ResumeMonitor', 'Channel' => call.channel do |complete_event|
66
- command.response = true
67
- end
58
+ ami_client.send_action 'ResumeMonitor', 'Channel' => call.channel
59
+ command.response = true
68
60
  else
69
61
  super
70
62
  end