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