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