Class: Signalwire::Relay::Calling::Call

Inherits:
Object
  • Object
show all
Extended by:
Forwardable, Gem::Deprecate
Includes:
Blade::EventHandler, Common, Logger, CallConvenienceMethods, CallDetectMethods
Defined in:
lib/signalwire/relay/calling/call.rb

Constant Summary collapse

DETECT_DEPRECATE_MONTH =
10

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CallDetectMethods

#amd, #amd!, #detect, #detect!, #detect_answering_machine, #detect_answering_machine!, #detect_digit, #detect_digit!, #detect_fax, #detect_fax!, #detect_human, #detect_human!, #detect_machine, #detect_machine!

Methods included from CallConvenienceMethods

#play_audio, #play_audio!, #play_ringtone, #play_ringtone!, #play_silence, #play_silence!, #play_tts, #play_tts!, #prompt_audio, #prompt_audio!, #prompt_ringtone, #prompt_ringtone!, #prompt_silence, #prompt_silence!, #prompt_tts, #prompt_tts!, #wait_for_answered, #wait_for_ended, #wait_for_ending, #wait_for_ringing

Methods included from Blade::EventHandler

#broadcast

Methods included from Logger

#level=, #logger, logger

Constructor Details

#initialize(client, call_options) ⇒ Call

Returns a new instance of Call.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/signalwire/relay/calling/call.rb', line 30

def initialize(client, call_options)
  @client = client

  @id = call_options[:call_id]
  setup_call_options(call_options)
  @type = @device[:type]

  @from = @device[:params][:from_number]
  @to = @device[:params][:to_number]
  @timeout = @device[:params][:timeout] || 30
  @tag = SecureRandom.uuid

  @components = []

  setup_call_event_handlers
end

Instance Attribute Details

#busyObject (readonly)

Returns the value of attribute busy.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def busy
  @busy
end

#clientObject (readonly)

Returns the value of attribute client.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def client
  @client
end

#componentsObject (readonly)

Returns the value of attribute components.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def components
  @components
end

#contextObject (readonly)

Returns the value of attribute context.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def context
  @context
end

#deviceObject (readonly)

Returns the value of attribute device.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def device
  @device
end

#failedObject (readonly)

Returns the value of attribute failed.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def failed
  @failed
end

#fromObject (readonly)

Returns the value of attribute from.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def from
  @from
end

#node_idObject (readonly)

Returns the value of attribute node_id.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def node_id
  @node_id
end

#peer_callObject (readonly)

Returns the value of attribute peer_call.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def peer_call
  @peer_call
end

#previous_stateObject (readonly)

Returns the value of attribute previous_state.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def previous_state
  @previous_state
end

#stateObject (readonly)

Returns the value of attribute state.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def state
  @state
end

#tagObject (readonly)

Returns the value of attribute tag.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def tag
  @tag
end

#timeoutObject (readonly)

Returns the value of attribute timeout.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def timeout
  @timeout
end

#toObject (readonly)

Returns the value of attribute to.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def to
  @to
end

#typeObject (readonly)

Returns the value of attribute type.



21
22
23
# File 'lib/signalwire/relay/calling/call.rb', line 21

def type
  @type
end

Class Method Details

.from_event(client, event) ⇒ Object



26
27
28
# File 'lib/signalwire/relay/calling/call.rb', line 26

def self.from_event(client, event)
  new(client, event.call_params)
end

Instance Method Details

#active?Boolean

Returns:

  • (Boolean)


102
103
104
# File 'lib/signalwire/relay/calling/call.rb', line 102

def active?
  !ended?
end

#answerObject



110
111
112
113
114
# File 'lib/signalwire/relay/calling/call.rb', line 110

def answer
  answer_component = Signalwire::Relay::Calling::Answer.new(call: self)
  answer_component.wait_for(Relay::CallState::ANSWERED, Relay::CallState::ENDING, Relay::CallState::ENDED)
  AnswerResult.new(component: answer_component)
end

#answered?Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/signalwire/relay/calling/call.rb', line 94

def answered?
  @state == 'answered'
end

#call_match_event(event) ⇒ Object



83
84
85
86
87
88
# File 'lib/signalwire/relay/calling/call.rb', line 83

def call_match_event(event)
  event.event_type &&
    event.event_type.match(/calling\.call/) &&
    !event.event_type.match(/receive/) &&
    (event.call_id == id || event.call_params[:tag] == tag)
end

#change_call_state(event_params) ⇒ Object



