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.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/adhearsion/call.rb', line 77

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
  @call_terminating = false

  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



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

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



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

def auto_hangup
  @auto_hangup
end

#controllersArray<Adhearsion::CallController> (readonly)

Returns the set of call controllers executing on the call.

Returns:



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

def controllers
  @controllers
end

#end_codeString (readonly)

Returns the reason code for the call ending.

Returns:

  • (String)

    the reason code for the call ending



40
41
42
# File 'lib/adhearsion/call.rb', line 40

def end_code
  @end_code
end

#end_reasonSymbol (readonly)

Returns the reason for the call ending.

Returns:

  • (Symbol)

    the reason for the call ending



37
38
39
# File 'lib/adhearsion/call.rb', line 37

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.



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

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.



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

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



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

def variables
  @variables
end

Class Method Details

.uri(transport, id, domain) ⇒ Object



68
69
70
71
72
73
74
75
# File 'lib/adhearsion/call.rb', line 68

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



323
324
325
326
327
# File 'lib/adhearsion/call.rb', line 323

def accept(headers = nil)
  @accept_command ||= write_and_await_response Punchblock::Command::Accept.new(:headers => headers)
rescue Punchblock::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)



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

def active?
  !end_reason
end

#answer(headers = nil) ⇒ Object



329
330
331
332
333
# File 'lib/adhearsion/call.rb', line 329

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

#commandsObject



197
198
199
# File 'lib/adhearsion/call.rb', line 197

def commands
  @commands.clone
end

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



189
190
191
192
193
194
# File 'lib/adhearsion/call.rb', line 189

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



108
109
110
# File 'lib/adhearsion/call.rb', line 108

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



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

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)


551
552
553
554
555
556
# File 'lib/adhearsion/call.rb', line 551

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.inspect}"
  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



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

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

#hangup(headers = nil) ⇒ Object



362
363
364
365
366
367
368
369
# File 'lib/adhearsion/call.rb', line 362

def hangup(headers = nil)
  return false unless active?
  logger.info "Hanging up"
  @end_reason = true
  write_and_await_response Punchblock::Command::Hangup.new(:headers => headers)
rescue Punchblock::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



100
101
102
# File 'lib/adhearsion/call.rb', line 100

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



386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# File 'lib/adhearsion/call.rb', line 386

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 = Punchblock::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 Punchblock::ProtocolError => e
  abort e
end

#muteObject



464
465
466
467
468
# File 'lib/adhearsion/call.rb', line 464

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

#on_end(&block) ⇒ Object



300
301
302
# File 'lib/adhearsion/call.rb', line 300

def on_end(&block)
  register_event_handler Punchblock::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



278
279
280
281
282
# File 'lib/adhearsion/call.rb', line 278

def on_joined(target = nil, &block)
  register_event_handler Punchblock::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



291
292
293
# File 'lib/adhearsion/call.rb', line 291

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

#peersHash<String => Adhearsion::Call>

Hash of joined peers

Returns:



158
159
160
# File 'lib/adhearsion/call.rb', line 158

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



356
357
358
359
360
# File 'lib/adhearsion/call.rb', line 356

def redirect(to, headers = nil)
  write_and_await_response Punchblock::Command::Redirect.new(to: to, headers: headers)
rescue Punchblock::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:



185
186
187
# File 'lib/adhearsion/call.rb', line 185

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

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



335
336
337
338
339
340
# File 'lib/adhearsion/call.rb', line 335

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

#remove_tag(label) ⇒ Object

Remove a label

Parameters:

  • label (String, Symbol)


141
142
143
# File 'lib/adhearsion/call.rb', line 141

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.



521
522
523
524
# File 'lib/adhearsion/call.rb', line 521

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



131
132
133
134
# File 'lib/adhearsion/call.rb', line 131

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)


150
151
152
# File 'lib/adhearsion/call.rb', line 150

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.



122
123
124
# File 'lib/adhearsion/call.rb', line 122

def tags
  @tags.clone
end

#terminating!Object



304
305
306
307
# File 'lib/adhearsion/call.rb', line 304

def terminating!
  logger.debug "Call is terminating"
  @call_terminating = true
end

#terminating?Boolean

Returns if the call is currently terminating/terminated.

Returns:

  • (Boolean)

    if the call is currently terminating/terminated



312
313
314
# File 'lib/adhearsion/call.rb', line 312

def terminating?
  !active? || @call_terminating
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



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

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



418
419
420
421
422
423
424
# File 'lib/adhearsion/call.rb', line 418

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

#unmuteObject



470
471
472
473
474
# File 'lib/adhearsion/call.rb', line 470

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

#uriString?

Returns The uri at which the call resides.

Returns:

  • (String, nil)

    The uri at which the call resides



115
116
117
# File 'lib/adhearsion/call.rb', line 115

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

#wait_for_endSymbol

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

Returns:

  • (Symbol)

    the reason for the call ending



166
167
168
169
170
171
172
# File 'lib/adhearsion/call.rb', line 166

def wait_for_end
  if end_reason
    end_reason
  else
    @end_blocker.wait
  end
end

#wait_for_joined(expected_target) ⇒ Object



450
451
452
453
454
455
# File 'lib/adhearsion/call.rb', line 450

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

#wait_for_unjoined(expected_target) ⇒ Object



457
458
459
460
461
462
# File 'lib/adhearsion/call.rb', line 457

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