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
19namespace webrtc {
20
21namespace {
22
23const int kSampleRateHz = 8000;
24
25AudioEncoderIlbc::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
35const size_t AudioEncoderIlbc::kMaxSamplesPerPacket;
36
37bool 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
44AudioEncoderIlbc::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
52AudioEncoderIlbc::AudioEncoderIlbc(const CodecInst& codec_inst)
53    : AudioEncoderIlbc(CreateConfig(codec_inst)) {}
54
55AudioEncoderIlbc::~AudioEncoderIlbc() {
56  RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_));
57}
58
59size_t AudioEncoderIlbc::MaxEncodedBytes() const {
60  return RequiredOutputSizeBytes();
61}
62
63int AudioEncoderIlbc::SampleRateHz() const {
64  return kSampleRateHz;
65}
66
67size_t AudioEncoderIlbc::NumChannels() const {
68  return 1;
69}
70
71size_t AudioEncoderIlbc::Num10MsFramesInNextPacket() const {
72  return num_10ms_frames_per_packet_;
73}
74
75size_t AudioEncoderIlbc::Max10MsFramesInAPacket() const {
76  return num_10ms_frames_per_packet_;
77}
78
79int 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
92AudioEncoder::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
131void 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
143size_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