Class: Webmidi::Network::RTP::Session

Inherits:
Object
  • Object
show all
Defined in:
lib/webmidi/network/rtp.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(port:, name:, mode: :server, ssrc: SecureRandom.random_number(0xFFFFFFFF)) ⇒ Session

Returns a new instance of Session.



226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/webmidi/network/rtp.rb', line 226

def initialize(port:, name:, mode: :server, ssrc: SecureRandom.random_number(0xFFFFFFFF))
  @port = port
  @name = name
  @mode = mode
  @ssrc = ssrc
  @sequence_number = 0
  @peers = []
  @callbacks = []
  @control_callbacks = []
  @error_callbacks = []
  @mutex = Mutex.new
  @running = false
  @socket = nil
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



224
225
226
# File 'lib/webmidi/network/rtp.rb', line 224

def name
  @name
end

#portObject (readonly)

Returns the value of attribute port.



257
258
259
# File 'lib/webmidi/network/rtp.rb', line 257

def port
  @port
end

#ssrcObject (readonly)

Returns the value of attribute ssrc.



224
225
226
# File 'lib/webmidi/network/rtp.rb', line 224

def ssrc
  @ssrc
end

Instance Method Details

#add_peer(host, port) ⇒ Object



265
266
267
268
269
270
# File 'lib/webmidi/network/rtp.rb', line 265

def add_peer(host, port)
  validate_peer!(host, port)
  peer = {host: host, port: port}
  @mutex.synchronize { @peers << peer unless @peers.include?(peer) }
  self
end

#closeObject



331
332
333
# File 'lib/webmidi/network/rtp.rb', line 331

def close
  stop
end

#connect_to(host, port) ⇒ Object



259
260
261
262
263
# File 'lib/webmidi/network/rtp.rb', line 259

def connect_to(host, port)
  start unless @running
  add_peer(host, port)
  self
end

#on_control_packet(&block) ⇒ Object

Raises:

  • (ArgumentError)


316
317
318
319
320
321
322
323
# File 'lib/webmidi/network/rtp.rb', line 316

def on_control_packet(&block)
  raise ArgumentError, "on_control_packet requires a block" unless block

  @mutex.synchronize { @control_callbacks << block }
  CallbackSubscription.new do
    @mutex.synchronize { @control_callbacks.delete(block) }
  end
end

#on_error(&block) ⇒ Object

Raises:

  • (ArgumentError)


307
308
309
310
311
312
313
314
# File 'lib/webmidi/network/rtp.rb', line 307

def on_error(&block)
  raise ArgumentError, "on_error requires a block" unless block

  @mutex.synchronize { @error_callbacks << block }
  CallbackSubscription.new do
    @mutex.synchronize { @error_callbacks.delete(block) }
  end
end

#on_message(&block) ⇒ Object

Raises:

  • (ArgumentError)


298
299
300
301
302
303
304
305
# File 'lib/webmidi/network/rtp.rb', line 298

def on_message(&block)
  raise ArgumentError, "on_message requires a block" unless block

  @mutex.synchronize { @callbacks << block }
  CallbackSubscription.new do
    @mutex.synchronize { @callbacks.delete(block) }
  end
end

#peersObject



277
278
279
# File 'lib/webmidi/network/rtp.rb', line 277

def peers
  @mutex.synchronize { @peers.map(&:dup) }
end

#remove_peer(host, port) ⇒ Object



272
273
274
275
# File 'lib/webmidi/network/rtp.rb', line 272

def remove_peer(host, port)
  @mutex.synchronize { @peers.delete({host: host, port: port}) }
  self
end

#send(message) ⇒ Object



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/webmidi/network/rtp.rb', line 281

def send(message)
  bytes = outbound_midi_bytes(message)

  packet = Packet.new(
    sequence_number: next_sequence,
    timestamp: (Process.clock_gettime(Process::CLOCK_MONOTONIC) * 1000).to_i,
    ssrc: @ssrc,
    midi_data: bytes
  )

  packet_bytes = packet.to_bytes
  @mutex.synchronize do
    @peers.each { |peer| @socket&.send(packet_bytes, 0, peer[:host], peer[:port]) }
  end
  self
end

#send_control_packet(packet, host, port) ⇒ Object



325
326
327
328
329
# File 'lib/webmidi/network/rtp.rb', line 325

def send_control_packet(packet, host, port)
  start unless @running
  @socket&.send(packet.to_bytes, 0, host, port)
  self
end

#startObject



241
242
243
244
245
246
247
248
# File 'lib/webmidi/network/rtp.rb', line 241

def start
  @socket = UDPSocket.new
  @socket.bind("0.0.0.0", @port)
  @port = @socket.addr[1] if @port.zero?
  @running = true
  @receive_thread = Thread.new { receive_loop }
  self
end

#stopObject



250
251
252
253
254
255
# File 'lib/webmidi/network/rtp.rb', line 250

def stop
  @running = false
  @socket&.close
  @receive_thread&.join(1)
  self
end