lib/rtcp.rb

Summary

Maintainability
A
0 mins
Test Coverage
require_relative 'rtcp/version'
require_relative 'rtcp/decode_error'
require_relative 'rtcp/sr'
require_relative 'rtcp/rr'
require_relative 'rtcp/sdes'
require_relative 'rtcp/bye'
require_relative 'rtcp/xr'
require_relative 'rtcp/app'
require_relative 'rtcp/rsi'
require_relative 'rtcp/psfb'

class RTCP

  attr_reader :length, :type_id

  @@packet_classes = {}
  self.constants.each do |sym|
    const = self.const_get(sym)
    if const.is_a?(Class) && const <= self
      @@packet_classes[const::PT_ID] = const
    end
  end

  # Decodes the supplied RTCP packet and returns it
  def self.decode(data)
    raise(RTCP::DecodeError, "Truncated Packet") if (data.length < 4)

    packet_type, length = data.unpack('xCn')
    length = 4 * (length + 1)
    raise(RTCP::DecodeError, "Truncated Packet") if (data.length < length)

    self.packet_class(packet_type).new.decode(data.slice(0..(length - 1)))
  end

  # Decodes all RTCP packets in the supplied string returns them in an array
  def self.decode_all(data)
    packets = []
    while data && data.length > 0
      packet = self.decode(data)
      packets.push(packet)
      data = data.slice(packet.length..-1)
    end
    packets
  end

  def decode(packet_data)
    @type_id, length = packet_data.unpack('xCn')
    @length      = 4 * (length + 1)

    @packet_data = packet_data
    self
  end

  # Returns the packet as RTCP data string
  def to_s
    @packet_data
  end

  protected

  # Ensures that the current RTCP Packet object is able to decode the RTCP
  # packet with the given Packet Type ID.
  #
  # Raises an RTCP::DecodeError exception when this is not the case.
  def ensure_packet_type(packet_type)
    if packet_type != self.class::PT_ID
      raise(RTCP::DecodeError, "Wrong Packet Type. packet_type=#{packet_type}")
    end
  end

  # Extracts and returns the payload data from the given packet_data using the
  # supplied packet length and header_length values.
  #
  # It also sets the @packet_data instance variable, which is currently used
  # by the to_s method for returning the packet data.
  #
  # Raises an RTCP::DecodeError exception when the packet_data is shorter
  # than packet_length.
  def payload_data(packet_data, packet_length, header_length)
    if packet_data.length > packet_length
      @packet_data = packet_data[0..packet_length]
    elsif packet_data.length == packet_length
      @packet_data = packet_data
    else
      raise RTCP::DecodeError, "Truncated Packet"
    end

    @packet_data[header_length..-1]
  end

  private

  # Returns the Class to use for handling RTCP packets of the given packet
  # type.
  def self.packet_class(packet_type)
    @@packet_classes[packet_type] || self
  end

end