punchblock 1.3.0 → 1.4.0

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 (42) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/lib/punchblock.rb +1 -1
  3. data/lib/punchblock/connection.rb +1 -0
  4. data/lib/punchblock/connection/asterisk.rb +0 -1
  5. data/lib/punchblock/connection/freeswitch.rb +49 -0
  6. data/lib/punchblock/event/offer.rb +1 -1
  7. data/lib/punchblock/translator.rb +5 -0
  8. data/lib/punchblock/translator/asterisk.rb +16 -28
  9. data/lib/punchblock/translator/asterisk/call.rb +4 -21
  10. data/lib/punchblock/translator/asterisk/component.rb +0 -5
  11. data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +0 -3
  12. data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +0 -1
  13. data/lib/punchblock/translator/asterisk/component/input.rb +7 -97
  14. data/lib/punchblock/translator/asterisk/component/output.rb +0 -4
  15. data/lib/punchblock/translator/asterisk/component/record.rb +0 -2
  16. data/lib/punchblock/translator/freeswitch.rb +153 -0
  17. data/lib/punchblock/translator/freeswitch/call.rb +265 -0
  18. data/lib/punchblock/translator/freeswitch/component.rb +92 -0
  19. data/lib/punchblock/translator/freeswitch/component/abstract_output.rb +57 -0
  20. data/lib/punchblock/translator/freeswitch/component/flite_output.rb +17 -0
  21. data/lib/punchblock/translator/freeswitch/component/input.rb +29 -0
  22. data/lib/punchblock/translator/freeswitch/component/output.rb +56 -0
  23. data/lib/punchblock/translator/freeswitch/component/record.rb +79 -0
  24. data/lib/punchblock/translator/freeswitch/component/tts_output.rb +26 -0
  25. data/lib/punchblock/translator/input_component.rb +108 -0
  26. data/lib/punchblock/version.rb +1 -1
  27. data/punchblock.gemspec +3 -2
  28. data/spec/punchblock/connection/freeswitch_spec.rb +90 -0
  29. data/spec/punchblock/translator/asterisk/call_spec.rb +23 -2
  30. data/spec/punchblock/translator/asterisk/component/input_spec.rb +3 -3
  31. data/spec/punchblock/translator/asterisk_spec.rb +1 -1
  32. data/spec/punchblock/translator/freeswitch/call_spec.rb +922 -0
  33. data/spec/punchblock/translator/freeswitch/component/flite_output_spec.rb +279 -0
  34. data/spec/punchblock/translator/freeswitch/component/input_spec.rb +312 -0
  35. data/spec/punchblock/translator/freeswitch/component/output_spec.rb +369 -0
  36. data/spec/punchblock/translator/freeswitch/component/record_spec.rb +373 -0
  37. data/spec/punchblock/translator/freeswitch/component/tts_output_spec.rb +285 -0
  38. data/spec/punchblock/translator/freeswitch/component_spec.rb +118 -0
  39. data/spec/punchblock/translator/freeswitch_spec.rb +597 -0
  40. data/spec/punchblock_spec.rb +11 -0
  41. data/spec/spec_helper.rb +1 -0
  42. metadata +52 -7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # [develop](https://github.com/adhearsion/punchblock)
2
2
 
3
+ # [v1.4.0](https://github.com/adhearsion/punchblock/compare/v1.3.0...v1.4.0) - [2012-08-07](https://rubygems.org/gems/punchblock/versions/1.4.0)
4
+ * Feature: FreeSWITCH support (mostly complete, experimental, proceed with caution)
5
+ * Bugfix: Report the correct caller ID in offers from Asterisk
6
+ * Bugfix: Strip out caller ID name from dial commands on Asterisk
7
+
3
8
  # [v1.3.0](https://github.com/adhearsion/punchblock/compare/v1.2.0...v1.3.0) - [2012-07-22](https://rubygems.org/gems/punchblock/versions/1.3.0)
4
9
  * Change: Asterisk output now uses Playback rather than STREAM FILE
5
10
  * Feature: The recordings dir is now checked for existence on startup, and logs an error if it is not there. Asterisk only.
data/lib/punchblock.rb CHANGED
@@ -44,7 +44,7 @@ module Punchblock
44
44
  #
45
45
  # Get a new Punchblock client with a connection attached
46
46
  #
