Home | History | Annotate | Download | only in ilbc
      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 
     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 
     37 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 
     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 
     52 AudioEncoderIlbc::AudioEncoderIlbc(const CodecInst& codec_inst)
     53     : AudioEncoderIlbc(CreateConfig(codec_inst)) {}
     54 
     55 AudioEncoderIlbc::~AudioEncoderIlbc() {
     56   RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_));
     57 }
     58 
     59 size_t AudioEncoderIlbc::MaxEncodedBytes() const {
     60   return RequiredOutputSizeBytes();
     61 }
     62 
     63 int AudioEncoderIlbc::SampleRateHz() const {
     64   return kSampleRateHz;
     65 }
     66 
     67 size_t AudioEncoderIlbc::NumChannels() const {
     68   return 1;
     69 }
     70 
     71 size_t AudioEncoderIlbc::Num10MsFramesInNextPacket() const {
     72   return num_10ms_frames_per_packet_;
     73 }
     74 
     75 size_t AudioEncoderIlbc::Max10MsFramesInAPacket() const {
     76   return num_10ms_frames_per_packet_;
     77 }
     78 
     79 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 
     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 
    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 
    143 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