blob: fce7721dd6e9f7b1f299da9ecc45bc7b986386cb [file] [log] [blame]
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h"
#include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h"
namespace webrtc {
namespace {
// We always encode at 48 kHz.
const int kSampleRateHz = 48000;
int16_t ClampInt16(size_t x) {
return static_cast<int16_t>(
std::min(x, static_cast<size_t>(std::numeric_limits<int16_t>::max())));
}
int16_t CastInt16(size_t x) {
DCHECK_LE(x, static_cast<size_t>(std::numeric_limits<int16_t>::max()));
return static_cast<int16_t>(x);
}
} // namespace
AudioEncoderOpus::Config::Config()
: frame_size_ms(20),
num_channels(1),
payload_type(120),
application(kVoip) {
}
bool AudioEncoderOpus::Config::IsOk() const {
if (frame_size_ms <= 0 || frame_size_ms % 10 != 0)
return false;
if (num_channels <= 0)
return false;
return true;
}
AudioEncoderOpus::AudioEncoderOpus(const Config& config)
: num_10ms_frames_per_packet_(
rtc::CheckedDivExact(config.frame_size_ms, 10)),
num_channels_(config.num_channels),
payload_type_(config.payload_type),
application_(config.application),
samples_per_10ms_frame_(rtc::CheckedDivExact(kSampleRateHz, 100) *
num_channels_) {
CHECK(config.IsOk());
input_buffer_.reserve(num_10ms_frames_per_packet_ * samples_per_10ms_frame_);
CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, num_channels_, application_));
}
AudioEncoderOpus::~AudioEncoderOpus() {
CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
}
int AudioEncoderOpus::sample_rate_hz() const {
return kSampleRateHz;
}
int AudioEncoderOpus::num_channels() const {
return num_channels_;
}
int AudioEncoderOpus::Num10MsFramesInNextPacket() const {
return num_10ms_frames_per_packet_;
}
int AudioEncoderOpus::Max10MsFramesInAPacket() const {
return num_10ms_frames_per_packet_;
}
bool AudioEncoderOpus::EncodeInternal(uint32_t timestamp,
const int16_t* audio,
size_t max_encoded_bytes,
uint8_t* encoded,
EncodedInfo* info) {
if (input_buffer_.empty())
first_timestamp_in_buffer_ = timestamp;
input_buffer_.insert(input_buffer_.end(), audio,
audio + samples_per_10ms_frame_);
if (input_buffer_.size() < (static_cast<size_t>(num_10ms_frames_per_packet_) *
samples_per_10ms_frame_)) {
info->encoded_bytes = 0;
return true;
}
CHECK_EQ(input_buffer_.size(),
static_cast<size_t>(num_10ms_frames_per_packet_) *
samples_per_10ms_frame_);
int16_t r = WebRtcOpus_Encode(
inst_, &input_buffer_[0],
rtc::CheckedDivExact(CastInt16(input_buffer_.size()),
static_cast<int16_t>(num_channels_)),
ClampInt16(max_encoded_bytes), encoded);
input_buffer_.clear();
if (r < 0)
return false;
info->encoded_bytes = r;
info->encoded_timestamp = first_timestamp_in_buffer_;
info->payload_type = payload_type_;
return true;
}
} // namespace webrtc