47
- # @param [Symbol] type the connection type (eg :XMPP, :asterisk)
47
+ # @param [Symbol] type the connection type (eg :XMPP, :asterisk, :freeswitch)
48
48
  # @param [Hash] options the options to pass to the connection (credentials, etc
49
49
  #
50
50
  # @return [Punchblock::Client] a punchblock client object
@@ -6,6 +6,7 @@ module Punchblock
6
6
 
7
7
  autoload :Asterisk
8
8
  autoload :Connected
9
+ autoload :Freeswitch
9
10
  autoload :GenericConnection
10
11
  autoload :XMPP
11
12
  end
@@ -15,7 +15,6 @@ module Punchblock
15
15
  end
16
16
 
17
17
  def run
18
- pb_logger.debug "Starting the RubyAMI client"
19
18
  ami_client.start
20
19
  raise DisconnectedError
21
20
  end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'ruby_fs'
4
+
5
+ module Punchblock
6
+ module Connection
7
+ class Freeswitch < GenericConnection
8
+ attr_reader :translator, :stream
9
+ attr_accessor :event_handler
10
+
11
+ def initialize(options = {})
12
+ @translator = Translator::Freeswitch.new self, options[:media_engine], options[:default_voice]
13
+ @stream_options = options.values_at(:host, :port, :password)
14
+ @stream = new_fs_stream
15
+ super()
16
+ end
17
+
18
+ def run
19
+ pb_logger.debug "Starting the RubyFS stream"
20
+ start_stream
21
+ raise DisconnectedError
22
+ end
23
+
24
+ def stop
25
+ stream.shutdown
26
+ translator.terminate
27
+ end
28
+
29
+ def write(command, options)
30
+ translator.execute_command! command, options
31
+ end
32
+
33
+ def handle_event(event)
34
+ event_handler.call event if event_handler.respond_to?(:call)
35
+ end
36
+
37
+ private
38
+
39
+ def new_fs_stream
40
+ RubyFS::Stream.new(*@stream_options, lambda { |e| translator.handle_es_event! e })
41
+ end
42
+
43
+ def start_stream
44
+ @stream = new_fs_stream unless @stream.alive?
45
+ @stream.run
46
+ end
47
+ end
48
+ end
49
+ end
@@ -28,7 +28,7 @@ module Punchblock
28
28
  end
29
29
 
30
30
  def inspect
31
- "#<Punchblock::Event::Offer to=\"#{to}\", from=\"#{from}\", call_id=\"#{target_call_id}\""
31
+ "#<Punchblock::Event::Offer to=\"#{to}\", from=\"#{from}\", headers=#{headers_hash.inspect}, call_id=\"#{target_call_id}\""
32
32
  end
33
33
  end # Offer
34
34
  end
@@ -4,6 +4,11 @@ module Punchblock
4
4
  module Translator
5
5
  extend ActiveSupport::Autoload
6
6
 
7
+ OptionError = Class.new Punchblock::Error
8
+
7
9
  autoload :Asterisk
10
+ autoload :Freeswitch
11
+
12
+ autoload :InputComponent
8
13
  end
9
14
  end
@@ -22,7 +22,6 @@ module Punchblock
22
22
  trap_exit :actor_died
23
23
 
24
24
  def initialize(ami_client, connection, media_engine = nil)
25
- pb_logger.debug "Starting up..."
26
25
  @ami_client, @connection, @media_engine = ami_client, connection, media_engine
27
26
  @calls, @components, @channel_to_call_id = {}, {}, {}
28
27
  @fully_booted_count = 0
@@ -55,42 +54,38 @@ module Punchblock
55
54
  end
56
55
 
57
56
  def shutdown
58
- pb_logger.debug "Shutting down"
59
57
  @calls.values.each(&:shutdown!)
60
58
  current_actor.terminate!
61
59
  end
62
60
 
63
61
  def handle_ami_event(event)
64
- exclusive do
65
- return unless event.is_a? RubyAMI::Event
66
-
67
- if event.name.downcase == "fullybooted"
68
- pb_logger.trace "Counting FullyBooted event"
69
- @fully_booted_count += 1
70
- if @fully_booted_count >= 2
71
- handle_pb_event Connection::Connected.new
72
- @fully_booted_count = 0
73
- run_at_fully_booted
74
- end
75
- return
62
+ return unless event.is_a? RubyAMI::Event
63
+
64
+ if event.name.downcase == "fullybooted"
65
+ @fully_booted_count += 1
66
+ if @fully_booted_count >= 2
67
+ handle_pb_event Connection::Connected.new
68
+ @fully_booted_count = 0
69
+ run_at_fully_booted
76
70
  end
