Class: Adhearsion::Call

Inherits:
Object show all
Includes:
Celluloid, HasGuardedHandlers
Defined in:
lib/adhearsion/call.rb

Overview

Encapsulates call-related data and behavior.

Direct Known Subclasses

OutboundCall

Constant Summary collapse

Hangup =
Class.new Adhearsion::Error
CommandTimeout =
Class.new Adhearsion::Error
ExpiredError =
Class.new Celluloid::DeadActorError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Celluloid

logger

Constructor Details

#initialize(offer = nil) ⇒ Call

Returns a new instance of Call



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/adhearsion/call.rb', line 83

def initialize(offer = nil)
  register_initial_handlers

  @offer        = nil
  @tags         = []
  @commands     = CommandRegistry.new
  @variables    = HashWithIndifferentAccess.new
  @controllers  = []
  @end_reason   = nil
  @end_code     = nil
  @end_blocker  = Celluloid::Condition.new
  @peers        = {}
  @duration     = nil
  @auto_hangup  = true
  @after_hangup_lifetime = nil

  self << offer if offer
end

Instance Attribute Details

#after_hangup_lifetimeInteger

Returns the number of seconds after the call is hung up that the controller will remain active

Returns:

  • (Integer)

    the number of seconds after the call is hung up that the controller will remain active



64
65
66
# File 'lib/adhearsion/call.rb', line 64

def after_hangup_lifetime
  @after_hangup_lifetime
end

#auto_hanguptrue, false

Returns whether or not the call should be automatically hung up after executing its controller

Returns:

  • (true, false)

    whether or not the call should be automatically hung up after executing its controller



61
62
63
# File 'lib/adhearsion/call.rb', line 61

def auto_hangup
  @auto_hangup
end

#controllersArray<Adhearsion::CallController> (readonly)

Returns the set of call controllers executing on the call

Returns:



49
50
51
# File 'lib/adhearsion/call.rb', line 49

def controllers
  @controllers
end

#end_codeString (readonly)

Returns the reason code for the call ending

Returns:

  • (String)

    the reason code for the call ending



46
47
48
# File 'lib/adhearsion/call.rb', line 46

def end_code
  @end_code
end

#end_reasonSymbol (readonly)

Returns the reason for the call ending

Returns:

  • (Symbol)

    the reason for the call ending



43
44
45
# File 'lib/adhearsion/call.rb', line 43

def end_reason
  @end_reason
end

#end_timeTime (readonly)

Returns the time at which the call began. For inbound calls this is the time at which the call was offered to Adhearsion. For outbound calls it is the time at which the remote party answered.

Returns:

  • (Time)

    the time at which the call began. For inbound calls this is the time at which the call was offered to Adhearsion. For outbound calls it is the time at which the remote party answered.



58
59
60
# File 'lib/adhearsion/call.rb', line 58

def end_time
  @end_time
end

#start_timeTime (readonly)

Returns the time at which the call began. For inbound calls this is the time at which the call was offered to Adhearsion. For outbound calls it is the time at which the remote party answered.

Returns:

  • (Time)

    the time at which the call began. For inbound calls this is the time at which the call was offered to Adhearsion. For outbound calls it is the time at which the remote party answered.



55
56
57
# File 'lib/adhearsion/call.rb', line 55

def start_time
  @start_time
end

#variablesHash<String => String> (readonly)

Returns a collection of SIP headers set during the call

Returns:

  • (Hash<String => String>)

    a collection of SIP headers set during the call



52
53
54
# File 'lib/adhearsion/call.rb', line 52

def variables
  @variables
end

Class Method Details

.uri(transport, id, domain) ⇒ Object



74
75
76
77
78
79
80
81
# File 'lib/adhearsion/call.rb', line 74

def self.uri(transport, id, domain)
  return nil unless id
  s = ""
  s << transport << ":" if transport
  s << id
  s << "@" << domain if domain
  s
end

Instance Method Details

#accept(headers = nil) ⇒ Object



313
314
315
316
317
# File 'lib/adhearsion/call.rb', line 313

def accept(headers = nil)
  @accept_command ||= write_and_await_response Adhearsion::Rayo::Command::Accept.new(:headers => headers)
rescue Adhearsion::ProtocolError => e
  abort e
end

#active?Boolean

Returns if the call is currently active or not (disconnected)

