punchblock 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +1 -1
- data/lib/punchblock/component/component_node.rb +1 -1
- data/lib/punchblock/component/stop.rb +2 -2
- data/lib/punchblock/connection/asterisk.rb +3 -3
- data/lib/punchblock/connection/freeswitch.rb +2 -2
- data/lib/punchblock/connection/xmpp.rb +1 -1
- data/lib/punchblock/translator.rb +1 -0
- data/lib/punchblock/translator/asterisk.rb +10 -9
- data/lib/punchblock/translator/asterisk/call.rb +15 -7
- data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +1 -1
- data/lib/punchblock/translator/asterisk/component/input.rb +3 -4
- data/lib/punchblock/translator/asterisk/component/output.rb +6 -6
- data/lib/punchblock/translator/asterisk/component/record.rb +7 -7
- data/lib/punchblock/translator/asterisk/component/stop_by_redirect.rb +3 -3
- data/lib/punchblock/translator/dtmf_recognizer.rb +87 -0
- data/lib/punchblock/translator/freeswitch.rb +9 -7
- data/lib/punchblock/translator/freeswitch/call.rb +6 -4
- data/lib/punchblock/translator/freeswitch/component/input.rb +1 -2
- data/lib/punchblock/translator/freeswitch/component/output.rb +1 -2
- data/lib/punchblock/translator/freeswitch/component/tts_output.rb +1 -1
- data/lib/punchblock/translator/input_component.rb +17 -64
- data/lib/punchblock/version.rb +1 -1
- data/punchblock.gemspec +1 -1
- data/spec/punchblock/component/input_spec.rb +1 -1
- data/spec/punchblock/component/output_spec.rb +33 -3
- data/spec/punchblock/component/record_spec.rb +1 -1
- data/spec/punchblock/connection/asterisk_spec.rb +3 -3
- data/spec/punchblock/connection/freeswitch_spec.rb +3 -2
- data/spec/punchblock/connection/xmpp_spec.rb +18 -6
- data/spec/punchblock/translator/asterisk/call_spec.rb +83 -31
- data/spec/punchblock/translator/asterisk/component/input_spec.rb +1 -1
- data/spec/punchblock/translator/asterisk/component/output_spec.rb +32 -27
- data/spec/punchblock/translator/asterisk/component/record_spec.rb +47 -43
- data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +2 -2
- data/spec/punchblock/translator/asterisk_spec.rb +28 -26
- data/spec/punchblock/translator/freeswitch/call_spec.rb +24 -15
- data/spec/punchblock/translator/freeswitch/component/input_spec.rb +1 -1
- data/spec/punchblock/translator/freeswitch/component/output_spec.rb +2 -3
- data/spec/punchblock/translator/freeswitch/component/record_spec.rb +1 -1
- data/spec/punchblock/translator/freeswitch_spec.rb +75 -18
- data/spec/spec_helper.rb +1 -1
- metadata +24 -74
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 73b10610c29750367e41a8f99669d79fd5b8bcb8
|
|
4
|
+
data.tar.gz: 66d4bd7dea9d5c33ca580ef361fbf20bfe147015
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6bdf955c26d3ebea75ce690c7feafd969c3542403f0e2c392a8eab91d05e5981514b1bc95bfe025eab8894f864e0638fae051221c7ec382f867baa9db5de2901
|
|
7
|
+
data.tar.gz: 1c9d7bb96f8112ce3e55dc83d5a847a27e73e11ac8d1c20c6907bfe9c7d22956d91de608f65d6f915cdb8de021562029ea84b1cd4956a5d974a42474567bd4b3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# [develop](https://github.com/adhearsion/punchblock)
|
|
2
2
|
|
|
3
|
+
# [v1.8.1](https://github.com/adhearsion/punchblock/compare/v1.8.0...v1.8.1) - [2013-03-25](https://rubygems.org/gems/punchblock/versions/1.8.1)
|
|
4
|
+
* Bugfix: FreeSWITCH was requiring a from attribute on a dial command
|
|
5
|
+
* Bugfix: Asterisk translator now properly checks for existence of the recordings directory
|
|
6
|
+
* Bugfix: Components should transition state before unblocking
|
|
7
|
+
* Bugfix: Asterisk joins are now more robustly responded to when the join begins
|
|
8
|
+
* Bugfix: On FreeSWITCH, only events relating to bridge start/end should be delivered to bridged calls
|
|
9
|
+
* Bugfix: On FreeSWITCH, a voice value on an audio-only output component should not prevent execution
|
|
10
|
+
* Bugfix: XMPP Ping should be an IQ get, not set
|
|
11
|
+
* Bugfix: Stop command should be in Rayo ext namespace
|
|
12
|
+
* Bugfix: XMPP specs were mistakenly resetting the logger object for other tests.
|
|
13
|
+
* CS: Avoid Celluloid deprecation warnings
|
|
14
|
+
|
|
3
15
|
# [v1.8.0](https://github.com/adhearsion/punchblock/compare/v1.7.1...v1.8.0) - [2013-01-10](https://rubygems.org/gems/punchblock/versions/1.8.0)
|
|
4
16
|
* Feature: Join command now enforces a list of valid direction attribute values
|
|
5
17
|
* Feature: Added support for media direction to the Record component
|
data/Gemfile
CHANGED
|
@@ -50,8 +50,8 @@ module Punchblock
|
|
|
50
50
|
def complete_event=(other)
|
|
51
51
|
return if @complete_event_resource.set_yet?
|
|
52
52
|
client.delete_component_registration self if client
|
|
53
|
-
@complete_event_resource.resource = other
|
|
54
53
|
complete!
|
|
54
|
+
@complete_event_resource.resource = other
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
##
|
|
@@ -9,7 +9,7 @@ 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.handle_ami_event
|
|
12
|
+
@ami_client = RubyAMI::Client.new options.merge(:event_handler => lambda { |event| translator.async.handle_ami_event event }, :logger => pb_logger)
|
|
13
13
|
@translator = Translator::Asterisk.new @ami_client, self, options[:media_engine]
|
|
14
14
|
super()
|
|
15
15
|
end
|
|
@@ -20,12 +20,12 @@ module Punchblock
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def stop
|
|
23
|
-
translator.shutdown
|
|
23
|
+
translator.async.shutdown
|
|
24
24
|
ami_client.stop
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def write(command, options)
|
|
28
|
-
translator.execute_command
|
|
28
|
+
translator.async.execute_command command, options
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def handle_event(event)
|
|
@@ -27,7 +27,7 @@ module Punchblock
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def write(command, options)
|
|
30
|
-
translator.execute_command
|
|
30
|
+
translator.async.execute_command command, options
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def handle_event(event)
|
|
@@ -37,7 +37,7 @@ module Punchblock
|
|
|
37
37
|
private
|
|
38
38
|
|
|
39
39
|
def new_fs_stream
|
|
40
|
-
RubyFS::Stream.new(*@stream_options, lambda { |e| translator.handle_es_event
|
|
40
|
+
RubyFS::Stream.new(*@stream_options, lambda { |e| translator.async.handle_es_event e })
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def start_stream
|
|
@@ -175,7 +175,7 @@ module Punchblock
|
|
|
175
175
|
end
|
|
176
176
|
|
|
177
177
|
def ping_rayo
|
|
178
|
-
client.write_with_handler Blather::Stanza::Iq::Ping.new(:
|
|
178
|
+
client.write_with_handler Blather::Stanza::Iq::Ping.new(:get, root_domain) do |response|
|
|
179
179
|
begin
|
|
180
180
|
handle_error response if response.is_a? Blather::BlatherError
|
|
181
181
|
rescue ProtocolError => e
|
|
@@ -57,7 +57,7 @@ module Punchblock
|
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def shutdown
|
|
60
|
-
@calls.values.each
|
|
60
|
+
@calls.values.each { |call| call.async.shutdown }
|
|
61
61
|
terminate
|
|
62
62
|
end
|
|
63
63
|
|
|
@@ -105,7 +105,7 @@ module Punchblock
|
|
|
105
105
|
|
|
106
106
|
def execute_call_command(command)
|
|
107
107
|
if call = call_with_id(command.target_call_id)
|
|
108
|
-
call.execute_command
|
|
108
|
+
call.async.execute_command command
|
|
109
109
|
else
|
|
110
110
|
command.response = ProtocolError.new.setup :item_not_found, "Could not find a call with ID #{command.target_call_id}", command.target_call_id
|
|
111
111
|
end
|
|
@@ -113,7 +113,7 @@ module Punchblock
|
|
|
113
113
|
|
|
114
114
|
def execute_component_command(command)
|
|
115
115
|
if (component = component_with_id(command.component_id))
|
|
116
|
-
component.execute_command
|
|
116
|
+
component.async.execute_command command
|
|
117
117
|
else
|
|
118
118
|
command.response = ProtocolError.new.setup :item_not_found, "Could not find a component with ID #{command.component_id}", command.target_call_id, command.component_id
|
|
119
119
|
end
|
|
@@ -124,11 +124,11 @@ module Punchblock
|
|
|
124
124
|
when Punchblock::Component::Asterisk::AMI::Action
|
|
125
125
|
component = Component::Asterisk::AMIAction.new command, current_actor
|
|
126
126
|
register_component component
|
|
127
|
-
component.execute
|
|
127
|
+
component.async.execute
|
|
128
128
|
when Punchblock::Command::Dial
|
|
129
129
|
call = Call.new_link command.to, current_actor
|
|
130
130
|
register_call call
|
|
131
|
-
call.dial
|
|
131
|
+
call.async.dial command
|
|
132
132
|
else
|
|
133
133
|
command.response = ProtocolError.new.setup 'command-not-acceptable', "Did not understand command"
|
|
134
134
|
end
|
|
@@ -149,10 +149,11 @@ module Punchblock
|
|
|
149
149
|
pb_logger.error "Punchblock failed to add the #{REDIRECT_EXTENSION} extension to the #{REDIRECT_CONTEXT} context. Please add a [#{REDIRECT_CONTEXT}] entry to your dialplan."
|
|
150
150
|
end
|
|
151
151
|
end
|
|
152
|
+
check_recording_directory
|
|
152
153
|
end
|
|
153
154
|
|
|
154
155
|
def check_recording_directory
|
|
155
|
-
pb_logger.
|
|
156
|
+
pb_logger.warn "Recordings directory #{Component::Record::RECORDING_BASE_PATH} does not exist. Recording might not work. This warning can be ignored if Adhearsion is running on a separate machine than Asterisk. See http://adhearsion.com/docs/call-controllers#recording" unless File.exists?(Component::Record::RECORDING_BASE_PATH)
|
|
156
157
|
end
|
|
157
158
|
|
|
158
159
|
def actor_died(actor, reason)
|
|
@@ -181,9 +182,9 @@ module Punchblock
|
|
|
181
182
|
call = call_for_channel channel
|
|
182
183
|
if call
|
|
183
184
|
if channel_is_bridged?(channel)
|
|
184
|
-
call.process_ami_event
|
|
185
|
+
call.async.process_ami_event event if EVENTS_ALLOWED_BRIDGED.include?(event.name.downcase)
|
|
185
186
|
else
|
|
186
|
-
call.process_ami_event
|
|
187
|
+
call.async.process_ami_event event
|
|
187
188
|
end
|
|
188
189
|
end
|
|
189
190
|
end
|
|
@@ -215,7 +216,7 @@ module Punchblock
|
|
|
215
216
|
call = Call.new event['Channel'], current_actor, env
|
|
216
217
|
link call
|
|
217
218
|
register_call call
|
|
218
|
-
call.send_offer
|
|
219
|
+
call.async.send_offer
|
|
219
220
|
end
|
|
220
221
|
end
|
|
221
222
|
end
|
|
@@ -8,7 +8,7 @@ module Punchblock
|
|
|
8
8
|
include Celluloid
|
|
9
9
|
include DeadActorSafety
|
|
10
10
|
|
|
11
|
-
attr_reader :id, :channel, :translator, :agi_env, :direction
|
|
11
|
+
attr_reader :id, :channel, :translator, :agi_env, :direction
|
|
12
12
|
|
|
13
13
|
HANGUP_CAUSE_TO_END_REASON = Hash.new { :error }
|
|
14
14
|
HANGUP_CAUSE_TO_END_REASON[0] = :hangup
|
|
@@ -29,6 +29,7 @@ module Punchblock
|
|
|
29
29
|
@answered = false
|
|
30
30
|
@pending_joins = {}
|
|
31
31
|
@progress_sent = false
|
|
32
|
+
@block_commands = false
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
def register_component(component)
|
|
@@ -69,7 +70,7 @@ module Punchblock
|
|
|
69
70
|
originate_action = Punchblock::Component::Asterisk::AMI::Action.new :name => 'Originate',
|
|
70
71
|
:params => params
|
|
71
72
|
originate_action.request!
|
|
72
|
-
translator.execute_global_command
|
|
73
|
+
translator.async.execute_global_command originate_action
|
|
73
74
|
dial_command.response = Ref.new :id => id
|
|
74
75
|
end
|
|
75
76
|
|
|
@@ -100,6 +101,7 @@ module Punchblock
|
|
|
100
101
|
|
|
101
102
|
case ami_event.name
|
|
102
103
|
when 'Hangup'
|
|
104
|
+
@block_commands = true
|
|
103
105
|
@components.dup.each_pair do |id, component|
|
|
104
106
|
safe_from_dead_actors do
|
|
105
107
|
component.call_ended if component.alive?
|
|
@@ -123,9 +125,9 @@ module Punchblock
|
|
|
123
125
|
send_end_event :error
|
|
124
126
|
end
|
|
125
127
|
when 'BridgeExec'
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
join_command = @pending_joins.delete ami_event['Channel1']
|
|
129
|
+
join_command ||= @pending_joins.delete ami_event['Channel2']
|
|
130
|
+
join_command.response = true if join_command
|
|
129
131
|
when 'Bridge'
|
|
130
132
|
other_call_channel = ([ami_event['Channel1'], ami_event['Channel2']] - [channel]).first
|
|
131
133
|
if other_call = translator.call_for_channel(other_call_channel)
|
|
@@ -154,6 +156,10 @@ module Punchblock
|
|
|
154
156
|
end
|
|
155
157
|
|
|
156
158
|
def execute_command(command)
|
|
159
|
+
if @block_commands
|
|
160
|
+
command.response = ProtocolError.new.setup :item_not_found, "Could not find a call with ID #{id}", id
|
|
161
|
+
return
|
|
162
|
+
end
|
|
157
163
|
if command.component_id
|
|
158
164
|
if component = component_with_id(command.component_id)
|
|
159
165
|
component.execute_command command
|
|
@@ -180,7 +186,7 @@ module Punchblock
|
|
|
180
186
|
end
|
|
181
187
|
when Command::Join
|
|
182
188
|
other_call = translator.call_with_id command.call_id
|
|
183
|
-
pending_joins[other_call.channel] = command
|
|
189
|
+
@pending_joins[other_call.channel] = command
|
|
184
190
|
send_agi_action 'EXEC Bridge', other_call.channel
|
|
185
191
|
when Command::Unjoin
|
|
186
192
|
other_call = translator.call_with_id command.call_id
|
|
@@ -217,6 +223,8 @@ module Punchblock
|
|
|
217
223
|
else
|
|
218
224
|
command.response = ProtocolError.new.setup 'command-not-acceptable', "Did not understand command for call #{id}", id
|
|
219
225
|
end
|
|
226
|
+
rescue Celluloid::DeadActorError
|
|
227
|
+
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
|
|
220
228
|
end
|
|
221
229
|
|
|
222
230
|
def send_agi_action(command, *params, &block)
|
|
@@ -276,7 +284,7 @@ module Punchblock
|
|
|
276
284
|
type.new_link(command, current_actor).tap do |component|
|
|
277
285
|
register_component component
|
|
278
286
|
component.internal = true if options[:internal]
|
|
279
|
-
component.execute
|
|
287
|
+
component.async.execute
|
|
280
288
|
end
|
|
281
289
|
end
|
|
282
290
|
|
|
@@ -16,14 +16,13 @@ module Punchblock
|
|
|
16
16
|
private
|
|
17
17
|
|
|
18
18
|
def register_dtmf_event_handler
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
component.process_dtmf! event['Digit'] if event['End'] == 'Yes'
|
|
19
|
+
call.register_handler :ami, :name => 'DTMF', [:[], 'End'] => 'Yes' do |event|
|
|
20
|
+
@recognizer << event['Digit']
|
|
22
21
|
end
|
|
23
22
|
end
|
|
24
23
|
|
|
25
24
|
def unregister_dtmf_event_handler
|
|
26
|
-
call.unregister_handler :ami, @dtmf_handler_id if instance_variable_defined?(:@dtmf_handler_id)
|
|
25
|
+
call.async.unregister_handler :ami, @dtmf_handler_id if instance_variable_defined?(:@dtmf_handler_id)
|
|
27
26
|
end
|
|
28
27
|
end
|
|
29
28
|
end
|
|
@@ -55,13 +55,13 @@ module Punchblock
|
|
|
55
55
|
playback opts
|
|
56
56
|
when :unimrcp
|
|
57
57
|
send_ref
|
|
58
|
-
@call.send_agi_action
|
|
59
|
-
output_component.send_complete_event
|
|
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
60
|
end
|
|
61
61
|
when :swift
|
|
62
62
|
send_ref
|
|
63
|
-
@call.send_agi_action
|
|
64
|
-
output_component.send_complete_event
|
|
63
|
+
@call.async.send_agi_action 'EXEC Swift', swift_doc do |complete_event|
|
|
64
|
+
output_component.async.send_complete_event success_reason
|
|
65
65
|
end
|
|
66
66
|
else
|
|
67
67
|
raise OptionError, 'The renderer foobar is unsupported.'
|
|
@@ -92,8 +92,8 @@ module Punchblock
|
|
|
92
92
|
|
|
93
93
|
def playback(path)
|
|
94
94
|
op = current_actor
|
|
95
|
-
@call.send_agi_action
|
|
96
|
-
op.send_complete_event
|
|
95
|
+
@call.async.send_agi_action 'EXEC Playback', path do |complete_event|
|
|
96
|
+
op.async.send_complete_event success_reason
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
|
|
@@ -31,16 +31,16 @@ module Punchblock
|
|
|
31
31
|
send_ref
|
|
32
32
|
|
|
33
33
|
if @component_node.start_beep
|
|
34
|
-
@call.send_agi_action
|
|
35
|
-
component.signal
|
|
34
|
+
@call.async.send_agi_action 'STREAM FILE', 'beep', '""' do
|
|
35
|
+
component.async.signal :beep_finished
|
|
36
36
|
end
|
|
37
37
|
wait :beep_finished
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
call.send_ami_action
|
|
40
|
+
call.async.send_ami_action 'Monitor', 'Channel' => call.channel, 'File' => filename, 'Format' => @format, 'Mix' => true
|
|
41
41
|
unless max_duration == -1
|
|
42
42
|
after max_duration/1000 do
|
|
43
|
-
call.send_ami_action
|
|
43
|
+
call.async.send_ami_action 'StopMonitor', 'Channel' => call.channel
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
rescue OptionError => e
|
|
@@ -52,17 +52,17 @@ module Punchblock
|
|
|
52
52
|
when Punchblock::Component::Stop
|
|
53
53
|
command.response = true
|
|
54
54
|
a = current_actor
|
|
55
|
-
call.send_ami_action
|
|
55
|
+
call.async.send_ami_action 'StopMonitor', 'Channel' => call.channel do |complete_event|
|
|
56
56
|
@complete_reason = stop_reason
|
|
57
57
|
end
|
|
58
58
|
when Punchblock::Component::Record::Pause
|
|
59
59
|
a = current_actor
|
|
60
|
-
call.send_ami_action
|
|
60
|
+
call.async.send_ami_action 'PauseMonitor', 'Channel' => call.channel do |complete_event|
|
|
61
61
|
command.response = true
|
|
62
62
|
end
|
|
63
63
|
when Punchblock::Component::Record::Resume
|
|
64
64
|
a = current_actor
|
|
65
|
-
call.send_ami_action
|
|
65
|
+
call.async.send_ami_action 'ResumeMonitor', 'Channel' => call.channel do |complete_event|
|
|
66
66
|
command.response = true
|
|
67
67
|
end
|
|
68
68
|
else
|
|
@@ -9,7 +9,7 @@ module Punchblock
|
|
|
9
9
|
module StopByRedirect
|
|
10
10
|
def execute_command(command)
|
|
11
11
|
return super unless command.is_a?(Punchblock::Component::Stop)
|
|
12
|
-
if @complete
|
|
12
|
+
if @complete
|
|
13
13
|
command.response = ProtocolError.new.setup 'component-already-stopped', "Component #{id} is already stopped", call_id, id
|
|
14
14
|
else
|
|
15
15
|
stop_by_redirect Punchblock::Event::Complete::Stop.new
|
|
@@ -20,9 +20,9 @@ module Punchblock
|
|
|
20
20
|
def stop_by_redirect(complete_reason)
|
|
21
21
|
component_actor = current_actor
|
|
22
22
|
call.register_handler :ami, lambda { |e| e['SubEvent'] == 'Start' }, :name => 'AsyncAGI' do |event|
|
|
23
|
-
component_actor.send_complete_event
|
|
23
|
+
component_actor.async.send_complete_event complete_reason
|
|
24
24
|
end
|
|
25
|
-
call.redirect_back
|
|
25
|
+
call.async.redirect_back
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
module Translator
|
|
5
|
+
class DTMFRecognizer
|
|
6
|
+
include Celluloid
|
|
7
|
+
|
|
8
|
+
finalizer :finalize
|
|
9
|
+
|
|
10
|
+
def initialize(responder, grammar, initial_timeout = nil, inter_digit_timeout = nil)
|
|
11
|
+
@responder = responder
|
|
12
|
+
self.grammar = grammar
|
|
13
|
+
self.initial_timeout = initial_timeout || -1
|
|
14
|
+
self.inter_digit_timeout = inter_digit_timeout || -1
|
|
15
|
+
|
|
16
|
+
@buffer = ""
|
|
17
|
+
|
|
18
|
+
begin_initial_timer @initial_timeout/1000 unless @initial_timeout == -1
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def <<(digit)
|
|
22
|
+
@buffer << digit
|
|
23
|
+
cancel_initial_timer
|
|
24
|
+
case (match = @grammar.match @buffer.dup)
|
|
25
|
+
when RubySpeech::GRXML::Match
|
|
26
|
+
@responder.match match.mode, match.confidence, match.utterance, match.interpretation
|
|
27
|
+
when RubySpeech::GRXML::NoMatch
|
|
28
|
+
@responder.nomatch
|
|
29
|
+
when RubySpeech::GRXML::PotentialMatch
|
|
30
|
+
reset_inter_digit_timer
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def finalize
|
|
35
|
+
cancel_initial_timer
|
|
36
|
+
cancel_inter_digit_timer
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def grammar=(other)
|
|
42
|
+
@grammar = RubySpeech::GRXML.import other.to_s
|
|
43
|
+
@grammar.inline!
|
|
44
|
+
@grammar.tokenize!
|
|
45
|
+
@grammar.normalize_whitespace
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def initial_timeout=(other)
|
|
49
|
+
raise OptionError, 'An initial timeout value that is negative (and not -1) is invalid.' if other < -1
|
|
50
|
+
@initial_timeout = other
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def inter_digit_timeout=(other)
|
|
54
|
+
raise OptionError, 'An inter-digit timeout value that is negative (and not -1) is invalid.' if other < -1
|
|
55
|
+
@inter_digit_timeout = other
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def begin_initial_timer(timeout)
|
|
59
|
+
@initial_timer = after timeout do
|
|
60
|
+
@responder.noinput
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def cancel_initial_timer
|
|
65
|
+
return unless instance_variable_defined?(:@initial_timer) && @initial_timer
|
|
66
|
+
@initial_timer.cancel
|
|
67
|
+
@initial_timer = nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def reset_inter_digit_timer
|
|
71
|
+
return if @inter_digit_timeout == -1
|
|
72
|
+
@inter_digit_timer ||= begin
|
|
73
|
+
after @inter_digit_timeout/1000 do
|
|
74
|
+
@responder.nomatch
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
@inter_digit_timer.reset
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def cancel_inter_digit_timer
|
|
81
|
+
return unless instance_variable_defined?(:@inter_digit_timer) && @inter_digit_timer
|
|
82
|
+
@inter_digit_timer.cancel
|
|
83
|
+
@inter_digit_timer = nil
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|