71
+ return
72
+ end
77
73
 
78
- handle_varset_ami_event event
74
+ handle_varset_ami_event event
79
75
 
80
- ami_dispatch_to_or_create_call event
76
+ ami_dispatch_to_or_create_call event
81
77
 
82
- unless ami_event_known_call?(event)
83
- handle_pb_event Event::Asterisk::AMI::Event.new(:name => event.name, :attributes => event.headers)
84
- end
78
+ unless ami_event_known_call?(event)
79
+ handle_pb_event Event::Asterisk::AMI::Event.new(:name => event.name, :attributes => event.headers)
85
80
  end
86
81
  end
82
+ exclusive :handle_ami_event
87
83
 
88
84
  def handle_pb_event(event)
89
85
  connection.handle_event event
90
86
  end
91
87
 
92
88
  def execute_command(command, options = {})
93
- pb_logger.trace "Executing command #{command.inspect}"
94
89
  command.request!
95
90
 
96
91
  command.target_call_id ||= options[:call_id]
@@ -144,7 +139,6 @@ module Punchblock
144
139
  send_ami_action('Command', {
145
140
  'Command' => "dialplan add extension #{REDIRECT_EXTENSION},#{REDIRECT_PRIORITY},AGI,agi:async into #{REDIRECT_CONTEXT}"
146
141
  })
147
- pb_logger.trace "Added extension extension #{REDIRECT_EXTENSION},#{REDIRECT_PRIORITY},AGI,agi:async into #{REDIRECT_CONTEXT}"
148
142
  send_ami_action('Command', {
149
143
  'Command' => "dialplan show #{REDIRECT_CONTEXT}"
150
144
  }) do |result|
@@ -160,9 +154,7 @@ module Punchblock
160
154
 
161
155
  def actor_died(actor, reason)
162
156
  return unless reason
163
- pb_logger.error "A linked actor (#{actor.inspect}) died due to #{reason.inspect}"
164
157
  if id = @calls.key(actor)
165
- pb_logger.info "Dead actor was a call we know about, with ID #{id}. Removing it from the registry..."
166
158
  @calls.delete id
167
159
  end_event = Punchblock::Event::End.new :target_call_id => id,
168
160
  :reason => :error
@@ -175,9 +167,7 @@ module Punchblock
175
167
  def handle_varset_ami_event(event)
176
168
  return unless event.name == 'VarSet' && event['Variable'] == 'punchblock_call_id' && (call = call_with_id event['Value'])
177
169
 
178
- pb_logger.trace "Received a VarSet event indicating the full channel for call #{call}"
179
170
  @channel_to_call_id.delete call.channel
180
- pb_logger.trace "Removed call with old channel from channel map: #{@channel_to_call_id}"
181
171
  call.channel = event['Channel']
182
172
  register_call call
183
173
  end
@@ -206,10 +196,8 @@ module Punchblock
206
196
  def handle_async_agi_start_event(event)
207
197
  env = RubyAMI::AsyncAGIEnvironmentParser.new(event['Env']).to_hash
208
198
 
209
- return pb_logger.warn "Ignoring AsyncAGI Start event because it is for an 'h' extension" if env[:agi_extension] == 'h'
210
- return pb_logger.warn "Ignoring AsyncAGI Start event because it is for an 'Kill' type" if env[:agi_type] == 'Kill'
199
+ return if env[:agi_extension] == 'h' || env[:agi_type] == 'Kill'
211
200
 
212
- pb_logger.trace "Handling AsyncAGI Start event by creating a new call"
213
201
  call = Call.new event['Channel'], current_actor, env
214
202
  link call
215
203
  register_call call
@@ -28,7 +28,6 @@ module Punchblock
28
28
  @id, @components = Punchblock.new_uuid, {}
29
29
  @answered = false
30
30
  @pending_joins = {}
31
- pb_logger.debug "Starting up call with channel #{channel}, id #{@id}"
32
31
  @progress_sent = false
33
32
  end
34
33
 
@@ -46,7 +45,6 @@ module Punchblock
46
45
  end
47
46
 
48
47
  def shutdown
49
- pb_logger.debug "Shutting down"
50
48
  current_actor.terminate!
51
49
  end
