signalwire 2.1.3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/examples/relay/inbound_send_digits.rb +29 -0
- data/examples/relay/outbound_collect.rb +1 -1
- data/examples/relay/outbound_record.rb +1 -1
- data/examples/relay/outbound_tap.rb +1 -4
- data/lib/signalwire/blade/event_handler.rb +4 -1
- data/lib/signalwire/relay.rb +3 -0
- data/lib/signalwire/relay/calling/action/send_digits_action.rb +11 -0
- data/lib/signalwire/relay/calling/call.rb +130 -10
- data/lib/signalwire/relay/calling/call_convenience_methods.rb +37 -12
- data/lib/signalwire/relay/calling/call_detect_methods.rb +55 -45
- data/lib/signalwire/relay/calling/component.rb +8 -3
- data/lib/signalwire/relay/calling/component/detect.rb +43 -15
- data/lib/signalwire/relay/calling/component/send_digits.rb +45 -0
- data/lib/signalwire/relay/calling/result/send_digits_result.rb +6 -0
- data/lib/signalwire/relay/constants.rb +7 -0
- data/lib/signalwire/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 325c0f2a81d0a8486fdb356dc91c78284228b30440129ee2a60c3332b1e725b5
|
4
|
+
data.tar.gz: 1f5f8d9227de1b684f05e88d6b1b53246de7f29479c0e11cef94cd792dc8171c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6362ec6503c1a04505f72b13edfbb29c2bb7ca4002f7e13fd7926099dbac08142254d0a41447c96f2b44a54639fdfb367d12ab710c6a6e628c39143a823e9028
|
7
|
+
data.tar.gz: e8dce6ff15120bc77452aa97667a0aa468d923cd744e0e4ec15c74db0100424b321e9d86438710750d1cb4285f04db4aa3ab1f09f5e93352a2ebfa7c59874edd
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,15 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
5
5
|
|
6
6
|
## [Unreleased]
|
7
7
|
|
8
|
+
## [2.2.0] - 2019-09-09
|
9
|
+
### Added
|
10
|
+
- `detect_answering_machine` method with its `amd` alias
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
- Flatten parameter structures for better readability
|
14
|
+
- Log all exceptions as errors by default.
|
15
|
+
- Deprecated `detect_human` and `detect_machine` methods in favor of `detect_answering_machine`
|
16
|
+
|
8
17
|
## [2.1.3] - 2019-08-20
|
9
18
|
### Fixed
|
10
19
|
- Restore the correct parameter for the REST client space URL
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
4
|
+
%w[
|
5
|
+
bundler/setup
|
6
|
+
signalwire
|
7
|
+
].each { |f| require f }
|
8
|
+
|
9
|
+
# Setup your ENV with:
|
10
|
+
# SIGNALWIRE_PROJECT_KEY=YOUR_SIGNALWIRE_ACCOUNT_ID
|
11
|
+
# SIGNALWIRE_TOKEN=YOUR_SIGNALWIRE_ACCOUNT_TOKEN
|
12
|
+
#
|
13
|
+
Signalwire::Logger.logger.level = ::Logger::DEBUG
|
14
|
+
|
15
|
+
class MyConsumer < Signalwire::Relay::Consumer
|
16
|
+
contexts ['incoming']
|
17
|
+
|
18
|
+
def on_incoming_call(call)
|
19
|
+
call.answer
|
20
|
+
call.send_digits "1234"
|
21
|
+
|
22
|
+
call.hangup
|
23
|
+
rescue StandardError => e
|
24
|
+
logger.error e.inspect
|
25
|
+
logger.error e.backtrace
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
MyConsumer.new.run
|
@@ -13,7 +13,7 @@ class OutboundConsumer < Signalwire::Relay::Consumer
|
|
13
13
|
def ready
|
14
14
|
dial_result = client.calling.new_call(from: ENV['FROM_NUMBER'], to: ENV['TO_NUMBER']).dial
|
15
15
|
collect_params = { "initial_timeout": 10.0, "digits": { "max": 1, "digit_timeout": 5.0 } }
|
16
|
-
result = dial_result.call.prompt_tts collect: collect_params, text: 'how many hamburgers would you like to order?'
|
16
|
+
result = dial_result.call.prompt_tts collect: collect_params, text: 'how many hamburgers would you like to order?'
|
17
17
|
|
18
18
|
dial_result.call.play_tts text: "You ordered #{result.result} hamburgers. Thank you!"
|
19
19
|
dial_result.call.hangup
|
@@ -15,7 +15,7 @@ class OutboundConsumer < Signalwire::Relay::Consumer
|
|
15
15
|
call = client.calling.new_call(from: ENV['FROM_NUMBER'], to: ENV['TO_NUMBER'])
|
16
16
|
call.dial
|
17
17
|
call.play_tts text: 'please leave your message after the beep. Press pound when done.'
|
18
|
-
result = call.record(
|
18
|
+
result = call.record(beep: true, terminators: "#")
|
19
19
|
call.play_tts text: 'you said:'
|
20
20
|
call.play_audio result.url
|
21
21
|
call.hangup
|
@@ -14,11 +14,8 @@ class OutboundConsumer < Signalwire::Relay::Consumer
|
|
14
14
|
logger.info 'Dialing out'
|
15
15
|
call = client.calling.new_call(from: ENV['FROM_NUMBER'], to: ENV['TO_NUMBER'])
|
16
16
|
call.dial
|
17
|
-
|
18
|
-
tap_arguments = { type: "audio", params: { direction: "listen" } }
|
19
|
-
device_arguments = { type: "rtp", params: { addr: "127.0.0.1", port: 1234 } }
|
20
17
|
|
21
|
-
call.tap_media(
|
18
|
+
call.tap_media(audio_direction: "both", target_addr: "127.0.0.1", target_port: 1234)
|
22
19
|
|
23
20
|
call.hangup
|
24
21
|
rescue StandardError => e
|
@@ -9,7 +9,10 @@ module Signalwire::Blade
|
|
9
9
|
alias once register_tmp_handler
|
10
10
|
|
11
11
|
def broadcast(event_type, event)
|
12
|
-
trigger_handler event_type, event, broadcast: true
|
12
|
+
trigger_handler event_type, event, broadcast: true, exception_callback: Proc.new { |e|
|
13
|
+
logger.error "#{e.class}: #{e.message}"
|
14
|
+
logger.error e.backtrace.join("\n")
|
15
|
+
}
|
13
16
|
end
|
14
17
|
end
|
15
18
|
end
|
data/lib/signalwire/relay.rb
CHANGED
@@ -24,6 +24,7 @@ require 'signalwire/relay/calling/action/prompt_action'
|
|
24
24
|
require 'signalwire/relay/calling/action/record_action'
|
25
25
|
require 'signalwire/relay/calling/action/fax_action'
|
26
26
|
require 'signalwire/relay/calling/action/tap_action'
|
27
|
+
require 'signalwire/relay/calling/action/send_digits_action'
|
27
28
|
|
28
29
|
require 'signalwire/relay/calling/result'
|
29
30
|
require 'signalwire/relay/calling/result/answer_result'
|
@@ -36,6 +37,7 @@ require 'signalwire/relay/calling/result/prompt_result'
|
|
36
37
|
require 'signalwire/relay/calling/result/record_result'
|
37
38
|
require 'signalwire/relay/calling/result/fax_result'
|
38
39
|
require 'signalwire/relay/calling/result/tap_result'
|
40
|
+
require 'signalwire/relay/calling/result/send_digits_result'
|
39
41
|
|
40
42
|
require 'signalwire/relay/calling/component'
|
41
43
|
require 'signalwire/relay/calling/control_component'
|
@@ -52,6 +54,7 @@ require 'signalwire/relay/calling/component/base_fax'
|
|
52
54
|
require 'signalwire/relay/calling/component/fax_send'
|
53
55
|
require 'signalwire/relay/calling/component/fax_receive'
|
54
56
|
require 'signalwire/relay/calling/component/tap'
|
57
|
+
require 'signalwire/relay/calling/component/send_digits'
|
55
58
|
|
56
59
|
require 'signalwire/relay/messaging'
|
57
60
|
require 'signalwire/relay/messaging/message'
|
@@ -11,6 +11,13 @@ module Signalwire::Relay::Calling
|
|
11
11
|
include Signalwire::Relay::Calling::CallDetectMethods
|
12
12
|
extend Forwardable
|
13
13
|
|
14
|
+
extend Gem::Deprecate
|
15
|
+
DETECT_DEPRECATE_MONTH = 10
|
16
|
+
deprecate :detect_human, :amd, 2019, DETECT_DEPRECATE_MONTH
|
17
|
+
deprecate :detect_human!, :amd!, 2019, DETECT_DEPRECATE_MONTH
|
18
|
+
deprecate :detect_machine, :amd, 2019, DETECT_DEPRECATE_MONTH
|
19
|
+
deprecate :detect_machine!, :amd!, 2019, DETECT_DEPRECATE_MONTH
|
20
|
+
|
14
21
|
attr_reader :device, :type, :node_id, :context, :from, :to,
|
15
22
|
:timeout, :tag, :client, :state, :previous_state, :components,
|
16
23
|
:busy, :failed, :peer_call
|
@@ -117,7 +124,12 @@ module Signalwire::Relay::Calling
|
|
117
124
|
PlayAction.new(component: play_component)
|
118
125
|
end
|
119
126
|
|
120
|
-
def prompt(collect_p = nil, play_p = nil,
|
127
|
+
def prompt(collect_p = nil, play_p = nil, **args)
|
128
|
+
|
129
|
+
collect = args.delete(:collect)
|
130
|
+
play = args.delete(:play)
|
131
|
+
|
132
|
+
collect = compile_collect_arguments(args) if collect.nil? && collect_p.nil?
|
121
133
|
set_parameters(binding, %i{collect play}, %i{collect play})
|
122
134
|
|
123
135
|
component = Prompt.new(call: self, collect: collect, play: play)
|
@@ -127,7 +139,8 @@ module Signalwire::Relay::Calling
|
|
127
139
|
PromptResult.new(component: component)
|
128
140
|
end
|
129
141
|
|
130
|
-
def prompt!(collect_p = nil, play_p = nil,
|
142
|
+
def prompt!(collect_p = nil, play_p = nil, **args)
|
143
|
+
collect = compile_collect_arguments(args) if collect.nil? && collect_p.nil?
|
131
144
|
set_parameters(binding, %i{collect play}, %i{collect play})
|
132
145
|
|
133
146
|
component = Prompt,new(call: self, collect: collect, play: play)
|
@@ -147,13 +160,47 @@ module Signalwire::Relay::Calling
|
|
147
160
|
ConnectAction.new(component: component)
|
148
161
|
end
|
149
162
|
|
150
|
-
def record(
|
163
|
+
def record(audio: nil, type: 'audio', beep: false, format: 'mp3', stereo: false, direction: 'speak', initial_timeout: 5, end_silence_timeout: 1, terminators: "#*")
|
164
|
+
if audio.nil?
|
165
|
+
record_object = {
|
166
|
+
"#{type}":
|
167
|
+
{
|
168
|
+
beep: beep,
|
169
|
+
format: format,
|
170
|
+
stereo: stereo,
|
171
|
+
direction: direction,
|
172
|
+
initial_timeout: initial_timeout,
|
173
|
+
end_silence_timeout: end_silence_timeout,
|
174
|
+
terminators: terminators
|
175
|
+
}
|
176
|
+
}
|
177
|
+
else
|
178
|
+
record_object = { "#{type}": audio }
|
179
|
+
end
|
180
|
+
|
151
181
|
component = Record.new(call: self, record: record_object)
|
152
182
|
component.wait_for(Relay::CallRecordState::NO_INPUT, Relay::CallRecordState::FINISHED)
|
153
183
|
RecordResult.new(component: component)
|
154
184
|
end
|
155
185
|
|
156
|
-
def record!(
|
186
|
+
def record!(audio: nil, type: 'audio', beep: false, format: 'mp3', stereo: false, direction: 'speak', initial_timeout: 5, end_silence_timeout: 1, terminators: "#*")
|
187
|
+
if audio.nil?
|
188
|
+
record_object = {
|
189
|
+
"#{type}":
|
190
|
+
{
|
191
|
+
beep: beep,
|
192
|
+
format: format,
|
193
|
+
stereo: stereo,
|
194
|
+
direction: direction,
|
195
|
+
initial_timeout: initial_timeout,
|
196
|
+
end_silence_timeout: end_silence_timeout,
|
197
|
+
terminators: terminators
|
198
|
+
}
|
199
|
+
}
|
200
|
+
else
|
201
|
+
record_object = { "#{type}": audio }
|
202
|
+
end
|
203
|
+
|
157
204
|
component = Record.new(call: self, record: record_object)
|
158
205
|
component.execute
|
159
206
|
RecordAction.new(component: component)
|
@@ -183,30 +230,54 @@ module Signalwire::Relay::Calling
|
|
183
230
|
FaxAction.new(component: component)
|
184
231
|
end
|
185
232
|
|
186
|
-
def fax_send(document
|
233
|
+
def fax_send(document:, identity: nil, header: nil)
|
187
234
|
component = Signalwire::Relay::Calling::FaxSend.new(call: self, document: document, identity: identity, header: header)
|
188
235
|
component.wait_for(Relay::CallFaxState::ERROR, Relay::CallFaxState::FINISHED)
|
189
236
|
FaxResult.new(component: component)
|
190
237
|
end
|
191
238
|
|
192
|
-
def fax_send!(document
|
239
|
+
def fax_send!(document:, identity: nil, header: nil)
|
193
240
|
component = Signalwire::Relay::Calling::FaxSend.new(call: self, document: document, identity: identity, header: header)
|
194
241
|
component.execute
|
195
242
|
FaxAction.new(component: component)
|
196
243
|
end
|
197
244
|
|
198
|
-
def tap_media(
|
245
|
+
def tap_media(**args)
|
246
|
+
tap = args.delete(:tap)
|
247
|
+
device = args.delete(:device)
|
248
|
+
|
249
|
+
tap = compile_tap_arguments(args) if tap.nil?
|
250
|
+
device = compile_tap_device_arguments(args) if device.nil?
|
251
|
+
|
199
252
|
component = Signalwire::Relay::Calling::Tap.new(call: self, tap: tap, device: device)
|
200
253
|
component.wait_for(Relay::CallTapState::FINISHED)
|
201
254
|
TapResult.new(component: component)
|
202
255
|
end
|
203
256
|
|
204
|
-
def tap_media!(
|
257
|
+
def tap_media!(**args)
|
258
|
+
tap = args.delete(:tap)
|
259
|
+
device = args.delete(:device)
|
260
|
+
|
261
|
+
tap = compile_tap_arguments(args) if tap.nil?
|
262
|
+
device = compile_tap_device_arguments(args) if device.nil?
|
263
|
+
|
205
264
|
component = Signalwire::Relay::Calling::Tap.new(call: self, tap: tap, device: device)
|
206
265
|
component.execute
|
207
266
|
TapAction.new(component: component)
|
208
267
|
end
|
209
268
|
|
269
|
+
def send_digits(digits)
|
270
|
+
component = Signalwire::Relay::Calling::SendDigits.new(call: self, digits: digits)
|
271
|
+
component.wait_for(Relay::CallSendDigitsState::FINISHED)
|
272
|
+
SendDigitsResult.new(component: component)
|
273
|
+
end
|
274
|
+
|
275
|
+
def send_digits!(digits)
|
276
|
+
component = Signalwire::Relay::Calling::SendDigits.new(call: self, digits: digits)
|
277
|
+
component.execute
|
278
|
+
SendDigitsAction.new(component: component)
|
279
|
+
end
|
280
|
+
|
210
281
|
def wait_for(*events)
|
211
282
|
events = [Relay::CallState::ENDED] if events.empty?
|
212
283
|
|
@@ -226,7 +297,7 @@ module Signalwire::Relay::Calling
|
|
226
297
|
|
227
298
|
def terminate_components(params = {})
|
228
299
|
@components.each do |comp|
|
229
|
-
comp.terminate(params) unless
|
300
|
+
comp.terminate(params) unless comp.completed
|
230
301
|
end
|
231
302
|
end
|
232
303
|
|
@@ -257,8 +328,57 @@ module Signalwire::Relay::Calling
|
|
257
328
|
passed_binding.local_variable_set(x, passed_binding.local_variable_get(x) || passed_binding.local_variable_get("#{x}_p"))
|
258
329
|
end
|
259
330
|
mandatory_keys.each do |x|
|
260
|
-
raise ArgumentError if passed_binding.local_variable_get(x).nil?
|
331
|
+
raise ArgumentError, "The #{x} argument must be provided" if passed_binding.local_variable_get(x).nil?
|
261
332
|
end
|
262
333
|
end
|
334
|
+
|
335
|
+
def compile_tap_arguments(args)
|
336
|
+
tap = { params: {} }
|
337
|
+
tap[:type] = args[:media_type] || 'audio'
|
338
|
+
tap[:params][:direction] = args[:audio_direction] if args[:audio_direction]
|
339
|
+
tap[:params][:rate] = args[:rate] if args[:rate]
|
340
|
+
tap[:params][:codec] = args[:codec] if args[:codec]
|
341
|
+
tap
|
342
|
+
end
|
343
|
+
|
344
|
+
def compile_tap_device_arguments(args)
|
345
|
+
device = { params: {} }
|
346
|
+
device[:type] = args[:target_type] || 'rtp'
|
347
|
+
device[:params][:addr] = args[:target_addr] if args[:target_addr]
|
348
|
+
device[:params][:port] = args[:target_port] if args[:target_port]
|
349
|
+
device[:params][:ptime] = args[:target_ptime] if args[:target_ptime]
|
350
|
+
device[:params][:uri] = args[:target_uri] if args[:target_uri]
|
351
|
+
device
|
352
|
+
end
|
353
|
+
|
354
|
+
def compile_collect_arguments(args)
|
355
|
+
generic_fields = %i{initial_timeout partial_results}
|
356
|
+
digit_fields = %i{digits_max digits_terminators digits_timeout}
|
357
|
+
speech_fields = %i{speech_timeout speech_language speech_hints end_silence_timeout}
|
358
|
+
has_digits = (digit_fields & args.keys).any?
|
359
|
+
has_speech = (speech_fields & args.keys).any?
|
360
|
+
|
361
|
+
collect = {}
|
362
|
+
generic_fields.each { |gf| collect[gf] = args[gf] if args[gf] }
|
363
|
+
|
364
|
+
if has_digits
|
365
|
+
digits_obj = {}
|
366
|
+
digits_obj[:max] = args[:digits_max] if args[:digits_max]
|
367
|
+
digits_obj[:terminators] = args[:digits_terminators] if args[:digits_terminators]
|
368
|
+
digits_obj[:digit_timeout] = args[:digits_timeout] if args[:digits_timeout]
|
369
|
+
collect[:digits] = digits_obj
|
370
|
+
end
|
371
|
+
|
372
|
+
if has_speech
|
373
|
+
speech_obj = {}
|
374
|
+
speech_obj[:timeout] = args[:speech_timeout] if args[:speech_timeout]
|
375
|
+
speech_obj[:language] = args[:speech_language] if args[:speech_language]
|
376
|
+
speech_obj[:hints] = args[:speech_hints] if args[:speech_hints]
|
377
|
+
speech_obj[:end_silence_timeout] = args[:end_silence_timeout] if args[:end_silence_timeout]
|
378
|
+
collect[:digits] = digits_obj
|
379
|
+
end
|
380
|
+
|
381
|
+
collect
|
382
|
+
end
|
263
383
|
end
|
264
384
|
end
|
@@ -27,39 +27,64 @@ module Signalwire::Relay::Calling
|
|
27
27
|
play! tts_payload(text, language, gender)
|
28
28
|
end
|
29
29
|
|
30
|
-
def prompt_audio(collect_p = nil, url_p = nil,
|
30
|
+
def prompt_audio(collect_p = nil, url_p = nil, **args)
|
31
|
+
collect = args.delete(:collect)
|
32
|
+
url = args.delete(:url)
|
33
|
+
collect = compile_collect_arguments(args) if collect.nil? && collect_p.nil?
|
31
34
|
set_parameters(binding, %i{collect url}, %i{collect url})
|
32
35
|
|
33
|
-
prompt(collect, audio_payload(url))
|
36
|
+
prompt(collect: collect, play: audio_payload(url))
|
34
37
|
end
|
35
38
|
|
36
|
-
def prompt_audio!(collect_p = nil, url_p = nil,
|
39
|
+
def prompt_audio!(collect_p = nil, url_p = nil, **args)
|
40
|
+
collect = args.delete(:collect)
|
41
|
+
url = args.delete(:url)
|
42
|
+
collect = compile_collect_arguments(args) if collect.nil? && collect_p.nil?
|
37
43
|
set_parameters(binding, %i{collect url}, %i{collect url})
|
38
44
|
|
39
|
-
prompt!(collect, audio_payload(url))
|
45
|
+
prompt!(collect: collect, play: audio_payload(url))
|
40
46
|
end
|
41
47
|
|
42
|
-
def prompt_silence(collect_p = nil, duration_p = nil,
|
48
|
+
def prompt_silence(collect_p = nil, duration_p = nil, **args)
|
49
|
+
collect = args.delete(:collect)
|
50
|
+
duration = args.delete(:duration)
|
51
|
+
collect = compile_collect_arguments(args) if collect.nil? && collect_p.nil?
|
43
52
|
set_parameters(binding, %i{collect duration}, %i{collect duration})
|
44
53
|
|
45
|
-
prompt(collect, silence_payload(duration))
|
54
|
+
prompt(collect: collect, play: silence_payload(duration))
|
46
55
|
end
|
47
56
|
|
48
|
-
def prompt_silence!(collect_p = nil, duration_p = nil,
|
57
|
+
def prompt_silence!(collect_p = nil, duration_p = nil, **args)
|
58
|
+
collect = args.delete(:collect)
|
59
|
+
duration = args.delete(:duration)
|
60
|
+
collect = compile_collect_arguments(args) if collect.nil? && collect_p.nil?
|
49
61
|
set_parameters(binding, %i{collect duration}, %i{collect duration})
|
50
62
|
|
51
|
-
prompt!(collect, silence_payload(duration))
|
63
|
+
prompt!(collect: collect, play: silence_payload(duration))
|
52
64
|
end
|
53
65
|
|
54
|
-
def prompt_tts(collect_p = nil, text_p = nil, language_p=Relay::DEFAULT_LANGUAGE, gender_p=Relay::DEFAULT_GENDER,
|
66
|
+
def prompt_tts(collect_p = nil, text_p = nil, language_p=Relay::DEFAULT_LANGUAGE, gender_p=Relay::DEFAULT_GENDER, **args)
|
67
|
+
collect = args.delete(:collect)
|
68
|
+
text = args.delete(:text)
|
69
|
+
language = args.delete(:language) || Relay::DEFAULT_LANGUAGE
|
70
|
+
gender = args.delete(:gender) || Relay::DEFAULT_GENDER
|
71
|
+
collect = compile_collect_arguments(args) if collect.nil? && collect_p.nil?
|
72
|
+
|
55
73
|
set_parameters(binding, %i{collect text language gender}, %i{collect text})
|
56
|
-
|
74
|
+
|
75
|
+
prompt(collect: collect, play: tts_payload(text, language, gender))
|
57
76
|
end
|
58
77
|
|
59
|
-
def prompt_tts!(collect_p = nil, text_p = nil, language_p=Relay::DEFAULT_LANGUAGE, gender_p=Relay::DEFAULT_GENDER,
|
78
|
+
def prompt_tts!(collect_p = nil, text_p = nil, language_p=Relay::DEFAULT_LANGUAGE, gender_p=Relay::DEFAULT_GENDER, **args)
|
79
|
+
collect = args.delete(:collect)
|
80
|
+
text = args.delete(:text)
|
81
|
+
language = args.delete(:language) || Relay::DEFAULT_LANGUAGE
|
82
|
+
gender = args.delete(:gender) || Relay::DEFAULT_GENDER
|
83
|
+
collect = compile_collect_arguments(args) if collect.nil? && collect_p.nil?
|
84
|
+
|
60
85
|
set_parameters(binding, %i{collect text language gender}, %i{collect text})
|
61
86
|
|
62
|
-
prompt!(collect, tts_payload(text, language, gender))
|
87
|
+
prompt!(collect: collect, play: tts_payload(text, language, gender))
|
63
88
|
end
|
64
89
|
|
65
90
|
def wait_for_ringing
|
@@ -1,110 +1,120 @@
|
|
1
1
|
module Signalwire::Relay::Calling
|
2
2
|
module CallDetectMethods
|
3
|
-
|
4
|
-
|
5
|
-
component
|
3
|
+
|
4
|
+
def detect(type:, **args)
|
5
|
+
component = build_detect_component(type, args)
|
6
|
+
component.wait_for(Relay::CallDetectState::MACHINE, Relay::CallDetectState::HUMAN,
|
7
|
+
Relay::CallDetectState::UNKNOWN, Relay::CallDetectState::CED, Relay::CallDetectState::CNG)
|
6
8
|
DetectResult.new(component: component)
|
7
9
|
end
|
8
10
|
|
9
|
-
def detect!(
|
10
|
-
component =
|
11
|
+
def detect!(type:, **args)
|
12
|
+
component = build_detect_component(type, args)
|
11
13
|
component.execute
|
12
14
|
DetectAction.new(component: component)
|
13
15
|
end
|
14
16
|
|
17
|
+
def detect_answering_machine(**args)
|
18
|
+
detect(type: :machine, **args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def detect_answering_machine!(**args)
|
22
|
+
detect!(type: :machine, **args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def amd(**args)
|
26
|
+
detect(type: :machine, **args)
|
27
|
+
end
|
28
|
+
|
29
|
+
def amd!(**args)
|
30
|
+
detect!(type: :machine, **args)
|
31
|
+
end
|
32
|
+
|
33
|
+
# deprecated since version 2.2. Will be deleted in version 3.0.
|
15
34
|
def detect_human(params: {}, timeout: Relay::DEFAULT_CALL_TIMEOUT)
|
16
35
|
detect = {
|
17
36
|
type: Relay::CallDetectType::MACHINE,
|
18
37
|
params: params
|
19
38
|
}
|
20
39
|
component = Signalwire::Relay::Calling::Detect.new(call: self, detect: detect, timeout: timeout)
|
21
|
-
component.wait_for(Relay::CallDetectState::
|
40
|
+
component.wait_for(Relay::CallDetectState::MACHINE, Relay::CallDetectState::UNKNOWN, Relay::CallDetectState::HUMAN)
|
22
41
|
DetectResult.new(component: component)
|
23
42
|
end
|
24
43
|
|
44
|
+
# deprecated since version 2.2. Will be deleted in version 3.0.
|
25
45
|
def detect_human!(params: {}, timeout: Relay::DEFAULT_CALL_TIMEOUT)
|
26
46
|
detect = {
|
27
47
|
type: Relay::CallDetectType::MACHINE,
|
28
48
|
params: params
|
29
49
|
}
|
30
50
|
component = Signalwire::Relay::Calling::Detect.new(call: self, detect: detect, timeout: timeout)
|
31
|
-
component.setup_waiting_events([Relay::CallDetectState::
|
51
|
+
component.setup_waiting_events([Relay::CallDetectState::MACHINE, Relay::CallDetectState::UNKNOWN, Relay::CallDetectState::HUMAN])
|
32
52
|
component.execute
|
33
53
|
DetectAction.new(component: component)
|
34
54
|
end
|
35
55
|
|
56
|
+
# deprecated since version 2.2. Will be deleted in version 3.0.
|
36
57
|
def detect_machine(params: {}, timeout: Relay::DEFAULT_CALL_TIMEOUT)
|
37
58
|
detect = {
|
38
59
|
type: Relay::CallDetectType::MACHINE,
|
39
60
|
params: params
|
40
61
|
}
|
41
62
|
component = Signalwire::Relay::Calling::Detect.new(call: self, detect: detect, timeout: timeout)
|
42
|
-
component.wait_for(Relay::CallDetectState::
|
43
|
-
Relay::CallDetectState::MACHINE, Relay::CallDetectState::READY,
|
44
|
-
Relay::CallDetectState::NOT_READY)
|
63
|
+
component.wait_for(Relay::CallDetectState::MACHINE, Relay::CallDetectState::UNKNOWN, Relay::CallDetectState::HUMAN)
|
45
64
|
DetectResult.new(component: component)
|
46
65
|
end
|
47
66
|
|
67
|
+
# deprecated since version 2.2. Will be deleted in version 3.0.
|
48
68
|
def detect_machine!(params: {}, timeout: Relay::DEFAULT_CALL_TIMEOUT)
|
49
69
|
detect = {
|
50
70
|
type: Relay::CallDetectType::MACHINE,
|
51
71
|
params: params
|
52
72
|
}
|
53
73
|
component = Signalwire::Relay::Calling::Detect.new(call: self, detect: detect, timeout: timeout)
|
54
|
-
component.setup_waiting_events([Relay::CallDetectState::
|
55
|
-
Relay::CallDetectState::MACHINE, Relay::CallDetectState::READY,
|
56
|
-
Relay::CallDetectState::NOT_READY])
|
74
|
+
component.setup_waiting_events([Relay::CallDetectState::MACHINE, Relay::CallDetectState::UNKNOWN, Relay::CallDetectState::HUMAN])
|
57
75
|
component.execute
|
58
76
|
DetectAction.new(component: component)
|
59
77
|
end
|
60
78
|
|
61
79
|
def detect_fax(tone: nil, timeout: Relay::DEFAULT_CALL_TIMEOUT)
|
62
|
-
detect,
|
63
|
-
|
64
|
-
component = Signalwire::Relay::Calling::Detect.new(call: self, detect: detect, timeout: timeout)
|
65
|
-
component.wait_for(*events)
|
66
|
-
DetectResult.new(component: component)
|
80
|
+
detect(type: :fax, tone: tone, timeout: timeout)
|
67
81
|
end
|
68
82
|
|
69
83
|
def detect_fax!(tone: nil, timeout: Relay::DEFAULT_CALL_TIMEOUT)
|
70
|
-
detect,
|
71
|
-
component = Signalwire::Relay::Calling::Detect.new(call: self, detect: detect, timeout: timeout)
|
72
|
-
component.setup_waiting_events(events)
|
73
|
-
component.execute
|
74
|
-
DetectAction.new(component: component)
|
84
|
+
detect!(type: :fax, tone: tone, timeout: timeout)
|
75
85
|
end
|
76
86
|
|
77
87
|
def detect_digit(digits: nil, timeout: Relay::DEFAULT_CALL_TIMEOUT)
|
78
|
-
detect
|
79
|
-
type: Relay::CallDetectType::DIGIT,
|
80
|
-
params: {}
|
81
|
-
}
|
82
|
-
detect[:params][:digits] = digits if digits
|
83
|
-
detect(detect: detect, timeout: timeout)
|
88
|
+
detect(type: :digit, digits: digits, timeout: timeout)
|
84
89
|
end
|
85
90
|
|
86
91
|
def detect_digit!(digits: nil, timeout: Relay::DEFAULT_CALL_TIMEOUT)
|
87
|
-
detect
|
88
|
-
type: Relay::CallDetectType::DIGIT,
|
89
|
-
params: {}
|
90
|
-
}
|
91
|
-
detect[:params][:digits] = digits if digits
|
92
|
-
detect!(detect: detect, timeout: timeout)
|
92
|
+
detect!(type: :digit, digits: digits, timeout: timeout)
|
93
93
|
end
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
detect =
|
95
|
+
private
|
96
|
+
|
97
|
+
def build_detect_component(type, args)
|
98
|
+
detect = args.delete(:detect)
|
99
|
+
timeout = args.delete(:timeout) || Relay::DEFAULT_CALL_TIMEOUT
|
100
|
+
wait_for_beep = args.delete(:wait_for_beep)
|
99
101
|
|
100
|
-
if
|
101
|
-
detect
|
102
|
-
|
103
|
-
|
104
|
-
|
102
|
+
if detect.nil?
|
103
|
+
detect = { params: {} }
|
104
|
+
detect[:type] = type.to_sym || :machine
|
105
|
+
|
106
|
+
if detect[:type] == :machine
|
107
|
+
%i{initial_timeout end_silence_timeout machine_voice_threshold machine_words_threshold}.each do |key|
|
108
|
+
detect[:params][key] = args[key] if args[key]
|
109
|
+
end
|
110
|
+
elsif detect[:type] == :fax
|
111
|
+
detect[:params][:tone] = args[:tone]
|
112
|
+
elsif detect[:type] == :digit
|
113
|
+
detect[:params][:digits] = args[:digits]
|
114
|
+
end
|
105
115
|
end
|
106
116
|
|
107
|
-
|
117
|
+
component = Signalwire::Relay::Calling::Detect.new(call: self, detect: detect, wait_for_beep: wait_for_beep, timeout: timeout)
|
108
118
|
end
|
109
119
|
end
|
110
120
|
end
|
@@ -2,13 +2,14 @@
|
|
2
2
|
|
3
3
|
module Signalwire::Relay::Calling
|
4
4
|
class Component
|
5
|
+
include Signalwire::Logger
|
5
6
|
attr_reader :completed, :state, :successful, :event, :execute_result, :call
|
6
7
|
|
7
8
|
def initialize(call:)
|
8
9
|
@call = call
|
9
10
|
@completed = false
|
10
11
|
@successful = false
|
11
|
-
|
12
|
+
@events_waiting = []
|
12
13
|
@call.register_component(self)
|
13
14
|
end
|
14
15
|
|
@@ -69,7 +70,7 @@ module Signalwire::Relay::Calling
|
|
69
70
|
@successful = false
|
70
71
|
@state = 'failed'
|
71
72
|
@event = event if event
|
72
|
-
blocker&.reject
|
73
|
+
blocker&.reject false
|
73
74
|
end
|
74
75
|
|
75
76
|
def setup_waiting_events(events)
|
@@ -87,6 +88,10 @@ module Signalwire::Relay::Calling
|
|
87
88
|
blocker.wait
|
88
89
|
end
|
89
90
|
|
91
|
+
def has_blocker?
|
92
|
+
!@blocker.nil?
|
93
|
+
end
|
94
|
+
|
90
95
|
# This is the most important method to implement in a subclass
|
91
96
|
#
|
92
97
|
def notification_handler(_event)
|
@@ -103,7 +108,7 @@ module Signalwire::Relay::Calling
|
|
103
108
|
end
|
104
109
|
|
105
110
|
def unblock(value)
|
106
|
-
blocker&.resolve value
|
111
|
+
blocker&.resolve value if has_blocker? && blocker.pending?
|
107
112
|
end
|
108
113
|
|
109
114
|
attr_reader :blocker
|
@@ -4,11 +4,16 @@ module Signalwire::Relay::Calling
|
|
4
4
|
class Detect < ControlComponent
|
5
5
|
attr_reader :result, :type
|
6
6
|
|
7
|
-
|
7
|
+
FINISHED_EVENTS = [Relay::CallDetectState::FINISHED, Relay::CallDetectState::ERROR]
|
8
|
+
MACHINE_EVENTS = [Relay::CallDetectState::READY, Relay::CallDetectState::NOT_READY]
|
9
|
+
|
10
|
+
def initialize(call:, detect:, wait_for_beep: false, timeout: 30)
|
8
11
|
super(call: call)
|
9
12
|
@detect = detect
|
10
13
|
@timeout = timeout
|
14
|
+
@wait_for_beep = wait_for_beep
|
11
15
|
@received_events = Concurrent::Array.new
|
16
|
+
@waiting_for_ready = false
|
12
17
|
end
|
13
18
|
|
14
19
|
def method
|
@@ -30,33 +35,56 @@ module Signalwire::Relay::Calling
|
|
30
35
|
end
|
31
36
|
|
32
37
|
def notification_handler(event)
|
33
|
-
|
34
|
-
@type =
|
35
|
-
params =
|
38
|
+
detect_result = event.call_params[:detect]
|
39
|
+
@type = detect_result[:type]
|
40
|
+
params = detect_result[:params]
|
36
41
|
res_event = params[:event]
|
37
42
|
@state = res_event
|
38
43
|
|
39
|
-
if @state
|
40
|
-
@received_events << res_event
|
41
|
-
end
|
44
|
+
return complete(event) if FINISHED_EVENTS.include?(@state) || @type == Relay::CallDetectType::DIGIT
|
42
45
|
|
43
|
-
|
46
|
+
if has_blocker?
|
47
|
+
@received_events << @state
|
48
|
+
return
|
49
|
+
end
|
44
50
|
|
45
|
-
if @
|
46
|
-
|
47
|
-
@result = @received_events.join(' ')
|
48
|
-
@event = event
|
49
|
-
unblock(event)
|
51
|
+
if @waiting_for_ready
|
52
|
+
return (@state == Relay::CallDetectState::READY ? complete(event) : nil)
|
50
53
|
end
|
51
54
|
|
55
|
+
if (@wait_for_beep && @state == Relay::CallDetectState::MACHINE)
|
56
|
+
@waiting_for_ready = true
|
57
|
+
return
|
58
|
+
end
|
59
|
+
|
60
|
+
check_for_waiting_events
|
52
61
|
broadcast_event(event)
|
53
|
-
# This component has complex logic so we handle it separately
|
54
|
-
# check_for_waiting_events
|
55
62
|
end
|
56
63
|
|
57
64
|
def broadcast_event(event)
|
58
65
|
@call.broadcast "detect_#{@state}".to_sym, event
|
59
66
|
@call.broadcast :detect_state_change, event
|
60
67
|
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def complete(event)
|
72
|
+
@completed = true
|
73
|
+
@event = event
|
74
|
+
|
75
|
+
if has_blocker?
|
76
|
+
@successful = !FINISHED_EVENTS.include?(@state)
|
77
|
+
|
78
|
+
if MACHINE_EVENTS.include?(@state)
|
79
|
+
@result = Relay::CallDetectState::MACHINE
|
80
|
+
else
|
81
|
+
@result = @state
|
82
|
+
end
|
83
|
+
unblock(event)
|
84
|
+
else
|
85
|
+
@result = @received_events.join(',')
|
86
|
+
@successful = @state != Relay::CallDetectState::ERROR
|
87
|
+
end
|
88
|
+
end
|
61
89
|
end
|
62
90
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Signalwire::Relay::Calling
|
2
|
+
class SendDigits < ControlComponent
|
3
|
+
def initialize(call:, digits:)
|
4
|
+
super(call: call)
|
5
|
+
@digits = digits
|
6
|
+
end
|
7
|
+
|
8
|
+
def method
|
9
|
+
Relay::ComponentMethod::SEND_DIGITS
|
10
|
+
end
|
11
|
+
|
12
|
+
def event_type
|
13
|
+
Relay::CallNotification::SEND_DIGITS
|
14
|
+
end
|
15
|
+
|
16
|
+
def inner_params
|
17
|
+
{
|
18
|
+
node_id: @call.node_id,
|
19
|
+
call_id: @call.id,
|
20
|
+
control_id: control_id,
|
21
|
+
digits: @digits
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def notification_handler(event)
|
26
|
+
@state = event.call_params[:state]
|
27
|
+
|
28
|
+
@completed = @state == Relay::CallSendDigitsState::FINISHED
|
29
|
+
@successful = @completed
|
30
|
+
@event = event
|
31
|
+
|
32
|
+
broadcast_event(event)
|
33
|
+
check_for_waiting_events
|
34
|
+
end
|
35
|
+
|
36
|
+
def broadcast_event(event)
|
37
|
+
@call.broadcast "send_digits_#{@state}".to_sym, event
|
38
|
+
@call.broadcast :send_digits_change, event
|
39
|
+
end
|
40
|
+
|
41
|
+
def stop
|
42
|
+
logger.warn "SendDigits does not implement a stop action"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -33,6 +33,7 @@ module Signalwire::Relay
|
|
33
33
|
NO_ANSWER = 'noAnswer'
|
34
34
|
DECLINE = 'decline'
|
35
35
|
ERROR = 'error'
|
36
|
+
FAILED = 'failed'
|
36
37
|
end
|
37
38
|
|
38
39
|
module DisconnectSource
|
@@ -65,6 +66,7 @@ module Signalwire::Relay
|
|
65
66
|
FAX = 'calling.call.fax'
|
66
67
|
TAP = 'calling.call.tap'
|
67
68
|
DETECT = 'calling.call.detect'
|
69
|
+
SEND_DIGITS = 'calling.call.send_digits'
|
68
70
|
end
|
69
71
|
|
70
72
|
CALL_EVENT_STATE_FIELDS = {
|
@@ -117,6 +119,7 @@ module Signalwire::Relay
|
|
117
119
|
RECEIVE_FAX = 'calling.receive_fax'
|
118
120
|
TAP = 'calling.tap'
|
119
121
|
DETECT = 'calling.detect'
|
122
|
+
SEND_DIGITS = 'calling.send_digits'
|
120
123
|
end
|
121
124
|
|
122
125
|
module CommonState
|
@@ -151,6 +154,10 @@ module Signalwire::Relay
|
|
151
154
|
MACHINE = "machine"
|
152
155
|
DIGIT = "digit"
|
153
156
|
end
|
157
|
+
|
158
|
+
module CallSendDigitsState
|
159
|
+
FINISHED = 'finished'
|
160
|
+
end
|
154
161
|
end
|
155
162
|
|
156
163
|
Relay = Signalwire::Relay
|
data/lib/signalwire/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: signalwire
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SignalWire Team
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -259,6 +259,7 @@ files:
|
|
259
259
|
- examples/relay/fax/fax_send.rb
|
260
260
|
- examples/relay/inbound_consumer.rb
|
261
261
|
- examples/relay/inbound_dial.rb
|
262
|
+
- examples/relay/inbound_send_digits.rb
|
262
263
|
- examples/relay/messaging/messaging_receive.rb
|
263
264
|
- examples/relay/messaging/messaging_send.rb
|
264
265
|
- examples/relay/outbound_collect.rb
|
@@ -288,6 +289,7 @@ files:
|
|
288
289
|
- lib/signalwire/relay/calling/action/play_action.rb
|
289
290
|
- lib/signalwire/relay/calling/action/prompt_action.rb
|
290
291
|
- lib/signalwire/relay/calling/action/record_action.rb
|
292
|
+
- lib/signalwire/relay/calling/action/send_digits_action.rb
|
291
293
|
- lib/signalwire/relay/calling/action/tap_action.rb
|
292
294
|
- lib/signalwire/relay/calling/call.rb
|
293
295
|
- lib/signalwire/relay/calling/call_convenience_methods.rb
|
@@ -305,6 +307,7 @@ files:
|
|
305
307
|
- lib/signalwire/relay/calling/component/play.rb
|
306
308
|
- lib/signalwire/relay/calling/component/prompt.rb
|
307
309
|
- lib/signalwire/relay/calling/component/record.rb
|
310
|
+
- lib/signalwire/relay/calling/component/send_digits.rb
|
308
311
|
- lib/signalwire/relay/calling/component/tap.rb
|
309
312
|
- lib/signalwire/relay/calling/control_component.rb
|
310
313
|
- lib/signalwire/relay/calling/result.rb
|
@@ -317,6 +320,7 @@ files:
|
|
317
320
|
- lib/signalwire/relay/calling/result/play_result.rb
|
318
321
|
- lib/signalwire/relay/calling/result/prompt_result.rb
|
319
322
|
- lib/signalwire/relay/calling/result/record_result.rb
|
323
|
+
- lib/signalwire/relay/calling/result/send_digits_result.rb
|
320
324
|
- lib/signalwire/relay/calling/result/tap_result.rb
|
321
325
|
- lib/signalwire/relay/client.rb
|
322
326
|
- lib/signalwire/relay/constants.rb
|