Returns:

  • (Boolean)

    if the call is currently active or not (disconnected)



309
310
311
# File 'lib/adhearsion/call.rb', line 309

def active?
  !end_reason
end

#answer(headers = nil) ⇒ Object



319
320
321
322
323
# File 'lib/adhearsion/call.rb', line 319

def answer(headers = nil)
  write_and_await_response Adhearsion::Rayo::Command::Answer.new(:headers => headers)
rescue Adhearsion::ProtocolError => e
  abort e
end

#commandsObject



206
207
208
# File 'lib/adhearsion/call.rb', line 206

def commands
  @commands.clone
end

#deliver_message(message) ⇒ Object Also known as: <<



198
199
200
201
202
203
# File 'lib/adhearsion/call.rb', line 198

def deliver_message(message)
  logger.debug "Receiving message: #{message.inspect}"
  catching_standard_errors do
    trigger_handler :event, message, broadcast: true, exception_callback: ->(e) { Adhearsion::Events.trigger :exception, [e, logger] }
  end
end

#domainString?

Returns The domain on which the call resides

Returns:

  • (String, nil)

    The domain on which the call resides



113
114
115
# File 'lib/adhearsion/call.rb', line 113

def domain
  offer.domain if offer
end

#durationFloat

Returns The call duration until the current time, or until the call was disconnected, whichever is earlier

Returns:

  • (Float)

    The call duration until the current time, or until the call was disconnected, whichever is earlier



263
264
265
266
267
268
269
270
271
# File 'lib/adhearsion/call.rb', line 263

def duration
  if @duration
    @duration
  elsif @start_time
    Time.now - @start_time
  else
    0.0
  end
end

#execute_controller(controller = nil, completion_callback = nil) { ... } ⇒ Celluloid::ThreadHandle

Execute a call controller asynchronously against this call.

To block and wait until the controller completes, call `#join` on the result of this method.

Parameters:

  • controller (Adhearsion::CallController) (defaults to: nil)

    an instance of a controller initialized for this call

  • a (Proc)

    callback to be executed when the controller finishes execution

Yields:

  • execute the current block as the body of a controller by specifying no controller instance

Returns:

  • (Celluloid::ThreadHandle)

Raises:

  • (ArgumentError)


541
542
543
544
545
546
# File 'lib/adhearsion/call.rb', line 541

def execute_controller(controller = nil, completion_callback = nil, &block)
  raise ArgumentError, "Cannot supply a controller and a block at the same time" if controller && block_given?
  controller ||= CallController.new current_actor, &block
  logger.info "Executing controller #{controller.class}"
  controller.bg_exec completion_callback
end

#fromString

Returns the value of the From header from the signaling protocol

Returns:

  • (String)

    the value of the From header from the signaling protocol



72
# File 'lib/adhearsion/call.rb', line 72

delegate :from, to: :offer, allow_nil: true

#hangup(headers = nil) ⇒ Object



352
353
354
355
356
357
358
359
# File 'lib/adhearsion/call.rb', line 352

def hangup(headers = nil)
  return false unless active?
  logger.info "Hanging up"
  @end_reason = true
  write_and_await_response Adhearsion::Rayo::Command::Hangup.new(:headers => headers)
rescue Adhearsion::ProtocolError => e
  abort e
end

#idString? Also known as: to_s

Returns The globally unique ID for the call

Returns:

  • (String, nil)

    The globally unique ID for the call



105
106
107
# File 'lib/adhearsion/call.rb', line 105

def id
  offer.target_call_id if offer
end

#join(target, options = {}) ⇒ Hash

Joins this call to another call or a mixer

Parameters:

  • target (Call, String, Hash)

    the target to join to. May be a Call object, a call ID (String, Hash) or a mixer name (Hash)

  • options (Hash, Optional) (defaults to: {})

    further options to be joined with

Options Hash (target):

  • call_uri (String)

    The call ID to join to

  • mixer_name (String)

    The mixer to join to

Returns:

  • (Hash)

    where :command is the issued command, :joined_waiter is a #wait responder which is triggered when the join is complete, and :unjoined_waiter is a #wait responder which is triggered when the entities are unjoined



376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/adhearsion/call.rb', line 376

