punchblock 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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