class Signalwire::Relay::Calling::Call

Constants

DETECT_DEPRECATE_MONTH

Attributes

busy[R]
client[R]
components[R]
context[R]
device[R]
failed[R]
from[R]
node_id[R]
peer_call[R]
previous_state[R]
state[R]
tag[R]
timeout[R]
to[R]
type[R]

Public Class Methods

from_event(client, event) click to toggle source
# File lib/signalwire/relay/calling/call.rb, line 26
def self.from_event(client, event)
  new(client, event.call_params)
end
new(client, call_options) click to toggle source
# 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

Public Instance Methods

active?() click to toggle source
# File lib/signalwire/relay/calling/call.rb, line 102
def active?
  !ended?
end
answer() click to toggle source
# 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?() click to toggle source
# File lib/signalwire/relay/calling/call.rb, line 94
def answered?
  @state == 'answered'
end
call_match_event(event) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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
dial() click to toggle source
# 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?() click to toggle source
# File lib/signalwire/relay/calling/call.rb, line 98
def ended?
  @state == 'ending' || @state == 'ended'
end
fax_receive() click to toggle source
# 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!() click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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') click to toggle source
# 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
id() click to toggle source
# File lib/signalwire/relay/calling/call.rb, line 90
def id
  @id ||= SecureRandom.uuid
end
peer() click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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: " click to toggle source
# 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: " click to toggle source
# 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) click to toggle source
# File lib/signalwire/relay/calling/call.rb, line 309
def register_component(component)
  @components << component
end
send_digits(digits) click to toggle source
# 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) click to toggle source
# 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_handlers() click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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 = {}) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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

Private Instance Methods

compile_collect_arguments(args) click to toggle source
# File lib/signalwire/relay/calling/call.rb, line 370
def compile_collect_arguments(args)
  generic_fields = %i{initial_timeout partial_results}
  digit_fields = %i{digits_max digits_terminators digits_timeout}
  speech_fields = %i{speech_timeout speech_language speech_hints end_silence_timeout}
  has_digits = (digit_fields & args.keys).any?
  has_speech = (speech_fields & args.keys).any?

  collect = {}
  generic_fields.each { |gf| collect[gf] = args[gf] if args[gf] }

  if has_digits
    digits_obj = {}
    digits_obj[:max] = args[:digits_max] if args[:digits_max]
    digits_obj[:terminators] = args[:digits_terminators] if args[:digits_terminators]
    digits_obj[:digit_timeout] = args[:digits_timeout] if args[:digits_timeout]
    collect[:digits] = digits_obj
  end

  if has_speech
    speech_obj = {}
    speech_obj[:timeout] = args[:speech_timeout] if args[:speech_timeout]
    speech_obj[:language] = args[:speech_language] if args[:speech_language]
    speech_obj[:hints] = args[:speech_hints] if args[:speech_hints]
    speech_obj[:end_silence_timeout] = args[:end_silence_timeout] if args[:end_silence_timeout]
    collect[:speech] = speech_obj
  end

  collect
end
compile_tap_arguments(args) click to toggle source
# File lib/signalwire/relay/calling/call.rb, line 351
def compile_tap_arguments(args)
  tap = { params: {} }
  tap[:type] = args[:media_type] || 'audio'
  tap[:params][:direction] = args[:audio_direction] if args[:audio_direction]
  tap[:params][:rate] = args[:rate] if args[:rate]
  tap[:params][:codec] = args[:codec] if args[:codec]
  tap
end
compile_tap_device_arguments(args) click to toggle source
# File lib/signalwire/relay/calling/call.rb, line 360
def compile_tap_device_arguments(args)
  device = { params: {} }
  device[:type] = args[:target_type] || 'rtp'
  device[:params][:addr] = args[:target_addr] if args[:target_addr]
  device[:params][:port] = args[:target_port] if args[:target_port]
  device[:params][:ptime] = args[:target_ptime] if args[:target_ptime]
  device[:params][:uri] = args[:target_uri] if args[:target_uri]
  device
end
set_parameters(passed_binding, keys, mandatory_keys) click to toggle source
# File lib/signalwire/relay/calling/call.rb, line 342
def set_parameters(passed_binding, keys, mandatory_keys)
  keys.each do |x| 
    passed_binding.local_variable_set(x, passed_binding.local_variable_get(x) || passed_binding.local_variable_get("#{x}_p"))
  end
  mandatory_keys.each do |x|
    raise ArgumentError, "The #{x} argument must be provided" if passed_binding.local_variable_get(x).nil?
  end
end
setup_call_options(call_options) click to toggle source
# File lib/signalwire/relay/calling/call.rb, line 330
def setup_call_options(call_options)
  @node_id = call_options[:node_id]
  @context = call_options[:context]
  @previous_state = nil
  @state = call_options[:call_state]
  @previous_connect_state = nil
  @connect_state = call_options[:connect_state]
  @device = call_options[:device]
  @busy = false
  @failed = false
end