62
63
64
65
66
67
68
69
# File 'lib/signalwire/relay/calling/call.rb', line 62

def change_call_state(event_params)
  call_state = event_params[:params]
  @previous_state = @state
  @state = call_state[:call_state]
  broadcast :call_state_change, previous_state: @previous_state, state: @state
  broadcast @state.to_sym, previous_state: @previous_state, state: @state
  finish_call(event_params) if @state == Relay::CallState::ENDED
end

#change_connect_state(new_connect_state) ⇒ Object



77
78
79
80
81
# File 'lib/signalwire/relay/calling/call.rb', line 77

def change_connect_state(new_connect_state)
  @previous_connect_state = @connect_state
  @connect_state = new_connect_state
  broadcast :connect_state_change, previous_state: @previous_connect_state, state: @connect_state
end

#connect(devices_p = nil, ringback_p = nil, devices: nil, ringback: nil) ⇒ Object



164
165
166
167
168
169
# File 'lib/signalwire/relay/calling/call.rb', line 164

def connect(devices_p = nil, ringback_p = nil, devices: nil, ringback: nil)
  set_parameters(binding, %i{devices ringback}, %i{devices})
  component = ringback.nil?  ? Connect.new(call: self, devices: devices) : Connect.new(call: self, devices: devices, ringback: ringback)
  component.wait_for(Relay::CallConnectState::CONNECTED, Relay::CallConnectState::FAILED)
  ConnectResult.new(component: component)
end

#connect!(devices_p = nil, ringback_p = nil, devices: nil, ringback: nil) ⇒ Object



171
172
173
174
175
176
# File 'lib/signalwire/relay/calling/call.rb', line 171

def connect!(devices_p = nil, ringback_p = nil, devices: nil, ringback: nil)
  set_parameters(binding, %i{devices ringback}, %i{devices})
  component = ringback.nil?  ? Connect.new(call: self, devices: devices) : Connect.new(call: self, devices: devices, ringback: ringback)
  component.execute
  ConnectAction.new(component: component)
end

#dialObject



230
231
232
233
234
# File 'lib/signalwire/relay/calling/call.rb', line 230

def dial
  dial_component = Signalwire::Relay::Calling::Dial.new(call: self)
  dial_component.wait_for(Relay::CallState::ANSWERED, Relay::CallState::ENDING, Relay::CallState::ENDED)
  DialResult.new(component: dial_component)
end

#ended?Boolean

Returns:

  • (Boolean)


98
99
100
# File 'lib/signalwire/relay/calling/call.rb', line 98

def ended?
  @state == 'ending' || @state == 'ended'
end

#fax_receiveObject



236
237
238
239
240
# File 'lib/signalwire/relay/calling/call.rb', line 236

def fax_receive
  component = Signalwire::Relay::Calling::FaxReceive.new(call: self)
  component.wait_for(Relay::CallFaxState::ERROR, Relay::CallFaxState::FINISHED)
  FaxResult.new(component: component)
end

#fax_receive!Object



242
243
244
245
246
# File 'lib/signalwire/relay/calling/call.rb', line 242

def fax_receive!
  component = Signalwire::Relay::Calling::FaxReceive.new(call: self)
  component.execute
  FaxAction.new(component: component)
end

#fax_send(document:, identity: nil, header: nil) ⇒ Object



248
249
250
251
252
# File 'lib/signalwire/relay/calling/call.rb', line 248

def fax_send(document:, identity: nil, header: nil)
  component = Signalwire::Relay::Calling::FaxSend.new(call: self, document: document, identity: identity, header: header)
  component.wait_for(Relay::CallFaxState::ERROR, Relay::CallFaxState::FINISHED)
  FaxResult.new(component: component)
end

#fax_send!(document:, identity: nil, header: nil) ⇒ Object



254
255
256
257
258
# File 'lib/signalwire/relay/calling/call.rb', line 254

def fax_send!(document:, identity: nil, header: nil)
  component = Signalwire::Relay::Calling::FaxSend.new(call: self, document: document, identity: identity, header: header)
  component.execute
  FaxAction.new(component: component)
end

#finish_call(params) ⇒ Object



319
320
321
322
323
324
325
326
# File 'lib/signalwire/relay/calling/call.rb', line 319

def finish_call(params)
  @client.unregister_handler(:event, @call_event_handler)
  terminate_components(params)
  client.calling.end_call(id)
  @busy = true if params[:reason] == Relay::DisconnectReason::BUSY
  @failed = true if params[:reason] == Relay::DisconnectReason::FAILED
  broadcast :ended, previous_state: @previous_state, state: @state
