signalwire 2.1.3 → 2.2.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.
- 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
|