defmodule Membrane.Opus.Decoder do
@moduledoc """
This element performs decoding of Opus audio.
"""
use Membrane.Filter
require Membrane.Logger
alias __MODULE__.Native
alias Membrane.{Buffer, Opus, RemoteStream}
alias Membrane.Opus.Util
alias Membrane.RawAudio
def_options sample_rate: [
spec: 8_000 | 12_000 | 16_000 | 24_000 | 48_000,
default: 48_000,
description: """
Sample rate to decode at. Note: Opus is able to decode any stream
at any supported sample rate. 48 kHz is recommended. For details,
see https://tools.ietf.org/html/rfc7845#section-5.1 point 5.
"""
]
def_input_pad :input,
accepted_format:
any_of(
%Opus{self_delimiting?: false},
%RemoteStream{type: :packetized, content_format: format} when format in [Opus, nil]
)
def_output_pad :output, accepted_format: %RawAudio{sample_format: :s16le}
@impl true
def handle_init(_ctx, %__MODULE__{} = options) do
state =
options
|> Map.from_struct()
|> Map.merge(%{native: nil, channels: nil})
{[], state}
end
@impl true
def handle_stream_format(:input, %Opus{channels: channels}, _ctx, state) do
maybe_make_native(channels, state)
end
@impl true
def handle_stream_format(:input, _stream_format, _ctx, state) do
{[], state}
end
@impl true
def handle_buffer(:input, buffer, _ctx, state) do
if buffer.payload === "" do
Membrane.Logger.warning("Payload is empty.")
{[], state}
else
{:ok, _config_number, stereo_flag, _frame_packing} = Util.parse_toc_byte(buffer.payload)
channels = Util.parse_channels(stereo_flag)
{stream_format, state} = maybe_make_native(channels, state)
decoded = Native.decode_packet(state.native, buffer.payload)
buffer = %Buffer{buffer | payload: decoded}
{stream_format ++ [buffer: {:output, buffer}], state}
end
end
defp maybe_make_native(channels, %{channels: channels} = state) do
{[], state}
end
defp maybe_make_native(channels, state) do
native = Native.create(state.sample_rate, channels)
stream_format = %RawAudio{
sample_format: :s16le,
channels: channels,
sample_rate: state.sample_rate
}
{[stream_format: {:output, stream_format}], %{state | native: native, channels: channels}}
end
end