/* * 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. */ #ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ #define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ #include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h" #include "webrtc/base/checks.h" namespace webrtc { template typename AudioEncoderIsacT::Config CreateIsacConfig( const CodecInst& codec_inst, LockedIsacBandwidthInfo* bwinfo) { typename AudioEncoderIsacT::Config config; config.bwinfo = bwinfo; config.payload_type = codec_inst.pltype; config.sample_rate_hz = codec_inst.plfreq; config.frame_size_ms = rtc::CheckedDivExact(1000 * codec_inst.pacsize, config.sample_rate_hz); config.adaptive_mode = (codec_inst.rate == -1); if (codec_inst.rate != -1) config.bit_rate = codec_inst.rate; return config; } template bool AudioEncoderIsacT::Config::IsOk() const { if (max_bit_rate < 32000 && max_bit_rate != -1) return false; if (max_payload_size_bytes < 120 && max_payload_size_bytes != -1) return false; if (adaptive_mode && !bwinfo) return false; switch (sample_rate_hz) { case 16000: if (max_bit_rate > 53400) return false; if (max_payload_size_bytes > 400) return false; return (frame_size_ms == 30 || frame_size_ms == 60) && (bit_rate == 0 || (bit_rate >= 10000 && bit_rate <= 32000)); case 32000: if (max_bit_rate > 160000) return false; if (max_payload_size_bytes > 600) return false; return T::has_swb && (frame_size_ms == 30 && (bit_rate == 0 || (bit_rate >= 10000 && bit_rate <= 56000))); default: return false; } } template AudioEncoderIsacT::AudioEncoderIsacT(const Config& config) { RecreateEncoderInstance(config); } template AudioEncoderIsacT::AudioEncoderIsacT(const CodecInst& codec_inst, LockedIsacBandwidthInfo* bwinfo) : AudioEncoderIsacT(CreateIsacConfig(codec_inst, bwinfo)) {} template AudioEncoderIsacT::~AudioEncoderIsacT() { RTC_CHECK_EQ(0, T::Free(isac_state_)); } template size_t AudioEncoderIsacT::MaxEncodedBytes() const { return kSufficientEncodeBufferSizeBytes; } template int AudioEncoderIsacT::SampleRateHz() const { return T::EncSampRate(isac_state_); } template int AudioEncoderIsacT::NumChannels() const { return 1; } template size_t AudioEncoderIsacT::Num10MsFramesInNextPacket() const { const int samples_in_next_packet = T::GetNewFrameLen(isac_state_); return static_cast( rtc::CheckedDivExact(samples_in_next_packet, rtc::CheckedDivExact(SampleRateHz(), 100))); } template size_t AudioEncoderIsacT::Max10MsFramesInAPacket() const { return 6; // iSAC puts at most 60 ms in a packet. } template int AudioEncoderIsacT::GetTargetBitrate() const { if (config_.adaptive_mode) return -1; return config_.bit_rate == 0 ? kDefaultBitRate : config_.bit_rate; } template AudioEncoder::EncodedInfo AudioEncoderIsacT::EncodeInternal( uint32_t rtp_timestamp, const int16_t* audio, size_t max_encoded_bytes, uint8_t* encoded) { if (!packet_in_progress_) { // Starting a new packet; remember the timestamp for later. packet_in_progress_ = true; packet_timestamp_ = rtp_timestamp; } if (bwinfo_) { IsacBandwidthInfo bwinfo = bwinfo_->Get(); T::SetBandwidthInfo(isac_state_, &bwinfo); } int r = T::Encode(isac_state_, audio, encoded); RTC_CHECK_GE(r, 0) << "Encode failed (error code " << T::GetErrorCode(isac_state_) << ")"; // T::Encode doesn't allow us to tell it the size of the output // buffer. All we can do is check for an overrun after the fact. RTC_CHECK_LE(static_cast(r), max_encoded_bytes); if (r == 0) return EncodedInfo(); // Got enough input to produce a packet. Return the saved timestamp from // the first chunk of input that went into the packet. packet_in_progress_ = false; EncodedInfo info; info.encoded_bytes = r; info.encoded_timestamp = packet_timestamp_; info.payload_type = config_.payload_type; return info; } template void AudioEncoderIsacT::Reset() { RecreateEncoderInstance(config_); } template void AudioEncoderIsacT::RecreateEncoderInstance(const Config& config) { RTC_CHECK(config.IsOk()); packet_in_progress_ = false; bwinfo_ = config.bwinfo; if (isac_state_) RTC_CHECK_EQ(0, T::Free(isac_state_)); RTC_CHECK_EQ(0, T::Create(&isac_state_)); RTC_CHECK_EQ(0, T::EncoderInit(isac_state_, config.adaptive_mode ? 0 : 1)); RTC_CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz)); const int bit_rate = config.bit_rate == 0 ? kDefaultBitRate : config.bit_rate; if (config.adaptive_mode) { RTC_CHECK_EQ(0, T::ControlBwe(isac_state_, bit_rate, config.frame_size_ms, config.enforce_frame_size)); } else { RTC_CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms)); } if (config.max_payload_size_bytes != -1) RTC_CHECK_EQ( 0, T::SetMaxPayloadSize(isac_state_, config.max_payload_size_bytes)); if (config.max_bit_rate != -1) RTC_CHECK_EQ(0, T::SetMaxRate(isac_state_, config.max_bit_rate)); // Set the decoder sample rate even though we just use the encoder. This // doesn't appear to be necessary to produce a valid encoding, but without it // we get an encoding that isn't bit-for-bit identical with what a combined // encoder+decoder object produces. RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, config.sample_rate_hz)); config_ = config; } } // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_