-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaudio.ex
125 lines (104 loc) · 3.45 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
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()
) :: ChildrenSpec.builder()
def plug_audio_transcoding(builder, input_format, output_format)
when is_audio_format(input_format) and is_audio_format(output_format) do
do_plug_audio_transcoding(builder, input_format, output_format)
end
defp do_plug_audio_transcoding(builder, %format_module{}, %format_module{}) 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{}) do
builder |> child(:opus_parser, Opus.Parser)
end
defp do_plug_audio_transcoding(builder, input_format, output_format) 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