52
50
 
@@ -57,10 +55,12 @@ module Punchblock
57
55
 
58
56
  def dial(dial_command)
59
57
  @direction = :outbound
58
+ channel = dial_command.to || ''
59
+ channel.match(/.* <(?<channel>.*)>/) { |m| channel = m[:channel] }
60
60
  params = { :async => true,
61
61
  :application => 'AGI',
62
62
  :data => 'agi:async',
63
- :channel => dial_command.to,
63
+ :channel => channel,
64
64
  :callerid => dial_command.from,
65
65
  :variable => "punchblock_call_id=#{id}"
66
66
  }
@@ -87,13 +87,11 @@ module Punchblock
87
87
 
88
88
  def send_progress
89
89
  return if answered? || outbound? || @progress_sent
90
- pb_logger.debug "Sending Progress to start early media"
91
90
  @progress_sent = true
92
91
  send_agi_action "EXEC Progress"
93
92
  end
94
93
 
95
94
  def channel=(other)
96
- pb_logger.info "Channel is changing from #{channel} to #{other}."
97
95
  @channel = other
98
96
  end
99
97
 
@@ -102,7 +100,6 @@ module Punchblock
102
100
 
103
101
  case ami_event.name
104
102
  when 'Hangup'
105
- pb_logger.trace "Received a Hangup AMI event. Sending End event."
106
103
  @components.dup.each_pair do |id, component|
107
104
  safe_from_dead_actors do
108
105
  component.call_ended if component.alive?
@@ -110,14 +107,10 @@ module Punchblock
110
107
  end
111
108
  send_end_event HANGUP_CAUSE_TO_END_REASON[ami_event['Cause'].to_i]
112
109
  when 'AsyncAGI'
113
- pb_logger.trace "Received an AsyncAGI event. Looking for matching AGICommand component."
114
110
  if component = component_with_id(ami_event['CommandID'])
115
111
  component.handle_ami_event ami_event
116
- else
117
- pb_logger.trace "Could not find component for AMI event: #{ami_event.inspect}"
118
112
  end
119
113
  when 'Newstate'
120
- pb_logger.trace "Received a Newstate AMI event with state #{ami_event['ChannelState']}: #{ami_event['ChannelStateDesc']}"
121
114
  case ami_event['ChannelState']
122
115
  when '5'
123
116
  send_pb_event Event::Ringing.new
@@ -127,7 +120,6 @@ module Punchblock
127
120
  end
128
121
  when 'OriginateResponse'
129
122
  if ami_event['Response'] == 'Failure' && ami_event['Uniqueid'] == '<null>'
130
- pb_logger.info "Outbound call could not be established!"
131
123
  send_end_event :error
132
124
  end
133
125
  when 'BridgeExec'
@@ -162,7 +154,6 @@ module Punchblock
162
154
  end
163
155
 
164
156
  def execute_command(command)
165
- pb_logger.debug "Executing command: #{command.inspect}"
166
157
  if command.component_id
167
158
  if component = component_with_id(command.component_id)
168
159
  component.execute_command command
@@ -173,10 +164,8 @@ module Punchblock
173
164
  case command
174
165
  when Command::Accept
175
166
  if outbound?
176
- pb_logger.trace "Attempting to accept an outbound call. Skipping RINGING."
177
167
  command.response = true
178
168
  else
179
- pb_logger.trace "Attempting to accept an inbound call. Executing RINGING."
180
169
  send_agi_action 'EXEC RINGING' do |response|
181
170
  command.response = true
182
171
  end
@@ -231,11 +220,9 @@ module Punchblock
231
220
  end
232
221
 
233
222
  def send_agi_action(command, *params, &block)
234
- pb_logger.trace "Sending AGI action #{command}"
235
223
  @current_agi_command = Punchblock::Component::Asterisk::AGI::Command.new :name => command, :params => params, :target_call_id => id
236
224
  @current_agi_command.request!
237
225
  @current_agi_command.register_handler :internal, Punchblock::Event::Complete do |e|
238
- pb_logger.trace "AGI action received complete event #{e.inspect}"
239
226
  block.call e if block
240
227
  end
241
228
  execute_component Component::Asterisk::AGICommand, @current_agi_command, :internal => true
@@ -244,7 +231,6 @@ module Punchblock
244
231
  def send_ami_action(name, headers = {}, &block)
