Class: Punchblock::Translator::Freeswitch::Call

Inherits:
Object
  • Object
show all
Extended by:
ActorHasGuardedHandlers
Includes:
Celluloid, HasGuardedHandlers, DeadActorSafety
Defined in:
lib/punchblock/translator/freeswitch/call.rb

Constant Summary collapse

HANGUP_CAUSE_TO_END_REASON =
Hash.new :error
REJECT_TO_HANGUP_REASON =
Hash.new 'NORMAL_TEMPORARY_FAILURE'

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ActorHasGuardedHandlers

execute_guarded_handlers_on_receiver

Methods included from DeadActorSafety

#safe_from_dead_actors

Constructor Details

#initialize(id, translator, es_env = nil, stream = nil) ⇒ Call

Returns a new instance of Call.



44
45
46
47
48
49
50
51
# File 'lib/punchblock/translator/freeswitch/call.rb', line 44

def initialize(id, translator, es_env = nil, stream = nil)
  @id, @translator, @stream = id, translator, stream
  @es_env = es_env || {}
  @components = {}
  @pending_joins, @pending_unjoins = {}, {}
  @answered = false
  setup_handlers
end

Instance Attribute Details

#directionObject (readonly)

Returns the value of attribute direction.



40
41
42
# File 'lib/punchblock/translator/freeswitch/call.rb', line 40

def direction
  @direction
end

#es_envObject (readonly)

Returns the value of attribute es_env.



40
41
42
# File 'lib/punchblock/translator/freeswitch/call.rb', line 40

def es_env
  @es_env
end

#idObject (readonly)

Returns the value of attribute id.



40
41
42
# File 'lib/punchblock/translator/freeswitch/call.rb', line 40

def id
  @id
end

#streamObject (readonly)

Returns the value of attribute stream.



40
41
42
# File 'lib/punchblock/translator/freeswitch/call.rb', line 40

def stream
  @stream
end

#translatorObject (readonly)

Returns the value of attribute translator.



40
41
42
# File 'lib/punchblock/translator/freeswitch/call.rb', line 40

def translator
  @translator
end

Instance Method Details

#actor_died(actor, reason) ⇒ Object



234
235
236
237
238
239
240
241
242
# File 'lib/punchblock/translator/freeswitch/call.rb', line 234

def actor_died(actor, reason)
  return unless reason
  pb_logger.error "A linked actor (#{actor.inspect}) died due to #{reason.inspect}"
  if id = @components.key(actor)
    @components.delete id
    complete_event = Punchblock::Event::Complete.new :component_id => id, source_uri: id, :reason => Punchblock::Event::Complete::Error.new
    send_pb_event complete_event
  end
end

#answered?Boolean

Returns:

  • (Boolean)


169
170
171
# File 'lib/punchblock/translator/freeswitch/call.rb', line 169

def answered?
  @answered
end

#application(*args) ⇒ Object



119
120
121
# File 'lib/punchblock/translator/freeswitch/call.rb', line 119

def application(*args)
  stream.application id, *args
end

#component_with_id(component_id) ⇒ Object



57
58
59
# File 'lib/punchblock/translator/freeswitch/call.rb', line 57

def component_with_id(component_id)
  @components[component_id]
end

#dial(dial_command) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/punchblock/translator/freeswitch/call.rb', line 131

def dial(dial_command)
  @direction = :outbound

  cid_number, cid_name = dial_command.from, nil
  if dial_command.from
    dial_command.from.match(/(?<cid_name>.*)<(?<cid_number>.*)>/) do |m|
      cid_name = m[:cid_name].strip
      cid_number = m[:cid_number]
    end
  end

  options = {
    :return_ring_ready  => true,
    :origination_uuid   => id
  }
  options[:origination_caller_id_number] = "'#{cid_number}'" if cid_number.present?
  options[:origination_caller_id_name] = "'#{cid_name}'" if cid_name.present?
  options[:originate_timeout] = dial_command.timeout/1000 if dial_command.timeout
  dial_command.headers.each do |name, value|
    options["sip_h_#{name}"] = "'#{value}'"
  end
  opts = options.inject([]) do |a, (k, v)|
    a << "#{k}=#{v}"
  end.join(',')

  stream.bgapi "originate {#{opts}}#{dial_command.to} &park()"

  dial_command.response = Ref.new uri: id
end

#execute_command(command) ⇒ Object



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/punchblock/translator/freeswitch/call.rb', line 173

