Packages
parrot_platform
0.0.1-alpha.3
Elixir libraries and OTP behaviours for building telecom applications with SIP protocol and media handling
Current section
Files
Jump to
Current section
Files
lib/parrot/media/simple_rtp_receiver.ex
defmodule Parrot.Media.SimpleRTPReceiver do
@moduledoc """
A simple RTP receiver that extracts audio payload from RTP packets.
This bypasses the complexity of the RTP SessionBin for basic G.711 audio.
"""
use Membrane.Filter
alias Membrane.Buffer
alias Membrane.G711
def_input_pad(:input,
accepted_format: %Membrane.RemoteStream{type: :packetized},
availability: :always
)
def_output_pad(:output,
accepted_format: %G711{encoding: _encoding},
availability: :always
)
def_options(
clock_rate: [
spec: pos_integer(),
default: 8000,
description: "Clock rate for the codec"
],
selected_codec: [
spec: :pcmu | :pcma,
default: :pcmu,
description: "Selected codec"
]
)
@impl true
def handle_init(_ctx, opts) do
state = %{
clock_rate: opts.clock_rate,
selected_codec: opts.selected_codec,
last_timestamp: nil,
last_seq_num: nil
}
{[], state}
end
@impl true
def handle_playing(_ctx, state) do
{[], state}
end
@impl true
def handle_stream_format(:input, _stream_format, _ctx, state) do
# Output the appropriate G.711 format
format =
case state.selected_codec do
:pcma -> %G711{encoding: :PCMA}
:pcmu -> %G711{encoding: :PCMU}
end
{[stream_format: {:output, format}], state}
end
@impl true
def handle_buffer(:input, buffer, _ctx, state) do
require Logger
Logger.debug("SimpleRTPReceiver got buffer, size: #{byte_size(buffer.payload)}")
# Parse RTP packet
case parse_rtp_packet(buffer.payload) do
{:ok, payload, seq_num, timestamp, payload_type} ->
Logger.debug(
"RTP packet received: seq=#{seq_num}, ts=#{timestamp}, pt=#{payload_type}, payload_size=#{byte_size(payload)}"
)
# Create output buffer with just the audio payload
output_buffer = %Buffer{
payload: payload,
metadata: buffer.metadata,
pts: buffer.pts,
dts: buffer.dts
}
{[buffer: {:output, output_buffer}], state}
{:error, reason} ->
Logger.warning(
"Failed to parse RTP packet: #{reason}, buffer size: #{byte_size(buffer.payload)}"
)
# Skip malformed packets
{[], state}
end
end
# Simple RTP parser - extracts payload from RTP packet
defp parse_rtp_packet(<<
_version::2,
_padding::1,
_extension::1,
cc::4,
_marker::1,
payload_type::7,
seq_num::16,
timestamp::32,
_ssrc::32,
_csrc::binary-size(cc * 4),
payload::binary
>>) do
{:ok, payload, seq_num, timestamp, payload_type}
end
defp parse_rtp_packet(_), do: {:error, :invalid_packet}
end