blob: 84a62a10b316b927529520e4b47fc67fa3614b9b [file] [log] [blame]
Alex Loiko44c21f42019-04-25 15:09:32 +02001/*
2 * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11/*
12 * LEFT TO DO:
13 * - WRITE TESTS for the stuff in this file.
14 * - Check the creation, maybe make it safer by returning an empty optional or
15 * unique_ptr. --- It looks OK, but RecreateEncoderInstance can perhaps crash
16 * on a valid config. Can run it in the fuzzer for some time. Should prbl also
17 * fuzz the config.
18 */
19
20#include "modules/audio_coding/codecs/opus/audio_encoder_multi_channel_opus_impl.h"
21
22#include <algorithm>
23#include <memory>
24#include <string>
25#include <vector>
26
27#include "absl/memory/memory.h"
28#include "absl/strings/match.h"
29#include "modules/audio_coding/codecs/opus/audio_coder_opus_common.h"
30#include "rtc_base/arraysize.h"
31#include "rtc_base/checks.h"
32#include "rtc_base/logging.h"
33#include "rtc_base/string_to_number.h"
34
35namespace webrtc {
36
37namespace {
38
39// Recommended bitrates for one channel:
40// 8-12 kb/s for NB speech,
41// 16-20 kb/s for WB speech,
42// 28-40 kb/s for FB speech,
43// 48-64 kb/s for FB mono music, and
44// 64-128 kb/s for FB stereo music.
45// The current implementation multiplies these values by the number of channels.
46constexpr int kOpusBitrateNbBps = 12000;
47constexpr int kOpusBitrateWbBps = 20000;
48constexpr int kOpusBitrateFbBps = 32000;
49
50constexpr int kDefaultMaxPlaybackRate = 48000;
51// These two lists must be sorted from low to high
52#if WEBRTC_OPUS_SUPPORT_120MS_PTIME
53constexpr int kOpusSupportedFrameLengths[] = {10, 20, 40, 60, 120};
54#else
55constexpr int kOpusSupportedFrameLengths[] = {10, 20, 40, 60};
56#endif
57
58int GetBitrateBps(const AudioEncoderMultiChannelOpusConfig& config) {
59 RTC_DCHECK(config.IsOk());
60 return config.bitrate_bps;
61}
62int GetMaxPlaybackRate(const SdpAudioFormat& format) {
63 const auto param = GetFormatParameter<int>(format, "maxplaybackrate");
64 if (param && *param >= 8000) {
65 return std::min(*param, kDefaultMaxPlaybackRate);
66 }
67 return kDefaultMaxPlaybackRate;
68}
69
70int GetFrameSizeMs(const SdpAudioFormat& format) {
71 const auto ptime = GetFormatParameter<int>(format, "ptime");
72 if (ptime.has_value()) {
73 // Pick the next highest supported frame length from
74 // kOpusSupportedFrameLengths.
75 for (const int supported_frame_length : kOpusSupportedFrameLengths) {
76 if (supported_frame_length >= *ptime) {
77 return supported_frame_length;
78 }
79 }
80 // If none was found, return the largest supported frame length.
81 return *(std::end(kOpusSupportedFrameLengths) - 1);
82 }
83
84 return AudioEncoderOpusConfig::kDefaultFrameSizeMs;
85}
86
87int CalculateDefaultBitrate(int max_playback_rate, size_t num_channels) {
88 const int bitrate = [&] {
89 if (max_playback_rate <= 8000) {
90 return kOpusBitrateNbBps * rtc::dchecked_cast<int>(num_channels);
91 } else if (max_playback_rate <= 16000) {
92 return kOpusBitrateWbBps * rtc::dchecked_cast<int>(num_channels);
93 } else {
94 return kOpusBitrateFbBps * rtc::dchecked_cast<int>(num_channels);
95 }
96 }();
97 RTC_DCHECK_GE(bitrate, AudioEncoderMultiChannelOpusConfig::kMinBitrateBps);
98 return bitrate;
99}
100
101// Get the maxaveragebitrate parameter in string-form, so we can properly figure
102// out how invalid it is and accurately log invalid values.
103int CalculateBitrate(int max_playback_rate_hz,
104 size_t num_channels,
105 absl::optional<std::string> bitrate_param) {
106 const int default_bitrate =
107 CalculateDefaultBitrate(max_playback_rate_hz, num_channels);
108
109 if (bitrate_param) {
110 const auto bitrate = rtc::StringToNumber<int>(*bitrate_param);
111 if (bitrate) {
112 const int chosen_bitrate =
113 std::max(AudioEncoderOpusConfig::kMinBitrateBps,
114 std::min(*bitrate, AudioEncoderOpusConfig::kMaxBitrateBps));
115 if (bitrate != chosen_bitrate) {
116 RTC_LOG(LS_WARNING) << "Invalid maxaveragebitrate " << *bitrate
117 << " clamped to " << chosen_bitrate;
118 }
119 return chosen_bitrate;
120 }
121 RTC_LOG(LS_WARNING) << "Invalid maxaveragebitrate \"" << *bitrate_param
122 << "\" replaced by default bitrate " << default_bitrate;
123 }
124
125 return default_bitrate;
126}
127
128} // namespace
129
130std::unique_ptr<AudioEncoder>
131AudioEncoderMultiChannelOpusImpl::MakeAudioEncoder(
132 const AudioEncoderMultiChannelOpusConfig& config,
133 int payload_type) {
134 if (!config.IsOk()) {
135 return nullptr;
136 }
137 return absl::make_unique<AudioEncoderMultiChannelOpusImpl>(config,
138 payload_type);
139}
140
141AudioEncoderMultiChannelOpusImpl::AudioEncoderMultiChannelOpusImpl(
142 const AudioEncoderMultiChannelOpusConfig& config,
143 int payload_type)
144 : payload_type_(payload_type), inst_(nullptr) {
145 RTC_DCHECK(0 <= payload_type && payload_type <= 127);
146
147 RTC_CHECK(RecreateEncoderInstance(config));
148}
149
150AudioEncoderMultiChannelOpusImpl::~AudioEncoderMultiChannelOpusImpl() {
151 RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
152}
153
154size_t AudioEncoderMultiChannelOpusImpl::SufficientOutputBufferSize() const {
155 // Calculate the number of bytes we expect the encoder to produce,
156 // then multiply by two to give a wide margin for error.
157 const size_t bytes_per_millisecond =
158 static_cast<size_t>(GetBitrateBps(config_) / (1000 * 8) + 1);
159 const size_t approx_encoded_bytes =
160 Num10msFramesPerPacket() * 10 * bytes_per_millisecond;
161 return 2 * approx_encoded_bytes;
162}
163
164void AudioEncoderMultiChannelOpusImpl::Reset() {
165 RTC_CHECK(RecreateEncoderInstance(config_));
166}
167
168// If the given config is OK, recreate the Opus encoder instance with those
169// settings, save the config, and return true. Otherwise, do nothing and return
170// false.
171bool AudioEncoderMultiChannelOpusImpl::RecreateEncoderInstance(
172 const AudioEncoderMultiChannelOpusConfig& config) {
173 if (!config.IsOk())
174 return false;
175 config_ = config;
176 if (inst_)
177 RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
178 input_buffer_.clear();
179 input_buffer_.reserve(Num10msFramesPerPacket() * SamplesPer10msFrame());
180 RTC_CHECK_EQ(
181 0, WebRtcOpus_MultistreamEncoderCreate(
182 &inst_, config.num_channels,
183 config.application ==
184 AudioEncoderMultiChannelOpusConfig::ApplicationMode::kVoip
185 ? 0
186 : 1,
187 config.num_streams, config.coupled_streams,
188 config.channel_mapping.data()));
189 const int bitrate = GetBitrateBps(config);
190 RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, bitrate));
191 RTC_LOG(LS_VERBOSE) << "Set Opus bitrate to " << bitrate << " bps.";
192 if (config.fec_enabled) {
193 RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_));
194 RTC_LOG(LS_VERBOSE) << "Opus enable FEC";
195 } else {
196 RTC_CHECK_EQ(0, WebRtcOpus_DisableFec(inst_));
197 RTC_LOG(LS_VERBOSE) << "Opus disable FEC";
198 }
199 RTC_CHECK_EQ(
200 0, WebRtcOpus_SetMaxPlaybackRate(inst_, config.max_playback_rate_hz));
201 RTC_LOG(LS_VERBOSE) << "Set Opus playback rate to "
202 << config.max_playback_rate_hz << " hz.";
203
204 // Use the DEFAULT complexity.
205 RTC_CHECK_EQ(
206 0, WebRtcOpus_SetComplexity(inst_, AudioEncoderOpusConfig().complexity));
207 RTC_LOG(LS_VERBOSE) << "Set Opus coding complexity to "
208 << AudioEncoderOpusConfig().complexity;
209
210 if (config.dtx_enabled) {
211 RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_));
212 RTC_LOG(LS_VERBOSE) << "Opus enable DTX";
213 } else {
214 RTC_CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_));
215 RTC_LOG(LS_VERBOSE) << "Opus disable DTX";
216 }
217
218 if (config.cbr_enabled) {
219 RTC_CHECK_EQ(0, WebRtcOpus_EnableCbr(inst_));
220 RTC_LOG(LS_VERBOSE) << "Opus enable CBR";
221 } else {
222 RTC_CHECK_EQ(0, WebRtcOpus_DisableCbr(inst_));
223 RTC_LOG(LS_VERBOSE) << "Opus disable CBR";
224 }
225 num_channels_to_encode_ = NumChannels();
226 next_frame_length_ms_ = config_.frame_size_ms;
227 RTC_LOG(LS_VERBOSE) << "Set Opus frame length to " << config_.frame_size_ms
228 << " ms";
229 return true;
230}
231
232absl::optional<AudioEncoderMultiChannelOpusConfig>
233AudioEncoderMultiChannelOpusImpl::SdpToConfig(const SdpAudioFormat& format) {
234 if (!absl::EqualsIgnoreCase(format.name, "multiopus") ||
235 format.clockrate_hz != 48000) {
236 return absl::nullopt;
237 }
238
239 AudioEncoderMultiChannelOpusConfig config;
240 config.num_channels = format.num_channels;
241 config.frame_size_ms = GetFrameSizeMs(format);
242 config.max_playback_rate_hz = GetMaxPlaybackRate(format);
243 config.fec_enabled = (GetFormatParameter(format, "useinbandfec") == "1");
244 config.dtx_enabled = (GetFormatParameter(format, "usedtx") == "1");
245 config.cbr_enabled = (GetFormatParameter(format, "cbr") == "1");
246 config.bitrate_bps =
247 CalculateBitrate(config.max_playback_rate_hz, config.num_channels,
248 GetFormatParameter(format, "maxaveragebitrate"));
249 config.application =
250 config.num_channels == 1
251 ? AudioEncoderMultiChannelOpusConfig::ApplicationMode::kVoip
252 : AudioEncoderMultiChannelOpusConfig::ApplicationMode::kAudio;
253
254 config.supported_frame_lengths_ms.clear();
255 std::copy(std::begin(kOpusSupportedFrameLengths),
256 std::end(kOpusSupportedFrameLengths),
257 std::back_inserter(config.supported_frame_lengths_ms));
258
259 auto num_streams = GetFormatParameter<int>(format, "num_streams");
260 if (!num_streams.has_value()) {
261 return absl::nullopt;
262 }
263 config.num_streams = *num_streams;
264
265 auto coupled_streams = GetFormatParameter<int>(format, "coupled_streams");
266 if (!coupled_streams.has_value()) {
267 return absl::nullopt;
268 }
269 config.coupled_streams = *coupled_streams;
270
271 auto channel_mapping =
272 GetFormatParameter<std::vector<unsigned char>>(format, "channel_mapping");
273 if (!channel_mapping.has_value()) {
274 return absl::nullopt;
275 }
276 config.channel_mapping = *channel_mapping;
277
278 return config;
279}
280
281AudioCodecInfo AudioEncoderMultiChannelOpusImpl::QueryAudioEncoder(
282 const AudioEncoderMultiChannelOpusConfig& config) {
283 RTC_DCHECK(config.IsOk());
284 AudioCodecInfo info(48000, config.num_channels, config.bitrate_bps,
285 AudioEncoderOpusConfig::kMinBitrateBps,
286 AudioEncoderOpusConfig::kMaxBitrateBps);
287 info.allow_comfort_noise = false;
288 info.supports_network_adaption = false;
289 return info;
290}
291
292size_t AudioEncoderMultiChannelOpusImpl::Num10msFramesPerPacket() const {
293 return static_cast<size_t>(rtc::CheckedDivExact(config_.frame_size_ms, 10));
294}
295size_t AudioEncoderMultiChannelOpusImpl::SamplesPer10msFrame() const {
296 return rtc::CheckedDivExact(48000, 100) * config_.num_channels;
297}
298int AudioEncoderMultiChannelOpusImpl::SampleRateHz() const {
299 return 48000;
300}
301size_t AudioEncoderMultiChannelOpusImpl::NumChannels() const {
302 return config_.num_channels;
303}
304size_t AudioEncoderMultiChannelOpusImpl::Num10MsFramesInNextPacket() const {
305 return Num10msFramesPerPacket();
306}
307size_t AudioEncoderMultiChannelOpusImpl::Max10MsFramesInAPacket() const {
308 return Num10msFramesPerPacket();
309}
310int AudioEncoderMultiChannelOpusImpl::GetTargetBitrate() const {
311 return GetBitrateBps(config_);
312}
313
314AudioEncoder::EncodedInfo AudioEncoderMultiChannelOpusImpl::EncodeImpl(
315 uint32_t rtp_timestamp,
316 rtc::ArrayView<const int16_t> audio,
317 rtc::Buffer* encoded) {
318 if (input_buffer_.empty())
319 first_timestamp_in_buffer_ = rtp_timestamp;
320
321 input_buffer_.insert(input_buffer_.end(), audio.cbegin(), audio.cend());
322 if (input_buffer_.size() <
323 (Num10msFramesPerPacket() * SamplesPer10msFrame())) {
324 return EncodedInfo();
325 }
326 RTC_CHECK_EQ(input_buffer_.size(),
327 Num10msFramesPerPacket() * SamplesPer10msFrame());
328
329 const size_t max_encoded_bytes = SufficientOutputBufferSize();
330 EncodedInfo info;
331 info.encoded_bytes = encoded->AppendData(
332 max_encoded_bytes, [&](rtc::ArrayView<uint8_t> encoded) {
333 int status = WebRtcOpus_Encode(
334 inst_, &input_buffer_[0],
335 rtc::CheckedDivExact(input_buffer_.size(), config_.num_channels),
336 rtc::saturated_cast<int16_t>(max_encoded_bytes), encoded.data());
337
338 RTC_CHECK_GE(status, 0); // Fails only if fed invalid data.
339
340 return static_cast<size_t>(status);
341 });
342 input_buffer_.clear();
343
344 // Will use new packet size for next encoding.
345 config_.frame_size_ms = next_frame_length_ms_;
346
347 info.encoded_timestamp = first_timestamp_in_buffer_;
348 info.payload_type = payload_type_;
349 info.send_even_if_empty = true; // Allows Opus to send empty packets.
350
351 info.speech = true;
352 info.encoder_type = CodecType::kOther;
353
354 return info;
355}
356
357} // namespace webrtc