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
# 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

  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



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

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)



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

def active?
  !end_reason
end

#answer(headers = nil) ⇒ Object



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

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

#commandsObject



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

def commands
  @commands.clone
end

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



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

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



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

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



253
254
255
256
257
258
259
260
261
# File 'lib/adhearsion/call.rb', line 253

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)


531
532
533
534
535
536
# File 'lib/adhearsion/call.rb', line 531

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



342
343
344
345
346
347
348
349
# File 'lib/adhearsion/call.rb', line 342

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



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

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



366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/adhearsion/call.rb', line 366

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



444
445
446
447
448
# File 'lib/adhearsion/call.rb', line 444

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

#on_end(&block) ⇒ Object



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

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



270
271
272
273
274
# File 'lib/adhearsion/call.rb', line 270

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



283
284
285
# File 'lib/adhearsion/call.rb', line 283

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:



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

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



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

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:



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

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

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



315
316
317
318
319
320
# File 'lib/adhearsion/call.rb', line 315

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)


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

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.



501
502
503
504
# File 'lib/adhearsion/call.rb', line 501

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



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

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)


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

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.



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

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



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



398
399
400
401
402
403
404
# File 'lib/adhearsion/call.rb', line 398

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



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

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



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

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



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

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

#wait_for_joined(expected_target) ⇒ Object



430
431
432
433
434
435
# File 'lib/adhearsion/call.rb', line 430

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

#wait_for_unjoined(expected_target) ⇒ Object



437
438
439
440
441
442
# File 'lib/adhearsion/call.rb', line 437

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