end

#hangup(reason = 'hangup') ⇒ Object



224
225
226
227
228
# File 'lib/signalwire/relay/calling/call.rb', line 224

def hangup(reason = 'hangup')
  hangup_component = Signalwire::Relay::Calling::Hangup.new(call: self, reason: reason)
  hangup_component.wait_for(Relay::CallState::ENDED)
  HangupResult.new(component: hangup_component)
end

#idObject



90
91
92
# File 'lib/signalwire/relay/calling/call.rb', line 90

def id
  @id ||= SecureRandom.uuid
end

#peerObject



106
107
108
# File 'lib/signalwire/relay/calling/call.rb', line 106

def peer
  @client.calling.find_call_by_id(@peer_call[:call_id]) if @peer_call && @peer_call[:call_id]
end

#play(play_p = nil, volume_p = nil, **args) ⇒ Object



116
117
118
119
120
121
122
123
124
# File 'lib/signalwire/relay/calling/call.rb', line 116

def play(play_p = nil, volume_p = nil, **args)
  play = args.delete(:play)
  volume = args.delete(:volume)
  set_parameters(binding, %i{play volume}, %i{play})

  play_component = Signalwire::Relay::Calling::Play.new(call: self, play: play, volume: volume)
  play_component.wait_for(Relay::CallPlayState::FINISHED, Relay::CallPlayState::ERROR)
  PlayResult.new(component: play_component)
end

#play!(play_p = nil, volume_p = nil, **args) ⇒ Object



126
127
128
129
130
131
132
133
134
# File 'lib/signalwire/relay/calling/call.rb', line 126

def play!(play_p = nil, volume_p = nil, **args)
  play = args.delete(:play)
  volume = args.delete(:volume)
  set_parameters(binding, %i{play volume}, %i{play})

  play_component = Signalwire::Relay::Calling::Play.new(call: self, play: play, volume: volume)
  play_component.execute
  PlayAction.new(component: play_component)
end

#prompt(collect_p = nil, play_p = nil, volume_p = nil, **args) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/signalwire/relay/calling/call.rb', line 136

def prompt(collect_p = nil, play_p = nil, volume_p = nil, **args)
  collect = args.delete(:collect)
  play = args.delete(:play)
  volume = args.delete(:volume)

  collect = compile_collect_arguments(args) if collect.nil? && collect_p.nil?
  set_parameters(binding, %i{collect play}, %i{collect play})

  component = Prompt.new(call: self, collect: collect, play: play, volume: volume)
  component.wait_for(Relay::CallPromptState::ERROR, Relay::CallPromptState::NO_INPUT, 
                     Relay::CallPromptState::NO_MATCH, Relay::CallPromptState::DIGIT,
                     Relay::CallPromptState::SPEECH)
  PromptResult.new(component: component)
end

#prompt!(collect_p = nil, play_p = nil, volume_p = nil, **args) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/signalwire/relay/calling/call.rb', line 151

def prompt!(collect_p = nil, play_p = nil, volume_p = nil, **args)
  collect = args.delete(:collect)
  play = args.delete(:play)
  volume = args.delete(:volume)

  collect = compile_collect_arguments(args) if collect.nil? && collect_p.nil?
  set_parameters(binding, %i{collect play}, %i{collect play})

  component = Prompt.new(call: self, collect: collect, play: play, volume: volume)
  component.execute
  PromptAction.new(component: component)
end

#record(audio: nil, type: 'audio', beep: false, format: 'mp3', stereo: false, direction: 'speak', initial_timeout: 5, end_silence_timeout: 1, terminators: "#*") ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/signalwire/relay/calling/call.rb', line 178

def record(audio: nil, type: 'audio', beep: false, format: 'mp3', stereo: false, direction: 'speak', initial_timeout: 5, end_silence_timeout: 1, terminators: "#*")
  if audio.nil?
    record_object = {
      "#{type}": 
      { 
        beep: beep,
        format: format,
        stereo: stereo,
        direction: direction,
        initial_timeout: initial_timeout,
        end_silence_timeout: end_silence_timeout,
        terminators: terminators
      } 
    }
  else
    record_object = { "#{type}": audio }
  end

  component = Record.new(call: self, record: record_object)
  component.wait_for(Relay::CallRecordState::NO_INPUT, Relay::CallRecordState::FINISHED)
  RecordResult.new(component: component)
