1 /*
2  *  Copyright (c) 2017 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 #include "api/audio_codecs/ilbc/audio_encoder_ilbc.h"
12 
13 #include <memory>
14 #include <vector>
15 
16 #include "absl/strings/match.h"
17 #include "modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h"
18 #include "rtc_base/numerics/safe_conversions.h"
19 #include "rtc_base/numerics/safe_minmax.h"
20 #include "rtc_base/string_to_number.h"
21 
22 namespace webrtc {
23 namespace {
GetIlbcBitrate(int ptime)24 int GetIlbcBitrate(int ptime) {
25   switch (ptime) {
26     case 20:
27     case 40:
28       // 38 bytes per frame of 20 ms => 15200 bits/s.
29       return 15200;
30     case 30:
31     case 60:
32       // 50 bytes per frame of 30 ms => (approx) 13333 bits/s.
33       return 13333;
34     default:
35       FATAL();
36   }
37 }
38 }  // namespace
39 
SdpToConfig(const SdpAudioFormat & format)40 absl::optional<AudioEncoderIlbcConfig> AudioEncoderIlbc::SdpToConfig(
41     const SdpAudioFormat& format) {
42   if (!absl::EqualsIgnoreCase(format.name.c_str(), "ILBC") ||
43       format.clockrate_hz != 8000 || format.num_channels != 1) {
44     return absl::nullopt;
45   }
46 
47   AudioEncoderIlbcConfig config;
48   auto ptime_iter = format.parameters.find("ptime");
49   if (ptime_iter != format.parameters.end()) {
50     auto ptime = rtc::StringToNumber<int>(ptime_iter->second);
51     if (ptime && *ptime > 0) {
52       const int whole_packets = *ptime / 10;
53       config.frame_size_ms = rtc::SafeClamp<int>(whole_packets * 10, 20, 60);
54     }
55   }
56   return config.IsOk() ? absl::optional<AudioEncoderIlbcConfig>(config)
57                        : absl::nullopt;
58 }
59 
AppendSupportedEncoders(std::vector<AudioCodecSpec> * specs)60 void AudioEncoderIlbc::AppendSupportedEncoders(
61     std::vector<AudioCodecSpec>* specs) {
62   const SdpAudioFormat fmt = {"ILBC", 8000, 1};
63   const AudioCodecInfo info = QueryAudioEncoder(*SdpToConfig(fmt));
64   specs->push_back({fmt, info});
65 }
66 
QueryAudioEncoder(const AudioEncoderIlbcConfig & config)67 AudioCodecInfo AudioEncoderIlbc::QueryAudioEncoder(
68     const AudioEncoderIlbcConfig& config) {
69   RTC_DCHECK(config.IsOk());
70   return {8000, 1, GetIlbcBitrate(config.frame_size_ms)};
71 }
72 
MakeAudioEncoder(const AudioEncoderIlbcConfig & config,int payload_type,absl::optional<AudioCodecPairId>)73 std::unique_ptr<AudioEncoder> AudioEncoderIlbc::MakeAudioEncoder(
74     const AudioEncoderIlbcConfig& config,
75     int payload_type,
76     absl::optional<AudioCodecPairId> /*codec_pair_id*/) {
77   RTC_DCHECK(config.IsOk());
78   return std::make_unique<AudioEncoderIlbcImpl>(config, payload_type);
79 }
80 
81 }  // namespace webrtc
82