-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaudio.ex
136 lines (115 loc) · 3.69 KB
/
audio.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
defmodule Membrane.Transcoder.Audio do
@moduledoc false
import Membrane.ChildrenSpec
require Membrane.Logger
alias Membrane.{AAC, ChildrenSpec, Opus, RawAudio, RemoteStream}
@opus_sample_rate 48_000
@aac_sample_rates [
96_000,
88_200,
64_000,
48_000,
44_100,
32_000,
24_000,
22_050,
16_000,
12_000,
11_025,
8000
]
@type audio_stream_format :: AAC.t() | Opus.t() | RawAudio.t()
defguard is_audio_format(format)
when is_struct(format) and
(format.__struct__ in [AAC, Opus, RawAudio] or
(format.__struct__ == RemoteStream and format.content_format == Opus and
format.type == :packetized))
@spec plug_audio_transcoding(
ChildrenSpec.builder(),
audio_stream_format() | RemoteStream.t(),
audio_stream_format(),
boolean()
) :: ChildrenSpec.builder()
def plug_audio_transcoding(builder, input_format, output_format, enforce_transcoding?)
when is_audio_format(input_format) and is_audio_format(output_format) do
do_plug_audio_transcoding(builder, input_format, output_format, enforce_transcoding?)
end
defp do_plug_audio_transcoding(
builder,
%format_module{},
%format_module{},
false = _enforce_transcoding?
) do
Membrane.Logger.debug("""
This bin will only forward buffers, as the input stream format is the same as the output stream format.
""")
builder
end
defp do_plug_audio_transcoding(
builder,
%RemoteStream{content_format: Opus},
%Opus{},
false = _enforce_transcoding?
) do
builder |> child(:opus_parser, Opus.Parser)
end
defp do_plug_audio_transcoding(builder, input_format, output_format, _enforce_transcoding?) do
builder
|> maybe_plug_parser(input_format)
|> maybe_plug_decoder(input_format)
|> maybe_plug_resampler(input_format, output_format)
|> maybe_plug_encoder(output_format)
end
defp maybe_plug_parser(builder, %AAC{}) do
builder |> child(:aac_parser, AAC.Parser)
end
defp maybe_plug_parser(builder, _input_format) do
builder
end
defp maybe_plug_decoder(builder, %Opus{}) do
builder |> child(:opus_decoder, Opus.Decoder)
end
defp maybe_plug_decoder(builder, %RemoteStream{content_format: Opus, type: :packetized}) do
builder |> child(:opus_decoder, Opus.Decoder)
end
defp maybe_plug_decoder(builder, %AAC{}) do
builder |> child(:aac_decoder, AAC.FDK.Decoder)
end
defp maybe_plug_decoder(builder, %RawAudio{}) do
builder
end
defp maybe_plug_resampler(builder, %{sample_rate: sample_rate} = input_format, %Opus{})
when sample_rate != @opus_sample_rate do
builder
|> child(:resampler, %Membrane.FFmpeg.SWResample.Converter{
output_stream_format: %RawAudio{
sample_format: :s16le,
sample_rate: @opus_sample_rate,
channels: input_format.channels
}
})
end
defp maybe_plug_resampler(builder, %{sample_rate: sample_rate} = input_format, %AAC{})
when sample_rate not in @aac_sample_rates do
builder
|> child(:resampler, %Membrane.FFmpeg.SWResample.Converter{
output_stream_format: %RawAudio{
sample_format: :s16le,
sample_rate: 44_100,
channels: input_format.channels
}
})
end
defp maybe_plug_resampler(builder, _input_format, _output_format) do
builder
end
defp maybe_plug_encoder(builder, %Opus{}) do
builder |> child(:opus_encoder, Opus.Encoder)
end
defp maybe_plug_encoder(builder, %AAC{}) do
builder |> child(:aac_encoder, AAC.FDK.Encoder)
end
defp maybe_plug_encoder(builder, %RawAudio{}) do
builder
end
end