245
232
  (name.is_a?(RubyAMI::Action) ? name : RubyAMI::Action.new(name, headers, &block)).tap do |action|
246
233
  @current_ami_action = action
247
- pb_logger.trace "Sending AMI action #{action.inspect}"
248
234
  translator.send_ami_action action
249
235
  end
250
236
  end
@@ -271,9 +257,7 @@ module Punchblock
271
257
 
272
258
  def actor_died(actor, reason)
273
259
  return unless reason
274
- pb_logger.error "A linked actor (#{actor.inspect}) died due to #{reason.inspect}"
275
260
  if id = @components.key(actor)
276
- pb_logger.info "Dead actor was a component we know about, with ID #{id}. Removing it from the registry..."
277
261
  @components.delete id
278
262
  complete_event = Punchblock::Event::Complete.new :component_id => id, :reason => Punchblock::Event::Complete::Error.new
279
263
  send_pb_event complete_event
@@ -298,13 +282,12 @@ module Punchblock
298
282
 
299
283
  def send_pb_event(event)
300
284
  event.target_call_id = id
301
- pb_logger.trace "Sending Punchblock event: #{event.inspect}"
302
285
  translator.handle_pb_event event
303
286
  end
304
287
 
305
288
  def offer_event
306
289
  Event::Offer.new :to => agi_env.values_at(:agi_dnid, :agi_extension).detect { |e| e && e != 'unknown' },
307
- :from => "#{agi_env[:agi_calleridname]} <#{[agi_env[:agi_type].downcase, agi_env[:agi_callerid]].join(':')}>",
290
+ :from => "#{agi_env[:agi_calleridname]} <#{[agi_env[:agi_type], agi_env[:agi_callerid]].join('/')}>",
308
291
  :headers => sip_headers
309
292
  end
310
293
 
@@ -13,8 +13,6 @@ module Punchblock
13
13
  autoload :StopByRedirect
14
14
 
15
15
  class Component
16
- OptionError = Class.new Punchblock::Error
17
-
18
16
  include Celluloid
19
17
  include DeadActorSafety
20
18
 
@@ -27,7 +25,6 @@ module Punchblock
27
25
  @id = Punchblock.new_uuid
28
26
  @complete = false
29
27
  setup
30
- pb_logger.debug "Starting up..."
31
28
  end
32
29
 
33
30
  def setup
@@ -51,7 +48,6 @@ module Punchblock
51
48
  def send_event(event)
52
49
  event.component_id = id
53
50
  event.target_call_id = call_id
54
- pb_logger.debug "Sending event #{event}"
55
51
  if internal
56
52
  @component_node.add_event event
57
53
  else
@@ -74,7 +70,6 @@ module Punchblock
74
70
  end
75
71
 
76
72
  def set_node_response(value)
77
- pb_logger.debug "Setting response on component node to #{value}"
78
73
  @component_node.response = value
79
74
  end
80
75
 
@@ -20,17 +20,14 @@ module Punchblock
20
20
  end
21
21
 
22
22
  def handle_ami_event(event)
23
- pb_logger.debug "Handling AMI event: #{event.inspect}"
24
23
  if event.name == 'AsyncAGI'
25
24
  if event['SubEvent'] == 'Exec'
26
- pb_logger.debug "Received AsyncAGI:Exec event, sending complete event."
27
25
  send_complete_event success_reason(event)
28
26
  end
29
27
  end
30
28
  end
31
29
 
32
30
  def handle_response(response)
33
- pb_logger.debug "Handling response: #{response.inspect}"
34
31
  case response
35
32
  when RubyAMI::Error
36
33
  set_node_response false
@@ -24,7 +24,6 @@ module Punchblock
24
24
  end
25
25
 
26
26
  def handle_response(response)
27
- pb_logger.debug "Handling response #{response.inspect}"
28
27
  case response
29
28
  when RubyAMI::Error
30
29
  send_complete_event error_reason(response)
@@ -6,114 +6,24 @@ module Punchblock
6
6
  module Component
7
7
  class Input < Component
8
8
 
9
- attr_reader :grammar, :buffer
10
-
11
- def setup
12
- @buffer = ""
13
- end
9
+ include InputComponent
14
10
 
15
11
  def execute
16
12
  @call.send_progress