def join(target, options = {})
  logger.debug "Joining to #{target}"

  joined_condition = CountDownLatch.new(1)
  on_joined target do
    joined_condition.countdown!
  end

  unjoined_condition = CountDownLatch.new(1)
  on_unjoined target do
    unjoined_condition.countdown!
  end

  on_end do
    joined_condition.countdown!
    unjoined_condition.countdown!
  end

  command = Adhearsion::Rayo::Command::Join.new options.merge(join_options_with_target(target))
  write_and_await_response command
  {command: command, joined_condition: joined_condition, unjoined_condition: unjoined_condition}
rescue Adhearsion::ProtocolError => e
  abort e
end

#muteObject



454
455
456
457
458
# File 'lib/adhearsion/call.rb', line 454

def mute
  write_and_await_response Adhearsion::Rayo::Command::Mute.new
rescue Adhearsion::ProtocolError => e
  abort e
end

#on_end(&block) ⇒ Object



302
303
304
# File 'lib/adhearsion/call.rb', line 302

def on_end(&block)
  register_event_handler Adhearsion::Event::End, &block
end

#on_joined(target = nil, &block) ⇒ Object

Registers a callback for when this call is joined to another call or a mixer

Parameters:

  • target (Call, String, Hash, nil) (defaults to: nil)

    the target to guard on. May be a Call object, a call ID (String, Hash) or a mixer name (Hash)

Options Hash (target):

  • call_uri (String)

    The call ID to guard on

  • mixer_name (String)

    The mixer name to guard on



280
281
282
283
284
# File 'lib/adhearsion/call.rb', line 280

def on_joined(target = nil, &block)
  register_event_handler Adhearsion::Event::Joined, *guards_for_target(target) do |event|
    block.call event
  end
end

#on_unjoined(target = nil, &block) ⇒ Object

Registers a callback for when this call is unjoined from another call or a mixer

Parameters:

  • target (Call, String, Hash, nil) (defaults to: nil)

    the target to guard on. May be a Call object, a call ID (String, Hash) or a mixer name (Hash)

Options Hash (target):

  • call_uri (String)

    The call ID to guard on

  • mixer_name (String)

    The mixer name to guard on



293
294
295
# File 'lib/adhearsion/call.rb', line 293

def on_unjoined(target = nil, &block)
  register_event_handler Adhearsion::Event::Unjoined, *guards_for_target(target), &block
end

#peersHash<String => Adhearsion::Call>

Hash of joined peers

Returns:



163
164
165
# File 'lib/adhearsion/call.rb', line 163

def peers
  @peers.clone
end

#redirect(to, headers = nil) ⇒ Object

Redirect the call to some other target system.

If the redirect is successful, the call will be released from the telephony engine and Adhearsion will lose control of the call.

Note that for the common case, this will result in a SIP 302 or SIP REFER, which provides the caller with a new URI to dial. As such, the redirect target cannot be any telephony-engine specific address (such as sofia/gateway, agent/101, or SIP/mypeer); instead it should be a fully-qualified external SIP URI that the caller can independently reach.

Parameters:

  • to (String)

    the target to redirect to, eg a SIP URI

  • headers (Hash, optional) (defaults to: nil)

    a set of headers to send along with the redirect instruction



346
347
348
349
350
# File 'lib/adhearsion/call.rb', line 346

def redirect(to, headers = nil)
  write_and_await_response Adhearsion::Rayo::Command::Redirect.new(to: to, headers: headers)
rescue Adhearsion::ProtocolError => e
  abort e
end

#register_event_handler(*guards) {|Object| ... } ⇒ String

Register a handler for events on this call. Note that Adhearsion::Call implements the has-guarded-handlers API, and all of its methods are available. Specifically, all Adhearsion events are available on the `:event` channel.

Parameters:

  • guards (guards)

    take a look at the guards documentation

Yields:

  • (Object)

    trigger_object the incoming event

Returns:

  • (String)

    handler ID for later manipulation

See Also:



194
195
196
# File 'lib/adhearsion/call.rb', line 194

def register_event_handler(*guards, &block)
  register_handler :event, *guards, &block
end

#reject(reason = :busy, headers = nil) ⇒ Object



325
326
327
328
329
330
# File 'lib/adhearsion/call.rb', line 325

def reject(reason = :busy, headers = nil)
  write_and_await_response Adhearsion::Rayo::Command::Reject.new(:reason => reason, :headers => headers)
  Adhearsion::Events.trigger_immediately :call_rejected, call: current_actor, reason: reason
