Class: Webmidi::Network::RTP::Packet

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sequence_number:, timestamp:, ssrc:, midi_data:) ⇒ Packet

Returns a new instance of Packet.



156
157
158
159
160
161
162
163
164
165
# File 'lib/webmidi/network/rtp.rb', line 156

def initialize(sequence_number:, timestamp:, ssrc:, midi_data:)
  self.class.validate_range!(sequence_number, "Sequence number", 0, 0xFFFF)
  self.class.validate_range!(timestamp, "Timestamp", 0, 0xFFFF_FFFF)
  self.class.validate_range!(ssrc, "SSRC", 0, 0xFFFF_FFFF)
  self.class.validate_midi_data!(midi_data)
  @sequence_number = sequence_number
  @timestamp = timestamp
  @ssrc = ssrc
  @midi_data = midi_data.dup.freeze
end

Instance Attribute Details

#midi_dataObject (readonly)

Returns the value of attribute midi_data.



154
155
156
# File 'lib/webmidi/network/rtp.rb', line 154

def midi_data
  @midi_data
end

#sequence_numberObject (readonly)

Returns the value of attribute sequence_number.



154
155
156
# File 'lib/webmidi/network/rtp.rb', line 154

def sequence_number
  @sequence_number
end

#ssrcObject (readonly)

Returns the value of attribute ssrc.



154
155
156
# File 'lib/webmidi/network/rtp.rb', line 154

def ssrc
  @ssrc
end

#timestampObject (readonly)

Returns the value of attribute timestamp.



154
155
156
# File 'lib/webmidi/network/rtp.rb', line 154

def timestamp
  @timestamp
end

Class Method Details

.parse(bytes) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/webmidi/network/rtp.rb', line 183

def self.parse(bytes)
  return nil if bytes.bytesize < 14

  flags, payload_type, seq = bytes[0, 4].unpack("CCn")
  return nil unless (flags >> 6) == PROTOCOL_VERSION
  return nil unless payload_type == MIDI_PAYLOAD_TYPE

  timestamp, ssrc = bytes[4, 8].unpack("NN")
  midi_length = bytes[12, 2].unpack1("n")
  return nil unless bytes.bytesize == 14 + midi_length

  midi_data = bytes[14, midi_length].bytes

  new(
    sequence_number: seq,
    timestamp: timestamp,
    ssrc: ssrc,
    midi_data: midi_data
  )
end

.validate_midi_data!(midi_data) ⇒ Object



210
211
212
213
214
215
216
217
218
219
220
# File 'lib/webmidi/network/rtp.rb', line 210

def self.validate_midi_data!(midi_data)
  unless midi_data.respond_to?(:each)
    raise InvalidMessageError, "MIDI data must be enumerable, got #{midi_data.class}"
  end

  midi_data.each_with_index do |byte, index|
    next if byte.is_a?(Integer) && byte.between?(0, 255)

    raise InvalidMessageError, "MIDI data byte #{index} must be between 0 and 255, got #{byte.inspect}"
  end
end

.validate_range!(value, name, min, max) ⇒ Object



204
205
206
207
208
# File 'lib/webmidi/network/rtp.rb', line 204

def self.validate_range!(value, name, min, max)
  return if value.is_a?(Integer) && value.between?(min, max)

  raise InvalidMessageError, "#{name} must be between #{min} and #{max}, got #{value.inspect}"
end

Instance Method Details

#to_bytesObject



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/webmidi/network/rtp.rb', line 167

def to_bytes
  midi_bytes = @midi_data.flatten
  header = [
    (PROTOCOL_VERSION << 6) | 0x00,
    MIDI_PAYLOAD_TYPE,
    @sequence_number & 0xFFFF
  ].pack("CCn")

  header += [@timestamp, @ssrc].pack("NN")

  header += [midi_bytes.size].pack("n")
  header += midi_bytes.pack("C*")

  header
end