17
- initial_timeout = @component_node.initial_timeout || -1
18
- @inter_digit_timeout = @component_node.inter_digit_timeout || -1
19
-
20
- raise OptionError, 'A grammar document is required.' unless @component_node.grammar
21
- raise OptionError, 'A mode value other than DTMF is unsupported on Asterisk.' unless @component_node.mode == :dtmf
22
- raise OptionError, 'An initial timeout value that is negative (and not -1) is invalid.' unless initial_timeout >= -1
23
- raise OptionError, 'An inter-digit timeout value that is negative (and not -1) is invalid.' unless @inter_digit_timeout >= -1
24
-
25
- send_ref
26
-
27
- @grammar = @component_node.grammar.value.clone
28
- grammar.inline!
29
- grammar.tokenize!
30
- grammar.normalize_whitespace
31
-
32
- begin_initial_timer initial_timeout/1000 unless initial_timeout == -1
33
-
34
- component = current_actor
35
-
36
- @dtmf_handler_id = call.register_handler :ami, :name => 'DTMF' do |event|
37
- component.process_dtmf! event['Digit'] if event['End'] == 'Yes'
38
- end
39
- rescue OptionError => e
40
- with_error 'option error', e.message
41
- end
42
-
43
- def process_dtmf(digit)
44
- pb_logger.trace "Processing incoming DTMF digit #{digit}"
45
- buffer << digit
46
- cancel_initial_timer
47
- case (match = grammar.match buffer.dup)
48
- when RubySpeech::GRXML::Match
49
- pb_logger.trace "Found a match against buffer #{buffer}"
50
- complete success_reason(match)
51
- when RubySpeech::GRXML::NoMatch
52
- pb_logger.trace "Buffer #{buffer} does not match grammar"
53
- complete Punchblock::Component::Input::Complete::NoMatch.new
54
- when RubySpeech::GRXML::PotentialMatch
55
- pb_logger.trace "Buffer #{buffer} potentially matches grammar. Waiting..."
56
- reset_inter_digit_timer
57
- end
58
- end
59
-
60
- def execute_command(command)
61
- case command
62
- when Punchblock::Component::Stop
63
- command.response = true
64
- complete Punchblock::Event::Complete::Stop.new
65
- else
66
- super
67
- end
13
+ super
68
14
  end
69
15
 
70
16
  private
71
17
 
72
- def begin_initial_timer(timeout)
73
- pb_logger.trace "Setting initial timer for #{timeout} seconds"
74
- @initial_timer = after timeout do
75
- pb_logger.trace "Initial timer expired."
76
- complete Punchblock::Component::Input::Complete::NoInput.new
77
- end
78
- end
79
-
80
- def cancel_initial_timer
81
- return unless instance_variable_defined?(:@initial_timer) && @initial_timer
82
- @initial_timer.cancel
83
- @initial_timer = nil
84
- end
85
-
86
- def reset_inter_digit_timer
87
- return if @inter_digit_timeout == -1
88
- @inter_digit_timer ||= begin
89
- pb_logger.trace "Setting inter-digit timer for #{@inter_digit_timeout/1000} seconds"
90
- after @inter_digit_timeout/1000 do
91
- pb_logger.trace "Inter digit-timer expired."
92
- complete Punchblock::Component::Input::Complete::NoMatch.new
93
- end
18
+ def register_dtmf_event_handler
19
+ component = current_actor
20
+ call.register_handler :ami, :name => 'DTMF' do |event|
21
+ component.process_dtmf! event['Digit'] if event['End'] == 'Yes'
94
22
  end
95
- pb_logger.trace "Resetting inter-digit timer"
96
- @inter_digit_timer.reset
97
- end
98
-
99
- def cancel_inter_digit_timer
100
- return unless instance_variable_defined?(:@inter_digit_timer) && @inter_digit_timer
101
- @inter_digit_timer.cancel
102
- @inter_digit_timer = nil
103
- end
104
-
105
- def success_reason(match)
106
- Punchblock::Component::Input::Complete::Success.new :mode => match.mode,
107
- :confidence => match.confidence,
108
- :utterance => match.utterance,
109
- :interpretation => match.interpretation
110
23
  end
111
24
 
112
- def complete(reason)
25
+ def unregister_dtmf_event_handler
113
26
  call.unregister_handler :ami, @dtmf_handler_id if instance_variable_defined?(:@dtmf_handler_id)
114
- cancel_initial_timer
115
- cancel_inter_digit_timer
116
- send_complete_event reason
117
27
  end
118
28
  end
119
29
  end