defmodule Membrane.SilenceGenerator do
@moduledoc """
Element responsible for generating silence as raw audio.
"""
use Membrane.Source
alias Membrane.{Buffer, Time}
alias Membrane.RawAudio
def_options caps: [
type: :struct,
spec: RawAudio.t(),
description:
"Audio caps of generated samples (`t:Membrane.Caps.Audio.RawAudio.t/0`)"
],
duration: [
type: :timeout,
spec: Time.t() | :infinity,
description: "Duration of the generated silent samples"
],
frames_per_buffer: [
type: :integer,
spec: pos_integer(),
description: """
Assumed number of raw audio frames in each buffer.
Used when converting demand from buffers into bytes.
""",
default: 2048
]
def_output_pad :output, caps: RawAudio
@impl true
def handle_init(opts) do
state =
opts
|> Map.from_struct()
|> Map.put(:passed_time, 0)
{:ok, state}
end
@impl true
def handle_prepared_to_playing(_context, %{caps: caps} = state) do
{{:ok, caps: {:output, caps}}, state}
end
@impl true
def handle_demand(:output, size, :bytes, _ctx, %{caps: caps} = state) do
time = RawAudio.bytes_to_time(size, caps)
do_handle_demand(time, state)
end
def handle_demand(:output, buffers, :buffers, _ctx, state) do
%{caps: caps, frames_per_buffer: frames_per_buffer} = state
time = buffers * RawAudio.frames_to_time(frames_per_buffer, caps)
do_handle_demand(time, state)
end
defp do_handle_demand(
time,
%{caps: caps, duration: :infinity, passed_time: passed_time} = state
) do
buffer = %Buffer{payload: RawAudio.silence(caps, time), pts: passed_time}
{{:ok, buffer: {:output, buffer}}, %{state | passed_time: passed_time + time}}
end
defp do_handle_demand(time, state) do
%{caps: caps, duration: duration, passed_time: passed_time} = state
if passed_time + time < duration do
buffer = %Buffer{payload: RawAudio.silence(caps, time), pts: passed_time}
{{:ok, buffer: {:output, buffer}}, %{state | passed_time: passed_time + time}}
else
buffer = %Buffer{payload: RawAudio.silence(caps, duration - passed_time), pts: passed_time}
{{:ok, buffer: {:output, buffer}, end_of_stream: :output}, %{state | passed_time: duration}}
end
end
end