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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b79e0a17481f2f0fcb5cdf7a1b5860f86565e60826808b3b0c4c671f6797d173
4
- data.tar.gz: d798019a441d67cf6d6cdbba6093e13b43353a788465b7333bdf48bf9e0ab969
3
+ metadata.gz: 325c0f2a81d0a8486fdb356dc91c78284228b30440129ee2a60c3332b1e725b5
4
+ data.tar.gz: 1f5f8d9227de1b684f05e88d6b1b53246de7f29479c0e11cef94cd792dc8171c
5
5
  SHA512:
6
- metadata.gz: fcadfef6643451bea578ce6a8fd8355307f53704545c6078e0265ed109c03b7c24b196d25c8703416db25a93ca2aa3158bb49818197294493fa01f43922c054d
7
- data.tar.gz: 4cf8ec00e2eb43921000836f1f48012f82e05506c44070960c9b2736d8ffefeb32d5331c8ad5dabe7f537f56bd6a949ef3ab9a70668a3ab8532789dfd4323075
6
+ metadata.gz: 6362ec6503c1a04505f72b13edfbb29c2bb7ca4002f7e13fd7926099dbac08142254d0a41447c96f2b44a54639fdfb367d12ab710c6a6e628c39143a823e9028
7
+ data.tar.gz: e8dce6ff15120bc77452aa97667a0aa468d923cd744e0e4ec15c74db0100424b321e9d86438710750d1cb4285f04db4aa3ab1f09f5e93352a2ebfa7c59874edd
@@ -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({"audio": { "beep": "true", "terminators": "#"}})
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(tap: tap_arguments, device: device_arguments)
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
@@ -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'
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Signalwire::Relay::Calling
6
+ class SendDigitsAction < Action
7
+ def result
8
+ SendDigitsResult.new(@component)
9
+ end
10
+ end
11
+ end
@@ -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, collect: nil, play: 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, collect: nil, play: 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(record_object)
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!(record_object)
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: , identity: nil, header: nil)
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: , identity: nil, header: nil)
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(tap:, device:)
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!(tap:, device:)
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 component.completed
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, collect: nil, url: 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, collect: nil, url: 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, collect: nil, duration: 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, collect: nil, duration: 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, collect: nil, text: nil, language: Relay::DEFAULT_LANGUAGE, gender: 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
- prompt(collect, tts_payload(text, language, gender))
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, collect: nil, text: nil, language: Relay::DEFAULT_LANGUAGE, gender: 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
- def detect(detect:, timeout: Relay::DEFAULT_CALL_TIMEOUT)
4
- component = Signalwire::Relay::Calling::Detect.new(call: self, detect: detect, timeout: timeout)
5
- component.wait_for(Relay::CallDetectState::FINISHED, Relay::CallDetectState::ERROR)
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!(detect:, timeout: Relay::DEFAULT_CALL_TIMEOUT)
10
- component = Signalwire::Relay::Calling::Detect.new(call: self, detect: detect, timeout: timeout)
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::FINISHED, Relay::CallDetectState::ERROR, Relay::CallDetectState::HUMAN)
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::FINISHED, Relay::CallDetectState::ERROR, Relay::CallDetectState::HUMAN])
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::FINISHED, Relay::CallDetectState::ERROR,
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::FINISHED, Relay::CallDetectState::ERROR,
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, events = prepare_fax_arguments(tone)
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, events = prepare_fax_arguments(tone)
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
- def prepare_fax_arguments(tone)
96
- fax_events = [Relay::CallDetectState::CED, Relay::CallDetectState::CNG]
97
- events = [Relay::CallDetectState::FINISHED, Relay::CallDetectState::ERROR]
98
- detect = { type: Relay::CallDetectType::FAX, params: {} }
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 fax_events.include?(tone)
101
- detect[:params] = { tone: tone }
102
- events << tone
103
- else
104
- events = events + fax_events
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
- [detect, events]
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
- def initialize(call:, detect:, timeout: 30)
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
- result = event.call_params[:detect]
34
- @type = result[:type]
35
- params = result[: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 != Relay::CallDetectState::FINISHED && @state != Relay::CallDetectState::ERROR
40
- @received_events << res_event
41
- end
44
+ return complete(event) if FINISHED_EVENTS.include?(@state) || @type == Relay::CallDetectType::DIGIT
42
45
 
43
- @completed = @events_waiting.include?(@state)
46
+ if has_blocker?
47
+ @received_events << @state
48
+ return
49
+ end
44
50
 
45
- if @completed
46
- @successful = @state != Relay::CallDetectState::ERROR
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
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Signalwire::Relay::Calling
4
+ class SendDigitsResult < Result
5
+ end
6
+ 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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Signalwire
4
- VERSION = '2.1.3'
4
+ VERSION = '2.2.0'
5
5
  end
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.1.3
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-08-20 00:00:00.000000000 Z
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