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/g711/audio_encoder_pcm.h"
12 
13 #include <algorithm>
14 #include <limits>
15 
16 #include "common_types.h"  // NOLINT(build/include)
17 #include "modules/audio_coding/codecs/g711/g711_interface.h"
18 #include "rtc_base/checks.h"
19 
20 namespace webrtc {
21 
22 namespace {
23 
24 template <typename T>
CreateConfig(const CodecInst & codec_inst)25 typename T::Config CreateConfig(const CodecInst& codec_inst) {
26   typename T::Config config;
27   config.frame_size_ms = codec_inst.pacsize / 8;
28   config.num_channels = codec_inst.channels;
29   config.payload_type = codec_inst.pltype;
30   return config;
31 }
32 
33 }  // namespace
34 
IsOk() const35 bool AudioEncoderPcm::Config::IsOk() const {
36   return (frame_size_ms % 10 == 0) && (num_channels >= 1);
37 }
38 
AudioEncoderPcm(const Config & config,int sample_rate_hz)39 AudioEncoderPcm::AudioEncoderPcm(const Config& config, int sample_rate_hz)
40     : sample_rate_hz_(sample_rate_hz),
41       num_channels_(config.num_channels),
42       payload_type_(config.payload_type),
43       num_10ms_frames_per_packet_(
44           static_cast<size_t>(config.frame_size_ms / 10)),
45       full_frame_samples_(
46           config.num_channels * config.frame_size_ms * sample_rate_hz / 1000),
47       first_timestamp_in_buffer_(0) {
48   RTC_CHECK_GT(sample_rate_hz, 0) << "Sample rate must be larger than 0 Hz";
49   RTC_CHECK_EQ(config.frame_size_ms % 10, 0)
50       << "Frame size must be an integer multiple of 10 ms.";
51   speech_buffer_.reserve(full_frame_samples_);
52 }
53 
54 AudioEncoderPcm::~AudioEncoderPcm() = default;
55 
SampleRateHz() const56 int AudioEncoderPcm::SampleRateHz() const {
57   return sample_rate_hz_;
58 }
59 
NumChannels() const60 size_t AudioEncoderPcm::NumChannels() const {
61   return num_channels_;
62 }
63 
Num10MsFramesInNextPacket() const64 size_t AudioEncoderPcm::Num10MsFramesInNextPacket() const {
65   return num_10ms_frames_per_packet_;
66 }
67 
Max10MsFramesInAPacket() const68 size_t AudioEncoderPcm::Max10MsFramesInAPacket() const {
69   return num_10ms_frames_per_packet_;
70 }
71 
GetTargetBitrate() const72 int AudioEncoderPcm::GetTargetBitrate() const {
73   return static_cast<int>(
74       8 * BytesPerSample() * SampleRateHz() * NumChannels());
75 }
76 
EncodeImpl(uint32_t rtp_timestamp,rtc::ArrayView<const int16_t> audio,rtc::Buffer * encoded)77 AudioEncoder::EncodedInfo AudioEncoderPcm::EncodeImpl(
78     uint32_t rtp_timestamp,
79     rtc::ArrayView<const int16_t> audio,
80     rtc::Buffer* encoded) {
81   if (speech_buffer_.empty()) {
82     first_timestamp_in_buffer_ = rtp_timestamp;
83   }
84   speech_buffer_.insert(speech_buffer_.end(), audio.begin(), audio.end());
85   if (speech_buffer_.size() < full_frame_samples_) {
86     return EncodedInfo();
87   }
88   RTC_CHECK_EQ(speech_buffer_.size(), full_frame_samples_);
89   EncodedInfo info;
90   info.encoded_timestamp = first_timestamp_in_buffer_;
91   info.payload_type = payload_type_;
92   info.encoded_bytes =
93       encoded->AppendData(full_frame_samples_ * BytesPerSample(),
94                           [&] (rtc::ArrayView<uint8_t> encoded) {
95                             return EncodeCall(&speech_buffer_[0],
96                                               full_frame_samples_,
97                                               encoded.data());
98                           });
99   speech_buffer_.clear();
100   info.encoder_type = GetCodecType();
101   return info;
102 }
103 
Reset()104 void AudioEncoderPcm::Reset() {
105   speech_buffer_.clear();
106 }
107 
AudioEncoderPcmA(const CodecInst & codec_inst)108 AudioEncoderPcmA::AudioEncoderPcmA(const CodecInst& codec_inst)
109     : AudioEncoderPcmA(CreateConfig<AudioEncoderPcmA>(codec_inst)) {}
110 
EncodeCall(const int16_t * audio,size_t input_len,uint8_t * encoded)111 size_t AudioEncoderPcmA::EncodeCall(const int16_t* audio,
112                                     size_t input_len,
113                                     uint8_t* encoded) {
114   return WebRtcG711_EncodeA(audio, input_len, encoded);
115 }
116 
BytesPerSample() const117 size_t AudioEncoderPcmA::BytesPerSample() const {
118   return 1;
119 }
120 
GetCodecType() const121 AudioEncoder::CodecType AudioEncoderPcmA::GetCodecType() const {
122   return AudioEncoder::CodecType::kPcmA;
123 }
124 
AudioEncoderPcmU(const CodecInst & codec_inst)125 AudioEncoderPcmU::AudioEncoderPcmU(const CodecInst& codec_inst)
126     : AudioEncoderPcmU(CreateConfig<AudioEncoderPcmU>(codec_inst)) {}
127 
EncodeCall(const int16_t * audio,size_t input_len,uint8_t * encoded)128 size_t AudioEncoderPcmU::EncodeCall(const int16_t* audio,
129                                     size_t input_len,
130                                     uint8_t* encoded) {
131   return WebRtcG711_EncodeU(audio, input_len, encoded);
132 }
133 
BytesPerSample() const134 size_t AudioEncoderPcmU::BytesPerSample() const {
135   return 1;
136 }
137 
GetCodecType() const138 AudioEncoder::CodecType AudioEncoderPcmU::GetCodecType() const {
139   return AudioEncoder::CodecType::kPcmU;
140 }
141 
142 }  // namespace webrtc
143