/* * 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 MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ #include "rtc_base/checks.h" namespace webrtc { 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; 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() { RTC_CHECK_EQ(0, T::Free(isac_state_)); } template int AudioEncoderIsacT::SampleRateHz() const { return T::EncSampRate(isac_state_); } template size_t 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 { return config_.bit_rate == 0 ? kDefaultBitRate : config_.bit_rate; } template AudioEncoder::EncodedInfo AudioEncoderIsacT::EncodeImpl( uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded) { if (!packet_in_progress_) { // Starting a new packet; remember the timestamp for later. packet_in_progress_ = true; packet_timestamp_ = rtp_timestamp; } size_t encoded_bytes = encoded->AppendData( kSufficientEncodeBufferSizeBytes, [&](rtc::ArrayView encoded) { int r = T::Encode(isac_state_, audio.data(), encoded.data()); RTC_CHECK_GE(r, 0) << "Encode failed (error code " << T::GetErrorCode(isac_state_) << ")"; return static_cast(r); }); if (encoded_bytes == 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 = encoded_bytes; info.encoded_timestamp = packet_timestamp_; info.payload_type = config_.payload_type; info.encoder_type = CodecType::kIsac; return info; } template void AudioEncoderIsacT::Reset() { RecreateEncoderInstance(config_); } template void AudioEncoderIsacT::RecreateEncoderInstance(const Config& config) { RTC_CHECK(config.IsOk()); packet_in_progress_ = false; 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_, /*coding_mode=*/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; 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 // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_