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

Inherits:
Object
  • Object
show all
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 DeadActorSafety

#safe_from_dead_actors

Constructor Details

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

Returns a new instance of Call.



40
41
42
43
44
45
46
47
# File 'lib/punchblock/translator/freeswitch/call.rb', line 40

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

Instance Attribute Details

#default_voiceObject (readonly)

Returns the value of attribute default_voice.



36
37
38
# File 'lib/punchblock/translator/freeswitch/call.rb', line 36

def default_voice
  @default_voice
end

#directionObject (readonly)

Returns the value of attribute direction.



36
37
38
# File 'lib/punchblock/translator/freeswitch/call.rb', line 36

def direction
  @direction
end

#es_envObject (readonly)

Returns the value of attribute es_env.



36
37
38
# File 'lib/punchblock/translator/freeswitch/call.rb', line 36

def es_env
  @es_env
end

#idObject (readonly)

Returns the value of attribute id.



36
37
38
# File 'lib/punchblock/translator/freeswitch/call.rb', line 36

def id
  @id
end

#media_engineObject (readonly)

Returns the value of attribute media_engine.



36
37
38
# File 'lib/punchblock/translator/freeswitch/call.rb', line 36

def media_engine
  @media_engine
end

#streamObject (readonly)

Returns the value of attribute stream.



36
37
38
# File 'lib/punchblock/translator/freeswitch/call.rb', line 36

def stream
  @stream
end

#translatorObject (readonly)

Returns the value of attribute translator.



36
37
38
# File 'lib/punchblock/translator/freeswitch/call.rb', line 36

def translator
  @translator
end

Instance Method Details

#actor_died(actor, reason) ⇒ Object



220
221
222
223
224
225
226
227
228
# File 'lib/punchblock/translator/freeswitch/call.rb', line 220

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, :reason => Punchblock::Event::Complete::Error.new
    send_pb_event complete_event
  end
end

#answered?Boolean

Returns:

  • (Boolean)


159
160
161
# File 'lib/punchblock/translator/freeswitch/call.rb', line 159

def answered?
  @answered
end

#application(*args) ⇒ Object



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

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

#component_with_id(component_id) ⇒ Object



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

def component_with_id(component_id)
  @components[component_id]
end

#dial(dial_command) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/punchblock/translator/freeswitch/call.rb', line 126

def dial(dial_command)
  @direction = :outbound

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

  options = {
    :return_ring_ready            => true,
    :origination_uuid             => id,
    :origination_caller_id_number => "'#{cid_number}'"
  }
  options[:origination_caller_id_name] = "'#{cid_name}'" if cid_name
  options[:originate_timeout] = dial_command.timeout/1000 if dial_command.timeout
  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 :id => id
end

#execute_command(command) ⇒ Object



163
164
165
166
167
168
169
170
171
172
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
# File 'lib/punchblock/translator/freeswitch/call.rb', line 163

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
    command_id = Punchblock.new_uuid
    register_tmp_handler :es, :event_name => 'CHANNEL_ANSWER', [:[], :scope_variable_punchblock_command_id] => command_id do
      @answered = true
      command.response = true
    end
    application 'answer', "%[punchblock_command_id=#{command_id}]"
  when Command::Hangup
    hangup
    command.response = true
  when Command::Join
    @pending_joins[command.call_id] = command
    uuid_foo :bridge, command.call_id
  when Command::Unjoin
    @pending_unjoins[command.call_id] = command
    uuid_foo :transfer, '-both park inline'
  when Command::Reject
    hangup REJECT_TO_HANGUP_REASON[command.reason]
    command.response = true
  when Punchblock::Component::Output
    case media_engine
    when :freeswitch, :native, nil
      execute_component Component::Output, command
    when :flite
      execute_component Component::FliteOutput, command, media_engine, default_voice
    else
      execute_component Component::TTSOutput, command, media_engine, default_voice
    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



110
111
112
# File 'lib/punchblock/translator/freeswitch/call.rb', line 110

def handle_es_event(event)
  trigger_handler :es, event
end

#hangup(reason = 'NORMAL_CLEARING') ⇒ Object



212
213
214
# File 'lib/punchblock/translator/freeswitch/call.rb', line 212

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

#inbound?Boolean

Returns:

  • (Boolean)


155
156
157
# File 'lib/punchblock/translator/freeswitch/call.rb', line 155

def inbound?
  direction == :inbound
end

#logger_idObject



216
217
218
# File 'lib/punchblock/translator/freeswitch/call.rb', line 216

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

#outbound?Boolean

Returns:

  • (Boolean)


151
152
153
# File 'lib/punchblock/translator/freeswitch/call.rb', line 151

def outbound?
  direction == :outbound
end

#register_component(component) ⇒ Object



49
50
51
# File 'lib/punchblock/translator/freeswitch/call.rb', line 49

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

#send_offerObject



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

def send_offer
  @direction = :inbound
  send_pb_event offer_event
end

#sendmsg(*args) ⇒ Object



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

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

#setup_handlersObject



67
68
69
70
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
# File 'lib/punchblock/translator/freeswitch/call.rb', line 67

def setup_handlers
  register_handler :es, :event_name => 'CHANNEL_ANSWER' do
    @answered = true
    send_pb_event Event::Answered.new
  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_id = event[:unique_id] == id ? event[:other_leg_unique_id] : event[:unique_id]
    send_pb_event Event::Joined.new(:call_id => other_call_id)
  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_id = event[:unique_id] == id ? event[:other_leg_unique_id] : event[:unique_id]
    send_pb_event Event::Unjoined.new(:call_id => other_call_id)
  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
  end
end

#to_sObject Also known as: inspect



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

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

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



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

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