rescue Adhearsion::ProtocolError => e
  abort e
end

#remove_tag(label) ⇒ Object

Remove a label

Parameters:

  • label (String, Symbol)


146
147
148
# File 'lib/adhearsion/call.rb', line 146

def remove_tag(label)
  @tags.reject! { |tag| tag == label }
end

#send_message(body, options = {}) ⇒ Object

Sends a message to the caller

Parameters:

  • body (String)

    The message text.

  • options (Hash, Optional) (defaults to: {})

    The message options.

Options Hash (options):

  • subject (String)

    The message subject.



511
512
513
514
# File 'lib/adhearsion/call.rb', line 511

def send_message(body, options = {})
  logger.debug "Sending message: #{body}"
  client.send_message id, domain, body, options
end

#tag(label) ⇒ Object

Tag a call with an arbitrary label

Parameters:

  • label (String, Symbol)

    String or Symbol with which to tag this call



136
137
138
139
# File 'lib/adhearsion/call.rb', line 136

def tag(label)
  abort ArgumentError.new "Tag must be a String or Symbol" unless [String, Symbol].include?(label.class)
  @tags << label
end

#tagged_with?(label) ⇒ Boolean

Establish if the call is tagged with the provided label

Parameters:

  • label (String, Symbol)

Returns:

  • (Boolean)


155
156
157
# File 'lib/adhearsion/call.rb', line 155

def tagged_with?(label)
  @tags.include? label
end

#tagsArray

Returns The set of labels with which this call has been tagged.

Returns:

  • (Array)

    The set of labels with which this call has been tagged.



127
128
129
# File 'lib/adhearsion/call.rb', line 127

def tags
  @tags.clone
end

#toString

Returns the value of the To header from the signaling protocol

Returns:

  • (String)

    the value of the To header from the signaling protocol



69
# File 'lib/adhearsion/call.rb', line 69

delegate :to, to: :offer, allow_nil: true

#unjoin(target = nil) ⇒ Object

Unjoins this call from another call or a mixer

Parameters:

  • target (Call, String, Hash, nil) (defaults to: nil)

    the target to unjoin from. May be a Call object, a call ID (String, Hash), a mixer name (Hash) or missing to unjoin from every existing join (nil)

Options Hash (target):

  • call_uri (String)

    The call ID to unjoin from

  • mixer_name (String)

    The mixer to unjoin from



408
409
410
411
412
413
414
# File 'lib/adhearsion/call.rb', line 408

def unjoin(target = nil)
  logger.info "Unjoining from #{target}"
  command = Adhearsion::Rayo::Command::Unjoin.new join_options_with_target(target)
  write_and_await_response command
rescue Adhearsion::ProtocolError => e
  abort e
end

#unmuteObject



460
461
462
463
464
# File 'lib/adhearsion/call.rb', line 460

def unmute
  write_and_await_response Adhearsion::Rayo::Command::Unmute.new
rescue Adhearsion::ProtocolError => e
  abort e
end

#uriString?

Returns The uri at which the call resides

Returns:

  • (String, nil)

    The uri at which the call resides



120
121
122
# File 'lib/adhearsion/call.rb', line 120

def uri
  self.class.uri(transport, id, domain)
end

#wait_for_end(timeout = nil) ⇒ Symbol

Wait for the call to end. Returns immediately if the call has already ended, else blocks until it does so.

Parameters:

  • timeout (Integer, nil) (defaults to: nil)

    a timeout after which to unblock, returning `:timeout`

Returns:

  • (Symbol)

    the reason for the call ending



173
174
175
176
177
178
179
180
181
# File 'lib/adhearsion/call.rb', line 173

def wait_for_end(timeout = nil)
  if end_reason
    end_reason
  else
    @end_blocker.wait(timeout)
  end
rescue Celluloid::ConditionError => e
  abort e
end

#wait_for_joined(expected_target) ⇒ Object



440
441
442
443
444
445
# File 'lib/adhearsion/call.rb', line 440

def wait_for_joined(expected_target)
  target = nil
  until target == expected_target do
    target = wait :joined
  end
end

#wait_for_unjoined(expected_target) ⇒ Object



447
448
449
450
451
452
# File 'lib/adhearsion/call.rb', line 447

def wait_for_unjoined(expected_target)
  target = nil
  until target == expected_target do
    target = wait :unjoined
  end
end