1 /*
2  *  Copyright (c) 2014 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 "modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h"
12 
13 #include <algorithm>
14 #include <limits>
15 #include "common_types.h"  // NOLINT(build/include)
16 #include "modules/audio_coding/codecs/ilbc/ilbc.h"
17 #include "rtc_base/checks.h"
18 #include "rtc_base/numerics/safe_conversions.h"
19 
20 namespace webrtc {
21 
22 namespace {
23 
24 const int kSampleRateHz = 8000;
25 
CreateConfig(const CodecInst & codec_inst)26 AudioEncoderIlbcConfig CreateConfig(const CodecInst& codec_inst) {
27   AudioEncoderIlbcConfig config;
28   config.frame_size_ms = codec_inst.pacsize / 8;
29   return config;
30 }
31 
GetIlbcBitrate(int ptime)32 int GetIlbcBitrate(int ptime) {
33   switch (ptime) {
34     case 20:
35     case 40:
36       // 38 bytes per frame of 20 ms => 15200 bits/s.
37       return 15200;
38     case 30:
39     case 60:
40       // 50 bytes per frame of 30 ms => (approx) 13333 bits/s.
41       return 13333;
42     default:
43       FATAL();
44   }
45 }
46 
47 }  // namespace
48 
AudioEncoderIlbcImpl(const AudioEncoderIlbcConfig & config,int payload_type)49 AudioEncoderIlbcImpl::AudioEncoderIlbcImpl(const AudioEncoderIlbcConfig& config,
50                                            int payload_type)
51     : frame_size_ms_(config.frame_size_ms),
52       payload_type_(payload_type),
53       num_10ms_frames_per_packet_(
54           static_cast<size_t>(config.frame_size_ms / 10)),
55       encoder_(nullptr) {
56   RTC_CHECK(config.IsOk());
57   Reset();
58 }
59 
AudioEncoderIlbcImpl(const CodecInst & codec_inst)60 AudioEncoderIlbcImpl::AudioEncoderIlbcImpl(const CodecInst& codec_inst)
61     : AudioEncoderIlbcImpl(CreateConfig(codec_inst), codec_inst.pltype) {}
62 
~AudioEncoderIlbcImpl()63 AudioEncoderIlbcImpl::~AudioEncoderIlbcImpl() {
64   RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_));
65 }
66 
SampleRateHz() const67 int AudioEncoderIlbcImpl::SampleRateHz() const {
68   return kSampleRateHz;
69 }
70 
NumChannels() const71 size_t AudioEncoderIlbcImpl::NumChannels() const {
72   return 1;
73 }
74 
Num10MsFramesInNextPacket() const75 size_t AudioEncoderIlbcImpl::Num10MsFramesInNextPacket() const {
76   return num_10ms_frames_per_packet_;
77 }
78 
Max10MsFramesInAPacket() const79 size_t AudioEncoderIlbcImpl::Max10MsFramesInAPacket() const {
80   return num_10ms_frames_per_packet_;
81 }
82 
GetTargetBitrate() const83 int AudioEncoderIlbcImpl::GetTargetBitrate() const {
84   return GetIlbcBitrate(rtc::dchecked_cast<int>(num_10ms_frames_per_packet_) *
85                         10);
86 }
87 
EncodeImpl(uint32_t rtp_timestamp,rtc::ArrayView<const int16_t> audio,rtc::Buffer * encoded)88 AudioEncoder::EncodedInfo AudioEncoderIlbcImpl::EncodeImpl(
89     uint32_t rtp_timestamp,
90     rtc::ArrayView<const int16_t> audio,
91     rtc::Buffer* encoded) {
92 
93   // Save timestamp if starting a new packet.
94   if (num_10ms_frames_buffered_ == 0)
95     first_timestamp_in_buffer_ = rtp_timestamp;
96 
97   // Buffer input.
98   std::copy(audio.cbegin(), audio.cend(),
99             input_buffer_ + kSampleRateHz / 100 * num_10ms_frames_buffered_);
100 
101   // If we don't yet have enough buffered input for a whole packet, we're done
102   // for now.
103   if (++num_10ms_frames_buffered_ < num_10ms_frames_per_packet_) {
104     return EncodedInfo();
105   }
106 
107   // Encode buffered input.
108   RTC_DCHECK_EQ(num_10ms_frames_buffered_, num_10ms_frames_per_packet_);
109   num_10ms_frames_buffered_ = 0;
110   size_t encoded_bytes =
111       encoded->AppendData(
112           RequiredOutputSizeBytes(),
113           [&] (rtc::ArrayView<uint8_t> encoded) {
114             const int r = WebRtcIlbcfix_Encode(
115                 encoder_,
116                 input_buffer_,
117                 kSampleRateHz / 100 * num_10ms_frames_per_packet_,
118                 encoded.data());
119             RTC_CHECK_GE(r, 0);
120 
121             return static_cast<size_t>(r);
122           });
123 
124   RTC_DCHECK_EQ(encoded_bytes, RequiredOutputSizeBytes());
125 
126   EncodedInfo info;
127   info.encoded_bytes = encoded_bytes;
128   info.encoded_timestamp = first_timestamp_in_buffer_;
129   info.payload_type = payload_type_;
130   info.encoder_type = CodecType::kIlbc;
131   return info;
132 }
133 
Reset()134 void AudioEncoderIlbcImpl::Reset() {
135   if (encoder_)
136     RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_));
137   RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderCreate(&encoder_));
138   const int encoder_frame_size_ms = frame_size_ms_ > 30
139                                         ? frame_size_ms_ / 2
140                                         : frame_size_ms_;
141   RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderInit(encoder_, encoder_frame_size_ms));
142   num_10ms_frames_buffered_ = 0;
143 }
144 
RequiredOutputSizeBytes() const145 size_t AudioEncoderIlbcImpl::RequiredOutputSizeBytes() const {
146   switch (num_10ms_frames_per_packet_) {
147     case 2:   return 38;
148     case 3:   return 50;
149     case 4:   return 2 * 38;
150     case 6:   return 2 * 50;
151     default:  FATAL();
152   }
153 }
154 
155 }  // namespace webrtc
156