end

#record!(audio: nil, type: 'audio', beep: false, format: 'mp3', stereo: false, direction: 'speak', initial_timeout: 5, end_silence_timeout: 1, terminators: "#*") ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/signalwire/relay/calling/call.rb', line 201

def record!(audio: nil, type: 'audio', beep: false, format: 'mp3', stereo: false, direction: 'speak', initial_timeout: 5, end_silence_timeout: 1, terminators: "#*")
  if audio.nil?
    record_object = {
      "#{type}": 
      { 
        beep: beep,
        format: format,
        stereo: stereo,
        direction: direction,
        initial_timeout: initial_timeout,
        end_silence_timeout: end_silence_timeout,
        terminators: terminators
      } 
    }
  else
    record_object = { "#{type}": audio }
  end

  component = Record.new(call: self, record: record_object)
  component.execute
  RecordAction.new(component: component)
end

#register_component(component) ⇒ Object



309
310
311
# File 'lib/signalwire/relay/calling/call.rb', line 309

def register_component(component)
  @components << component
end

#send_digits(digits) ⇒ Object



284
285
286
287
288
# File 'lib/signalwire/relay/calling/call.rb', line 284

def send_digits(digits)
  component = Signalwire::Relay::Calling::SendDigits.new(call: self, digits: digits)
  component.wait_for(Relay::CallSendDigitsState::FINISHED)
  SendDigitsResult.new(component: component)
end

#send_digits!(digits) ⇒ Object



290
291
292
293
294
# File 'lib/signalwire/relay/calling/call.rb', line 290

def send_digits!(digits)
  component = Signalwire::Relay::Calling::SendDigits.new(call: self, digits: digits)
  component.execute
  SendDigitsAction.new(component: component)
end

#setup_call_event_handlersObject



47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/signalwire/relay/calling/call.rb', line 47

def setup_call_event_handlers
  @call_event_handler = @client.on(:event, proc { |evt| call_match_event(evt) }) do |event|
    case event.event_type
    when 'calling.call.connect'
      change_connect_state(event.call_params[:connect_state])
    when 'calling.call.state'
      change_call_state(event.event_params)
    end

    update_call_fields(event.call_params)
    broadcast :event, event
    broadcast :state_change, event
  end
end

#tap_media(**args) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
# File 'lib/signalwire/relay/calling/call.rb', line 260

def tap_media(**args)
  tap = args.delete(:tap)
  device = args.delete(:device)

  tap = compile_tap_arguments(args) if tap.nil?
  device = compile_tap_device_arguments(args) if device.nil?

  component = Signalwire::Relay::Calling::Tap.new(call: self, tap: tap, device: device)
  component.wait_for(Relay::CallTapState::FINISHED)
  TapResult.new(component: component)
end

#tap_media!(**args) ⇒ Object



272
273
274
275
276
277
278
279
280
281
282
# File 'lib/signalwire/relay/calling/call.rb', line 272

def tap_media!(**args)
  tap = args.delete(:tap)
  device = args.delete(:device)

  tap = compile_tap_arguments(args) if tap.nil?
  device = compile_tap_device_arguments(args) if device.nil?
  
  component = Signalwire::Relay::Calling::Tap.new(call: self, tap: tap, device: device)
  component.execute
  TapAction.new(component: component)
end

#terminate_components(params = {}) ⇒ Object



313
314
315
316
317
# File 'lib/signalwire/relay/calling/call.rb', line 313

def terminate_components(params = {})
  @components.each do |comp|
    comp.terminate(params) unless comp.completed
  end
end

#update_call_fields(call_state) ⇒ Object



71
72
73
74
75
# File 'lib/signalwire/relay/calling/call.rb', line 71

def update_call_fields(call_state)
  @id = call_state[:call_id] if call_state[:call_id]
  @node_id = call_state[:node_id] if call_state[:node_id]
  @peer_call = call_state[:peer] if call_state[:peer]
end

#wait_for(*events) ⇒ Object



296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/signalwire/relay/calling/call.rb', line 296

def wait_for(*events)
  events = [Relay::CallState::ENDED] if events.empty?
  
  current_state_index = Relay::CALL_STATES.find_index(@state)
  max_index = events.map { |evt| Relay::CALL_STATES.find_index(evt) }.max

  return true if current_state_index >= max_index

  component = Await.new(call: self)
  component.wait_for(*events)
  component.successful
end