def execute_command(command)
  if command.component_id
    if component = component_with_id(command.component_id)
      component.execute_command command
    else
      command.response = ProtocolError.new.setup :item_not_found, "Could not find a component with ID #{command.component_id} for call #{id}", id, command.component_id
    end
  end
  case command
  when Command::Accept
    application 'respond', '180 Ringing'
    command.response = true
  when Command::Answer
    if answered?
      command.response = true
    else
      command_id = Punchblock.new_uuid
      register_tmp_handler :es, :event_name => 'CHANNEL_ANSWER', [:[], :scope_variable_punchblock_command_id] => command_id do
        command.response = true
      end
      application 'answer', "%[punchblock_command_id=#{command_id}]"
    end
  when Command::Hangup
    hangup
    command.response = true
  when Command::Join
    @pending_joins[command.call_uri] = command
    uuid_foo :bridge, command.call_uri
  when Command::Unjoin
    @pending_unjoins[command.call_uri] = command
    uuid_foo :transfer, '-both park inline'
  when Command::Reject
    hangup REJECT_TO_HANGUP_REASON[command.reason]
    command.response = true
  when Punchblock::Component::Output
    media_renderer = command.renderer || :freeswitch
    case media_renderer.to_s
    when 'freeswitch', 'native'
      execute_component Component::Output, command
    when 'flite'
      execute_component Component::FliteOutput, command
    else
      execute_component Component::TTSOutput, command
    end
  when Punchblock::Component::Input
    execute_component Component::Input, command
  when Punchblock::Component::Record
    execute_component Component::Record, command
  else
    command.response = ProtocolError.new.setup 'command-not-acceptable', "Did not understand command for call #{id}", id
  end
end

#handle_es_event(event) ⇒ Object



115
116
117
# File 'lib/punchblock/translator/freeswitch/call.rb', line 115

def handle_es_event(event)
  trigger_handler :es, event
end

#hangup(reason = 'MANAGER_REQUEST') ⇒ Object



226
227
228
# File 'lib/punchblock/translator/freeswitch/call.rb', line 226

def hangup(reason = 'MANAGER_REQUEST')
  sendmsg :call_command => 'hangup', :hangup_cause => reason
end

#inbound?Boolean

Returns:

  • (Boolean)


165
166
167
# File 'lib/punchblock/translator/freeswitch/call.rb', line 165

def inbound?
  direction == :inbound
end

#logger_idObject



230
231
232
# File 'lib/punchblock/translator/freeswitch/call.rb', line 230

def logger_id
  "#{self.class}: #{id}"
end

#outbound?Boolean

Returns:

  • (Boolean)


161
162
163
# File 'lib/punchblock/translator/freeswitch/call.rb', line 161

def outbound?
  direction == :outbound
end

#register_component(component) ⇒ Object



53
54
55
# File 'lib/punchblock/translator/freeswitch/call.rb', line 53

def register_component(component)
  @components[component.id] ||= component
end

#send_offerObject



61
62
63
64
# File 'lib/punchblock/translator/freeswitch/call.rb', line 61

def send_offer
  @direction = :inbound
  send_pb_event offer_event
end

#sendmsg(*args) ⇒ Object



123
124
125
# File 'lib/punchblock/translator/freeswitch/call.rb', line 123

def sendmsg(*args)
  stream.sendmsg id, *args
end

#setup_handlersObject



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/punchblock/translator/freeswitch/call.rb', line 71

def setup_handlers
  register_handler :es, :event_name => 'CHANNEL_ANSWER' do
    @answered = true
    send_pb_event Event::Answered.new
    throw :pass
  end

  register_handler :es, :event_name => 'CHANNEL_STATE', [:[], :channel_call_state] => 'RINGING' do
    send_pb_event Event::Ringing.new
  end

  register_handler :es, :event_name => 'CHANNEL_HANGUP' do |event|
    @components.dup.each_pair do |id, component|
      safe_from_dead_actors do
        component.call_ended if component.alive?
      end
    end
    send_end_event HANGUP_CAUSE_TO_END_REASON[event[:hangup_cause]]
  end

  register_handler :es, :event_name => 'CHANNEL_BRIDGE' do |event|
    command = @pending_joins[event[:other_leg_unique_id]]
    command.response = true if command

    other_call_uri = event[:unique_id] == id ? event[:other_leg_unique_id] : event[:unique_id]
    send_pb_event Event::Joined.new(:call_uri => other_call_uri)
  end

  register_handler :es, :event_name => 'CHANNEL_UNBRIDGE' do |event|
    command = @pending_unjoins[event[:other_leg_unique_id]]
    command.response = true if command

    other_call_uri = event[:unique_id] == id ? event[:other_leg_unique_id] : event[:unique_id]
    send_pb_event Event::Unjoined.new(:call_uri => other_call_uri)
  end

  register_handler :es, [:has_key?, :scope_variable_punchblock_component_id] => true do |event|
    if component = component_with_id(event[:scope_variable_punchblock_component_id])
      safe_from_dead_actors { component.handle_es_event event if component.alive? }
    end
    throw :pass
  end
end

#to_sObject Also known as: inspect



66
67
68
# File 'lib/punchblock/translator/freeswitch/call.rb', line 66

def to_s
  "#<#{self.class}:#{id}>"
end

#uuid_foo(app, args = '') ⇒ Object



127
128
129
# File 'lib/punchblock/translator/freeswitch/call.rb', line 127

def uuid_foo(app, args = '')
  stream.bgapi "uuid_#{app} #{id} #{args}"
end