summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Desmottes <guillaume.desmottes@collabora.com>2020-03-26 15:32:43 +0100
committerGuillaume Desmottes <guillaume.desmottes@collabora.com>2020-03-27 14:52:22 +0100
commit34efc689c2bef3172e11300b44b6acb556348444 (patch)
treedeac1be081f77e2fa04235b1b19ca9795b8c0ca3
parentf13529b5b88b106f3f0d90b516f56098d6624c35 (diff)
downloadwebrtc-audio-processing-34efc689c2bef3172e11300b44b6acb556348444.tar.gz
add webrtc-audio-coding public library
This new lib contains the bare minimum to implement an iSAC encoder and decoder. The webrtc files have been copied from the revision as the existing imported files (c8b569e0a7ad0b369e15f0197b3a558699ec8efa).
-rw-r--r--meson.build12
-rw-r--r--webrtc/modules/audio_coding/codecs/audio_decoder.cc106
-rw-r--r--webrtc/modules/audio_coding/codecs/audio_decoder.h123
-rw-r--r--webrtc/modules/audio_coding/codecs/audio_encoder.cc55
-rw-r--r--webrtc/modules/audio_coding/codecs/audio_encoder.h143
-rw-r--r--webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h163
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h54
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h104
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h97
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h190
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h45
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h22
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h22
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/audio_decoder_isac.cc20
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc20
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c1031
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h184
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/crc.c110
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/crc.h46
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/decode.c304
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c89
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/encode.c1258
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/fft.c943
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/fft.h45
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/isac.c2363
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h117
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c218
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/transform.c125
-rw-r--r--webrtc/modules/audio_coding/meson.build43
-rw-r--r--webrtc/modules/audio_processing/meson.build2
30 files changed, 8046 insertions, 8 deletions
diff --git a/meson.build b/meson.build
index ca3ce8d..076f8f3 100644
--- a/meson.build
+++ b/meson.build
@@ -111,3 +111,15 @@ pkgconfig.generate(
] + platform_cflags,
libraries: libwebrtc_audio_processing,
)
+
+pkgconfig.generate(
+ name: 'webrtc-audio-coding',
+ description: 'WebRTC Audio Coding library',
+ version: meson.project_version(),
+ filebase: 'webrtc-audio-coding',
+ subdirs: 'webrtc_audio_processing',
+ extra_cflags: [
+ '-DWEBRTC_AUDIO_PROCESSING_ONLY_BUILD',
+ ] + platform_cflags,
+ libraries: libwebrtc_audio_coding,
+)
diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.cc b/webrtc/modules/audio_coding/codecs/audio_decoder.cc
new file mode 100644
index 0000000..08d101c
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/audio_decoder.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2012 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/audio_decoder.h"
+
+#include <assert.h>
+
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+int AudioDecoder::Decode(const uint8_t* encoded, size_t encoded_len,
+ int sample_rate_hz, size_t max_decoded_bytes,
+ int16_t* decoded, SpeechType* speech_type) {
+ int duration = PacketDuration(encoded, encoded_len);
+ if (duration >= 0 &&
+ duration * Channels() * sizeof(int16_t) > max_decoded_bytes) {
+ return -1;
+ }
+ return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
+ speech_type);
+}
+
+int AudioDecoder::DecodeRedundant(const uint8_t* encoded, size_t encoded_len,
+ int sample_rate_hz, size_t max_decoded_bytes,
+ int16_t* decoded, SpeechType* speech_type) {
+ int duration = PacketDurationRedundant(encoded, encoded_len);
+ if (duration >= 0 &&
+ duration * Channels() * sizeof(int16_t) > max_decoded_bytes) {
+ return -1;
+ }
+ return DecodeRedundantInternal(encoded, encoded_len, sample_rate_hz, decoded,
+ speech_type);
+}
+
+int AudioDecoder::DecodeInternal(const uint8_t* encoded, size_t encoded_len,
+ int sample_rate_hz, int16_t* decoded,
+ SpeechType* speech_type) {
+ return kNotImplemented;
+}
+
+int AudioDecoder::DecodeRedundantInternal(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz, int16_t* decoded,
+ SpeechType* speech_type) {
+ return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
+ speech_type);
+}
+
+bool AudioDecoder::HasDecodePlc() const { return false; }
+
+size_t AudioDecoder::DecodePlc(size_t num_frames, int16_t* decoded) {
+ return 0;
+}
+
+int AudioDecoder::IncomingPacket(const uint8_t* payload,
+ size_t payload_len,
+ uint16_t rtp_sequence_number,
+ uint32_t rtp_timestamp,
+ uint32_t arrival_timestamp) {
+ return 0;
+}
+
+int AudioDecoder::ErrorCode() { return 0; }
+
+int AudioDecoder::PacketDuration(const uint8_t* encoded,
+ size_t encoded_len) const {
+ return kNotImplemented;
+}
+
+int AudioDecoder::PacketDurationRedundant(const uint8_t* encoded,
+ size_t encoded_len) const {
+ return kNotImplemented;
+}
+
+bool AudioDecoder::PacketHasFec(const uint8_t* encoded,
+ size_t encoded_len) const {
+ return false;
+}
+
+CNG_dec_inst* AudioDecoder::CngDecoderInstance() {
+ FATAL() << "Not a CNG decoder";
+ return NULL;
+}
+
+AudioDecoder::SpeechType AudioDecoder::ConvertSpeechType(int16_t type) {
+ switch (type) {
+ case 0: // TODO(hlundin): Both iSAC and Opus return 0 for speech.
+ case 1:
+ return kSpeech;
+ case 2:
+ return kComfortNoise;
+ default:
+ assert(false);
+ return kSpeech;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.h b/webrtc/modules/audio_coding/codecs/audio_decoder.h
new file mode 100644
index 0000000..6189be0
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/audio_decoder.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2012 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_NETEQ_INCLUDE_AUDIO_DECODER_H_
+#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_INCLUDE_AUDIO_DECODER_H_
+
+#include <stdlib.h> // NULL
+
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+// This is the interface class for decoders in NetEQ. Each codec type will have
+// and implementation of this class.
+class AudioDecoder {
+ public:
+ enum SpeechType {
+ kSpeech = 1,
+ kComfortNoise = 2
+ };
+
+ // Used by PacketDuration below. Save the value -1 for errors.
+ enum { kNotImplemented = -2 };
+
+ AudioDecoder() = default;
+ virtual ~AudioDecoder() = default;
+
+ // Decodes |encode_len| bytes from |encoded| and writes the result in
+ // |decoded|. The maximum bytes allowed to be written into |decoded| is
+ // |max_decoded_bytes|. Returns the total number of samples across all
+ // channels. If the decoder produced comfort noise, |speech_type|
+ // is set to kComfortNoise, otherwise it is kSpeech. The desired output
+ // sample rate is provided in |sample_rate_hz|, which must be valid for the
+ // codec at hand.
+ virtual int Decode(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ size_t max_decoded_bytes,
+ int16_t* decoded,
+ SpeechType* speech_type);
+
+ // Same as Decode(), but interfaces to the decoders redundant decode function.
+ // The default implementation simply calls the regular Decode() method.
+ virtual int DecodeRedundant(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ size_t max_decoded_bytes,
+ int16_t* decoded,
+ SpeechType* speech_type);
+
+ // Indicates if the decoder implements the DecodePlc method.
+ virtual bool HasDecodePlc() const;
+
+ // Calls the packet-loss concealment of the decoder to update the state after
+ // one or several lost packets. The caller has to make sure that the
+ // memory allocated in |decoded| should accommodate |num_frames| frames.
+ virtual size_t DecodePlc(size_t num_frames, int16_t* decoded);
+
+ // Resets the decoder state (empty buffers etc.).
+ virtual void Reset() = 0;
+
+ // Notifies the decoder of an incoming packet to NetEQ.
+ virtual int IncomingPacket(const uint8_t* payload,
+ size_t payload_len,
+ uint16_t rtp_sequence_number,
+ uint32_t rtp_timestamp,
+ uint32_t arrival_timestamp);
+
+ // Returns the last error code from the decoder.
+ virtual int ErrorCode();
+
+ // Returns the duration in samples-per-channel of the payload in |encoded|
+ // which is |encoded_len| bytes long. Returns kNotImplemented if no duration
+ // estimate is available, or -1 in case of an error.
+ virtual int PacketDuration(const uint8_t* encoded, size_t encoded_len) const;
+
+ // Returns the duration in samples-per-channel of the redandant payload in
+ // |encoded| which is |encoded_len| bytes long. Returns kNotImplemented if no
+ // duration estimate is available, or -1 in case of an error.
+ virtual int PacketDurationRedundant(const uint8_t* encoded,
+ size_t encoded_len) const;
+
+ // Detects whether a packet has forward error correction. The packet is
+ // comprised of the samples in |encoded| which is |encoded_len| bytes long.
+ // Returns true if the packet has FEC and false otherwise.
+ virtual bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const;
+
+ // If this is a CNG decoder, return the underlying CNG_dec_inst*. If this
+ // isn't a CNG decoder, don't call this method.
+ virtual CNG_dec_inst* CngDecoderInstance();
+
+ virtual size_t Channels() const = 0;
+
+ protected:
+ static SpeechType ConvertSpeechType(int16_t type);
+
+ virtual int DecodeInternal(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ int16_t* decoded,
+ SpeechType* speech_type);
+
+ virtual int DecodeRedundantInternal(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ int16_t* decoded,
+ SpeechType* speech_type);
+
+ private:
+ RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoder);
+};
+
+} // namespace webrtc
+#endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_INCLUDE_AUDIO_DECODER_H_
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.cc b/webrtc/modules/audio_coding/codecs/audio_encoder.cc
new file mode 100644
index 0000000..6d76300
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/audio_encoder.cc
@@ -0,0 +1,55 @@
+/*
+ * 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/audio_encoder.h"
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+AudioEncoder::EncodedInfo::EncodedInfo() = default;
+
+AudioEncoder::EncodedInfo::~EncodedInfo() = default;
+
+int AudioEncoder::RtpTimestampRateHz() const {
+ return SampleRateHz();
+}
+
+AudioEncoder::EncodedInfo AudioEncoder::Encode(uint32_t rtp_timestamp,
+ const int16_t* audio,
+ size_t num_samples_per_channel,
+ size_t max_encoded_bytes,
+ uint8_t* encoded) {
+ RTC_CHECK_EQ(num_samples_per_channel,
+ static_cast<size_t>(SampleRateHz() / 100));
+ EncodedInfo info =
+ EncodeInternal(rtp_timestamp, audio, max_encoded_bytes, encoded);
+ RTC_CHECK_LE(info.encoded_bytes, max_encoded_bytes);
+ return info;
+}
+
+bool AudioEncoder::SetFec(bool enable) {
+ return !enable;
+}
+
+bool AudioEncoder::SetDtx(bool enable) {
+ return !enable;
+}
+
+bool AudioEncoder::SetApplication(Application application) {
+ return false;
+}
+
+void AudioEncoder::SetMaxPlaybackRate(int frequency_hz) {}
+
+void AudioEncoder::SetProjectedPacketLossRate(double fraction) {}
+
+void AudioEncoder::SetTargetBitrate(int target_bps) {}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.h b/webrtc/modules/audio_coding/codecs/audio_encoder.h
new file mode 100644
index 0000000..cda9d86
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/audio_encoder.h
@@ -0,0 +1,143 @@
+/*
+ * 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_AUDIO_ENCODER_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
+
+#include <algorithm>
+#include <vector>
+
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+// This is the interface class for encoders in AudioCoding module. Each codec
+// type must have an implementation of this class.
+class AudioEncoder {
+ public:
+ struct EncodedInfoLeaf {
+ size_t encoded_bytes = 0;
+ uint32_t encoded_timestamp = 0;
+ int payload_type = 0;
+ bool send_even_if_empty = false;
+ bool speech = true;
+ };
+
+ // This is the main struct for auxiliary encoding information. Each encoded
+ // packet should be accompanied by one EncodedInfo struct, containing the
+ // total number of |encoded_bytes|, the |encoded_timestamp| and the
+ // |payload_type|. If the packet contains redundant encodings, the |redundant|
+ // vector will be populated with EncodedInfoLeaf structs. Each struct in the
+ // vector represents one encoding; the order of structs in the vector is the
+ // same as the order in which the actual payloads are written to the byte
+ // stream. When EncoderInfoLeaf structs are present in the vector, the main
+ // struct's |encoded_bytes| will be the sum of all the |encoded_bytes| in the
+ // vector.
+ struct EncodedInfo : public EncodedInfoLeaf {
+ EncodedInfo();
+ ~EncodedInfo();
+
+ std::vector<EncodedInfoLeaf> redundant;
+ };
+
+ virtual ~AudioEncoder() = default;
+
+ // Returns the maximum number of bytes that can be produced by the encoder
+ // at each Encode() call. The caller can use the return value to determine
+ // the size of the buffer that needs to be allocated. This value is allowed
+ // to depend on encoder parameters like bitrate, frame size etc., so if
+ // any of these change, the caller of Encode() is responsible for checking
+ // that the buffer is large enough by calling MaxEncodedBytes() again.
+ virtual size_t MaxEncodedBytes() const = 0;
+
+ // Returns the input sample rate in Hz and the number of input channels.
+ // These are constants set at instantiation time.
+ virtual int SampleRateHz() const = 0;
+ virtual int NumChannels() const = 0;
+
+ // Returns the rate at which the RTP timestamps are updated. The default
+ // implementation returns SampleRateHz().
+ virtual int RtpTimestampRateHz() const;
+
+ // Returns the number of 10 ms frames the encoder will put in the next
+ // packet. This value may only change when Encode() outputs a packet; i.e.,
+ // the encoder may vary the number of 10 ms frames from packet to packet, but
+ // it must decide the length of the next packet no later than when outputting
+ // the preceding packet.
+ virtual size_t Num10MsFramesInNextPacket() const = 0;
+
+ // Returns the maximum value that can be returned by
+ // Num10MsFramesInNextPacket().
+ virtual size_t Max10MsFramesInAPacket() const = 0;
+
+ // Returns the current target bitrate in bits/s. The value -1 means that the
+ // codec adapts the target automatically, and a current target cannot be
+ // provided.
+ virtual int GetTargetBitrate() const = 0;
+
+ // Accepts one 10 ms block of input audio (i.e., SampleRateHz() / 100 *
+ // NumChannels() samples). Multi-channel audio must be sample-interleaved.
+ // The encoder produces zero or more bytes of output in |encoded| and
+ // returns additional encoding information.
+ // The caller is responsible for making sure that |max_encoded_bytes| is
+ // not smaller than the number of bytes actually produced by the encoder.
+ // Encode() checks some preconditions, calls EncodeInternal() which does the
+ // actual work, and then checks some postconditions.
+ EncodedInfo Encode(uint32_t rtp_timestamp,
+ const int16_t* audio,
+ size_t num_samples_per_channel,
+ size_t max_encoded_bytes,
+ uint8_t* encoded);
+
+ virtual EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
+ const int16_t* audio,
+ size_t max_encoded_bytes,
+ uint8_t* encoded) = 0;
+
+ // Resets the encoder to its starting state, discarding any input that has
+ // been fed to the encoder but not yet emitted in a packet.
+ virtual void Reset() = 0;
+
+ // Enables or disables codec-internal FEC (forward error correction). Returns
+ // true if the codec was able to comply. The default implementation returns
+ // true when asked to disable FEC and false when asked to enable it (meaning
+ // that FEC isn't supported).
+ virtual bool SetFec(bool enable);
+
+ // Enables or disables codec-internal VAD/DTX. Returns true if the codec was
+ // able to comply. The default implementation returns true when asked to
+ // disable DTX and false when asked to enable it (meaning that DTX isn't
+ // supported).
+ virtual bool SetDtx(bool enable);
+
+ // Sets the application mode. Returns true if the codec was able to comply.
+ // The default implementation just returns false.
+ enum class Application { kSpeech, kAudio };
+ virtual bool SetApplication(Application application);
+
+ // Tells the encoder about the highest sample rate the decoder is expected to
+ // use when decoding the bitstream. The encoder would typically use this
+ // information to adjust the quality of the encoding. The default
+ // implementation just returns true.
+ virtual void SetMaxPlaybackRate(int frequency_hz);
+
+ // Tells the encoder what the projected packet loss rate is. The rate is in
+ // the range [0.0, 1.0]. The encoder would typically use this information to
+ // adjust channel coding efforts, such as FEC. The default implementation
+ // does nothing.
+ virtual void SetProjectedPacketLossRate(double fraction);
+
+ // Tells the encoder what average bitrate we'd like it to produce. The
+ // encoder is free to adjust or disregard the given bitrate (the default
+ // implementation does the latter).
+ virtual void SetTargetBitrate(int target_bps);
+};
+} // namespace webrtc
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
diff --git a/webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h b/webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h
new file mode 100644
index 0000000..35660c4
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2012 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_CNG_MAIN_INCLUDE_WEBRTC_CNG_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_CNG_MAIN_INCLUDE_WEBRTC_CNG_H_
+
+#include <stddef.h>
+#include "webrtc/typedefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WEBRTC_CNG_MAX_LPC_ORDER 12
+#define WEBRTC_CNG_MAX_OUTSIZE_ORDER 640
+
+/* Define Error codes. */
+
+/* 6100 Encoder */
+#define CNG_ENCODER_NOT_INITIATED 6120
+#define CNG_DISALLOWED_LPC_ORDER 6130
+#define CNG_DISALLOWED_FRAME_SIZE 6140
+#define CNG_DISALLOWED_SAMPLING_FREQUENCY 6150
+/* 6200 Decoder */
+#define CNG_DECODER_NOT_INITIATED 6220
+
+typedef struct WebRtcCngEncInst CNG_enc_inst;
+typedef struct WebRtcCngDecInst CNG_dec_inst;
+
+/****************************************************************************
+ * WebRtcCng_CreateEnc/Dec(...)
+ *
+ * These functions create an instance to the specified structure
+ *
+ * Input:
+ * - XXX_inst : Pointer to created instance that should be created
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int16_t WebRtcCng_CreateEnc(CNG_enc_inst** cng_inst);
+int16_t WebRtcCng_CreateDec(CNG_dec_inst** cng_inst);
+
+/****************************************************************************
+ * WebRtcCng_InitEnc/Dec(...)
+ *
+ * This function initializes a instance
+ *
+ * Input:
+ * - cng_inst : Instance that should be initialized
+ *
+ * - fs : 8000 for narrowband and 16000 for wideband
+ * - interval : generate SID data every interval ms
+ * - quality : Number of refl. coefs, maximum allowed is 12
+ *
+ * Output:
+ * - cng_inst : Initialized instance
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+
+int WebRtcCng_InitEnc(CNG_enc_inst* cng_inst, int fs, int16_t interval,
+ int16_t quality);
+void WebRtcCng_InitDec(CNG_dec_inst* cng_inst);
+
+/****************************************************************************
+ * WebRtcCng_FreeEnc/Dec(...)
+ *
+ * These functions frees the dynamic memory of a specified instance
+ *
+ * Input:
+ * - cng_inst : Pointer to created instance that should be freed
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int16_t WebRtcCng_FreeEnc(CNG_enc_inst* cng_inst);
+int16_t WebRtcCng_FreeDec(CNG_dec_inst* cng_inst);
+
+/****************************************************************************
+ * WebRtcCng_Encode(...)
+ *
+ * These functions analyzes background noise
+ *
+ * Input:
+ * - cng_inst : Pointer to created instance
+ * - speech : Signal to be analyzed
+ * - nrOfSamples : Size of speech vector
+ * - forceSID : not zero to force SID frame and reset
+ *
+ * Output:
+ * - bytesOut : Nr of bytes to transmit, might be 0
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int WebRtcCng_Encode(CNG_enc_inst* cng_inst, int16_t* speech,
+ size_t nrOfSamples, uint8_t* SIDdata,
+ size_t* bytesOut, int16_t forceSID);
+
+/****************************************************************************
+ * WebRtcCng_UpdateSid(...)
+ *
+ * These functions updates the CN state, when a new SID packet arrives
+ *
+ * Input:
+ * - cng_inst : Pointer to created instance that should be freed
+ * - SID : SID packet, all headers removed
+ * - length : Length in bytes of SID packet
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int16_t WebRtcCng_UpdateSid(CNG_dec_inst* cng_inst, uint8_t* SID,
+ size_t length);
+
+/****************************************************************************
+ * WebRtcCng_Generate(...)
+ *
+ * These functions generates CN data when needed
+ *
+ * Input:
+ * - cng_inst : Pointer to created instance that should be freed
+ * - outData : pointer to area to write CN data
+ * - nrOfSamples : How much data to generate
+ * - new_period : >0 if a new period of CNG, will reset history
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int16_t WebRtcCng_Generate(CNG_dec_inst* cng_inst, int16_t* outData,
+ size_t nrOfSamples, int16_t new_period);
+
+/*****************************************************************************
+ * WebRtcCng_GetErrorCodeEnc/Dec(...)
+ *
+ * This functions can be used to check the error code of a CNG instance. When
+ * a function returns -1 a error code will be set for that instance. The
+ * function below extract the code of the last error that occurred in the
+ * specified instance.
+ *
+ * Input:
+ * - CNG_inst : CNG enc/dec instance
+ *
+ * Return value : Error code
+ */
+int16_t WebRtcCng_GetErrorCodeEnc(CNG_enc_inst* cng_inst);
+int16_t WebRtcCng_GetErrorCodeDec(CNG_dec_inst* cng_inst);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_CNG_MAIN_INCLUDE_WEBRTC_CNG_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
new file mode 100644
index 0000000..845af42
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 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_DECODER_ISAC_T_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
+
+#include <vector>
+
+#include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
+#include "webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
+
+namespace webrtc {
+
+template <typename T>
+class AudioDecoderIsacT final : public AudioDecoder {
+ public:
+ AudioDecoderIsacT();
+ explicit AudioDecoderIsacT(LockedIsacBandwidthInfo* bwinfo);
+ ~AudioDecoderIsacT() override;
+
+ bool HasDecodePlc() const override;
+ size_t DecodePlc(size_t num_frames, int16_t* decoded) override;
+ void Reset() override;
+ int IncomingPacket(const uint8_t* payload,
+ size_t payload_len,
+ uint16_t rtp_sequence_number,
+ uint32_t rtp_timestamp,
+ uint32_t arrival_timestamp) override;
+ int ErrorCode() override;
+ size_t Channels() const override;
+ int DecodeInternal(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ int16_t* decoded,
+ SpeechType* speech_type) override;
+
+ private:
+ typename T::instance_type* isac_state_;
+ LockedIsacBandwidthInfo* bwinfo_;
+ int decoder_sample_rate_hz_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacT);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h
new file mode 100644
index 0000000..a986bc4
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015 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_DECODER_ISAC_T_IMPL_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
+
+#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h"
+
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+template <typename T>
+AudioDecoderIsacT<T>::AudioDecoderIsacT()
+ : AudioDecoderIsacT(nullptr) {}
+
+template <typename T>
+AudioDecoderIsacT<T>::AudioDecoderIsacT(LockedIsacBandwidthInfo* bwinfo)
+ : bwinfo_(bwinfo), decoder_sample_rate_hz_(-1) {
+ RTC_CHECK_EQ(0, T::Create(&isac_state_));
+ T::DecoderInit(isac_state_);
+ if (bwinfo_) {
+ IsacBandwidthInfo bi;
+ T::GetBandwidthInfo(isac_state_, &bi);
+ bwinfo_->Set(bi);
+ }
+}
+
+template <typename T>
+AudioDecoderIsacT<T>::~AudioDecoderIsacT() {
+ RTC_CHECK_EQ(0, T::Free(isac_state_));
+}
+
+template <typename T>
+int AudioDecoderIsacT<T>::DecodeInternal(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ int16_t* decoded,
+ SpeechType* speech_type) {
+ RTC_CHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000)
+ << "Unsupported sample rate " << sample_rate_hz;
+ if (sample_rate_hz != decoder_sample_rate_hz_) {
+ RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, sample_rate_hz));
+ decoder_sample_rate_hz_ = sample_rate_hz;
+ }
+ int16_t temp_type = 1; // Default is speech.
+ int ret =
+ T::DecodeInternal(isac_state_, encoded, encoded_len, decoded, &temp_type);
+ *speech_type = ConvertSpeechType(temp_type);
+ return ret;
+}
+
+template <typename T>
+bool AudioDecoderIsacT<T>::HasDecodePlc() const {
+ return false;
+}
+
+template <typename T>
+size_t AudioDecoderIsacT<T>::DecodePlc(size_t num_frames, int16_t* decoded) {
+ return T::DecodePlc(isac_state_, decoded, num_frames);
+}
+
+template <typename T>
+void AudioDecoderIsacT<T>::Reset() {
+ T::DecoderInit(isac_state_);
+}
+
+template <typename T>
+int AudioDecoderIsacT<T>::IncomingPacket(const uint8_t* payload,
+ size_t payload_len,
+ uint16_t rtp_sequence_number,
+ uint32_t rtp_timestamp,
+ uint32_t arrival_timestamp) {
+ int ret = T::UpdateBwEstimate(isac_state_, payload, payload_len,
+ rtp_sequence_number, rtp_timestamp,
+ arrival_timestamp);
+ if (bwinfo_) {
+ IsacBandwidthInfo bwinfo;
+ T::GetBandwidthInfo(isac_state_, &bwinfo);
+ bwinfo_->Set(bwinfo);
+ }
+ return ret;
+}
+
+template <typename T>
+int AudioDecoderIsacT<T>::ErrorCode() {
+ return T::GetErrorCode(isac_state_);
+}
+
+template <typename T>
+size_t AudioDecoderIsacT<T>::Channels() const {
+ return 1;
+}
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
new file mode 100644
index 0000000..b15ad94
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
@@ -0,0 +1,97 @@
+/*
+ * 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_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
+
+#include <vector>
+
+#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
+#include "webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
+
+namespace webrtc {
+
+struct CodecInst;
+
+template <typename T>
+class AudioEncoderIsacT final : public AudioEncoder {
+ public:
+ // Allowed combinations of sample rate, frame size, and bit rate are
+ // - 16000 Hz, 30 ms, 10000-32000 bps
+ // - 16000 Hz, 60 ms, 10000-32000 bps
+ // - 32000 Hz, 30 ms, 10000-56000 bps (if T has super-wideband support)
+ struct Config {
+ bool IsOk() const;
+
+ LockedIsacBandwidthInfo* bwinfo = nullptr;
+
+ int payload_type = 103;
+ int sample_rate_hz = 16000;
+ int frame_size_ms = 30;
+ int bit_rate = kDefaultBitRate; // Limit on the short-term average bit
+ // rate, in bits/s.
+ int max_payload_size_bytes = -1;
+ int max_bit_rate = -1;
+
+ // If true, the encoder will dynamically adjust frame size and bit rate;
+ // the configured values are then merely the starting point.
+ bool adaptive_mode = false;
+
+ // In adaptive mode, prevent adaptive changes to the frame size. (Not used
+ // in nonadaptive mode.)
+ bool enforce_frame_size = false;
+ };
+
+ explicit AudioEncoderIsacT(const Config& config);
+ explicit AudioEncoderIsacT(const CodecInst& codec_inst,
+ LockedIsacBandwidthInfo* bwinfo);
+ ~AudioEncoderIsacT() override;
+
+ size_t MaxEncodedBytes() const override;
+ int SampleRateHz() const override;
+ int NumChannels() const override;
+ size_t Num10MsFramesInNextPacket() const override;
+ size_t Max10MsFramesInAPacket() const override;
+ int GetTargetBitrate() const override;
+ EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
+ const int16_t* audio,
+ size_t max_encoded_bytes,
+ uint8_t* encoded) override;
+ void Reset() override;
+
+ private:
+ // This value is taken from STREAM_SIZE_MAX_60 for iSAC float (60 ms) and
+ // STREAM_MAXW16_60MS for iSAC fix (60 ms).
+ static const size_t kSufficientEncodeBufferSizeBytes = 400;
+
+ static const int kDefaultBitRate = 32000;
+
+ // Recreate the iSAC encoder instance with the given settings, and save them.
+ void RecreateEncoderInstance(const Config& config);
+
+ Config config_;
+ typename T::instance_type* isac_state_ = nullptr;
+ LockedIsacBandwidthInfo* bwinfo_ = nullptr;
+
+ // Have we accepted input but not yet emitted it in a packet?
+ bool packet_in_progress_ = false;
+
+ // Timestamp of the first input of the currently in-progress packet.
+ uint32_t packet_timestamp_;
+
+ // Timestamp of the previously encoded packet.
+ uint32_t last_encoded_timestamp_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderIsacT);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
new file mode 100644
index 0000000..279f80d
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
@@ -0,0 +1,190 @@
+/*
+ * 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 T>
+typename AudioEncoderIsacT<T>::Config CreateIsacConfig(
+ const CodecInst& codec_inst,
+ LockedIsacBandwidthInfo* bwinfo) {
+ typename AudioEncoderIsacT<T>::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 <typename T>
+bool AudioEncoderIsacT<T>::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 <typename T>
+AudioEncoderIsacT<T>::AudioEncoderIsacT(const Config& config) {
+ RecreateEncoderInstance(config);
+}
+
+template <typename T>
+AudioEncoderIsacT<T>::AudioEncoderIsacT(const CodecInst& codec_inst,
+ LockedIsacBandwidthInfo* bwinfo)
+ : AudioEncoderIsacT(CreateIsacConfig<T>(codec_inst, bwinfo)) {}
+
+template <typename T>
+AudioEncoderIsacT<T>::~AudioEncoderIsacT() {
+ RTC_CHECK_EQ(0, T::Free(isac_state_));
+}
+
+template <typename T>
+size_t AudioEncoderIsacT<T>::MaxEncodedBytes() const {
+ return kSufficientEncodeBufferSizeBytes;
+}
+
+template <typename T>
+int AudioEncoderIsacT<T>::SampleRateHz() const {
+ return T::EncSampRate(isac_state_);
+}
+
+template <typename T>
+int AudioEncoderIsacT<T>::NumChannels() const {
+ return 1;
+}
+
+template <typename T>
+size_t AudioEncoderIsacT<T>::Num10MsFramesInNextPacket() const {
+ const int samples_in_next_packet = T::GetNewFrameLen(isac_state_);
+ return static_cast<size_t>(
+ rtc::CheckedDivExact(samples_in_next_packet,
+ rtc::CheckedDivExact(SampleRateHz(), 100)));
+}
+
+template <typename T>
+size_t AudioEncoderIsacT<T>::Max10MsFramesInAPacket() const {
+ return 6; // iSAC puts at most 60 ms in a packet.
+}
+
+template <typename T>
+int AudioEncoderIsacT<T>::GetTargetBitrate() const {
+ if (config_.adaptive_mode)
+ return -1;
+ return config_.bit_rate == 0 ? kDefaultBitRate : config_.bit_rate;
+}
+
+template <typename T>
+AudioEncoder::EncodedInfo AudioEncoderIsacT<T>::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<size_t>(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 <typename T>
+void AudioEncoderIsacT<T>::Reset() {
+ RecreateEncoderInstance(config_);
+}
+
+template <typename T>
+void AudioEncoderIsacT<T>::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_
diff --git a/webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h b/webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h
new file mode 100644
index 0000000..bbb040d
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015 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_LOCKED_BANDWIDTH_INFO_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_LOCKED_BANDWIDTH_INFO_H_
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/thread_annotations.h"
+#include "webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h"
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+
+namespace webrtc {
+
+// An IsacBandwidthInfo that's safe to access from multiple threads because
+// it's protected by a mutex.
+class LockedIsacBandwidthInfo final {
+ public:
+ LockedIsacBandwidthInfo();
+ ~LockedIsacBandwidthInfo();
+
+ IsacBandwidthInfo Get() const {
+ CriticalSectionScoped cs(lock_.get());
+ return bwinfo_;
+ }
+
+ void Set(const IsacBandwidthInfo& bwinfo) {
+ CriticalSectionScoped cs(lock_.get());
+ bwinfo_ = bwinfo;
+ }
+
+ private:
+ const rtc::scoped_ptr<CriticalSectionWrapper> lock_;
+ IsacBandwidthInfo bwinfo_ GUARDED_BY(lock_);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_LOCKED_BANDWIDTH_INFO_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h b/webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h
new file mode 100644
index 0000000..dcd4852
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2015 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_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_
+
+#include "webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h"
+#include "webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h"
+
+namespace webrtc {
+
+using AudioDecoderIsac = AudioDecoderIsacT<IsacFloat>;
+
+} // namespace webrtc
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h b/webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h
new file mode 100644
index 0000000..cc8665d
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h
@@ -0,0 +1,22 @@
+/*
+ * 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_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
+
+#include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h"
+#include "webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h"
+
+namespace webrtc {
+
+using AudioEncoderIsac = AudioEncoderIsacT<IsacFloat>;
+
+} // namespace webrtc
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_decoder_isac.cc b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_decoder_isac.cc
new file mode 100644
index 0000000..8e0603e
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_decoder_isac.cc
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015 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/isac/main/include/audio_decoder_isac.h"
+
+#include "webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h"
+
+namespace webrtc {
+
+// Explicit instantiation:
+template class AudioDecoderIsacT<IsacFloat>;
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc
new file mode 100644
index 0000000..64b9815
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc
@@ -0,0 +1,20 @@
+/*
+ * 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/isac/main/include/audio_encoder_isac.h"
+
+#include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h"
+
+namespace webrtc {
+
+// Explicit instantiation:
+template class AudioEncoderIsacT<IsacFloat>;
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c b/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c
new file mode 100644
index 0000000..82fd053
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c
@@ -0,0 +1,1031 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*
+ * BwEstimator.c
+ *
+ * This file contains the code for the Bandwidth Estimator designed
+ * for iSAC.
+ *
+ */
+
+#include "bandwidth_estimator.h"
+#include "settings.h"
+#include "webrtc/modules/audio_coding/codecs/isac/main/include/isac.h"
+
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+
+/* array of quantization levels for bottle neck info; Matlab code: */
+/* sprintf('%4.1ff, ', logspace(log10(5000), log10(40000), 12)) */
+static const float kQRateTableWb[12] =
+{
+ 10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f,
+ 18859.8f, 20963.3f, 23301.4f, 25900.3f, 28789.0f, 32000.0f};
+
+
+static const float kQRateTableSwb[24] =
+{
+ 10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f,
+ 18859.8f, 20963.3f, 23153.1f, 25342.9f, 27532.7f, 29722.5f,
+ 31912.3f, 34102.1f, 36291.9f, 38481.7f, 40671.4f, 42861.2f,
+ 45051.0f, 47240.8f, 49430.6f, 51620.4f, 53810.2f, 56000.0f,
+};
+
+
+
+
+int32_t WebRtcIsac_InitBandwidthEstimator(
+ BwEstimatorstr* bwest_str,
+ enum IsacSamplingRate encoderSampRate,
+ enum IsacSamplingRate decoderSampRate)
+{
+ switch(encoderSampRate)
+ {
+ case kIsacWideband:
+ {
+ bwest_str->send_bw_avg = INIT_BN_EST_WB;
+ break;
+ }
+ case kIsacSuperWideband:
+ {
+ bwest_str->send_bw_avg = INIT_BN_EST_SWB;
+ break;
+ }
+ }
+
+ switch(decoderSampRate)
+ {
+ case kIsacWideband:
+ {
+ bwest_str->prev_frame_length = INIT_FRAME_LEN_WB;
+ bwest_str->rec_bw_inv = 1.0f /
+ (INIT_BN_EST_WB + INIT_HDR_RATE_WB);
+ bwest_str->rec_bw = (int32_t)INIT_BN_EST_WB;
+ bwest_str->rec_bw_avg_Q = INIT_BN_EST_WB;
+ bwest_str->rec_bw_avg = INIT_BN_EST_WB + INIT_HDR_RATE_WB;
+ bwest_str->rec_header_rate = INIT_HDR_RATE_WB;
+ break;
+ }
+ case kIsacSuperWideband:
+ {
+ bwest_str->prev_frame_length = INIT_FRAME_LEN_SWB;
+ bwest_str->rec_bw_inv = 1.0f /
+ (INIT_BN_EST_SWB + INIT_HDR_RATE_SWB);
+ bwest_str->rec_bw = (int32_t)INIT_BN_EST_SWB;
+ bwest_str->rec_bw_avg_Q = INIT_BN_EST_SWB;
+ bwest_str->rec_bw_avg = INIT_BN_EST_SWB + INIT_HDR_RATE_SWB;
+ bwest_str->rec_header_rate = INIT_HDR_RATE_SWB;
+ break;
+ }
+ }
+
+ bwest_str->prev_rec_rtp_number = 0;
+ bwest_str->prev_rec_arr_ts = 0;
+ bwest_str->prev_rec_send_ts = 0;
+ bwest_str->prev_rec_rtp_rate = 1.0f;
+ bwest_str->last_update_ts = 0;
+ bwest_str->last_reduction_ts = 0;
+ bwest_str->count_tot_updates_rec = -9;
+ bwest_str->rec_jitter = 10.0f;
+ bwest_str->rec_jitter_short_term = 0.0f;
+ bwest_str->rec_jitter_short_term_abs = 5.0f;
+ bwest_str->rec_max_delay = 10.0f;
+ bwest_str->rec_max_delay_avg_Q = 10.0f;
+ bwest_str->num_pkts_rec = 0;
+
+ bwest_str->send_max_delay_avg = 10.0f;
+
+ bwest_str->hsn_detect_rec = 0;
+
+ bwest_str->num_consec_rec_pkts_over_30k = 0;
+
+ bwest_str->hsn_detect_snd = 0;
+
+ bwest_str->num_consec_snt_pkts_over_30k = 0;
+
+ bwest_str->in_wait_period = 0;
+
+ bwest_str->change_to_WB = 0;
+
+ bwest_str->numConsecLatePkts = 0;
+ bwest_str->consecLatency = 0;
+ bwest_str->inWaitLatePkts = 0;
+ bwest_str->senderTimestamp = 0;
+ bwest_str->receiverTimestamp = 0;
+
+ bwest_str->external_bw_info.in_use = 0;
+
+ return 0;
+}
+
+/* This function updates both bottle neck rates */
+/* Parameters: */
+/* rtp_number - value from RTP packet, from NetEq */
+/* frame length - length of signal frame in ms, from iSAC decoder */
+/* send_ts - value in RTP header giving send time in samples */
+/* arr_ts - value given by timeGetTime() time of arrival in samples of packet from NetEq */
+/* pksize - size of packet in bytes, from NetEq */
+/* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */
+/* returns 0 if everything went fine, -1 otherwise */
+int16_t WebRtcIsac_UpdateBandwidthEstimator(
+ BwEstimatorstr* bwest_str,
+ const uint16_t rtp_number,
+ const int32_t frame_length,
+ const uint32_t send_ts,
+ const uint32_t arr_ts,
+ const size_t pksize
+ /*, const uint16_t Index*/)
+{
+ float weight = 0.0f;
+ float curr_bw_inv = 0.0f;
+ float rec_rtp_rate;
+ float t_diff_proj;
+ float arr_ts_diff;
+ float send_ts_diff;
+ float arr_time_noise;
+ float arr_time_noise_abs;
+
+ float delay_correction_factor = 1;
+ float late_diff = 0.0f;
+ int immediate_set = 0;
+ int num_pkts_expected;
+
+ assert(!bwest_str->external_bw_info.in_use);
+
+ // We have to adjust the header-rate if the first packet has a
+ // frame-size different than the initialized value.
+ if ( frame_length != bwest_str->prev_frame_length )
+ {
+ bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f *
+ 1000.0f / (float)frame_length; /* bits/s */
+ }
+
+ /* UPDATE ESTIMATES ON THIS SIDE */
+ /* compute far-side transmission rate */
+ rec_rtp_rate = ((float)pksize * 8.0f * 1000.0f / (float)frame_length) +
+ bwest_str->rec_header_rate;
+ // rec_rtp_rate packet bits/s + header bits/s
+
+ /* check for timer wrap-around */
+ if (arr_ts < bwest_str->prev_rec_arr_ts)
+ {
+ bwest_str->prev_rec_arr_ts = arr_ts;
+ bwest_str->last_update_ts = arr_ts;
+ bwest_str->last_reduction_ts = arr_ts + 3*FS;
+ bwest_str->num_pkts_rec = 0;
+
+ /* store frame length */
+ bwest_str->prev_frame_length = frame_length;
+
+ /* store far-side transmission rate */
+ bwest_str->prev_rec_rtp_rate = rec_rtp_rate;
+
+ /* store far-side RTP time stamp */
+ bwest_str->prev_rec_rtp_number = rtp_number;
+
+ return 0;
+ }
+
+ bwest_str->num_pkts_rec++;
+
+ /* check that it's not one of the first 9 packets */
+ if ( bwest_str->count_tot_updates_rec > 0 )
+ {
+ if(bwest_str->in_wait_period > 0 )
+ {
+ bwest_str->in_wait_period--;
+ }
+
+ bwest_str->inWaitLatePkts -= ((bwest_str->inWaitLatePkts > 0)? 1:0);
+ send_ts_diff = (float)(send_ts - bwest_str->prev_rec_send_ts);
+
+ if (send_ts_diff <= (16 * frame_length)*2)
+ //doesn't allow for a dropped packet, not sure necessary to be
+ // that strict -DH
+ {
+ /* if not been updated for a long time, reduce the BN estimate */
+ if((uint32_t)(arr_ts - bwest_str->last_update_ts) *
+ 1000.0f / FS > 3000)
+ {
+ //how many frames should have been received since the last
+ // update if too many have been dropped or there have been
+ // big delays won't allow this reduction may no longer need
+ // the send_ts_diff here
+ num_pkts_expected = (int)(((float)(arr_ts -
+ bwest_str->last_update_ts) * 1000.0f /(float) FS) /
+ (float)frame_length);
+
+ if(((float)bwest_str->num_pkts_rec/(float)num_pkts_expected) >
+ 0.9)
+ {
+ float inv_bitrate = (float) pow( 0.99995,
+ (double)((uint32_t)(arr_ts -
+ bwest_str->last_reduction_ts)*1000.0f/FS) );
+
+ if ( inv_bitrate )
+ {
+ bwest_str->rec_bw_inv /= inv_bitrate;
+
+ //precautionary, likely never necessary
+ if (bwest_str->hsn_detect_snd &&
+ bwest_str->hsn_detect_rec)
+ {
+ if (bwest_str->rec_bw_inv > 0.000066f)
+ {
+ bwest_str->rec_bw_inv = 0.000066f;
+ }
+ }
+ }
+ else
+ {
+ bwest_str->rec_bw_inv = 1.0f /
+ (INIT_BN_EST_WB + INIT_HDR_RATE_WB);
+ }
+ /* reset time-since-update counter */
+ bwest_str->last_reduction_ts = arr_ts;
+ }
+ else
+ //reset here?
+ {
+ bwest_str->last_reduction_ts = arr_ts + 3*FS;
+ bwest_str->last_update_ts = arr_ts;
+ bwest_str->num_pkts_rec = 0;
+ }
+ }
+ }
+ else
+ {
+ bwest_str->last_reduction_ts = arr_ts + 3*FS;
+ bwest_str->last_update_ts = arr_ts;
+ bwest_str->num_pkts_rec = 0;
+ }
+
+
+ /* temporarily speed up adaptation if frame length has changed */
+ if ( frame_length != bwest_str->prev_frame_length )
+ {
+ bwest_str->count_tot_updates_rec = 10;
+ bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f *
+ 1000.0f / (float)frame_length; /* bits/s */
+
+ bwest_str->rec_bw_inv = 1.0f /((float)bwest_str->rec_bw +
+ bwest_str->rec_header_rate);
+ }
+
+ ////////////////////////
+ arr_ts_diff = (float)(arr_ts - bwest_str->prev_rec_arr_ts);
+
+ if (send_ts_diff > 0 )
+ {
+ late_diff = arr_ts_diff - send_ts_diff;
+ }
+ else
+ {
+ late_diff = arr_ts_diff - (float)(16 * frame_length);
+ }
+
+ if((late_diff > 0) && !bwest_str->inWaitLatePkts)
+ {
+ bwest_str->numConsecLatePkts++;
+ bwest_str->consecLatency += late_diff;
+ }
+ else
+ {
+ bwest_str->numConsecLatePkts = 0;
+ bwest_str->consecLatency = 0;
+ }
+ if(bwest_str->numConsecLatePkts > 50)
+ {
+ float latencyMs = bwest_str->consecLatency/(FS/1000);
+ float averageLatencyMs = latencyMs / bwest_str->numConsecLatePkts;
+ delay_correction_factor = frame_length / (frame_length + averageLatencyMs);
+ immediate_set = 1;
+ bwest_str->inWaitLatePkts = (int16_t)((bwest_str->consecLatency/(FS/1000)) / 30);// + 150;
+ bwest_str->start_wait_period = arr_ts;
+ }
+ ///////////////////////////////////////////////
+
+
+
+ /* update only if previous packet was not lost */
+ if ( rtp_number == bwest_str->prev_rec_rtp_number + 1 )
+ {
+
+
+ if (!(bwest_str->hsn_detect_snd && bwest_str->hsn_detect_rec))
+ {
+ if ((arr_ts_diff > (float)(16 * frame_length)))
+ {
+ //1/2 second
+ if ((late_diff > 8000.0f) && !bwest_str->in_wait_period)
+ {
+ delay_correction_factor = 0.7f;
+ bwest_str->in_wait_period = 55;
+ bwest_str->start_wait_period = arr_ts;
+ immediate_set = 1;
+ }
+ //320 ms
+ else if (late_diff > 5120.0f && !bwest_str->in_wait_period)
+ {
+ delay_correction_factor = 0.8f;
+ immediate_set = 1;
+ bwest_str->in_wait_period = 44;
+ bwest_str->start_wait_period = arr_ts;
+ }
+ }
+ }
+
+
+ if ((bwest_str->prev_rec_rtp_rate > bwest_str->rec_bw_avg) &&
+ (rec_rtp_rate > bwest_str->rec_bw_avg) &&
+ !bwest_str->in_wait_period)
+ {
+ /* test if still in initiation period and increment counter */
+ if (bwest_str->count_tot_updates_rec++ > 99)
+ {
+ /* constant weight after initiation part */
+ weight = 0.01f;
+ }
+ else
+ {
+ /* weight decreases with number of updates */
+ weight = 1.0f / (float) bwest_str->count_tot_updates_rec;
+ }
+ /* Bottle Neck Estimation */
+
+ /* limit outliers */
+ /* if more than 25 ms too much */
+ if (arr_ts_diff > frame_length * FS/1000 + 400.0f)
+ {
+ // in samples, why 25ms??
+ arr_ts_diff = frame_length * FS/1000 + 400.0f;
+ }
+ if(arr_ts_diff < (frame_length * FS/1000) - 160.0f)
+ {
+ /* don't allow it to be less than frame rate - 10 ms */
+ arr_ts_diff = (float)frame_length * FS/1000 - 160.0f;
+ }
+
+ /* compute inverse receiving rate for last packet */
+ curr_bw_inv = arr_ts_diff / ((float)(pksize + HEADER_SIZE) *
+ 8.0f * FS); // (180+35)*8*16000 = 27.5 Mbit....
+
+
+ if(curr_bw_inv <
+ (1.0f / (MAX_ISAC_BW + bwest_str->rec_header_rate)))
+ {
+ // don't allow inv rate to be larger than MAX
+ curr_bw_inv = (1.0f /
+ (MAX_ISAC_BW + bwest_str->rec_header_rate));
+ }
+
+ /* update bottle neck rate estimate */
+ bwest_str->rec_bw_inv = weight * curr_bw_inv +
+ (1.0f - weight) * bwest_str->rec_bw_inv;
+
+ /* reset time-since-update counter */
+ bwest_str->last_update_ts = arr_ts;
+ bwest_str->last_reduction_ts = arr_ts + 3 * FS;
+ bwest_str->num_pkts_rec = 0;
+
+ /* Jitter Estimation */
+ /* projected difference between arrival times */
+ t_diff_proj = ((float)(pksize + HEADER_SIZE) * 8.0f *
+ 1000.0f) / bwest_str->rec_bw_avg;
+
+
+ // difference between projected and actual
+ // arrival time differences
+ arr_time_noise = (float)(arr_ts_diff*1000.0f/FS) -
+ t_diff_proj;
+ arr_time_noise_abs = (float) fabs( arr_time_noise );
+
+ /* long term averaged absolute jitter */
+ bwest_str->rec_jitter = weight * arr_time_noise_abs +
+ (1.0f - weight) * bwest_str->rec_jitter;
+ if (bwest_str->rec_jitter > 10.0f)
+ {
+ bwest_str->rec_jitter = 10.0f;
+ }
+ /* short term averaged absolute jitter */
+ bwest_str->rec_jitter_short_term_abs = 0.05f *
+ arr_time_noise_abs + 0.95f *
+ bwest_str->rec_jitter_short_term_abs;
+
+ /* short term averaged jitter */
+ bwest_str->rec_jitter_short_term = 0.05f * arr_time_noise +
+ 0.95f * bwest_str->rec_jitter_short_term;
+ }
+ }
+ }
+ else
+ {
+ // reset time-since-update counter when
+ // receiving the first 9 packets
+ bwest_str->last_update_ts = arr_ts;
+ bwest_str->last_reduction_ts = arr_ts + 3*FS;
+ bwest_str->num_pkts_rec = 0;
+
+ bwest_str->count_tot_updates_rec++;
+ }
+
+ /* limit minimum bottle neck rate */
+ if (bwest_str->rec_bw_inv > 1.0f / ((float)MIN_ISAC_BW +
+ bwest_str->rec_header_rate))
+ {
+ bwest_str->rec_bw_inv = 1.0f / ((float)MIN_ISAC_BW +
+ bwest_str->rec_header_rate);
+ }
+
+ // limit maximum bitrate
+ if (bwest_str->rec_bw_inv < 1.0f / ((float)MAX_ISAC_BW +
+ bwest_str->rec_header_rate))
+ {
+ bwest_str->rec_bw_inv = 1.0f / ((float)MAX_ISAC_BW +
+ bwest_str->rec_header_rate);
+ }
+
+ /* store frame length */
+ bwest_str->prev_frame_length = frame_length;
+
+ /* store far-side transmission rate */
+ bwest_str->prev_rec_rtp_rate = rec_rtp_rate;
+
+ /* store far-side RTP time stamp */
+ bwest_str->prev_rec_rtp_number = rtp_number;
+
+ // Replace bwest_str->rec_max_delay by the new
+ // value (atomic operation)
+ bwest_str->rec_max_delay = 3.0f * bwest_str->rec_jitter;
+
+ /* store send and arrival time stamp */
+ bwest_str->prev_rec_arr_ts = arr_ts ;
+ bwest_str->prev_rec_send_ts = send_ts;
+
+ /* Replace bwest_str->rec_bw by the new value (atomic operation) */
+ bwest_str->rec_bw = (int32_t)(1.0f / bwest_str->rec_bw_inv -
+ bwest_str->rec_header_rate);
+
+ if (immediate_set)
+ {
+ bwest_str->rec_bw = (int32_t) (delay_correction_factor *
+ (float) bwest_str->rec_bw);
+
+ if (bwest_str->rec_bw < (int32_t) MIN_ISAC_BW)
+ {
+ bwest_str->rec_bw = (int32_t) MIN_ISAC_BW;
+ }
+
+ bwest_str->rec_bw_avg = bwest_str->rec_bw +
+ bwest_str->rec_header_rate;
+
+ bwest_str->rec_bw_avg_Q = (float) bwest_str->rec_bw;
+
+ bwest_str->rec_jitter_short_term = 0.0f;
+
+ bwest_str->rec_bw_inv = 1.0f / (bwest_str->rec_bw +
+ bwest_str->rec_header_rate);
+
+ bwest_str->count_tot_updates_rec = 1;
+
+ immediate_set = 0;
+ bwest_str->consecLatency = 0;
+ bwest_str->numConsecLatePkts = 0;
+ }
+
+ return 0;
+}
+
+
+/* This function updates the send bottle neck rate */
+/* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */
+/* returns 0 if everything went fine, -1 otherwise */
+int16_t WebRtcIsac_UpdateUplinkBwImpl(
+ BwEstimatorstr* bwest_str,
+ int16_t index,
+ enum IsacSamplingRate encoderSamplingFreq)
+{
+ assert(!bwest_str->external_bw_info.in_use);
+
+ if((index < 0) || (index > 23))
+ {
+ return -ISAC_RANGE_ERROR_BW_ESTIMATOR;
+ }
+
+ /* UPDATE ESTIMATES FROM OTHER SIDE */
+ if(encoderSamplingFreq == kIsacWideband)
+ {
+ if(index > 11)
+ {
+ index -= 12;
+ /* compute the jitter estimate as decoded on the other side */
+ bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
+ 0.1f * (float)MAX_ISAC_MD;
+ }
+ else
+ {
+ /* compute the jitter estimate as decoded on the other side */
+ bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
+ 0.1f * (float)MIN_ISAC_MD;
+ }
+
+ /* compute the BN estimate as decoded on the other side */
+ bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg +
+ 0.1f * kQRateTableWb[index];
+ }
+ else
+ {
+ /* compute the BN estimate as decoded on the other side */
+ bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg +
+ 0.1f * kQRateTableSwb[index];
+ }
+
+ if (bwest_str->send_bw_avg > (float) 28000 && !bwest_str->hsn_detect_snd)
+ {
+ bwest_str->num_consec_snt_pkts_over_30k++;
+
+ if (bwest_str->num_consec_snt_pkts_over_30k >= 66)
+ {
+ //approx 2 seconds with 30ms frames
+ bwest_str->hsn_detect_snd = 1;
+ }
+ }
+ else if (!bwest_str->hsn_detect_snd)
+ {
+ bwest_str->num_consec_snt_pkts_over_30k = 0;
+ }
+ return 0;
+}
+
+// called when there is upper-band bit-stream to update jitter
+// statistics.
+int16_t WebRtcIsac_UpdateUplinkJitter(
+ BwEstimatorstr* bwest_str,
+ int32_t index)
+{
+ assert(!bwest_str->external_bw_info.in_use);
+
+ if((index < 0) || (index > 23))
+ {
+ return -ISAC_RANGE_ERROR_BW_ESTIMATOR;
+ }
+
+ if(index > 0)
+ {
+ /* compute the jitter estimate as decoded on the other side */
+ bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
+ 0.1f * (float)MAX_ISAC_MD;
+ }
+ else
+ {
+ /* compute the jitter estimate as decoded on the other side */
+ bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
+ 0.1f * (float)MIN_ISAC_MD;
+ }
+
+ return 0;
+}
+
+
+
+// Returns the bandwidth/jitter estimation code (integer 0...23)
+// to put in the sending iSAC payload
+void
+WebRtcIsac_GetDownlinkBwJitIndexImpl(
+ BwEstimatorstr* bwest_str,
+ int16_t* bottleneckIndex,
+ int16_t* jitterInfo,
+ enum IsacSamplingRate decoderSamplingFreq)
+{
+ float MaxDelay;
+ //uint16_t MaxDelayBit;
+
+ float rate;
+ float r;
+ float e1, e2;
+ const float weight = 0.1f;
+ const float* ptrQuantizationTable;
+ int16_t addJitterInfo;
+ int16_t minInd;
+ int16_t maxInd;
+ int16_t midInd;
+
+ if (bwest_str->external_bw_info.in_use) {
+ *bottleneckIndex = bwest_str->external_bw_info.bottleneck_idx;
+ *jitterInfo = bwest_str->external_bw_info.jitter_info;
+ return;
+ }
+
+ /* Get Max Delay Bit */
+ /* get unquantized max delay */
+ MaxDelay = (float)WebRtcIsac_GetDownlinkMaxDelay(bwest_str);
+
+ if ( ((1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight *
+ MAX_ISAC_MD - MaxDelay) > (MaxDelay - (1.f-weight) *
+ bwest_str->rec_max_delay_avg_Q - weight * MIN_ISAC_MD) )
+ {
+ jitterInfo[0] = 0;
+ /* update quantized average */
+ bwest_str->rec_max_delay_avg_Q =
+ (1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight *
+ (float)MIN_ISAC_MD;
+ }
+ else
+ {
+ jitterInfo[0] = 1;
+ /* update quantized average */
+ bwest_str->rec_max_delay_avg_Q =
+ (1.f-weight) * bwest_str->rec_max_delay_avg_Q + weight *
+ (float)MAX_ISAC_MD;
+ }
+
+ // Get unquantized rate.
+ rate = (float)WebRtcIsac_GetDownlinkBandwidth(bwest_str);
+
+ /* Get Rate Index */
+ if(decoderSamplingFreq == kIsacWideband)
+ {
+ ptrQuantizationTable = kQRateTableWb;
+ addJitterInfo = 1;
+ maxInd = 11;
+ }
+ else
+ {
+ ptrQuantizationTable = kQRateTableSwb;
+ addJitterInfo = 0;
+ maxInd = 23;
+ }
+
+ minInd = 0;
+ while(maxInd > minInd + 1)
+ {
+ midInd = (maxInd + minInd) >> 1;
+ if(rate > ptrQuantizationTable[midInd])
+ {
+ minInd = midInd;
+ }
+ else
+ {
+ maxInd = midInd;
+ }
+ }
+ // Chose the index which gives results an average which is closest
+ // to rate
+ r = (1 - weight) * bwest_str->rec_bw_avg_Q - rate;
+ e1 = weight * ptrQuantizationTable[minInd] + r;
+ e2 = weight * ptrQuantizationTable[maxInd] + r;
+ e1 = (e1 > 0)? e1:-e1;
+ e2 = (e2 > 0)? e2:-e2;
+ if(e1 < e2)
+ {
+ bottleneckIndex[0] = minInd;
+ }
+ else
+ {
+ bottleneckIndex[0] = maxInd;
+ }
+
+ bwest_str->rec_bw_avg_Q = (1 - weight) * bwest_str->rec_bw_avg_Q +
+ weight * ptrQuantizationTable[bottleneckIndex[0]];
+ bottleneckIndex[0] += jitterInfo[0] * 12 * addJitterInfo;
+
+ bwest_str->rec_bw_avg = (1 - weight) * bwest_str->rec_bw_avg + weight *
+ (rate + bwest_str->rec_header_rate);
+}
+
+
+
+/* get the bottle neck rate from far side to here, as estimated on this side */
+int32_t WebRtcIsac_GetDownlinkBandwidth( const BwEstimatorstr *bwest_str)
+{
+ int32_t rec_bw;
+ float jitter_sign;
+ float bw_adjust;
+
+ assert(!bwest_str->external_bw_info.in_use);
+
+ /* create a value between -1.0 and 1.0 indicating "average sign" of jitter */
+ jitter_sign = bwest_str->rec_jitter_short_term /
+ bwest_str->rec_jitter_short_term_abs;
+
+ /* adjust bw proportionally to negative average jitter sign */
+ bw_adjust = 1.0f - jitter_sign * (0.15f + 0.15f * jitter_sign * jitter_sign);
+
+ /* adjust Rate if jitter sign is mostly constant */
+ rec_bw = (int32_t)(bwest_str->rec_bw * bw_adjust);
+
+ /* limit range of bottle neck rate */
+ if (rec_bw < MIN_ISAC_BW)
+ {
+ rec_bw = MIN_ISAC_BW;
+ }
+ else if (rec_bw > MAX_ISAC_BW)
+ {
+ rec_bw = MAX_ISAC_BW;
+ }
+ return rec_bw;
+}
+
+/* Returns the max delay (in ms) */
+int32_t
+WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str)
+{
+ int32_t rec_max_delay;
+
+ assert(!bwest_str->external_bw_info.in_use);
+
+ rec_max_delay = (int32_t)(bwest_str->rec_max_delay);
+
+ /* limit range of jitter estimate */
+ if (rec_max_delay < MIN_ISAC_MD)
+ {
+ rec_max_delay = MIN_ISAC_MD;
+ }
+ else if (rec_max_delay > MAX_ISAC_MD)
+ {
+ rec_max_delay = MAX_ISAC_MD;
+ }
+ return rec_max_delay;
+}
+
+/* Clamp val to the closed interval [min,max]. */
+static int32_t clamp(int32_t val, int32_t min, int32_t max) {
+ assert(min <= max);
+ return val < min ? min : (val > max ? max : val);
+}
+
+int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str) {
+ return bwest_str->external_bw_info.in_use
+ ? bwest_str->external_bw_info.send_bw_avg
+ : clamp(bwest_str->send_bw_avg, MIN_ISAC_BW, MAX_ISAC_BW);
+}
+
+int32_t WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr* bwest_str) {
+ return bwest_str->external_bw_info.in_use
+ ? bwest_str->external_bw_info.send_max_delay_avg
+ : clamp(bwest_str->send_max_delay_avg, MIN_ISAC_MD, MAX_ISAC_MD);
+}
+
+void WebRtcIsacBw_GetBandwidthInfo(BwEstimatorstr* bwest_str,
+ enum IsacSamplingRate decoder_sample_rate_hz,
+ IsacBandwidthInfo* bwinfo) {
+ assert(!bwest_str->external_bw_info.in_use);
+ bwinfo->in_use = 1;
+ bwinfo->send_bw_avg = WebRtcIsac_GetUplinkBandwidth(bwest_str);
+ bwinfo->send_max_delay_avg = WebRtcIsac_GetUplinkMaxDelay(bwest_str);
+ WebRtcIsac_GetDownlinkBwJitIndexImpl(bwest_str, &bwinfo->bottleneck_idx,
+ &bwinfo->jitter_info,
+ decoder_sample_rate_hz);
+}
+
+void WebRtcIsacBw_SetBandwidthInfo(BwEstimatorstr* bwest_str,
+ const IsacBandwidthInfo* bwinfo) {
+ memcpy(&bwest_str->external_bw_info, bwinfo,
+ sizeof bwest_str->external_bw_info);
+}
+
+/*
+ * update long-term average bitrate and amount of data in buffer
+ * returns minimum payload size (bytes)
+ */
+int WebRtcIsac_GetMinBytes(
+ RateModel* State,
+ int StreamSize, /* bytes in bitstream */
+ const int FrameSamples, /* samples per frame */
+ const double BottleNeck, /* bottle neck rate; excl headers (bps) */
+ const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */
+ enum ISACBandwidth bandwidth
+ /*,int16_t frequentLargePackets*/)
+{
+ double MinRate = 0.0;
+ int MinBytes;
+ double TransmissionTime;
+ int burstInterval = BURST_INTERVAL;
+
+ // first 10 packets @ low rate, then INIT_BURST_LEN packets @
+ // fixed rate of INIT_RATE bps
+ if (State->InitCounter > 0)
+ {
+ if (State->InitCounter-- <= INIT_BURST_LEN)
+ {
+ if(bandwidth == isac8kHz)
+ {
+ MinRate = INIT_RATE_WB;
+ }
+ else
+ {
+ MinRate = INIT_RATE_SWB;
+ }
+ }
+ else
+ {
+ MinRate = 0;
+ }
+ }
+ else
+ {
+ /* handle burst */
+ if (State->BurstCounter)
+ {
+ if (State->StillBuffered < (1.0 - 1.0/BURST_LEN) * DelayBuildUp)
+ {
+ /* max bps derived from BottleNeck and DelayBuildUp values */
+ MinRate = (1.0 + (FS/1000) * DelayBuildUp /
+ (double)(BURST_LEN * FrameSamples)) * BottleNeck;
+ }
+ else
+ {
+ // max bps derived from StillBuffered and DelayBuildUp
+ // values
+ MinRate = (1.0 + (FS/1000) * (DelayBuildUp -
+ State->StillBuffered) / (double)FrameSamples) * BottleNeck;
+ if (MinRate < 1.04 * BottleNeck)
+ {
+ MinRate = 1.04 * BottleNeck;
+ }
+ }
+ State->BurstCounter--;
+ }
+ }
+
+
+ /* convert rate from bits/second to bytes/packet */
+ MinBytes = (int) (MinRate * FrameSamples / (8.0 * FS));
+
+ /* StreamSize will be adjusted if less than MinBytes */
+ if (StreamSize < MinBytes)
+ {
+ StreamSize = MinBytes;
+ }
+
+ /* keep track of when bottle neck was last exceeded by at least 1% */
+ if (StreamSize * 8.0 * FS / FrameSamples > 1.01 * BottleNeck) {
+ if (State->PrevExceed) {
+ /* bottle_neck exceded twice in a row, decrease ExceedAgo */
+ State->ExceedAgo -= /*BURST_INTERVAL*/ burstInterval / (BURST_LEN - 1);
+ if (State->ExceedAgo < 0)
+ State->ExceedAgo = 0;
+ }
+ else
+ {
+ State->ExceedAgo += (FrameSamples * 1000) / FS; /* ms */
+ State->PrevExceed = 1;
+ }
+ }
+ else
+ {
+ State->PrevExceed = 0;
+ State->ExceedAgo += (FrameSamples * 1000) / FS; /* ms */
+ }
+
+ /* set burst flag if bottle neck not exceeded for long time */
+ if ((State->ExceedAgo > burstInterval) &&
+ (State->BurstCounter == 0))
+ {
+ if (State->PrevExceed)
+ {
+ State->BurstCounter = BURST_LEN - 1;
+ }
+ else
+ {
+ State->BurstCounter = BURST_LEN;
+ }
+ }
+
+
+ /* Update buffer delay */
+ TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck; /* ms */
+ State->StillBuffered += TransmissionTime;
+ State->StillBuffered -= (FrameSamples * 1000) / FS; /* ms */
+ if (State->StillBuffered < 0.0)
+ {
+ State->StillBuffered = 0.0;
+ }
+
+ return MinBytes;
+}
+
+
+/*
+ * update long-term average bitrate and amount of data in buffer
+ */
+void WebRtcIsac_UpdateRateModel(
+ RateModel *State,
+ int StreamSize, /* bytes in bitstream */
+ const int FrameSamples, /* samples per frame */
+ const double BottleNeck) /* bottle neck rate; excl headers (bps) */
+{
+ double TransmissionTime;
+
+ /* avoid the initial "high-rate" burst */
+ State->InitCounter = 0;
+
+ /* Update buffer delay */
+ TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck; /* ms */
+ State->StillBuffered += TransmissionTime;
+ State->StillBuffered -= (FrameSamples * 1000) / FS; /* ms */
+ if (State->StillBuffered < 0.0)
+ State->StillBuffered = 0.0;
+
+}
+
+
+void WebRtcIsac_InitRateModel(
+ RateModel *State)
+{
+ State->PrevExceed = 0; /* boolean */
+ State->ExceedAgo = 0; /* ms */
+ State->BurstCounter = 0; /* packets */
+ State->InitCounter = INIT_BURST_LEN + 10; /* packets */
+ State->StillBuffered = 1.0; /* ms */
+}
+
+int WebRtcIsac_GetNewFrameLength(
+ double bottle_neck,
+ int current_framesamples)
+{
+ int new_framesamples;
+
+ const int Thld_20_30 = 20000;
+
+ //const int Thld_30_20 = 30000;
+ const int Thld_30_20 = 1000000; // disable 20 ms frames
+
+ const int Thld_30_60 = 18000;
+ //const int Thld_30_60 = 0; // disable 60 ms frames
+
+ const int Thld_60_30 = 27000;
+
+
+ new_framesamples = current_framesamples;
+
+ /* find new framelength */
+ switch(current_framesamples) {
+ case 320:
+ if (bottle_neck < Thld_20_30)
+ new_framesamples = 480;
+ break;
+ case 480:
+ if (bottle_neck < Thld_30_60)
+ new_framesamples = 960;
+ else if (bottle_neck > Thld_30_20)
+ new_framesamples = 320;
+ break;
+ case 960:
+ if (bottle_neck >= Thld_60_30)
+ new_framesamples = 480;
+ break;
+ }
+
+ return new_framesamples;
+}
+
+double WebRtcIsac_GetSnr(
+ double bottle_neck,
+ int framesamples)
+{
+ double s2nr;
+
+ const double a_20 = -30.0;
+ const double b_20 = 0.8;
+ const double c_20 = 0.0;
+
+ const double a_30 = -23.0;
+ const double b_30 = 0.48;
+ const double c_30 = 0.0;
+
+ const double a_60 = -23.0;
+ const double b_60 = 0.53;
+ const double c_60 = 0.0;
+
+
+ /* find new SNR value */
+ switch(framesamples) {
+ case 320:
+ s2nr = a_20 + b_20 * bottle_neck * 0.001 + c_20 * bottle_neck *
+ bottle_neck * 0.000001;
+ break;
+ case 480:
+ s2nr = a_30 + b_30 * bottle_neck * 0.001 + c_30 * bottle_neck *
+ bottle_neck * 0.000001;
+ break;
+ case 960:
+ s2nr = a_60 + b_60 * bottle_neck * 0.001 + c_60 * bottle_neck *
+ bottle_neck * 0.000001;
+ break;
+ default:
+ s2nr = 0;
+ }
+
+ return s2nr;
+
+}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h b/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h
new file mode 100644
index 0000000..0704337
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2011 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.
+ */
+
+/*
+ * bandwidth_estimator.h
+ *
+ * This header file contains the API for the Bandwidth Estimator
+ * designed for iSAC.
+ *
+ */
+
+#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
+
+#include "structs.h"
+#include "settings.h"
+
+
+#define MIN_ISAC_BW 10000
+#define MIN_ISAC_BW_LB 10000
+#define MIN_ISAC_BW_UB 25000
+
+#define MAX_ISAC_BW 56000
+#define MAX_ISAC_BW_UB 32000
+#define MAX_ISAC_BW_LB 32000
+
+#define MIN_ISAC_MD 5
+#define MAX_ISAC_MD 25
+
+// assumed header size, in bytes; we don't know the exact number
+// (header compression may be used)
+#define HEADER_SIZE 35
+
+// Initial Frame-Size, in ms, for Wideband & Super-Wideband Mode
+#define INIT_FRAME_LEN_WB 60
+#define INIT_FRAME_LEN_SWB 30
+
+// Initial Bottleneck Estimate, in bits/sec, for
+// Wideband & Super-wideband mode
+#define INIT_BN_EST_WB 20e3f
+#define INIT_BN_EST_SWB 56e3f
+
+// Initial Header rate (header rate depends on frame-size),
+// in bits/sec, for Wideband & Super-Wideband mode.
+#define INIT_HDR_RATE_WB \
+ ((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_WB)
+#define INIT_HDR_RATE_SWB \
+ ((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_SWB)
+
+// number of packets in a row for a high rate burst
+#define BURST_LEN 3
+
+// ms, max time between two full bursts
+#define BURST_INTERVAL 500
+
+// number of packets in a row for initial high rate burst
+#define INIT_BURST_LEN 5
+
+// bits/s, rate for the first BURST_LEN packets
+#define INIT_RATE_WB INIT_BN_EST_WB
+#define INIT_RATE_SWB INIT_BN_EST_SWB
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+ /* This function initializes the struct */
+ /* to be called before using the struct for anything else */
+ /* returns 0 if everything went fine, -1 otherwise */
+ int32_t WebRtcIsac_InitBandwidthEstimator(
+ BwEstimatorstr* bwest_str,
+ enum IsacSamplingRate encoderSampRate,
+ enum IsacSamplingRate decoderSampRate);
+
+ /* This function updates the receiving estimate */
+ /* Parameters: */
+ /* rtp_number - value from RTP packet, from NetEq */
+ /* frame length - length of signal frame in ms, from iSAC decoder */
+ /* send_ts - value in RTP header giving send time in samples */
+ /* arr_ts - value given by timeGetTime() time of arrival in samples of packet from NetEq */
+ /* pksize - size of packet in bytes, from NetEq */
+ /* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */
+ /* returns 0 if everything went fine, -1 otherwise */
+ int16_t WebRtcIsac_UpdateBandwidthEstimator(
+ BwEstimatorstr* bwest_str,
+ const uint16_t rtp_number,
+ const int32_t frame_length,
+ const uint32_t send_ts,
+ const uint32_t arr_ts,
+ const size_t pksize);
+
+ /* Update receiving estimates. Used when we only receive BWE index, no iSAC data packet. */
+ int16_t WebRtcIsac_UpdateUplinkBwImpl(
+ BwEstimatorstr* bwest_str,
+ int16_t Index,
+ enum IsacSamplingRate encoderSamplingFreq);
+
+ /* Returns the bandwidth/jitter estimation code (integer 0...23) to put in the sending iSAC payload */
+ void WebRtcIsac_GetDownlinkBwJitIndexImpl(
+ BwEstimatorstr* bwest_str,
+ int16_t* bottleneckIndex,
+ int16_t* jitterInfo,
+ enum IsacSamplingRate decoderSamplingFreq);
+
+ /* Returns the bandwidth estimation (in bps) */
+ int32_t WebRtcIsac_GetDownlinkBandwidth(
+ const BwEstimatorstr *bwest_str);
+
+ /* Returns the max delay (in ms) */
+ int32_t WebRtcIsac_GetDownlinkMaxDelay(
+ const BwEstimatorstr *bwest_str);
+
+ /* Returns the bandwidth that iSAC should send with in bps */
+ int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str);
+
+ /* Returns the max delay value from the other side in ms */
+ int32_t WebRtcIsac_GetUplinkMaxDelay(
+ const BwEstimatorstr *bwest_str);
+
+ /* Fills in an IsacExternalBandwidthInfo struct. */
+ void WebRtcIsacBw_GetBandwidthInfo(
+ BwEstimatorstr* bwest_str,
+ enum IsacSamplingRate decoder_sample_rate_hz,
+ IsacBandwidthInfo* bwinfo);
+
+ /* Uses the values from an IsacExternalBandwidthInfo struct. */
+ void WebRtcIsacBw_SetBandwidthInfo(BwEstimatorstr* bwest_str,
+ const IsacBandwidthInfo* bwinfo);
+
+ /*
+ * update amount of data in bottle neck buffer and burst handling
+ * returns minimum payload size (bytes)
+ */
+ int WebRtcIsac_GetMinBytes(
+ RateModel* State,
+ int StreamSize, /* bytes in bitstream */
+ const int FrameLen, /* ms per frame */
+ const double BottleNeck, /* bottle neck rate; excl headers (bps) */
+ const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */
+ enum ISACBandwidth bandwidth
+ /*,int16_t frequentLargePackets*/);
+
+ /*
+ * update long-term average bitrate and amount of data in buffer
+ */
+ void WebRtcIsac_UpdateRateModel(
+ RateModel* State,
+ int StreamSize, /* bytes in bitstream */
+ const int FrameSamples, /* samples per frame */
+ const double BottleNeck); /* bottle neck rate; excl headers (bps) */
+
+
+ void WebRtcIsac_InitRateModel(
+ RateModel *State);
+
+ /* Returns the new framelength value (input argument: bottle_neck) */
+ int WebRtcIsac_GetNewFrameLength(
+ double bottle_neck,
+ int current_framelength);
+
+ /* Returns the new SNR value (input argument: bottle_neck) */
+ double WebRtcIsac_GetSnr(
+ double bottle_neck,
+ int new_framelength);
+
+
+ int16_t WebRtcIsac_UpdateUplinkJitter(
+ BwEstimatorstr* bwest_str,
+ int32_t index);
+
+#if defined(__cplusplus)
+}
+#endif
+
+
+#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/crc.c b/webrtc/modules/audio_coding/codecs/isac/main/source/crc.c
new file mode 100644
index 0000000..ebef595
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/crc.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2011 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 "crc.h"
+#include <stdlib.h>
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+
+#define POLYNOMIAL 0x04c11db7L
+
+
+static const uint32_t kCrcTable[256] = {
+ 0, 0x4c11db7, 0x9823b6e, 0xd4326d9, 0x130476dc, 0x17c56b6b,
+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
+ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
+ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
+ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
+ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x18aeb13, 0x54bf6a4,
+ 0x808d07d, 0xcc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
+ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
+ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
+ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
+ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
+ 0x3f9b762c, 0x3b5a6b9b, 0x315d626, 0x7d4cb91, 0xa97ed48, 0xe56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
+ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
+ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
+ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
+ 0x18197087, 0x1cd86d30, 0x29f3d35, 0x65e2082, 0xb1d065b, 0xfdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
+ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
+ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+};
+
+
+
+
+/****************************************************************************
+ * WebRtcIsac_GetCrc(...)
+ *
+ * This function returns a 32 bit CRC checksum of a bit stream
+ *
+ * Input:
+ * - bitstream : payload bitstream
+ * - len_bitstream_in_bytes : number of 8-bit words in the bit stream
+ *
+ * Output:
+ * - crc : checksum
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+
+int WebRtcIsac_GetCrc(const int16_t* bitstream,
+ int len_bitstream_in_bytes,
+ uint32_t* crc)
+{
+ uint8_t* bitstream_ptr_uw8;
+ uint32_t crc_state;
+ int byte_cntr;
+ int crc_tbl_indx;
+
+ /* Sanity Check. */
+ if (bitstream == NULL) {
+ return -1;
+ }
+ /* cast to UWord8 pointer */
+ bitstream_ptr_uw8 = (uint8_t *)bitstream;
+
+ /* initialize */
+ crc_state = 0xFFFFFFFF;
+
+ for (byte_cntr = 0; byte_cntr < len_bitstream_in_bytes; byte_cntr++) {
+ crc_tbl_indx = (WEBRTC_SPL_RSHIFT_U32(crc_state, 24) ^
+ bitstream_ptr_uw8[byte_cntr]) & 0xFF;
+ crc_state = (crc_state << 8) ^ kCrcTable[crc_tbl_indx];
+ }
+
+ *crc = ~crc_state;
+ return 0;
+}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/crc.h b/webrtc/modules/audio_coding/codecs/isac/main/source/crc.h
new file mode 100644
index 0000000..09583df
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/crc.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011 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.
+ */
+
+/*
+ * crc.h
+ *
+ * Checksum functions
+ *
+ */
+
+#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
+
+#include "webrtc/typedefs.h"
+
+/****************************************************************************
+ * WebRtcIsac_GetCrc(...)
+ *
+ * This function returns a 32 bit CRC checksum of a bit stream
+ *
+ * Input:
+ * - encoded : payload bit stream
+ * - no_of_word8s : number of 8-bit words in the bit stream
+ *
+ * Output:
+ * - crc : checksum
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+
+int WebRtcIsac_GetCrc(
+ const int16_t* encoded,
+ int no_of_word8s,
+ uint32_t* crc);
+
+
+
+#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/decode.c b/webrtc/modules/audio_coding/codecs/isac/main/source/decode.c
new file mode 100644
index 0000000..e925efb
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/decode.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*
+ * decode_B.c
+ *
+ * This file contains definition of funtions for decoding.
+ * Decoding of lower-band, including normal-decoding and RCU decoding.
+ * Decoding of upper-band, including 8-12 kHz, when the bandwidth is
+ * 0-12 kHz, and 8-16 kHz, when the bandwidth is 0-16 kHz.
+ *
+ */
+
+
+#include "codec.h"
+#include "entropy_coding.h"
+#include "pitch_estimator.h"
+#include "bandwidth_estimator.h"
+#include "structs.h"
+#include "settings.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*
+ * function to decode the bitstream
+ * returns the total number of bytes in the stream
+ */
+int WebRtcIsac_DecodeLb(const TransformTables* transform_tables,
+ float* signal_out, ISACLBDecStruct* ISACdecLB_obj,
+ int16_t* current_framesamples,
+ int16_t isRCUPayload) {
+ int k;
+ int len, err;
+ int16_t bandwidthInd;
+
+ float LP_dec_float[FRAMESAMPLES_HALF];
+ float HP_dec_float[FRAMESAMPLES_HALF];
+
+ double LPw[FRAMESAMPLES_HALF];
+ double HPw[FRAMESAMPLES_HALF];
+ double LPw_pf[FRAMESAMPLES_HALF];
+
+ double lo_filt_coef[(ORDERLO + 1)*SUBFRAMES];
+ double hi_filt_coef[(ORDERHI + 1)*SUBFRAMES];
+
+ double real_f[FRAMESAMPLES_HALF];
+ double imag_f[FRAMESAMPLES_HALF];
+
+ double PitchLags[4];
+ double PitchGains[4];
+ double AvgPitchGain;
+ int16_t PitchGains_Q12[4];
+ int16_t AvgPitchGain_Q12;
+
+ float gain;
+
+ int frame_nb; /* counter */
+ int frame_mode; /* 0 30ms, 1 for 60ms */
+ /* Processed_samples: 480 (30, 60 ms). Cannot take other values. */
+
+ WebRtcIsac_ResetBitstream(&(ISACdecLB_obj->bitstr_obj));
+
+ len = 0;
+
+ /* Decode framelength and BW estimation - not used,
+ only for stream pointer*/
+ err = WebRtcIsac_DecodeFrameLen(&ISACdecLB_obj->bitstr_obj,
+ current_framesamples);
+ if (err < 0) {
+ return err;
+ }
+
+ /* Frame_mode:
+ * 0: indicates 30 ms frame (480 samples)
+ * 1: indicates 60 ms frame (960 samples) */
+ frame_mode = *current_framesamples / MAX_FRAMESAMPLES;
+
+ err = WebRtcIsac_DecodeSendBW(&ISACdecLB_obj->bitstr_obj, &bandwidthInd);
+ if (err < 0) {
+ return err;
+ }
+
+ /* One loop if it's one frame (20 or 30ms), 2 loops if 2 frames
+ bundled together (60ms). */
+ for (frame_nb = 0; frame_nb <= frame_mode; frame_nb++) {
+ /* Decode & de-quantize pitch parameters */
+ err = WebRtcIsac_DecodePitchGain(&ISACdecLB_obj->bitstr_obj,
+ PitchGains_Q12);
+ if (err < 0) {
+ return err;
+ }
+
+ err = WebRtcIsac_DecodePitchLag(&ISACdecLB_obj->bitstr_obj, PitchGains_Q12,
+ PitchLags);
+ if (err < 0) {
+ return err;
+ }
+
+ AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] +
+ PitchGains_Q12[2] + PitchGains_Q12[3]) >> 2;
+
+ /* Decode & de-quantize filter coefficients. */
+ err = WebRtcIsac_DecodeLpc(&ISACdecLB_obj->bitstr_obj, lo_filt_coef,
+ hi_filt_coef);
+ if (err < 0) {
+ return err;
+ }
+ /* Decode & de-quantize spectrum. */
+ len = WebRtcIsac_DecodeSpec(&ISACdecLB_obj->bitstr_obj, AvgPitchGain_Q12,
+ kIsacLowerBand, real_f, imag_f);
+ if (len < 0) {
+ return len;
+ }
+
+ /* Inverse transform. */
+ WebRtcIsac_Spec2time(transform_tables, real_f, imag_f, LPw, HPw,
+ &ISACdecLB_obj->fftstr_obj);
+
+ /* Convert PitchGains back to float for pitchfilter_post */
+ for (k = 0; k < 4; k++) {
+ PitchGains[k] = ((float)PitchGains_Q12[k]) / 4096;
+ }
+ if (isRCUPayload) {
+ for (k = 0; k < 240; k++) {
+ LPw[k] *= RCU_TRANSCODING_SCALE_INVERSE;
+ HPw[k] *= RCU_TRANSCODING_SCALE_INVERSE;
+ }
+ }
+
+ /* Inverse pitch filter. */
+ WebRtcIsac_PitchfilterPost(LPw, LPw_pf, &ISACdecLB_obj->pitchfiltstr_obj,
+ PitchLags, PitchGains);
+ /* Convert AvgPitchGain back to float for computation of gain. */
+ AvgPitchGain = ((float)AvgPitchGain_Q12) / 4096;
+ gain = 1.0f - 0.45f * (float)AvgPitchGain;
+
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ /* Reduce gain to compensate for pitch enhancer. */
+ LPw_pf[k] *= gain;
+ }
+
+ if (isRCUPayload) {
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ /* Compensation for transcoding gain changes. */
+ LPw_pf[k] *= RCU_TRANSCODING_SCALE;
+ HPw[k] *= RCU_TRANSCODING_SCALE;
+ }
+ }
+ /* Perceptual post-filtering (using normalized lattice filter). */
+ WebRtcIsac_NormLatticeFilterAr(
+ ORDERLO, ISACdecLB_obj->maskfiltstr_obj.PostStateLoF,
+ (ISACdecLB_obj->maskfiltstr_obj).PostStateLoG, LPw_pf, lo_filt_coef,
+ LP_dec_float);
+ WebRtcIsac_NormLatticeFilterAr(
+ ORDERHI, ISACdecLB_obj->maskfiltstr_obj.PostStateHiF,
+ (ISACdecLB_obj->maskfiltstr_obj).PostStateHiG, HPw, hi_filt_coef,
+ HP_dec_float);
+
+ /* Recombine the 2 bands. */
+ WebRtcIsac_FilterAndCombineFloat(LP_dec_float, HP_dec_float,
+ signal_out + frame_nb * FRAMESAMPLES,
+ &ISACdecLB_obj->postfiltbankstr_obj);
+ }
+ return len;
+}
+
+
+/*
+ * This decode function is called when the codec is operating in 16 kHz
+ * bandwidth to decode the upperband, i.e. 8-16 kHz.
+ *
+ * Contrary to lower-band, the upper-band (8-16 kHz) is not split in
+ * frequency, but split to 12 sub-frames, i.e. twice as lower-band.
+ */
+int WebRtcIsac_DecodeUb16(const TransformTables* transform_tables,
+ float* signal_out, ISACUBDecStruct* ISACdecUB_obj,
+ int16_t isRCUPayload) {
+ int len, err;
+
+ double halfFrameFirst[FRAMESAMPLES_HALF];
+ double halfFrameSecond[FRAMESAMPLES_HALF];
+
+ double percepFilterParam[(UB_LPC_ORDER + 1) * (SUBFRAMES << 1) +
+ (UB_LPC_ORDER + 1)];
+
+ double real_f[FRAMESAMPLES_HALF];
+ double imag_f[FRAMESAMPLES_HALF];
+ const int16_t kAveragePitchGain = 0; /* No pitch-gain for upper-band. */
+ len = 0;
+
+ /* Decode & de-quantize filter coefficients. */
+ memset(percepFilterParam, 0, sizeof(percepFilterParam));
+ err = WebRtcIsac_DecodeInterpolLpcUb(&ISACdecUB_obj->bitstr_obj,
+ percepFilterParam, isac16kHz);
+ if (err < 0) {
+ return err;
+ }
+
+ /* Decode & de-quantize spectrum. */
+ len = WebRtcIsac_DecodeSpec(&ISACdecUB_obj->bitstr_obj, kAveragePitchGain,
+ kIsacUpperBand16, real_f, imag_f);
+ if (len < 0) {
+ return len;
+ }
+ if (isRCUPayload) {
+ int n;
+ for (n = 0; n < 240; n++) {
+ real_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE;
+ imag_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE;
+ }
+ }
+ /* Inverse transform. */
+ WebRtcIsac_Spec2time(transform_tables,
+ real_f, imag_f, halfFrameFirst, halfFrameSecond,
+ &ISACdecUB_obj->fftstr_obj);
+
+ /* Perceptual post-filtering (using normalized lattice filter). */
+ WebRtcIsac_NormLatticeFilterAr(
+ UB_LPC_ORDER, ISACdecUB_obj->maskfiltstr_obj.PostStateLoF,
+ (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, halfFrameFirst,
+ &percepFilterParam[(UB_LPC_ORDER + 1)], signal_out);
+
+ WebRtcIsac_NormLatticeFilterAr(
+ UB_LPC_ORDER, ISACdecUB_obj->maskfiltstr_obj.PostStateLoF,
+ (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, halfFrameSecond,
+ &percepFilterParam[(UB_LPC_ORDER + 1) * SUBFRAMES + (UB_LPC_ORDER + 1)],
+ &signal_out[FRAMESAMPLES_HALF]);
+
+ return len;
+}
+
+/*
+ * This decode function is called when the codec operates at 0-12 kHz
+ * bandwidth to decode the upperband, i.e. 8-12 kHz.
+ *
+ * At the encoder the upper-band is split into two band, 8-12 kHz & 12-16
+ * kHz, and only 8-12 kHz is encoded. At the decoder, 8-12 kHz band is
+ * reconstructed and 12-16 kHz replaced with zeros. Then two bands
+ * are combined, to reconstruct the upperband 8-16 kHz.
+ */
+int WebRtcIsac_DecodeUb12(const TransformTables* transform_tables,
+ float* signal_out, ISACUBDecStruct* ISACdecUB_obj,
+ int16_t isRCUPayload) {
+ int len, err;
+
+ float LP_dec_float[FRAMESAMPLES_HALF];
+ float HP_dec_float[FRAMESAMPLES_HALF];
+
+ double LPw[FRAMESAMPLES_HALF];
+ double HPw[FRAMESAMPLES_HALF];
+
+ double percepFilterParam[(UB_LPC_ORDER + 1)*SUBFRAMES];
+
+ double real_f[FRAMESAMPLES_HALF];
+ double imag_f[FRAMESAMPLES_HALF];
+ const int16_t kAveragePitchGain = 0; /* No pitch-gain for upper-band. */
+ len = 0;
+
+ /* Decode & dequantize filter coefficients. */
+ err = WebRtcIsac_DecodeInterpolLpcUb(&ISACdecUB_obj->bitstr_obj,
+ percepFilterParam, isac12kHz);
+ if (err < 0) {
+ return err;
+ }
+
+ /* Decode & de-quantize spectrum. */
+ len = WebRtcIsac_DecodeSpec(&ISACdecUB_obj->bitstr_obj, kAveragePitchGain,
+ kIsacUpperBand12, real_f, imag_f);
+ if (len < 0) {
+ return len;
+ }
+
+ if (isRCUPayload) {
+ int n;
+ for (n = 0; n < 240; n++) {
+ real_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE;
+ imag_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE;
+ }
+ }
+ /* Inverse transform. */
+ WebRtcIsac_Spec2time(transform_tables,
+ real_f, imag_f, LPw, HPw, &ISACdecUB_obj->fftstr_obj);
+ /* perceptual post-filtering (using normalized lattice filter) */
+ WebRtcIsac_NormLatticeFilterAr(UB_LPC_ORDER,
+ ISACdecUB_obj->maskfiltstr_obj.PostStateLoF,
+ (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG,
+ LPw, percepFilterParam, LP_dec_float);
+ /* Zero for 12-16 kHz. */
+ memset(HP_dec_float, 0, sizeof(float) * (FRAMESAMPLES_HALF));
+ /* Recombine the 2 bands. */
+ WebRtcIsac_FilterAndCombineFloat(HP_dec_float, LP_dec_float, signal_out,
+ &ISACdecUB_obj->postfiltbankstr_obj);
+ return len;
+}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c b/webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c
new file mode 100644
index 0000000..019cc89
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011 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 "structs.h"
+#include "bandwidth_estimator.h"
+#include "entropy_coding.h"
+#include "codec.h"
+
+
+int
+WebRtcIsac_EstimateBandwidth(
+ BwEstimatorstr* bwest_str,
+ Bitstr* streamdata,
+ size_t packet_size,
+ uint16_t rtp_seq_number,
+ uint32_t send_ts,
+ uint32_t arr_ts,
+ enum IsacSamplingRate encoderSampRate,
+ enum IsacSamplingRate decoderSampRate)
+{
+ int16_t index;
+ int16_t frame_samples;
+ uint32_t sendTimestampIn16kHz;
+ uint32_t arrivalTimestampIn16kHz;
+ uint32_t diffSendTime;
+ uint32_t diffArrivalTime;
+ int err;
+
+ /* decode framelength and BW estimation */
+ err = WebRtcIsac_DecodeFrameLen(streamdata, &frame_samples);
+ if(err < 0) // error check
+ {
+ return err;
+ }
+ err = WebRtcIsac_DecodeSendBW(streamdata, &index);
+ if(err < 0) // error check
+ {
+ return err;
+ }
+
+ /* UPDATE ESTIMATES FROM OTHER SIDE */
+ err = WebRtcIsac_UpdateUplinkBwImpl(bwest_str, index, encoderSampRate);
+ if(err < 0)
+ {
+ return err;
+ }
+
+ // We like BWE to work at 16 kHz sampling rate,
+ // therefore, we have to change the timestamps accordingly.
+ // translate the send timestamp if required
+ diffSendTime = (uint32_t)((uint32_t)send_ts -
+ (uint32_t)bwest_str->senderTimestamp);
+ bwest_str->senderTimestamp = send_ts;
+
+ diffArrivalTime = (uint32_t)((uint32_t)arr_ts -
+ (uint32_t)bwest_str->receiverTimestamp);
+ bwest_str->receiverTimestamp = arr_ts;
+
+ if(decoderSampRate == kIsacSuperWideband)
+ {
+ diffArrivalTime = (uint32_t)diffArrivalTime >> 1;
+ diffSendTime = (uint32_t)diffSendTime >> 1;
+ }
+
+ // arrival timestamp in 16 kHz
+ arrivalTimestampIn16kHz = (uint32_t)((uint32_t)
+ bwest_str->prev_rec_arr_ts + (uint32_t)diffArrivalTime);
+ // send timestamp in 16 kHz
+ sendTimestampIn16kHz = (uint32_t)((uint32_t)
+ bwest_str->prev_rec_send_ts + (uint32_t)diffSendTime);
+
+ err = WebRtcIsac_UpdateBandwidthEstimator(bwest_str, rtp_seq_number,
+ (frame_samples * 1000) / FS, sendTimestampIn16kHz,
+ arrivalTimestampIn16kHz, packet_size);
+ // error check
+ if(err < 0)
+ {
+ return err;
+ }
+
+ return 0;
+}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/encode.c b/webrtc/modules/audio_coding/codecs/isac/main/source/encode.c
new file mode 100644
index 0000000..3f1912b
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/encode.c
@@ -0,0 +1,1258 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*
+ * encode.c
+ *
+ * This file contains definition of funtions for encoding.
+ * Decoding of upper-band, including 8-12 kHz, when the bandwidth is
+ * 0-12 kHz, and 8-16 kHz, when the bandwidth is 0-16 kHz.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "structs.h"
+#include "codec.h"
+#include "pitch_estimator.h"
+#include "entropy_coding.h"
+#include "arith_routines.h"
+#include "pitch_gain_tables.h"
+#include "pitch_lag_tables.h"
+#include "spectrum_ar_model_tables.h"
+#include "lpc_tables.h"
+#include "lpc_analysis.h"
+#include "bandwidth_estimator.h"
+#include "lpc_shape_swb12_tables.h"
+#include "lpc_shape_swb16_tables.h"
+#include "lpc_gain_swb_tables.h"
+
+
+#define UB_LOOKAHEAD 24
+
+
+/*
+ Rate allocation tables of lower and upper-band bottleneck for
+ 12kHz & 16kHz bandwidth.
+
+ 12 kHz bandwidth
+ -----------------
+ The overall bottleneck of the coder is between 38 kbps and 45 kbps. We have
+ considered 7 enteries, uniformly distributed in this interval, i.e. 38,
+ 39.17, 40.33, 41.5, 42.67, 43.83 and 45. For every entery, the lower-band
+ and the upper-band bottlenecks are specified in
+ 'kLowerBandBitRate12' and 'kUpperBandBitRate12'
+ tables, respectively. E.g. the overall rate of 41.5 kbps corresponts to a
+ bottleneck of 31 kbps for lower-band and 27 kbps for upper-band. Given an
+ overall bottleneck of the codec, we use linear interpolation to get
+ lower-band and upper-band bottlenecks.
+
+ 16 kHz bandwidth
+ -----------------
+ The overall bottleneck of the coder is between 50 kbps and 56 kbps. We have
+ considered 7 enteries, uniformly distributed in this interval, i.e. 50, 51.2,
+ 52.4, 53.6, 54.8 and 56. For every entery, the lower-band and the upper-band
+ bottlenecks are specified in 'kLowerBandBitRate16' and
+ 'kUpperBandBitRate16' tables, respectively. E.g. the overall rate
+ of 53.6 kbps corresponts to a bottleneck of 32 kbps for lower-band and 30
+ kbps for upper-band. Given an overall bottleneck of the codec, we use linear
+ interpolation to get lower-band and upper-band bottlenecks.
+
+ */
+
+/* 38 39.17 40.33 41.5 42.67 43.83 45 */
+static const int16_t kLowerBandBitRate12[7] = {
+ 29000, 30000, 30000, 31000, 31000, 32000, 32000 };
+static const int16_t kUpperBandBitRate12[7] = {
+ 25000, 25000, 27000, 27000, 29000, 29000, 32000 };
+
+/* 50 51.2 52.4 53.6 54.8 56 */
+static const int16_t kLowerBandBitRate16[6] = {
+ 31000, 31000, 32000, 32000, 32000, 32000 };
+static const int16_t kUpperBandBitRate16[6] = {
+ 28000, 29000, 29000, 30000, 31000, 32000 };
+
+/******************************************************************************
+ * WebRtcIsac_RateAllocation()
+ * Internal function to perform a rate-allocation for upper and lower-band,
+ * given a total rate.
+ *
+ * Input:
+ * - inRateBitPerSec : a total bottleneck in bits/sec.
+ *
+ * Output:
+ * - rateLBBitPerSec : a bottleneck allocated to the lower-band
+ * in bits/sec.
+ * - rateUBBitPerSec : a bottleneck allocated to the upper-band
+ * in bits/sec.
+ *
+ * Return value : 0 if rate allocation has been successful.
+ * -1 if failed to allocate rates.
+ */
+
+int16_t WebRtcIsac_RateAllocation(int32_t inRateBitPerSec,
+ double* rateLBBitPerSec,
+ double* rateUBBitPerSec,
+ enum ISACBandwidth* bandwidthKHz) {
+ int16_t idx;
+ double idxD;
+ double idxErr;
+ if (inRateBitPerSec < 38000) {
+ /* If the given overall bottleneck is less than 38000 then
+ * then codec has to operate in wideband mode, i.e. 8 kHz
+ * bandwidth. */
+ *rateLBBitPerSec = (int16_t)((inRateBitPerSec > 32000) ?
+ 32000 : inRateBitPerSec);
+ *rateUBBitPerSec = 0;
+ *bandwidthKHz = isac8kHz;
+ } else if ((inRateBitPerSec >= 38000) && (inRateBitPerSec < 50000)) {
+ /* At a bottleneck between 38 and 50 kbps the codec is operating
+ * at 12 kHz bandwidth. Using xxxBandBitRate12[] to calculates
+ * upper/lower bottleneck */
+
+ /* Find the bottlenecks by linear interpolation,
+ * step is (45000 - 38000)/6.0 we use the inverse of it. */
+ const double stepSizeInv = 8.5714286e-4;
+ idxD = (inRateBitPerSec - 38000) * stepSizeInv;
+ idx = (idxD >= 6) ? 6 : ((int16_t)idxD);
+ idxErr = idxD - idx;
+ *rateLBBitPerSec = kLowerBandBitRate12[idx];
+ *rateUBBitPerSec = kUpperBandBitRate12[idx];
+
+ if (idx < 6) {
+ *rateLBBitPerSec += (int16_t)(
+ idxErr * (kLowerBandBitRate12[idx + 1] - kLowerBandBitRate12[idx]));
+ *rateUBBitPerSec += (int16_t)(
+ idxErr * (kUpperBandBitRate12[idx + 1] - kUpperBandBitRate12[idx]));
+ }
+ *bandwidthKHz = isac12kHz;
+ } else if ((inRateBitPerSec >= 50000) && (inRateBitPerSec <= 56000)) {
+ /* A bottleneck between 50 and 56 kbps corresponds to bandwidth
+ * of 16 kHz. Using xxxBandBitRate16[] to calculates
+ * upper/lower bottleneck. */
+
+ /* Find the bottlenecks by linear interpolation
+ * step is (56000 - 50000)/5 we use the inverse of it. */
+ const double stepSizeInv = 8.3333333e-4;
+ idxD = (inRateBitPerSec - 50000) * stepSizeInv;
+ idx = (idxD >= 5) ? 5 : ((int16_t)idxD);
+ idxErr = idxD - idx;
+ *rateLBBitPerSec = kLowerBandBitRate16[idx];
+ *rateUBBitPerSec = kUpperBandBitRate16[idx];
+
+ if (idx < 5) {
+ *rateLBBitPerSec += (int16_t)(idxErr *
+ (kLowerBandBitRate16[idx + 1] -
+ kLowerBandBitRate16[idx]));
+
+ *rateUBBitPerSec += (int16_t)(idxErr *
+ (kUpperBandBitRate16[idx + 1] -
+ kUpperBandBitRate16[idx]));
+ }
+ *bandwidthKHz = isac16kHz;
+ } else {
+ /* Out-of-range botlteneck value. */
+ return -1;
+ }
+
+ /* limit the values. */
+ *rateLBBitPerSec = (*rateLBBitPerSec > 32000) ? 32000 : *rateLBBitPerSec;
+ *rateUBBitPerSec = (*rateUBBitPerSec > 32000) ? 32000 : *rateUBBitPerSec;
+ return 0;
+}
+
+
+void WebRtcIsac_ResetBitstream(Bitstr* bit_stream) {
+ bit_stream->W_upper = 0xFFFFFFFF;
+ bit_stream->stream_index = 0;
+ bit_stream->streamval = 0;
+}
+
+int WebRtcIsac_EncodeLb(const TransformTables* transform_tables,
+ float* in, ISACLBEncStruct* ISACencLB_obj,
+ int16_t codingMode,
+ int16_t bottleneckIndex) {
+ int stream_length = 0;
+ int err;
+ int k;
+ int iterCntr;
+
+ double lofilt_coef[(ORDERLO + 1)*SUBFRAMES];
+ double hifilt_coef[(ORDERHI + 1)*SUBFRAMES];
+ float LP[FRAMESAMPLES_HALF];
+ float HP[FRAMESAMPLES_HALF];
+
+ double LP_lookahead[FRAMESAMPLES_HALF];
+ double HP_lookahead[FRAMESAMPLES_HALF];
+ double LP_lookahead_pf[FRAMESAMPLES_HALF + QLOOKAHEAD];
+ double LPw[FRAMESAMPLES_HALF];
+
+ double HPw[FRAMESAMPLES_HALF];
+ double LPw_pf[FRAMESAMPLES_HALF];
+ int16_t fre[FRAMESAMPLES_HALF]; /* Q7 */
+ int16_t fim[FRAMESAMPLES_HALF]; /* Q7 */
+
+ double PitchLags[4];
+ double PitchGains[4];
+ int16_t PitchGains_Q12[4];
+ int16_t AvgPitchGain_Q12;
+
+ int frame_mode; /* 0 for 30ms, 1 for 60ms */
+ int status = 0;
+ int my_index;
+ transcode_obj transcodingParam;
+ double bytesLeftSpecCoding;
+ uint16_t payloadLimitBytes;
+
+ /* Copy new frame-length and bottleneck rate only for the first 10 ms data */
+ if (ISACencLB_obj->buffer_index == 0) {
+ /* Set the framelength for the next packet. */
+ ISACencLB_obj->current_framesamples = ISACencLB_obj->new_framelength;
+ }
+ /* 'frame_mode' is 0 (30 ms) or 1 (60 ms). */
+ frame_mode = ISACencLB_obj->current_framesamples / MAX_FRAMESAMPLES;
+
+ /* buffer speech samples (by 10ms packet) until the frame-length */
+ /* is reached (30 or 60 ms). */
+ /*****************************************************************/
+
+ /* fill the buffer with 10ms input data */
+ for (k = 0; k < FRAMESAMPLES_10ms; k++) {
+ ISACencLB_obj->data_buffer_float[k + ISACencLB_obj->buffer_index] = in[k];
+ }
+
+ /* If buffersize is not equal to current framesize then increase index
+ * and return. We do no encoding untill we have enough audio. */
+ if (ISACencLB_obj->buffer_index + FRAMESAMPLES_10ms != FRAMESAMPLES) {
+ ISACencLB_obj->buffer_index += FRAMESAMPLES_10ms;
+ return 0;
+ }
+ /* If buffer reached the right size, reset index and continue with
+ * encoding the frame. */
+ ISACencLB_obj->buffer_index = 0;
+
+ /* End of buffer function. */
+ /**************************/
+
+ /* Encoding */
+ /************/
+
+ if (frame_mode == 0 || ISACencLB_obj->frame_nb == 0) {
+ /* This is to avoid Linux warnings until we change 'int' to 'Word32'
+ * at all places. */
+ int intVar;
+ /* reset bitstream */
+ WebRtcIsac_ResetBitstream(&(ISACencLB_obj->bitstr_obj));
+
+ if ((codingMode == 0) && (frame_mode == 0) &&
+ (ISACencLB_obj->enforceFrameSize == 0)) {
+ ISACencLB_obj->new_framelength = WebRtcIsac_GetNewFrameLength(
+ ISACencLB_obj->bottleneck, ISACencLB_obj->current_framesamples);
+ }
+
+ ISACencLB_obj->s2nr = WebRtcIsac_GetSnr(
+ ISACencLB_obj->bottleneck, ISACencLB_obj->current_framesamples);
+
+ /* Encode frame length. */
+ status = WebRtcIsac_EncodeFrameLen(
+ ISACencLB_obj->current_framesamples, &ISACencLB_obj->bitstr_obj);
+ if (status < 0) {
+ /* Wrong frame size. */
+ return status;
+ }
+ /* Save framelength for multiple packets memory. */
+ ISACencLB_obj->SaveEnc_obj.framelength =
+ ISACencLB_obj->current_framesamples;
+
+ /* To be used for Redundant Coding. */
+ ISACencLB_obj->lastBWIdx = bottleneckIndex;
+ intVar = (int)bottleneckIndex;
+ WebRtcIsac_EncodeReceiveBw(&intVar, &ISACencLB_obj->bitstr_obj);
+ }
+
+ /* Split signal in two bands. */
+ WebRtcIsac_SplitAndFilterFloat(ISACencLB_obj->data_buffer_float, LP, HP,
+ LP_lookahead, HP_lookahead,
+ &ISACencLB_obj->prefiltbankstr_obj);
+
+ /* estimate pitch parameters and pitch-filter lookahead signal */
+ WebRtcIsac_PitchAnalysis(LP_lookahead, LP_lookahead_pf,
+ &ISACencLB_obj->pitchanalysisstr_obj, PitchLags,
+ PitchGains);
+
+ /* Encode in FIX Q12. */
+
+ /* Convert PitchGain to Fixed point. */
+ for (k = 0; k < PITCH_SUBFRAMES; k++) {
+ PitchGains_Q12[k] = (int16_t)(PitchGains[k] * 4096.0);
+ }
+
+ /* Set where to store data in multiple packets memory. */
+ if (frame_mode == 0 || ISACencLB_obj->frame_nb == 0) {
+ ISACencLB_obj->SaveEnc_obj.startIdx = 0;
+ } else {
+ ISACencLB_obj->SaveEnc_obj.startIdx = 1;
+ }
+
+ /* Quantize & encode pitch parameters. */
+ WebRtcIsac_EncodePitchGain(PitchGains_Q12, &ISACencLB_obj->bitstr_obj,
+ &ISACencLB_obj->SaveEnc_obj);
+ WebRtcIsac_EncodePitchLag(PitchLags, PitchGains_Q12,
+ &ISACencLB_obj->bitstr_obj,
+ &ISACencLB_obj->SaveEnc_obj);
+
+ AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] +
+ PitchGains_Q12[2] + PitchGains_Q12[3]) >> 2;
+
+ /* Find coefficients for perceptual pre-filters. */
+ WebRtcIsac_GetLpcCoefLb(LP_lookahead_pf, HP_lookahead,
+ &ISACencLB_obj->maskfiltstr_obj, ISACencLB_obj->s2nr,
+ PitchGains_Q12, lofilt_coef, hifilt_coef);
+
+ /* Code LPC model and shape - gains not quantized yet. */
+ WebRtcIsac_EncodeLpcLb(lofilt_coef, hifilt_coef, &ISACencLB_obj->bitstr_obj,
+ &ISACencLB_obj->SaveEnc_obj);
+
+ /* Convert PitchGains back to FLOAT for pitchfilter_pre. */
+ for (k = 0; k < 4; k++) {
+ PitchGains[k] = ((float)PitchGains_Q12[k]) / 4096;
+ }
+
+ /* Store the state of arithmetic coder before coding LPC gains. */
+ transcodingParam.W_upper = ISACencLB_obj->bitstr_obj.W_upper;
+ transcodingParam.stream_index = ISACencLB_obj->bitstr_obj.stream_index;
+ transcodingParam.streamval = ISACencLB_obj->bitstr_obj.streamval;
+ transcodingParam.stream[0] =
+ ISACencLB_obj->bitstr_obj.stream[ISACencLB_obj->bitstr_obj.stream_index -
+ 2];
+ transcodingParam.stream[1] =
+ ISACencLB_obj->bitstr_obj.stream[ISACencLB_obj->bitstr_obj.stream_index -
+ 1];
+ transcodingParam.stream[2] =
+ ISACencLB_obj->bitstr_obj.stream[ISACencLB_obj->bitstr_obj.stream_index];
+
+ /* Store LPC Gains before encoding them. */
+ for (k = 0; k < SUBFRAMES; k++) {
+ transcodingParam.loFiltGain[k] = lofilt_coef[(LPC_LOBAND_ORDER + 1) * k];
+ transcodingParam.hiFiltGain[k] = hifilt_coef[(LPC_HIBAND_ORDER + 1) * k];
+ }
+
+ /* Code gains */
+ WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef,
+ &ISACencLB_obj->bitstr_obj,
+ &ISACencLB_obj->SaveEnc_obj);
+
+ /* Get the correct value for the payload limit and calculate the
+ * number of bytes left for coding the spectrum. */
+ if ((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) {
+ /* It is a 60ms and we are in the first 30ms then the limit at
+ * this point should be half of the assigned value. */
+ payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 >> 1;
+ } else if (frame_mode == 0) {
+ /* It is a 30ms frame */
+ /* Subract 3 because termination process may add 3 bytes. */
+ payloadLimitBytes = ISACencLB_obj->payloadLimitBytes30 - 3;
+ } else {
+ /* This is the second half of a 60ms frame. */
+ /* Subract 3 because termination process may add 3 bytes. */
+ payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 - 3;
+ }
+ bytesLeftSpecCoding = payloadLimitBytes - transcodingParam.stream_index;
+
+ /* Perceptual pre-filtering (using normalized lattice filter). */
+ /* Low-band filtering. */
+ WebRtcIsac_NormLatticeFilterMa(ORDERLO,
+ ISACencLB_obj->maskfiltstr_obj.PreStateLoF,
+ ISACencLB_obj->maskfiltstr_obj.PreStateLoG,
+ LP, lofilt_coef, LPw);
+ /* High-band filtering. */
+ WebRtcIsac_NormLatticeFilterMa(ORDERHI,
+ ISACencLB_obj->maskfiltstr_obj.PreStateHiF,
+ ISACencLB_obj->maskfiltstr_obj.PreStateHiG,
+ HP, hifilt_coef, HPw);
+ /* Pitch filter. */
+ WebRtcIsac_PitchfilterPre(LPw, LPw_pf, &ISACencLB_obj->pitchfiltstr_obj,
+ PitchLags, PitchGains);
+ /* Transform */
+ WebRtcIsac_Time2Spec(transform_tables,
+ LPw_pf, HPw, fre, fim, &ISACencLB_obj->fftstr_obj);
+
+ /* Save data for multiple packets memory. */
+ my_index = ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF;
+ memcpy(&ISACencLB_obj->SaveEnc_obj.fre[my_index], fre, sizeof(fre));
+ memcpy(&ISACencLB_obj->SaveEnc_obj.fim[my_index], fim, sizeof(fim));
+
+ ISACencLB_obj->SaveEnc_obj.AvgPitchGain[ISACencLB_obj->SaveEnc_obj.startIdx] =
+ AvgPitchGain_Q12;
+
+ /* Quantization and loss-less coding. */
+ err = WebRtcIsac_EncodeSpec(fre, fim, AvgPitchGain_Q12, kIsacLowerBand,
+ &ISACencLB_obj->bitstr_obj);
+ if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
+ /* There has been an error but it was not too large payload
+ (we can cure too large payload). */
+ if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) {
+ /* If this is the second 30ms of a 60ms frame reset
+ this such that in the next call encoder starts fresh. */
+ ISACencLB_obj->frame_nb = 0;
+ }
+ return err;
+ }
+ iterCntr = 0;
+ while ((ISACencLB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
+ (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
+ double bytesSpecCoderUsed;
+ double transcodeScale;
+
+ if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) {
+ /* We were not able to limit the payload size */
+ if ((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) {
+ /* This was the first 30ms of a 60ms frame. Although
+ the payload is larger than it should be but we let
+ the second 30ms be encoded. Maybe together we
+ won't exceed the limit. */
+ ISACencLB_obj->frame_nb = 1;
+ return 0;
+ } else if ((frame_mode == 1) && (ISACencLB_obj->frame_nb == 1)) {
+ ISACencLB_obj->frame_nb = 0;
+ }
+
+ if (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
+ return -ISAC_PAYLOAD_LARGER_THAN_LIMIT;
+ } else {
+ return status;
+ }
+ }
+
+ if (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
+ bytesSpecCoderUsed = STREAM_SIZE_MAX;
+ /* Being conservative */
+ transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5;
+ } else {
+ bytesSpecCoderUsed = ISACencLB_obj->bitstr_obj.stream_index -
+ transcodingParam.stream_index;
+ transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed;
+ }
+
+ /* To be safe, we reduce the scale depending on
+ the number of iterations. */
+ transcodeScale *= (1.0 - (0.9 * (double)iterCntr /
+ (double)MAX_PAYLOAD_LIMIT_ITERATION));
+
+ /* Scale the LPC Gains. */
+ for (k = 0; k < SUBFRAMES; k++) {
+ lofilt_coef[(LPC_LOBAND_ORDER + 1) * k] =
+ transcodingParam.loFiltGain[k] * transcodeScale;
+ hifilt_coef[(LPC_HIBAND_ORDER + 1) * k] =
+ transcodingParam.hiFiltGain[k] * transcodeScale;
+ transcodingParam.loFiltGain[k] = lofilt_coef[(LPC_LOBAND_ORDER + 1) * k];
+ transcodingParam.hiFiltGain[k] = hifilt_coef[(LPC_HIBAND_ORDER + 1) * k];
+ }
+
+ /* Scale DFT coefficients. */
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ fre[k] = (int16_t)(fre[k] * transcodeScale);
+ fim[k] = (int16_t)(fim[k] * transcodeScale);
+ }
+
+ /* Save data for multiple packets memory. */
+ my_index = ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF;
+ memcpy(&ISACencLB_obj->SaveEnc_obj.fre[my_index], fre, sizeof(fre));
+ memcpy(&ISACencLB_obj->SaveEnc_obj.fim[my_index], fim, sizeof(fim));
+
+ /* Re-store the state of arithmetic coder before coding LPC gains. */
+ ISACencLB_obj->bitstr_obj.W_upper = transcodingParam.W_upper;
+ ISACencLB_obj->bitstr_obj.stream_index = transcodingParam.stream_index;
+ ISACencLB_obj->bitstr_obj.streamval = transcodingParam.streamval;
+ ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] =
+ transcodingParam.stream[0];
+ ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] =
+ transcodingParam.stream[1];
+ ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index] =
+ transcodingParam.stream[2];
+
+ /* Code gains. */
+ WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef,
+ &ISACencLB_obj->bitstr_obj,
+ &ISACencLB_obj->SaveEnc_obj);
+
+ /* Update the number of bytes left for encoding the spectrum. */
+ bytesLeftSpecCoding = payloadLimitBytes - transcodingParam.stream_index;
+
+ /* Encode the spectrum. */
+ err = WebRtcIsac_EncodeSpec(fre, fim, AvgPitchGain_Q12, kIsacLowerBand,
+ &ISACencLB_obj->bitstr_obj);
+
+ if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
+ /* There has been an error but it was not too large
+ payload (we can cure too large payload). */
+ if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) {
+ /* If this is the second 30 ms of a 60 ms frame reset
+ this such that in the next call encoder starts fresh. */
+ ISACencLB_obj->frame_nb = 0;
+ }
+ return err;
+ }
+ iterCntr++;
+ }
+
+ /* If 60 ms frame-size and just processed the first 30 ms, */
+ /* go back to main function to buffer the other 30 ms speech frame. */
+ if (frame_mode == 1) {
+ if (ISACencLB_obj->frame_nb == 0) {
+ ISACencLB_obj->frame_nb = 1;
+ return 0;
+ } else if (ISACencLB_obj->frame_nb == 1) {
+ ISACencLB_obj->frame_nb = 0;
+ /* Also update the frame-length for next packet,
+ in Adaptive mode only. */
+ if (codingMode == 0 && (ISACencLB_obj->enforceFrameSize == 0)) {
+ ISACencLB_obj->new_framelength =
+ WebRtcIsac_GetNewFrameLength(ISACencLB_obj->bottleneck,
+ ISACencLB_obj->current_framesamples);
+ }
+ }
+ } else {
+ ISACencLB_obj->frame_nb = 0;
+ }
+
+ /* Complete arithmetic coding. */
+ stream_length = WebRtcIsac_EncTerminate(&ISACencLB_obj->bitstr_obj);
+ return stream_length;
+}
+
+
+
+static int LimitPayloadUb(ISACUBEncStruct* ISACencUB_obj,
+ uint16_t payloadLimitBytes,
+ double bytesLeftSpecCoding,
+ transcode_obj* transcodingParam,
+ int16_t* fre, int16_t* fim,
+ double* lpcGains, enum ISACBand band, int status) {
+
+ int iterCntr = 0;
+ int k;
+ double bytesSpecCoderUsed;
+ double transcodeScale;
+ const int16_t kAveragePitchGain = 0.0;
+
+ do {
+ if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) {
+ /* We were not able to limit the payload size. */
+ return -ISAC_PAYLOAD_LARGER_THAN_LIMIT;
+ }
+
+ if (status == -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
+ bytesSpecCoderUsed = STREAM_SIZE_MAX;
+ /* Being conservative. */
+ transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5;
+ } else {
+ bytesSpecCoderUsed = ISACencUB_obj->bitstr_obj.stream_index -
+ transcodingParam->stream_index;
+ transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed;
+ }
+
+ /* To be safe, we reduce the scale depending on the
+ number of iterations. */
+ transcodeScale *= (1.0 - (0.9 * (double)iterCntr /
+ (double)MAX_PAYLOAD_LIMIT_ITERATION));
+
+ /* Scale the LPC Gains. */
+ if (band == kIsacUpperBand16) {
+ /* Two sets of coefficients if 16 kHz. */
+ for (k = 0; k < SUBFRAMES; k++) {
+ transcodingParam->loFiltGain[k] *= transcodeScale;
+ transcodingParam->hiFiltGain[k] *= transcodeScale;
+ }
+ } else {
+ /* One sets of coefficients if 12 kHz. */
+ for (k = 0; k < SUBFRAMES; k++) {
+ transcodingParam->loFiltGain[k] *= transcodeScale;
+ }
+ }
+
+ /* Scale DFT coefficients. */
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ fre[k] = (int16_t)(fre[k] * transcodeScale + 0.5);
+ fim[k] = (int16_t)(fim[k] * transcodeScale + 0.5);
+ }
+ /* Store FFT coefficients for multiple encoding. */
+ memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre,
+ sizeof(ISACencUB_obj->SaveEnc_obj.realFFT));
+ memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
+ sizeof(ISACencUB_obj->SaveEnc_obj.imagFFT));
+
+ /* Store the state of arithmetic coder before coding LPC gains */
+ ISACencUB_obj->bitstr_obj.W_upper = transcodingParam->W_upper;
+ ISACencUB_obj->bitstr_obj.stream_index = transcodingParam->stream_index;
+ ISACencUB_obj->bitstr_obj.streamval = transcodingParam->streamval;
+ ISACencUB_obj->bitstr_obj.stream[transcodingParam->stream_index - 2] =
+ transcodingParam->stream[0];
+ ISACencUB_obj->bitstr_obj.stream[transcodingParam->stream_index - 1] =
+ transcodingParam->stream[1];
+ ISACencUB_obj->bitstr_obj.stream[transcodingParam->stream_index] =
+ transcodingParam->stream[2];
+
+ /* Store the gains for multiple encoding. */
+ memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains,
+ SUBFRAMES * sizeof(double));
+ /* Entropy Code lpc-gains, indices are stored for a later use.*/
+ WebRtcIsac_EncodeLpcGainUb(transcodingParam->loFiltGain,
+ &ISACencUB_obj->bitstr_obj,
+ ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
+
+ /* If 16kHz should do one more set. */
+ if (band == kIsacUpperBand16) {
+ /* Store the gains for multiple encoding. */
+ memcpy(&ISACencUB_obj->SaveEnc_obj.lpcGain[SUBFRAMES],
+ &lpcGains[SUBFRAMES], SUBFRAMES * sizeof(double));
+ /* Entropy Code lpc-gains, indices are stored for a later use.*/
+ WebRtcIsac_EncodeLpcGainUb(
+ transcodingParam->hiFiltGain, &ISACencUB_obj->bitstr_obj,
+ &ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]);
+ }
+
+ /* Update the number of bytes left for encoding the spectrum. */
+ bytesLeftSpecCoding = payloadLimitBytes -
+ ISACencUB_obj->bitstr_obj.stream_index;
+
+ /* Save the bit-stream object at this point for FEC. */
+ memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
+ &ISACencUB_obj->bitstr_obj, sizeof(Bitstr));
+
+ /* Encode the spectrum. */
+ status = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain,
+ band, &ISACencUB_obj->bitstr_obj);
+ if ((status < 0) && (status != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
+ /* There has been an error but it was not too large payload
+ (we can cure too large payload). */
+ return status;
+ }
+ iterCntr++;
+ } while ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
+ (status == -ISAC_DISALLOWED_BITSTREAM_LENGTH));
+ return 0;
+}
+
+int WebRtcIsac_EncodeUb16(const TransformTables* transform_tables,
+ float* in, ISACUBEncStruct* ISACencUB_obj,
+ int32_t jitterInfo) {
+ int err;
+ int k;
+
+ double lpcVecs[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
+ double percepFilterParams[(1 + UB_LPC_ORDER) * (SUBFRAMES << 1) +
+ (1 + UB_LPC_ORDER)];
+
+ double LP_lookahead[FRAMESAMPLES];
+ int16_t fre[FRAMESAMPLES_HALF]; /* Q7 */
+ int16_t fim[FRAMESAMPLES_HALF]; /* Q7 */
+
+ int status = 0;
+
+ double varscale[2];
+ double corr[SUBFRAMES << 1][UB_LPC_ORDER + 1];
+ double lpcGains[SUBFRAMES << 1];
+ transcode_obj transcodingParam;
+ uint16_t payloadLimitBytes;
+ double s2nr;
+ const int16_t kAveragePitchGain = 0.0;
+ int bytesLeftSpecCoding;
+
+ /* Buffer speech samples (by 10ms packet) until the frame-length is */
+ /* reached (30 ms). */
+ /*********************************************************************/
+
+ /* fill the buffer with 10ms input data */
+ memcpy(&ISACencUB_obj->data_buffer_float[ISACencUB_obj->buffer_index], in,
+ FRAMESAMPLES_10ms * sizeof(float));
+
+ /* If buffer size is not equal to current frame-size, and end of file is
+ * not reached yet, we don't do encoding unless we have the whole frame. */
+ if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) {
+ ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms;
+ return 0;
+ }
+
+ /* End of buffer function. */
+ /**************************/
+
+ /* Encoding */
+ /************/
+
+ /* Reset bit-stream */
+ WebRtcIsac_ResetBitstream(&(ISACencUB_obj->bitstr_obj));
+
+ /* Encoding of bandwidth information. */
+ WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj);
+
+ status = WebRtcIsac_EncodeBandwidth(isac16kHz, &ISACencUB_obj->bitstr_obj);
+ if (status < 0) {
+ return status;
+ }
+
+ s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck, FRAMESAMPLES);
+
+ memcpy(lpcVecs, ISACencUB_obj->lastLPCVec, UB_LPC_ORDER * sizeof(double));
+
+ for (k = 0; k < FRAMESAMPLES; k++) {
+ LP_lookahead[k] = ISACencUB_obj->data_buffer_float[UB_LOOKAHEAD + k];
+ }
+
+ /* Find coefficients for perceptual pre-filters. */
+ WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj,
+ &lpcVecs[UB_LPC_ORDER], corr, varscale, isac16kHz);
+
+ memcpy(ISACencUB_obj->lastLPCVec,
+ &lpcVecs[(UB16_LPC_VEC_PER_FRAME - 1) * (UB_LPC_ORDER)],
+ sizeof(double) * UB_LPC_ORDER);
+
+ /* Code LPC model and shape - gains not quantized yet. */
+ WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj,
+ percepFilterParams, isac16kHz,
+ &ISACencUB_obj->SaveEnc_obj);
+
+ /* the first set of lpc parameters are from the last sub-frame of
+ * the previous frame. so we don't care about them. */
+ WebRtcIsac_GetLpcGain(s2nr, &percepFilterParams[UB_LPC_ORDER + 1],
+ (SUBFRAMES << 1), lpcGains, corr, varscale);
+
+ /* Store the state of arithmetic coder before coding LPC gains */
+ transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index;
+ transcodingParam.W_upper = ISACencUB_obj->bitstr_obj.W_upper;
+ transcodingParam.streamval = ISACencUB_obj->bitstr_obj.streamval;
+ transcodingParam.stream[0] =
+ ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index -
+ 2];
+ transcodingParam.stream[1] =
+ ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index -
+ 1];
+ transcodingParam.stream[2] =
+ ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index];
+
+ /* Store LPC Gains before encoding them. */
+ for (k = 0; k < SUBFRAMES; k++) {
+ transcodingParam.loFiltGain[k] = lpcGains[k];
+ transcodingParam.hiFiltGain[k] = lpcGains[SUBFRAMES + k];
+ }
+
+ /* Store the gains for multiple encoding. */
+ memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains,
+ (SUBFRAMES << 1) * sizeof(double));
+
+ WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj,
+ ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
+ WebRtcIsac_EncodeLpcGainUb(
+ &lpcGains[SUBFRAMES], &ISACencUB_obj->bitstr_obj,
+ &ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]);
+
+ /* Get the correct value for the payload limit and calculate the number of
+ bytes left for coding the spectrum. It is a 30ms frame
+ Subract 3 because termination process may add 3 bytes */
+ payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes -
+ ISACencUB_obj->numBytesUsed - 3;
+ bytesLeftSpecCoding = payloadLimitBytes -
+ ISACencUB_obj->bitstr_obj.stream_index;
+
+ for (k = 0; k < (SUBFRAMES << 1); k++) {
+ percepFilterParams[k * (UB_LPC_ORDER + 1) + (UB_LPC_ORDER + 1)] =
+ lpcGains[k];
+ }
+
+ /* LPC filtering (using normalized lattice filter), */
+ /* first half-frame. */
+ WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER,
+ ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
+ ISACencUB_obj->maskfiltstr_obj.PreStateLoG,
+ &ISACencUB_obj->data_buffer_float[0],
+ &percepFilterParams[UB_LPC_ORDER + 1],
+ &LP_lookahead[0]);
+
+ /* Second half-frame filtering. */
+ WebRtcIsac_NormLatticeFilterMa(
+ UB_LPC_ORDER, ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
+ ISACencUB_obj->maskfiltstr_obj.PreStateLoG,
+ &ISACencUB_obj->data_buffer_float[FRAMESAMPLES_HALF],
+ &percepFilterParams[(UB_LPC_ORDER + 1) + SUBFRAMES * (UB_LPC_ORDER + 1)],
+ &LP_lookahead[FRAMESAMPLES_HALF]);
+
+ WebRtcIsac_Time2Spec(transform_tables,
+ &LP_lookahead[0], &LP_lookahead[FRAMESAMPLES_HALF],
+ fre, fim, &ISACencUB_obj->fftstr_obj);
+
+ /* Store FFT coefficients for multiple encoding. */
+ memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre, sizeof(fre));
+ memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim, sizeof(fim));
+
+ /* Prepare the audio buffer for the next packet
+ * move the last 3 ms to the beginning of the buffer. */
+ memcpy(ISACencUB_obj->data_buffer_float,
+ &ISACencUB_obj->data_buffer_float[FRAMESAMPLES],
+ LB_TOTAL_DELAY_SAMPLES * sizeof(float));
+ /* start writing with 3 ms delay to compensate for the delay
+ * of the lower-band. */
+ ISACencUB_obj->buffer_index = LB_TOTAL_DELAY_SAMPLES;
+
+ /* Save the bit-stream object at this point for FEC. */
+ memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj, &ISACencUB_obj->bitstr_obj,
+ sizeof(Bitstr));
+
+ /* Qantization and lossless coding */
+ /* Note that there is no pitch-gain for this band so kAveragePitchGain = 0
+ * is passed to the function. In fact, the function ignores the 3rd parameter
+ * for this band. */
+ err = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain, kIsacUpperBand16,
+ &ISACencUB_obj->bitstr_obj);
+ if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
+ return err;
+ }
+
+ if ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
+ (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
+ err = LimitPayloadUb(ISACencUB_obj, payloadLimitBytes, bytesLeftSpecCoding,
+ &transcodingParam, fre, fim, lpcGains,
+ kIsacUpperBand16, err);
+ }
+ if (err < 0) {
+ return err;
+ }
+ /* Complete arithmetic coding. */
+ return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj);
+}
+
+
+int WebRtcIsac_EncodeUb12(const TransformTables* transform_tables,
+ float* in, ISACUBEncStruct* ISACencUB_obj,
+ int32_t jitterInfo) {
+ int err;
+ int k;
+
+ double lpcVecs[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
+
+ double percepFilterParams[(1 + UB_LPC_ORDER) * SUBFRAMES];
+ float LP[FRAMESAMPLES_HALF];
+ float HP[FRAMESAMPLES_HALF];
+
+ double LP_lookahead[FRAMESAMPLES_HALF];
+ double HP_lookahead[FRAMESAMPLES_HALF];
+ double LPw[FRAMESAMPLES_HALF];
+
+ double HPw[FRAMESAMPLES_HALF];
+ int16_t fre[FRAMESAMPLES_HALF]; /* Q7 */
+ int16_t fim[FRAMESAMPLES_HALF]; /* Q7 */
+
+ int status = 0;
+
+ double varscale[1];
+
+ double corr[UB_LPC_GAIN_DIM][UB_LPC_ORDER + 1];
+ double lpcGains[SUBFRAMES];
+ transcode_obj transcodingParam;
+ uint16_t payloadLimitBytes;
+ double s2nr;
+ const int16_t kAveragePitchGain = 0.0;
+ double bytesLeftSpecCoding;
+
+ /* Buffer speech samples (by 10ms packet) until the framelength is */
+ /* reached (30 ms). */
+ /********************************************************************/
+
+ /* Fill the buffer with 10ms input data. */
+ memcpy(&ISACencUB_obj->data_buffer_float[ISACencUB_obj->buffer_index], in,
+ FRAMESAMPLES_10ms * sizeof(float));
+
+ /* if buffer-size is not equal to current frame-size then increase the
+ index and return. We do the encoding when we have enough audio. */
+ if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) {
+ ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms;
+ return 0;
+ }
+ /* If buffer reached the right size, reset index and continue
+ with encoding the frame */
+ ISACencUB_obj->buffer_index = 0;
+
+ /* End of buffer function */
+ /**************************/
+
+ /* Encoding */
+ /************/
+
+ /* Reset bit-stream. */
+ WebRtcIsac_ResetBitstream(&(ISACencUB_obj->bitstr_obj));
+
+ /* Encoding bandwidth information. */
+ WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj);
+ status = WebRtcIsac_EncodeBandwidth(isac12kHz, &ISACencUB_obj->bitstr_obj);
+ if (status < 0) {
+ return status;
+ }
+
+ s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck, FRAMESAMPLES);
+
+ /* Split signal in two bands. */
+ WebRtcIsac_SplitAndFilterFloat(ISACencUB_obj->data_buffer_float, HP, LP,
+ HP_lookahead, LP_lookahead,
+ &ISACencUB_obj->prefiltbankstr_obj);
+
+ /* Find coefficients for perceptual pre-filters. */
+ WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj,
+ lpcVecs, corr, varscale, isac12kHz);
+
+ /* Code LPC model and shape - gains not quantized yet. */
+ WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj,
+ percepFilterParams, isac12kHz,
+ &ISACencUB_obj->SaveEnc_obj);
+
+ WebRtcIsac_GetLpcGain(s2nr, percepFilterParams, SUBFRAMES, lpcGains, corr,
+ varscale);
+
+ /* Store the state of arithmetic coder before coding LPC gains. */
+ transcodingParam.W_upper = ISACencUB_obj->bitstr_obj.W_upper;
+ transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index;
+ transcodingParam.streamval = ISACencUB_obj->bitstr_obj.streamval;
+ transcodingParam.stream[0] =
+ ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index -
+ 2];
+ transcodingParam.stream[1] =
+ ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index -
+ 1];
+ transcodingParam.stream[2] =
+ ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index];
+
+ /* Store LPC Gains before encoding them. */
+ for (k = 0; k < SUBFRAMES; k++) {
+ transcodingParam.loFiltGain[k] = lpcGains[k];
+ }
+
+ /* Store the gains for multiple encoding. */
+ memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, SUBFRAMES *
+ sizeof(double));
+
+ WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj,
+ ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
+
+ for (k = 0; k < SUBFRAMES; k++) {
+ percepFilterParams[k * (UB_LPC_ORDER + 1)] = lpcGains[k];
+ }
+
+ /* perceptual pre-filtering (using normalized lattice filter) */
+ /* low-band filtering */
+ WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER,
+ ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
+ ISACencUB_obj->maskfiltstr_obj.PreStateLoG, LP,
+ percepFilterParams, LPw);
+
+ /* Get the correct value for the payload limit and calculate the number
+ of bytes left for coding the spectrum. It is a 30ms frame Subract 3
+ because termination process may add 3 bytes */
+ payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes -
+ ISACencUB_obj->numBytesUsed - 3;
+ bytesLeftSpecCoding = payloadLimitBytes -
+ ISACencUB_obj->bitstr_obj.stream_index;
+
+ memset(HPw, 0, sizeof(HPw));
+
+ /* Transform */
+ WebRtcIsac_Time2Spec(transform_tables,
+ LPw, HPw, fre, fim, &ISACencUB_obj->fftstr_obj);
+
+ /* Store FFT coefficients for multiple encoding. */
+ memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre,
+ sizeof(ISACencUB_obj->SaveEnc_obj.realFFT));
+ memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
+ sizeof(ISACencUB_obj->SaveEnc_obj.imagFFT));
+
+ /* Save the bit-stream object at this point for FEC. */
+ memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
+ &ISACencUB_obj->bitstr_obj, sizeof(Bitstr));
+
+ /* Quantization and loss-less coding */
+ /* The 4th parameter to this function is pitch-gain, which is only used
+ * when encoding 0-8 kHz band, and irrelevant in this function, therefore,
+ * we insert zero here. */
+ err = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain, kIsacUpperBand12,
+ &ISACencUB_obj->bitstr_obj);
+ if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
+ /* There has been an error but it was not too large
+ payload (we can cure too large payload) */
+ return err;
+ }
+
+ if ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
+ (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
+ err = LimitPayloadUb(ISACencUB_obj, payloadLimitBytes, bytesLeftSpecCoding,
+ &transcodingParam, fre, fim, lpcGains,
+ kIsacUpperBand12, err);
+ }
+ if (err < 0) {
+ return err;
+ }
+ /* Complete arithmetic coding. */
+ return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj);
+}
+
+
+
+
+
+
+/* This function is used to create a new bit-stream with new BWE.
+ The same data as previously encoded with the function WebRtcIsac_Encoder().
+ The data needed is taken from the structure, where it was stored
+ when calling the encoder. */
+
+int WebRtcIsac_EncodeStoredDataLb(const IsacSaveEncoderData* ISACSavedEnc_obj,
+ Bitstr* ISACBitStr_obj, int BWnumber,
+ float scale) {
+ int ii;
+ int status;
+ int BWno = BWnumber;
+
+ const uint16_t* WebRtcIsac_kQPitchGainCdf_ptr[1];
+ const uint16_t** cdf;
+
+ double tmpLPCcoeffs_lo[(ORDERLO + 1)*SUBFRAMES * 2];
+ double tmpLPCcoeffs_hi[(ORDERHI + 1)*SUBFRAMES * 2];
+ int tmpLPCindex_g[12 * 2];
+ int16_t tmp_fre[FRAMESAMPLES], tmp_fim[FRAMESAMPLES];
+ const int kModel = 0;
+
+ /* Sanity Check - possible values for BWnumber is 0 - 23. */
+ if ((BWnumber < 0) || (BWnumber > 23)) {
+ return -ISAC_RANGE_ERROR_BW_ESTIMATOR;
+ }
+
+ /* Reset bit-stream. */
+ WebRtcIsac_ResetBitstream(ISACBitStr_obj);
+
+ /* Encode frame length */
+ status = WebRtcIsac_EncodeFrameLen(ISACSavedEnc_obj->framelength,
+ ISACBitStr_obj);
+ if (status < 0) {
+ /* Wrong frame size. */
+ return status;
+ }
+
+ /* Transcoding */
+ if ((scale > 0.0) && (scale < 1.0)) {
+ /* Compensate LPC gain. */
+ for (ii = 0;
+ ii < ((ORDERLO + 1)* SUBFRAMES * (1 + ISACSavedEnc_obj->startIdx));
+ ii++) {
+ tmpLPCcoeffs_lo[ii] = scale * ISACSavedEnc_obj->LPCcoeffs_lo[ii];
+ }
+ for (ii = 0;
+ ii < ((ORDERHI + 1) * SUBFRAMES * (1 + ISACSavedEnc_obj->startIdx));
+ ii++) {
+ tmpLPCcoeffs_hi[ii] = scale * ISACSavedEnc_obj->LPCcoeffs_hi[ii];
+ }
+ /* Scale DFT. */
+ for (ii = 0;
+ ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx));
+ ii++) {
+ tmp_fre[ii] = (int16_t)((scale) * (float)ISACSavedEnc_obj->fre[ii]);
+ tmp_fim[ii] = (int16_t)((scale) * (float)ISACSavedEnc_obj->fim[ii]);
+ }
+ } else {
+ for (ii = 0;
+ ii < (KLT_ORDER_GAIN * (1 + ISACSavedEnc_obj->startIdx));
+ ii++) {
+ tmpLPCindex_g[ii] = ISACSavedEnc_obj->LPCindex_g[ii];
+ }
+ for (ii = 0;
+ ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx));
+ ii++) {
+ tmp_fre[ii] = ISACSavedEnc_obj->fre[ii];
+ tmp_fim[ii] = ISACSavedEnc_obj->fim[ii];
+ }
+ }
+
+ /* Encode bandwidth estimate. */
+ WebRtcIsac_EncodeReceiveBw(&BWno, ISACBitStr_obj);
+
+ /* Loop over number of 30 msec */
+ for (ii = 0; ii <= ISACSavedEnc_obj->startIdx; ii++) {
+ /* Encode pitch gains. */
+ *WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf;
+ WebRtcIsac_EncHistMulti(ISACBitStr_obj,
+ &ISACSavedEnc_obj->pitchGain_index[ii],
+ WebRtcIsac_kQPitchGainCdf_ptr, 1);
+
+ /* Entropy coding of quantization pitch lags */
+ /* Voicing classification. */
+ if (ISACSavedEnc_obj->meanGain[ii] < 0.2) {
+ cdf = WebRtcIsac_kQPitchLagCdfPtrLo;
+ } else if (ISACSavedEnc_obj->meanGain[ii] < 0.4) {
+ cdf = WebRtcIsac_kQPitchLagCdfPtrMid;
+ } else {
+ cdf = WebRtcIsac_kQPitchLagCdfPtrHi;
+ }
+ WebRtcIsac_EncHistMulti(ISACBitStr_obj,
+ &ISACSavedEnc_obj->pitchIndex[PITCH_SUBFRAMES * ii],
+ cdf, PITCH_SUBFRAMES);
+
+ /* LPC */
+ /* Only one model exists. The entropy coding is done only for backward
+ * compatibility. */
+ WebRtcIsac_EncHistMulti(ISACBitStr_obj, &kModel,
+ WebRtcIsac_kQKltModelCdfPtr, 1);
+ /* Entropy coding of quantization indices - LPC shape only. */
+ WebRtcIsac_EncHistMulti(ISACBitStr_obj,
+ &ISACSavedEnc_obj->LPCindex_s[KLT_ORDER_SHAPE * ii],
+ WebRtcIsac_kQKltCdfPtrShape,
+ KLT_ORDER_SHAPE);
+
+ /* If transcoding, get new LPC gain indices */
+ if (scale < 1.0) {
+ WebRtcIsac_TranscodeLPCCoef(
+ &tmpLPCcoeffs_lo[(ORDERLO + 1) * SUBFRAMES * ii],
+ &tmpLPCcoeffs_hi[(ORDERHI + 1)*SUBFRAMES * ii],
+ &tmpLPCindex_g[KLT_ORDER_GAIN * ii]);
+ }
+
+ /* Entropy coding of quantization indices - LPC gain. */
+ WebRtcIsac_EncHistMulti(ISACBitStr_obj, &tmpLPCindex_g[KLT_ORDER_GAIN * ii],
+ WebRtcIsac_kQKltCdfPtrGain, KLT_ORDER_GAIN);
+
+ /* Quantization and loss-less coding. */
+ status = WebRtcIsac_EncodeSpec(&tmp_fre[ii * FRAMESAMPLES_HALF],
+ &tmp_fim[ii * FRAMESAMPLES_HALF],
+ ISACSavedEnc_obj->AvgPitchGain[ii],
+ kIsacLowerBand, ISACBitStr_obj);
+ if (status < 0) {
+ return status;
+ }
+ }
+ /* Complete arithmetic coding. */
+ return WebRtcIsac_EncTerminate(ISACBitStr_obj);
+}
+
+
+int WebRtcIsac_EncodeStoredDataUb(
+ const ISACUBSaveEncDataStruct* ISACSavedEnc_obj,
+ Bitstr* bitStream,
+ int32_t jitterInfo,
+ float scale,
+ enum ISACBandwidth bandwidth) {
+ int n;
+ int err;
+ double lpcGain[SUBFRAMES];
+ int16_t realFFT[FRAMESAMPLES_HALF];
+ int16_t imagFFT[FRAMESAMPLES_HALF];
+ const uint16_t** shape_cdf;
+ int shape_len;
+ const int16_t kAveragePitchGain = 0.0;
+ enum ISACBand band;
+ /* Reset bitstream. */
+ WebRtcIsac_ResetBitstream(bitStream);
+
+ /* Encode jitter index. */
+ WebRtcIsac_EncodeJitterInfo(jitterInfo, bitStream);
+
+ err = WebRtcIsac_EncodeBandwidth(bandwidth, bitStream);
+ if (err < 0) {
+ return err;
+ }
+
+ /* Encode LPC-shape. */
+ if (bandwidth == isac12kHz) {
+ shape_cdf = WebRtcIsac_kLpcShapeCdfMatUb12;
+ shape_len = UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME;
+ band = kIsacUpperBand12;
+ } else {
+ shape_cdf = WebRtcIsac_kLpcShapeCdfMatUb16;
+ shape_len = UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME;
+ band = kIsacUpperBand16;
+ }
+ WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->indexLPCShape,
+ shape_cdf, shape_len);
+
+ if ((scale <= 0.0) || (scale >= 1.0)) {
+ /* We only consider scales between zero and one. */
+ WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->lpcGainIndex,
+ WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM);
+ if (bandwidth == isac16kHz) {
+ /* Store gain indices of the second half. */
+ WebRtcIsac_EncHistMulti(bitStream,
+ &ISACSavedEnc_obj->lpcGainIndex[SUBFRAMES],
+ WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM);
+ }
+ /* Store FFT coefficients. */
+ err = WebRtcIsac_EncodeSpec(ISACSavedEnc_obj->realFFT,
+ ISACSavedEnc_obj->imagFFT, kAveragePitchGain,
+ band, bitStream);
+ } else {
+ /* Scale LPC gain and FFT coefficients. */
+ for (n = 0; n < SUBFRAMES; n++) {
+ lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n];
+ }
+ /* Store LPC gains. */
+ WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream);
+
+ if (bandwidth == isac16kHz) {
+ /* Scale and code the gains of the second half of the frame, if 16kHz. */
+ for (n = 0; n < SUBFRAMES; n++) {
+ lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n + SUBFRAMES];
+ }
+ WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream);
+ }
+
+ for (n = 0; n < FRAMESAMPLES_HALF; n++) {
+ realFFT[n] = (int16_t)(scale * (float)ISACSavedEnc_obj->realFFT[n] +
+ 0.5f);
+ imagFFT[n] = (int16_t)(scale * (float)ISACSavedEnc_obj->imagFFT[n] +
+ 0.5f);
+ }
+ /* Store FFT coefficients. */
+ err = WebRtcIsac_EncodeSpec(realFFT, imagFFT, kAveragePitchGain,
+ band, bitStream);
+ }
+ if (err < 0) {
+ /* Error happened while encoding FFT coefficients. */
+ return err;
+ }
+
+ /* Complete arithmetic coding. */
+ return WebRtcIsac_EncTerminate(bitStream);
+}
+
+int16_t WebRtcIsac_GetRedPayloadUb(
+ const ISACUBSaveEncDataStruct* ISACSavedEncObj,
+ Bitstr* bitStreamObj,
+ enum ISACBandwidth bandwidth) {
+ int n;
+ int16_t status;
+ int16_t realFFT[FRAMESAMPLES_HALF];
+ int16_t imagFFT[FRAMESAMPLES_HALF];
+ enum ISACBand band;
+ const int16_t kAveragePitchGain = 0.0;
+ /* Store bit-stream object. */
+ memcpy(bitStreamObj, &ISACSavedEncObj->bitStreamObj, sizeof(Bitstr));
+
+ /* Scale FFT coefficients. */
+ for (n = 0; n < FRAMESAMPLES_HALF; n++) {
+ realFFT[n] = (int16_t)((float)ISACSavedEncObj->realFFT[n] *
+ RCU_TRANSCODING_SCALE_UB + 0.5);
+ imagFFT[n] = (int16_t)((float)ISACSavedEncObj->imagFFT[n] *
+ RCU_TRANSCODING_SCALE_UB + 0.5);
+ }
+
+ band = (bandwidth == isac12kHz) ? kIsacUpperBand12 : kIsacUpperBand16;
+ status = WebRtcIsac_EncodeSpec(realFFT, imagFFT, kAveragePitchGain, band,
+ bitStreamObj);
+ if (status < 0) {
+ return status;
+ } else {
+ /* Terminate entropy coding */
+ return WebRtcIsac_EncTerminate(bitStreamObj);
+ }
+}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/fft.c b/webrtc/modules/audio_coding/codecs/isac/main/source/fft.c
new file mode 100644
index 0000000..c854d8c
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/fft.c
@@ -0,0 +1,943 @@
+/*
+ * Copyright(c)1995,97 Mark Olesen <olesen@me.QueensU.CA>
+ * Queen's Univ at Kingston (Canada)
+ *
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose without fee is hereby granted, provided that this
+ * entire notice is included in all copies of any software which is
+ * or includes a copy or modification of this software and in all
+ * copies of the supporting documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR QUEEN'S
+ * UNIVERSITY AT KINGSTON MAKES ANY REPRESENTATION OR WARRANTY OF ANY
+ * KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * All of which is to say that you can do what you like with this
+ * source code provided you don't try to sell it as your own and you
+ * include an unaltered copy of this message (including the
+ * copyright).
+ *
+ * It is also implicitly understood that bug fixes and improvements
+ * should make their way back to the general Internet community so
+ * that everyone benefits.
+ *
+ * Changes:
+ * Trivial type modifications by the WebRTC authors.
+ */
+
+
+/*
+ * File:
+ * WebRtcIsac_Fftn.c
+ *
+ * Public:
+ * WebRtcIsac_Fftn / fftnf ();
+ *
+ * Private:
+ * WebRtcIsac_Fftradix / fftradixf ();
+ *
+ * Descript:
+ * multivariate complex Fourier transform, computed in place
+ * using mixed-radix Fast Fourier Transform algorithm.
+ *
+ * Fortran code by:
+ * RC Singleton, Stanford Research Institute, Sept. 1968
+ *
+ * translated by f2c (version 19950721).
+ *
+ * int WebRtcIsac_Fftn (int ndim, const int dims[], REAL Re[], REAL Im[],
+ * int iSign, double scaling);
+ *
+ * NDIM = the total number dimensions
+ * DIMS = a vector of array sizes
+ * if NDIM is zero then DIMS must be zero-terminated
+ *
+ * RE and IM hold the real and imaginary components of the data, and return
+ * the resulting real and imaginary Fourier coefficients. Multidimensional
+ * data *must* be allocated contiguously. There is no limit on the number
+ * of dimensions.
+ *
+ * ISIGN = the sign of the complex exponential (ie, forward or inverse FFT)
+ * the magnitude of ISIGN (normally 1) is used to determine the
+ * correct indexing increment (see below).
+ *
+ * SCALING = normalizing constant by which the final result is *divided*
+ * if SCALING == -1, normalize by total dimension of the transform
+ * if SCALING < -1, normalize by the square-root of the total dimension
+ *
+ * example:
+ * tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3]
+ *
+ * int dims[3] = {n1,n2,n3}
+ * WebRtcIsac_Fftn (3, dims, Re, Im, 1, scaling);
+ *
+ *-----------------------------------------------------------------------*
+ * int WebRtcIsac_Fftradix (REAL Re[], REAL Im[], size_t nTotal, size_t nPass,
+ * size_t nSpan, int iSign, size_t max_factors,
+ * size_t max_perm);
+ *
+ * RE, IM - see above documentation
+ *
+ * Although there is no limit on the number of dimensions, WebRtcIsac_Fftradix() must
+ * be called once for each dimension, but the calls may be in any order.
+ *
+ * NTOTAL = the total number of complex data values
+ * NPASS = the dimension of the current variable
+ * NSPAN/NPASS = the spacing of consecutive data values while indexing the
+ * current variable
+ * ISIGN - see above documentation
+ *
+ * example:
+ * tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3]
+ *
+ * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n1, n1, 1, maxf, maxp);
+ * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n2, n1*n2, 1, maxf, maxp);
+ * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n3, n1*n2*n3, 1, maxf, maxp);
+ *
+ * single-variate transform,
+ * NTOTAL = N = NSPAN = (number of complex data values),
+ *
+ * WebRtcIsac_Fftradix (Re, Im, n, n, n, 1, maxf, maxp);
+ *
+ * The data can also be stored in a single array with alternating real and
+ * imaginary parts, the magnitude of ISIGN is changed to 2 to give correct
+ * indexing increment, and data [0] and data [1] used to pass the initial
+ * addresses for the sequences of real and imaginary values,
+ *
+ * example:
+ * REAL data [2*NTOTAL];
+ * WebRtcIsac_Fftradix ( &data[0], &data[1], NTOTAL, nPass, nSpan, 2, maxf, maxp);
+ *
+ * for temporary allocation:
+ *
+ * MAX_FACTORS >= the maximum prime factor of NPASS
+ * MAX_PERM >= the number of prime factors of NPASS. In addition,
+ * if the square-free portion K of NPASS has two or more prime
+ * factors, then MAX_PERM >= (K-1)
+ *
+ * storage in FACTOR for a maximum of 15 prime factors of NPASS. if NPASS
+ * has more than one square-free factor, the product of the square-free
+ * factors must be <= 210 array storage for maximum prime factor of 23 the
+ * following two constants should agree with the array dimensions.
+ *
+ *----------------------------------------------------------------------*/
+#include "fft.h"
+
+#include <stdlib.h>
+#include <math.h>
+
+
+
+/* double precision routine */
+static int
+WebRtcIsac_Fftradix (double Re[], double Im[],
+ size_t nTotal, size_t nPass, size_t nSpan, int isign,
+ int max_factors, unsigned int max_perm,
+ FFTstr *fftstate);
+
+
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846264338327950288
+#endif
+
+#ifndef SIN60
+# define SIN60 0.86602540378443865 /* sin(60 deg) */
+# define COS72 0.30901699437494742 /* cos(72 deg) */
+# define SIN72 0.95105651629515357 /* sin(72 deg) */
+#endif
+
+# define REAL double
+# define FFTN WebRtcIsac_Fftn
+# define FFTNS "fftn"
+# define FFTRADIX WebRtcIsac_Fftradix
+# define FFTRADIXS "fftradix"
+
+
+int WebRtcIsac_Fftns(unsigned int ndim, const int dims[],
+ double Re[],
+ double Im[],
+ int iSign,
+ double scaling,
+ FFTstr *fftstate)
+{
+
+ size_t nSpan, nPass, nTotal;
+ unsigned int i;
+ int ret, max_factors, max_perm;
+
+ /*
+ * tally the number of elements in the data array
+ * and determine the number of dimensions
+ */
+ nTotal = 1;
+ if (ndim && dims [0])
+ {
+ for (i = 0; i < ndim; i++)
+ {
+ if (dims [i] <= 0)
+ {
+ return -1;
+ }
+ nTotal *= dims [i];
+ }
+ }
+ else
+ {
+ ndim = 0;
+ for (i = 0; dims [i]; i++)
+ {
+ if (dims [i] <= 0)
+ {
+ return -1;
+ }
+ nTotal *= dims [i];
+ ndim++;
+ }
+ }
+
+ /* determine maximum number of factors and permuations */
+#if 1
+ /*
+ * follow John Beale's example, just use the largest dimension and don't
+ * worry about excess allocation. May be someone else will do it?
+ */
+ max_factors = max_perm = 1;
+ for (i = 0; i < ndim; i++)
+ {
+ nSpan = dims [i];
+ if ((int)nSpan > max_factors)
+ {
+ max_factors = (int)nSpan;
+ }
+ if ((int)nSpan > max_perm)
+ {
+ max_perm = (int)nSpan;
+ }
+ }
+#else
+ /* use the constants used in the original Fortran code */
+ max_factors = 23;
+ max_perm = 209;
+#endif
+ /* loop over the dimensions: */
+ nPass = 1;
+ for (i = 0; i < ndim; i++)
+ {
+ nSpan = dims [i];
+ nPass *= nSpan;
+ ret = FFTRADIX (Re, Im, nTotal, nSpan, nPass, iSign,
+ max_factors, max_perm, fftstate);
+ /* exit, clean-up already done */
+ if (ret)
+ return ret;
+ }
+
+ /* Divide through by the normalizing constant: */
+ if (scaling && scaling != 1.0)
+ {
+ if (iSign < 0) iSign = -iSign;
+ if (scaling < 0.0)
+ {
+ scaling = (double)nTotal;
+ if (scaling < -1.0)
+ scaling = sqrt (scaling);
+ }
+ scaling = 1.0 / scaling; /* multiply is often faster */
+ for (i = 0; i < nTotal; i += iSign)
+ {
+ Re [i] *= scaling;
+ Im [i] *= scaling;
+ }
+ }
+ return 0;
+}
+
+/*
+ * singleton's mixed radix routine
+ *
+ * could move allocation out to WebRtcIsac_Fftn(), but leave it here so that it's
+ * possible to make this a standalone function
+ */
+
+static int FFTRADIX (REAL Re[],
+ REAL Im[],
+ size_t nTotal,
+ size_t nPass,
+ size_t nSpan,
+ int iSign,
+ int max_factors,
+ unsigned int max_perm,
+ FFTstr *fftstate)
+{
+ int ii, mfactor, kspan, ispan, inc;
+ int j, jc, jf, jj, k, k1, k2, k3, k4, kk, kt, nn, ns, nt;
+
+
+ REAL radf;
+ REAL c1, c2, c3, cd, aa, aj, ak, ajm, ajp, akm, akp;
+ REAL s1, s2, s3, sd, bb, bj, bk, bjm, bjp, bkm, bkp;
+
+ REAL *Rtmp = NULL; /* temp space for real part*/
+ REAL *Itmp = NULL; /* temp space for imaginary part */
+ REAL *Cos = NULL; /* Cosine values */
+ REAL *Sin = NULL; /* Sine values */
+
+ REAL s60 = SIN60; /* sin(60 deg) */
+ REAL c72 = COS72; /* cos(72 deg) */
+ REAL s72 = SIN72; /* sin(72 deg) */
+ REAL pi2 = M_PI; /* use PI first, 2 PI later */
+
+
+ fftstate->SpaceAlloced = 0;
+ fftstate->MaxPermAlloced = 0;
+
+
+ // initialize to avoid warnings
+ k3 = c2 = c3 = s2 = s3 = 0.0;
+
+ if (nPass < 2)
+ return 0;
+
+ /* allocate storage */
+ if (fftstate->SpaceAlloced < max_factors * sizeof (REAL))
+ {
+#ifdef SUN_BROKEN_REALLOC
+ if (!fftstate->SpaceAlloced) /* first time */
+ {
+ fftstate->SpaceAlloced = max_factors * sizeof (REAL);
+ }
+ else
+ {
+#endif
+ fftstate->SpaceAlloced = max_factors * sizeof (REAL);
+#ifdef SUN_BROKEN_REALLOC
+ }
+#endif
+ }
+ else
+ {
+ /* allow full use of alloc'd space */
+ max_factors = fftstate->SpaceAlloced / sizeof (REAL);
+ }
+ if (fftstate->MaxPermAlloced < max_perm)
+ {
+#ifdef SUN_BROKEN_REALLOC
+ if (!fftstate->MaxPermAlloced) /* first time */
+ else
+#endif
+ fftstate->MaxPermAlloced = max_perm;
+ }
+ else
+ {
+ /* allow full use of alloc'd space */
+ max_perm = fftstate->MaxPermAlloced;
+ }
+
+ /* assign pointers */
+ Rtmp = (REAL *) fftstate->Tmp0;
+ Itmp = (REAL *) fftstate->Tmp1;
+ Cos = (REAL *) fftstate->Tmp2;
+ Sin = (REAL *) fftstate->Tmp3;
+
+ /*
+ * Function Body
+ */
+ inc = iSign;
+ if (iSign < 0) {
+ s72 = -s72;
+ s60 = -s60;
+ pi2 = -pi2;
+ inc = -inc; /* absolute value */
+ }
+
+ /* adjust for strange increments */
+ nt = inc * (int)nTotal;
+ ns = inc * (int)nSpan;
+ kspan = ns;
+
+ nn = nt - inc;
+ jc = ns / (int)nPass;
+ radf = pi2 * (double) jc;
+ pi2 *= 2.0; /* use 2 PI from here on */
+
+ ii = 0;
+ jf = 0;
+ /* determine the factors of n */
+ mfactor = 0;
+ k = (int)nPass;
+ while (k % 16 == 0) {
+ mfactor++;
+ fftstate->factor [mfactor - 1] = 4;
+ k /= 16;
+ }
+ j = 3;
+ jj = 9;
+ do {
+ while (k % jj == 0) {
+ mfactor++;
+ fftstate->factor [mfactor - 1] = j;
+ k /= jj;
+ }
+ j += 2;
+ jj = j * j;
+ } while (jj <= k);
+ if (k <= 4) {
+ kt = mfactor;
+ fftstate->factor [mfactor] = k;
+ if (k != 1)
+ mfactor++;
+ } else {
+ if (k - (k / 4 << 2) == 0) {
+ mfactor++;
+ fftstate->factor [mfactor - 1] = 2;
+ k /= 4;
+ }
+ kt = mfactor;
+ j = 2;
+ do {
+ if (k % j == 0) {
+ mfactor++;
+ fftstate->factor [mfactor - 1] = j;
+ k /= j;
+ }
+ j = ((j + 1) / 2 << 1) + 1;
+ } while (j <= k);
+ }
+ if (kt) {
+ j = kt;
+ do {
+ mfactor++;
+ fftstate->factor [mfactor - 1] = fftstate->factor [j - 1];
+ j--;
+ } while (j);
+ }
+
+ /* test that mfactors is in range */
+ if (mfactor > NFACTOR)
+ {
+ return -1;
+ }
+
+ /* compute fourier transform */
+ for (;;) {
+ sd = radf / (double) kspan;
+ cd = sin(sd);
+ cd = 2.0 * cd * cd;
+ sd = sin(sd + sd);
+ kk = 0;
+ ii++;
+
+ switch (fftstate->factor [ii - 1]) {
+ case 2:
+ /* transform for factor of 2 (including rotation factor) */
+ kspan /= 2;
+ k1 = kspan + 2;
+ do {
+ do {
+ k2 = kk + kspan;
+ ak = Re [k2];
+ bk = Im [k2];
+ Re [k2] = Re [kk] - ak;
+ Im [k2] = Im [kk] - bk;
+ Re [kk] += ak;
+ Im [kk] += bk;
+ kk = k2 + kspan;
+ } while (kk < nn);
+ kk -= nn;
+ } while (kk < jc);
+ if (kk >= kspan)
+ goto Permute_Results_Label; /* exit infinite loop */
+ do {
+ c1 = 1.0 - cd;
+ s1 = sd;
+ do {
+ do {
+ do {
+ k2 = kk + kspan;
+ ak = Re [kk] - Re [k2];
+ bk = Im [kk] - Im [k2];
+ Re [kk] += Re [k2];
+ Im [kk] += Im [k2];
+ Re [k2] = c1 * ak - s1 * bk;
+ Im [k2] = s1 * ak + c1 * bk;
+ kk = k2 + kspan;
+ } while (kk < (nt-1));
+ k2 = kk - nt;
+ c1 = -c1;
+ kk = k1 - k2;
+ } while (kk > k2);
+ ak = c1 - (cd * c1 + sd * s1);
+ s1 = sd * c1 - cd * s1 + s1;
+ c1 = 2.0 - (ak * ak + s1 * s1);
+ s1 *= c1;
+ c1 *= ak;
+ kk += jc;
+ } while (kk < k2);
+ k1 += inc + inc;
+ kk = (k1 - kspan + 1) / 2 + jc - 1;
+ } while (kk < (jc + jc));
+ break;
+
+ case 4: /* transform for factor of 4 */
+ ispan = kspan;
+ kspan /= 4;
+
+ do {
+ c1 = 1.0;
+ s1 = 0.0;
+ do {
+ do {
+ k1 = kk + kspan;
+ k2 = k1 + kspan;
+ k3 = k2 + kspan;
+ akp = Re [kk] + Re [k2];
+ akm = Re [kk] - Re [k2];
+ ajp = Re [k1] + Re [k3];
+ ajm = Re [k1] - Re [k3];
+ bkp = Im [kk] + Im [k2];
+ bkm = Im [kk] - Im [k2];
+ bjp = Im [k1] + Im [k3];
+ bjm = Im [k1] - Im [k3];
+ Re [kk] = akp + ajp;
+ Im [kk] = bkp + bjp;
+ ajp = akp - ajp;
+ bjp = bkp - bjp;
+ if (iSign < 0) {
+ akp = akm + bjm;
+ bkp = bkm - ajm;
+ akm -= bjm;
+ bkm += ajm;
+ } else {
+ akp = akm - bjm;
+ bkp = bkm + ajm;
+ akm += bjm;
+ bkm -= ajm;
+ }
+ /* avoid useless multiplies */
+ if (s1 == 0.0) {
+ Re [k1] = akp;
+ Re [k2] = ajp;
+ Re [k3] = akm;
+ Im [k1] = bkp;
+ Im [k2] = bjp;
+ Im [k3] = bkm;
+ } else {
+ Re [k1] = akp * c1 - bkp * s1;
+ Re [k2] = ajp * c2 - bjp * s2;
+ Re [k3] = akm * c3 - bkm * s3;
+ Im [k1] = akp * s1 + bkp * c1;
+ Im [k2] = ajp * s2 + bjp * c2;
+ Im [k3] = akm * s3 + bkm * c3;
+ }
+ kk = k3 + kspan;
+ } while (kk < nt);
+
+ c2 = c1 - (cd * c1 + sd * s1);
+ s1 = sd * c1 - cd * s1 + s1;
+ c1 = 2.0 - (c2 * c2 + s1 * s1);
+ s1 *= c1;
+ c1 *= c2;
+ /* values of c2, c3, s2, s3 that will get used next time */
+ c2 = c1 * c1 - s1 * s1;
+ s2 = 2.0 * c1 * s1;
+ c3 = c2 * c1 - s2 * s1;
+ s3 = c2 * s1 + s2 * c1;
+ kk = kk - nt + jc;
+ } while (kk < kspan);
+ kk = kk - kspan + inc;
+ } while (kk < jc);
+ if (kspan == jc)
+ goto Permute_Results_Label; /* exit infinite loop */
+ break;
+
+ default:
+ /* transform for odd factors */
+#ifdef FFT_RADIX4
+ return -1;
+ break;
+#else /* FFT_RADIX4 */
+ k = fftstate->factor [ii - 1];
+ ispan = kspan;
+ kspan /= k;
+
+ switch (k) {
+ case 3: /* transform for factor of 3 (optional code) */
+ do {
+ do {
+ k1 = kk + kspan;
+ k2 = k1 + kspan;
+ ak = Re [kk];
+ bk = Im [kk];
+ aj = Re [k1] + Re [k2];
+ bj = Im [k1] + Im [k2];
+ Re [kk] = ak + aj;
+ Im [kk] = bk + bj;
+ ak -= 0.5 * aj;
+ bk -= 0.5 * bj;
+ aj = (Re [k1] - Re [k2]) * s60;
+ bj = (Im [k1] - Im [k2]) * s60;
+ Re [k1] = ak - bj;
+ Re [k2] = ak + bj;
+ Im [k1] = bk + aj;
+ Im [k2] = bk - aj;
+ kk = k2 + kspan;
+ } while (kk < (nn - 1));
+ kk -= nn;
+ } while (kk < kspan);
+ break;
+
+ case 5: /* transform for factor of 5 (optional code) */
+ c2 = c72 * c72 - s72 * s72;
+ s2 = 2.0 * c72 * s72;
+ do {
+ do {
+ k1 = kk + kspan;
+ k2 = k1 + kspan;
+ k3 = k2 + kspan;
+ k4 = k3 + kspan;
+ akp = Re [k1] + Re [k4];
+ akm = Re [k1] - Re [k4];
+ bkp = Im [k1] + Im [k4];
+ bkm = Im [k1] - Im [k4];
+ ajp = Re [k2] + Re [k3];
+ ajm = Re [k2] - Re [k3];
+ bjp = Im [k2] + Im [k3];
+ bjm = Im [k2] - Im [k3];
+ aa = Re [kk];
+ bb = Im [kk];
+ Re [kk] = aa + akp + ajp;
+ Im [kk] = bb + bkp + bjp;
+ ak = akp * c72 + ajp * c2 + aa;
+ bk = bkp * c72 + bjp * c2 + bb;
+ aj = akm * s72 + ajm * s2;
+ bj = bkm * s72 + bjm * s2;
+ Re [k1] = ak - bj;
+ Re [k4] = ak + bj;
+ Im [k1] = bk + aj;
+ Im [k4] = bk - aj;
+ ak = akp * c2 + ajp * c72 + aa;
+ bk = bkp * c2 + bjp * c72 + bb;
+ aj = akm * s2 - ajm * s72;
+ bj = bkm * s2 - bjm * s72;
+ Re [k2] = ak - bj;
+ Re [k3] = ak + bj;
+ Im [k2] = bk + aj;
+ Im [k3] = bk - aj;
+ kk = k4 + kspan;
+ } while (kk < (nn-1));
+ kk -= nn;
+ } while (kk < kspan);
+ break;
+
+ default:
+ if (k != jf) {
+ jf = k;
+ s1 = pi2 / (double) k;
+ c1 = cos(s1);
+ s1 = sin(s1);
+ if (jf > max_factors){
+ return -1;
+ }
+ Cos [jf - 1] = 1.0;
+ Sin [jf - 1] = 0.0;
+ j = 1;
+ do {
+ Cos [j - 1] = Cos [k - 1] * c1 + Sin [k - 1] * s1;
+ Sin [j - 1] = Cos [k - 1] * s1 - Sin [k - 1] * c1;
+ k--;
+ Cos [k - 1] = Cos [j - 1];
+ Sin [k - 1] = -Sin [j - 1];
+ j++;
+ } while (j < k);
+ }
+ do {
+ do {
+ k1 = kk;
+ k2 = kk + ispan;
+ ak = aa = Re [kk];
+ bk = bb = Im [kk];
+ j = 1;
+ k1 += kspan;
+ do {
+ k2 -= kspan;
+ j++;
+ Rtmp [j - 1] = Re [k1] + Re [k2];
+ ak += Rtmp [j - 1];
+ Itmp [j - 1] = Im [k1] + Im [k2];
+ bk += Itmp [j - 1];
+ j++;
+ Rtmp [j - 1] = Re [k1] - Re [k2];
+ Itmp [j - 1] = Im [k1] - Im [k2];
+ k1 += kspan;
+ } while (k1 < k2);
+ Re [kk] = ak;
+ Im [kk] = bk;
+ k1 = kk;
+ k2 = kk + ispan;
+ j = 1;
+ do {
+ k1 += kspan;
+ k2 -= kspan;
+ jj = j;
+ ak = aa;
+ bk = bb;
+ aj = 0.0;
+ bj = 0.0;
+ k = 1;
+ do {
+ k++;
+ ak += Rtmp [k - 1] * Cos [jj - 1];
+ bk += Itmp [k - 1] * Cos [jj - 1];
+ k++;
+ aj += Rtmp [k - 1] * Sin [jj - 1];
+ bj += Itmp [k - 1] * Sin [jj - 1];
+ jj += j;
+ if (jj > jf) {
+ jj -= jf;
+ }
+ } while (k < jf);
+ k = jf - j;
+ Re [k1] = ak - bj;
+ Im [k1] = bk + aj;
+ Re [k2] = ak + bj;
+ Im [k2] = bk - aj;
+ j++;
+ } while (j < k);
+ kk += ispan;
+ } while (kk < nn);
+ kk -= nn;
+ } while (kk < kspan);
+ break;
+ }
+
+ /* multiply by rotation factor (except for factors of 2 and 4) */
+ if (ii == mfactor)
+ goto Permute_Results_Label; /* exit infinite loop */
+ kk = jc;
+ do {
+ c2 = 1.0 - cd;
+ s1 = sd;
+ do {
+ c1 = c2;
+ s2 = s1;
+ kk += kspan;
+ do {
+ do {
+ ak = Re [kk];
+ Re [kk] = c2 * ak - s2 * Im [kk];
+ Im [kk] = s2 * ak + c2 * Im [kk];
+ kk += ispan;
+ } while (kk < nt);
+ ak = s1 * s2;
+ s2 = s1 * c2 + c1 * s2;
+ c2 = c1 * c2 - ak;
+ kk = kk - nt + kspan;
+ } while (kk < ispan);
+ c2 = c1 - (cd * c1 + sd * s1);
+ s1 += sd * c1 - cd * s1;
+ c1 = 2.0 - (c2 * c2 + s1 * s1);
+ s1 *= c1;
+ c2 *= c1;
+ kk = kk - ispan + jc;
+ } while (kk < kspan);
+ kk = kk - kspan + jc + inc;
+ } while (kk < (jc + jc));
+ break;
+#endif /* FFT_RADIX4 */
+ }
+ }
+
+ /* permute the results to normal order---done in two stages */
+ /* permutation for square factors of n */
+Permute_Results_Label:
+ fftstate->Perm [0] = ns;
+ if (kt) {
+ k = kt + kt + 1;
+ if (mfactor < k)
+ k--;
+ j = 1;
+ fftstate->Perm [k] = jc;
+ do {
+ fftstate->Perm [j] = fftstate->Perm [j - 1] / fftstate->factor [j - 1];
+ fftstate->Perm [k - 1] = fftstate->Perm [k] * fftstate->factor [j - 1];
+ j++;
+ k--;
+ } while (j < k);
+ k3 = fftstate->Perm [k];
+ kspan = fftstate->Perm [1];
+ kk = jc;
+ k2 = kspan;
+ j = 1;
+ if (nPass != nTotal) {
+ /* permutation for multivariate transform */
+ Permute_Multi_Label:
+ do {
+ do {
+ k = kk + jc;
+ do {
+ /* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */
+ ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak;
+ bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk;
+ kk += inc;
+ k2 += inc;
+ } while (kk < (k-1));
+ kk += ns - jc;
+ k2 += ns - jc;
+ } while (kk < (nt-1));
+ k2 = k2 - nt + kspan;
+ kk = kk - nt + jc;
+ } while (k2 < (ns-1));
+ do {
+ do {
+ k2 -= fftstate->Perm [j - 1];
+ j++;
+ k2 = fftstate->Perm [j] + k2;
+ } while (k2 > fftstate->Perm [j - 1]);
+ j = 1;
+ do {
+ if (kk < (k2-1))
+ goto Permute_Multi_Label;
+ kk += jc;
+ k2 += kspan;
+ } while (k2 < (ns-1));
+ } while (kk < (ns-1));
+ } else {
+ /* permutation for single-variate transform (optional code) */
+ Permute_Single_Label:
+ do {
+ /* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */
+ ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak;
+ bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk;
+ kk += inc;
+ k2 += kspan;
+ } while (k2 < (ns-1));
+ do {
+ do {
+ k2 -= fftstate->Perm [j - 1];
+ j++;
+ k2 = fftstate->Perm [j] + k2;
+ } while (k2 >= fftstate->Perm [j - 1]);
+ j = 1;
+ do {
+ if (kk < k2)
+ goto Permute_Single_Label;
+ kk += inc;
+ k2 += kspan;
+ } while (k2 < (ns-1));
+ } while (kk < (ns-1));
+ }
+ jc = k3;
+ }
+
+ if ((kt << 1) + 1 >= mfactor)
+ return 0;
+ ispan = fftstate->Perm [kt];
+ /* permutation for square-free factors of n */
+ j = mfactor - kt;
+ fftstate->factor [j] = 1;
+ do {
+ fftstate->factor [j - 1] *= fftstate->factor [j];
+ j--;
+ } while (j != kt);
+ kt++;
+ nn = fftstate->factor [kt - 1] - 1;
+ if (nn > (int) max_perm) {
+ return -1;
+ }
+ j = jj = 0;
+ for (;;) {
+ k = kt + 1;
+ k2 = fftstate->factor [kt - 1];
+ kk = fftstate->factor [k - 1];
+ j++;
+ if (j > nn)
+ break; /* exit infinite loop */
+ jj += kk;
+ while (jj >= k2) {
+ jj -= k2;
+ k2 = kk;
+ k++;
+ kk = fftstate->factor [k - 1];
+ jj += kk;
+ }
+ fftstate->Perm [j - 1] = jj;
+ }
+ /* determine the permutation cycles of length greater than 1 */
+ j = 0;
+ for (;;) {
+ do {
+ j++;
+ kk = fftstate->Perm [j - 1];
+ } while (kk < 0);
+ if (kk != j) {
+ do {
+ k = kk;
+ kk = fftstate->Perm [k - 1];
+ fftstate->Perm [k - 1] = -kk;
+ } while (kk != j);
+ k3 = kk;
+ } else {
+ fftstate->Perm [j - 1] = -j;
+ if (j == nn)
+ break; /* exit infinite loop */
+ }
+ }
+ max_factors *= inc;
+ /* reorder a and b, following the permutation cycles */
+ for (;;) {
+ j = k3 + 1;
+ nt -= ispan;
+ ii = nt - inc + 1;
+ if (nt < 0)
+ break; /* exit infinite loop */
+ do {
+ do {
+ j--;
+ } while (fftstate->Perm [j - 1] < 0);
+ jj = jc;
+ do {
+ kspan = jj;
+ if (jj > max_factors) {
+ kspan = max_factors;
+ }
+ jj -= kspan;
+ k = fftstate->Perm [j - 1];
+ kk = jc * k + ii + jj;
+ k1 = kk + kspan - 1;
+ k2 = 0;
+ do {
+ k2++;
+ Rtmp [k2 - 1] = Re [k1];
+ Itmp [k2 - 1] = Im [k1];
+ k1 -= inc;
+ } while (k1 != (kk-1));
+ do {
+ k1 = kk + kspan - 1;
+ k2 = k1 - jc * (k + fftstate->Perm [k - 1]);
+ k = -fftstate->Perm [k - 1];
+ do {
+ Re [k1] = Re [k2];
+ Im [k1] = Im [k2];
+ k1 -= inc;
+ k2 -= inc;
+ } while (k1 != (kk-1));
+ kk = k2 + 1;
+ } while (k != j);
+ k1 = kk + kspan - 1;
+ k2 = 0;
+ do {
+ k2++;
+ Re [k1] = Rtmp [k2 - 1];
+ Im [k1] = Itmp [k2 - 1];
+ k1 -= inc;
+ } while (k1 != (kk-1));
+ } while (jj);
+ } while (j != 1);
+ }
+ return 0; /* exit point here */
+}
+/* ---------------------- end-of-file (c source) ---------------------- */
+
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/fft.h b/webrtc/modules/audio_coding/codecs/isac/main/source/fft.h
new file mode 100644
index 0000000..a42f57b
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/fft.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 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.
+ */
+
+/*--------------------------------*-C-*---------------------------------*
+ * File:
+ * fftn.h
+ * ---------------------------------------------------------------------*
+ * Re[]: real value array
+ * Im[]: imaginary value array
+ * nTotal: total number of complex values
+ * nPass: number of elements involved in this pass of transform
+ * nSpan: nspan/nPass = number of bytes to increment pointer
+ * in Re[] and Im[]
+ * isign: exponent: +1 = forward -1 = reverse
+ * scaling: normalizing constant by which the final result is *divided*
+ * scaling == -1, normalize by total dimension of the transform
+ * scaling < -1, normalize by the square-root of the total dimension
+ *
+ * ----------------------------------------------------------------------
+ * See the comments in the code for correct usage!
+ */
+
+#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_
+
+
+#include "structs.h"
+
+
+/* double precision routine */
+
+
+int WebRtcIsac_Fftns (unsigned int ndim, const int dims[], double Re[], double Im[],
+ int isign, double scaling, FFTstr *fftstate);
+
+
+
+#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/isac.c b/webrtc/modules/audio_coding/codecs/isac/main/source/isac.c
new file mode 100644
index 0000000..875e7ac
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/isac.c
@@ -0,0 +1,2363 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/*
+ * isac.c
+ *
+ * This C file contains the functions for the ISAC API
+ *
+ */
+
+#include "webrtc/modules/audio_coding/codecs/isac/main/include/isac.h"
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
+#include "webrtc/modules/audio_coding/codecs/isac/main/source/codec.h"
+#include "webrtc/modules/audio_coding/codecs/isac/main/source/crc.h"
+#include "webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
+#include "webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
+#include "webrtc/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
+#include "webrtc/modules/audio_coding/codecs/isac/main/source/structs.h"
+
+#define BIT_MASK_DEC_INIT 0x0001
+#define BIT_MASK_ENC_INIT 0x0002
+
+#define LEN_CHECK_SUM_WORD8 4
+#define MAX_NUM_LAYERS 10
+
+
+/****************************************************************************
+ * UpdatePayloadSizeLimit(...)
+ *
+ * Call this function to update the limit on the payload size. The limit on
+ * payload size might change i) if a user ''directly changes the limit by
+ * calling xxx_setMaxPayloadSize() or xxx_setMaxRate(), or ii) indirectly
+ * when bandwidth is changing. The latter might be the result of bandwidth
+ * adaptation, or direct change of the bottleneck in instantaneous mode.
+ *
+ * This function takes the current overall limit on payload, and translates it
+ * to the limits on lower and upper-band. If the codec is in wideband mode,
+ * then the overall limit and the limit on the lower-band is the same.
+ * Otherwise, a fraction of the limit should be allocated to lower-band
+ * leaving some room for the upper-band bit-stream. That is why an update
+ * of limit is required every time that the bandwidth is changing.
+ *
+ */
+static void UpdatePayloadSizeLimit(ISACMainStruct* instISAC) {
+ int16_t lim30MsPayloadBytes = WEBRTC_SPL_MIN(
+ (instISAC->maxPayloadSizeBytes),
+ (instISAC->maxRateBytesPer30Ms));
+ int16_t lim60MsPayloadBytes = WEBRTC_SPL_MIN(
+ (instISAC->maxPayloadSizeBytes),
+ (instISAC->maxRateBytesPer30Ms << 1));
+
+ /* The only time that iSAC will have 60 ms
+ * frame-size is when operating in wideband, so
+ * there is no upper-band bit-stream. */
+
+ if (instISAC->bandwidthKHz == isac8kHz) {
+ /* At 8 kHz there is no upper-band bit-stream,
+ * therefore, the lower-band limit is the overall limit. */
+ instISAC->instLB.ISACencLB_obj.payloadLimitBytes60 =
+ lim60MsPayloadBytes;
+ instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 =
+ lim30MsPayloadBytes;
+ } else {
+ /* When in super-wideband, we only have 30 ms frames.
+ * Do a rate allocation for the given limit. */
+ if (lim30MsPayloadBytes > 250) {
+ /* 4/5 to lower-band the rest for upper-band. */
+ instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 =
+ (lim30MsPayloadBytes << 2) / 5;
+ } else if (lim30MsPayloadBytes > 200) {
+ /* For the interval of 200 to 250 the share of
+ * upper-band linearly grows from 20 to 50. */
+ instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 =
+ (lim30MsPayloadBytes << 1) / 5 + 100;
+ } else {
+ /* Allocate only 20 for upper-band. */
+ instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 =
+ lim30MsPayloadBytes - 20;
+ }
+ instISAC->instUB.ISACencUB_obj.maxPayloadSizeBytes =
+ lim30MsPayloadBytes;
+ }
+}
+
+
+/****************************************************************************
+ * UpdateBottleneck(...)
+ *
+ * This function updates the bottleneck only if the codec is operating in
+ * channel-adaptive mode. Furthermore, as the update of bottleneck might
+ * result in an update of bandwidth, therefore, the bottlenech should be
+ * updated just right before the first 10ms of a frame is pushed into encoder.
+ *
+ */
+static void UpdateBottleneck(ISACMainStruct* instISAC) {
+ /* Read the bottleneck from bandwidth estimator for the
+ * first 10 ms audio. This way, if there is a change
+ * in bandwidth, upper and lower-band will be in sync. */
+ if ((instISAC->codingMode == 0) &&
+ (instISAC->instLB.ISACencLB_obj.buffer_index == 0) &&
+ (instISAC->instLB.ISACencLB_obj.frame_nb == 0)) {
+ int32_t bottleneck =
+ WebRtcIsac_GetUplinkBandwidth(&instISAC->bwestimator_obj);
+
+ /* Adding hysteresis when increasing signal bandwidth. */
+ if ((instISAC->bandwidthKHz == isac8kHz)
+ && (bottleneck > 37000)
+ && (bottleneck < 41000)) {
+ bottleneck = 37000;
+ }
+
+ /* Switching from 12 kHz to 16 kHz is not allowed at this revision.
+ * If we let this happen, we have to take care of buffer_index and
+ * the last LPC vector. */
+ if ((instISAC->bandwidthKHz != isac16kHz) &&
+ (bottleneck > 46000)) {
+ bottleneck = 46000;
+ }
+
+ /* We might need a rate allocation. */
+ if (instISAC->encoderSamplingRateKHz == kIsacWideband) {
+ /* Wideband is the only choice we have here. */
+ instISAC->instLB.ISACencLB_obj.bottleneck =
+ (bottleneck > 32000) ? 32000 : bottleneck;
+ instISAC->bandwidthKHz = isac8kHz;
+ } else {
+ /* Do the rate-allocation and get the new bandwidth. */
+ enum ISACBandwidth bandwidth;
+ WebRtcIsac_RateAllocation(bottleneck,
+ &(instISAC->instLB.ISACencLB_obj.bottleneck),
+ &(instISAC->instUB.ISACencUB_obj.bottleneck),
+ &bandwidth);
+ if (bandwidth != isac8kHz) {
+ instISAC->instLB.ISACencLB_obj.new_framelength = 480;
+ }
+ if (bandwidth != instISAC->bandwidthKHz) {
+ /* Bandwidth is changing. */
+ instISAC->bandwidthKHz = bandwidth;
+ UpdatePayloadSizeLimit(instISAC);
+ if (bandwidth == isac12kHz) {
+ instISAC->instLB.ISACencLB_obj.buffer_index = 0;
+ }
+ /* Currently we don't let the bandwidth to switch to 16 kHz
+ * if in adaptive mode. If we let this happen, we have to take
+ * care of buffer_index and the last LPC vector. */
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ * GetSendBandwidthInfo(...)
+ *
+ * This is called to get the bandwidth info. This info is the bandwidth and
+ * the jitter of 'there-to-here' channel, estimated 'here.' These info
+ * is signaled in an in-band fashion to the other side.
+ *
+ * The call to the bandwidth estimator triggers a recursive averaging which
+ * has to be synchronized between encoder & decoder, therefore, the call to
+ * BWE should be once per packet. As the BWE info is inserted into bit-stream
+ * We need a valid info right before the encodeLB function is going to
+ * generate a bit-stream. That is when lower-band buffer has already 20ms
+ * of audio, and the 3rd block of 10ms is going to be injected into encoder.
+ *
+ * Inputs:
+ * - instISAC : iSAC instance.
+ *
+ * Outputs:
+ * - bandwidthIndex : an index which has to be encoded in
+ * lower-band bit-stream, indicating the
+ * bandwidth of there-to-here channel.
+ * - jitterInfo : this indicates if the jitter is high
+ * or low and it is encoded in upper-band
+ * bit-stream.
+ *
+ */
+static void GetSendBandwidthInfo(ISACMainStruct* instISAC,
+ int16_t* bandwidthIndex,
+ int16_t* jitterInfo) {
+ if ((instISAC->instLB.ISACencLB_obj.buffer_index ==
+ (FRAMESAMPLES_10ms << 1)) &&
+ (instISAC->instLB.ISACencLB_obj.frame_nb == 0)) {
+ /* Bandwidth estimation and coding. */
+ WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj),
+ bandwidthIndex, jitterInfo,
+ instISAC->decoderSamplingRateKHz);
+ }
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_AssignSize(...)
+ *
+ * This function returns the size of the ISAC instance, so that the instance
+ * can be created out side iSAC.
+ *
+ * Output:
+ * - sizeinbytes : number of bytes needed to allocate for the
+ * instance.
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int16_t WebRtcIsac_AssignSize(int* sizeInBytes) {
+ *sizeInBytes = sizeof(ISACMainStruct) * 2 / sizeof(int16_t);
+ return 0;
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_Assign(...)
+ *
+ * This function assigns the memory already created to the ISAC instance.
+ *
+ * Input:
+ * - ISAC_main_inst : address of the pointer to the coder instance.
+ * - instISAC_Addr : the already allocated memory, where we put the
+ * iSAC structure.
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int16_t WebRtcIsac_Assign(ISACStruct** ISAC_main_inst,
+ void* instISAC_Addr) {
+ if (instISAC_Addr != NULL) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)instISAC_Addr;
+ instISAC->errorCode = 0;
+ instISAC->initFlag = 0;
+
+ /* Assign the address. */
+ *ISAC_main_inst = (ISACStruct*)instISAC_Addr;
+
+ /* Default is wideband. */
+ instISAC->encoderSamplingRateKHz = kIsacWideband;
+ instISAC->decoderSamplingRateKHz = kIsacWideband;
+ instISAC->bandwidthKHz = isac8kHz;
+ instISAC->in_sample_rate_hz = 16000;
+
+ WebRtcIsac_InitTransform(&instISAC->transform_tables);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_Create(...)
+ *
+ * This function creates an ISAC instance, which will contain the state
+ * information for one coding/decoding channel.
+ *
+ * Input:
+ * - ISAC_main_inst : address of the pointer to the coder instance.
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int16_t WebRtcIsac_Create(ISACStruct** ISAC_main_inst) {
+ ISACMainStruct* instISAC;
+
+ if (ISAC_main_inst != NULL) {
+ instISAC = (ISACMainStruct*)malloc(sizeof(ISACMainStruct));
+ *ISAC_main_inst = (ISACStruct*)instISAC;
+ if (*ISAC_main_inst != NULL) {
+ instISAC->errorCode = 0;
+ instISAC->initFlag = 0;
+ /* Default is wideband. */
+ instISAC->bandwidthKHz = isac8kHz;
+ instISAC->encoderSamplingRateKHz = kIsacWideband;
+ instISAC->decoderSamplingRateKHz = kIsacWideband;
+ instISAC->in_sample_rate_hz = 16000;
+
+ WebRtcIsac_InitTransform(&instISAC->transform_tables);
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_Free(...)
+ *
+ * This function frees the ISAC instance created at the beginning.
+ *
+ * Input:
+ * - ISAC_main_inst : a ISAC instance.
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int16_t WebRtcIsac_Free(ISACStruct* ISAC_main_inst) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ free(instISAC);
+ return 0;
+}
+
+
+/****************************************************************************
+ * EncoderInitLb(...) - internal function for initialization of
+ * Lower Band
+ * EncoderInitUb(...) - internal function for initialization of
+ * Upper Band
+ * WebRtcIsac_EncoderInit(...) - API function
+ *
+ * This function initializes a ISAC instance prior to the encoder calls.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - CodingMode : 0 -> Bit rate and frame length are automatically
+ * adjusted to available bandwidth on
+ * transmission channel, applicable just to
+ * wideband mode.
+ * 1 -> User sets a frame length and a target bit
+ * rate which is taken as the maximum
+ * short-term average bit rate.
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+static int16_t EncoderInitLb(ISACLBStruct* instLB,
+ int16_t codingMode,
+ enum IsacSamplingRate sampRate) {
+ int16_t statusInit = 0;
+ int k;
+
+ /* Init stream vector to zero */
+ for (k = 0; k < STREAM_SIZE_MAX_60; k++) {
+ instLB->ISACencLB_obj.bitstr_obj.stream[k] = 0;
+ }
+
+ if ((codingMode == 1) || (sampRate == kIsacSuperWideband)) {
+ /* 30 ms frame-size if either in super-wideband or
+ * instantaneous mode (I-mode). */
+ instLB->ISACencLB_obj.new_framelength = 480;
+ } else {
+ instLB->ISACencLB_obj.new_framelength = INITIAL_FRAMESAMPLES;
+ }
+
+ WebRtcIsac_InitMasking(&instLB->ISACencLB_obj.maskfiltstr_obj);
+ WebRtcIsac_InitPreFilterbank(&instLB->ISACencLB_obj.prefiltbankstr_obj);
+ WebRtcIsac_InitPitchFilter(&instLB->ISACencLB_obj.pitchfiltstr_obj);
+ WebRtcIsac_InitPitchAnalysis(
+ &instLB->ISACencLB_obj.pitchanalysisstr_obj);
+
+ instLB->ISACencLB_obj.buffer_index = 0;
+ instLB->ISACencLB_obj.frame_nb = 0;
+ /* Default for I-mode. */
+ instLB->ISACencLB_obj.bottleneck = 32000;
+ instLB->ISACencLB_obj.current_framesamples = 0;
+ instLB->ISACencLB_obj.s2nr = 0;
+ instLB->ISACencLB_obj.payloadLimitBytes30 = STREAM_SIZE_MAX_30;
+ instLB->ISACencLB_obj.payloadLimitBytes60 = STREAM_SIZE_MAX_60;
+ instLB->ISACencLB_obj.maxPayloadBytes = STREAM_SIZE_MAX_60;
+ instLB->ISACencLB_obj.maxRateInBytes = STREAM_SIZE_MAX_30;
+ instLB->ISACencLB_obj.enforceFrameSize = 0;
+ /* Invalid value prevents getRedPayload to
+ run before encoder is called. */
+ instLB->ISACencLB_obj.lastBWIdx = -1;
+ return statusInit;
+}
+
+static int16_t EncoderInitUb(ISACUBStruct* instUB,
+ int16_t bandwidth) {
+ int16_t statusInit = 0;
+ int k;
+
+ /* Init stream vector to zero. */
+ for (k = 0; k < STREAM_SIZE_MAX_60; k++) {
+ instUB->ISACencUB_obj.bitstr_obj.stream[k] = 0;
+ }
+
+ WebRtcIsac_InitMasking(&instUB->ISACencUB_obj.maskfiltstr_obj);
+ WebRtcIsac_InitPreFilterbank(&instUB->ISACencUB_obj.prefiltbankstr_obj);
+
+ if (bandwidth == isac16kHz) {
+ instUB->ISACencUB_obj.buffer_index = LB_TOTAL_DELAY_SAMPLES;
+ } else {
+ instUB->ISACencUB_obj.buffer_index = 0;
+ }
+ /* Default for I-mode. */
+ instUB->ISACencUB_obj.bottleneck = 32000;
+ /* These store the limits for the wideband + super-wideband bit-stream. */
+ instUB->ISACencUB_obj.maxPayloadSizeBytes = STREAM_SIZE_MAX_30 << 1;
+ /* This has to be updated after each lower-band encoding to guarantee
+ * a correct payload-limitation. */
+ instUB->ISACencUB_obj.numBytesUsed = 0;
+ memset(instUB->ISACencUB_obj.data_buffer_float, 0,
+ (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES) * sizeof(float));
+
+ memcpy(&(instUB->ISACencUB_obj.lastLPCVec),
+ WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER);
+
+ return statusInit;
+}
+
+
+int16_t WebRtcIsac_EncoderInit(ISACStruct* ISAC_main_inst,
+ int16_t codingMode) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ int16_t status;
+
+ if ((codingMode != 0) && (codingMode != 1)) {
+ instISAC->errorCode = ISAC_DISALLOWED_CODING_MODE;
+ return -1;
+ }
+ /* Default bottleneck. */
+ instISAC->bottleneck = MAX_ISAC_BW;
+
+ if (instISAC->encoderSamplingRateKHz == kIsacWideband) {
+ instISAC->bandwidthKHz = isac8kHz;
+ instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60;
+ instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30;
+ } else {
+ instISAC->bandwidthKHz = isac16kHz;
+ instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX;
+ instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX;
+ }
+
+ /* Channel-adaptive = 0; Instantaneous (Channel-independent) = 1. */
+ instISAC->codingMode = codingMode;
+
+ WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj,
+ instISAC->encoderSamplingRateKHz,
+ instISAC->decoderSamplingRateKHz);
+
+ WebRtcIsac_InitRateModel(&instISAC->rate_data_obj);
+ /* Default for I-mode. */
+ instISAC->MaxDelay = 10.0;
+
+ status = EncoderInitLb(&instISAC->instLB, codingMode,
+ instISAC->encoderSamplingRateKHz);
+ if (status < 0) {
+ instISAC->errorCode = -status;
+ return -1;
+ }
+
+ if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) {
+ /* Initialize encoder filter-bank. */
+ memset(instISAC->analysisFBState1, 0,
+ FB_STATE_SIZE_WORD32 * sizeof(int32_t));
+ memset(instISAC->analysisFBState2, 0,
+ FB_STATE_SIZE_WORD32 * sizeof(int32_t));
+
+ status = EncoderInitUb(&(instISAC->instUB),
+ instISAC->bandwidthKHz);
+ if (status < 0) {
+ instISAC->errorCode = -status;
+ return -1;
+ }
+ }
+ /* Initialization is successful, set the flag. */
+ instISAC->initFlag |= BIT_MASK_ENC_INIT;
+ return 0;
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_Encode(...)
+ *
+ * This function encodes 10ms frame(s) and inserts it into a package.
+ * Input speech length has to be 160 samples (10ms). The encoder buffers those
+ * 10ms frames until it reaches the chosen Framesize (480 or 960 samples
+ * corresponding to 30 or 60 ms frames), and then proceeds to the encoding.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - speechIn : input speech vector.
+ *
+ * Output:
+ * - encoded : the encoded data vector
+ *
+ * Return value:
+ * : >0 - Length (in bytes) of coded data
+ * : 0 - The buffer didn't reach the chosen
+ * frameSize so it keeps buffering speech
+ * samples.
+ * : -1 - Error
+ */
+int WebRtcIsac_Encode(ISACStruct* ISAC_main_inst,
+ const int16_t* speechIn,
+ uint8_t* encoded) {
+ float inFrame[FRAMESAMPLES_10ms];
+ int16_t speechInLB[FRAMESAMPLES_10ms];
+ int16_t speechInUB[FRAMESAMPLES_10ms];
+ int streamLenLB = 0;
+ int streamLenUB = 0;
+ int streamLen = 0;
+ size_t k = 0;
+ uint8_t garbageLen = 0;
+ int32_t bottleneck = 0;
+ int16_t bottleneckIdx = 0;
+ int16_t jitterInfo = 0;
+
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ ISACLBStruct* instLB = &(instISAC->instLB);
+ ISACUBStruct* instUB = &(instISAC->instUB);
+
+ /* Check if encoder initiated. */
+ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
+ BIT_MASK_ENC_INIT) {
+ instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
+ return -1;
+ }
+
+ if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) {
+ WebRtcSpl_AnalysisQMF(speechIn, SWBFRAMESAMPLES_10ms, speechInLB,
+ speechInUB, instISAC->analysisFBState1,
+ instISAC->analysisFBState2);
+
+ /* Convert from fixed to floating point. */
+ for (k = 0; k < FRAMESAMPLES_10ms; k++) {
+ inFrame[k] = (float)speechInLB[k];
+ }
+ } else {
+ for (k = 0; k < FRAMESAMPLES_10ms; k++) {
+ inFrame[k] = (float) speechIn[k];
+ }
+ }
+
+ /* Add some noise to avoid denormal numbers. */
+ inFrame[0] += (float)1.23455334e-3;
+ inFrame[1] -= (float)2.04324239e-3;
+ inFrame[2] += (float)1.90854954e-3;
+ inFrame[9] += (float)1.84854878e-3;
+
+ /* This function will update the bottleneck if required. */
+ UpdateBottleneck(instISAC);
+
+ /* Get the bandwith information which has to be sent to the other side. */
+ GetSendBandwidthInfo(instISAC, &bottleneckIdx, &jitterInfo);
+
+ /* Encode lower-band. */
+ streamLenLB = WebRtcIsac_EncodeLb(&instISAC->transform_tables,
+ inFrame, &instLB->ISACencLB_obj,
+ instISAC->codingMode, bottleneckIdx);
+ if (streamLenLB < 0) {
+ return -1;
+ }
+
+ if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) {
+ instUB = &(instISAC->instUB);
+
+ /* Convert to float. */
+ for (k = 0; k < FRAMESAMPLES_10ms; k++) {
+ inFrame[k] = (float) speechInUB[k];
+ }
+
+ /* Add some noise to avoid denormal numbers. */
+ inFrame[0] += (float)1.23455334e-3;
+ inFrame[1] -= (float)2.04324239e-3;
+ inFrame[2] += (float)1.90854954e-3;
+ inFrame[9] += (float)1.84854878e-3;
+
+ /* Tell to upper-band the number of bytes used so far.
+ * This is for payload limitation. */
+ instUB->ISACencUB_obj.numBytesUsed =
+ (int16_t)(streamLenLB + 1 + LEN_CHECK_SUM_WORD8);
+ /* Encode upper-band. */
+ switch (instISAC->bandwidthKHz) {
+ case isac12kHz: {
+ streamLenUB = WebRtcIsac_EncodeUb12(&instISAC->transform_tables,
+ inFrame, &instUB->ISACencUB_obj,
+ jitterInfo);
+ break;
+ }
+ case isac16kHz: {
+ streamLenUB = WebRtcIsac_EncodeUb16(&instISAC->transform_tables,
+ inFrame, &instUB->ISACencUB_obj,
+ jitterInfo);
+ break;
+ }
+ case isac8kHz: {
+ streamLenUB = 0;
+ break;
+ }
+ }
+
+ if ((streamLenUB < 0) && (streamLenUB != -ISAC_PAYLOAD_LARGER_THAN_LIMIT)) {
+ /* An error has happened but this is not the error due to a
+ * bit-stream larger than the limit. */
+ return -1;
+ }
+
+ if (streamLenLB == 0) {
+ return 0;
+ }
+
+ /* One byte is allocated for the length. According to older decoders
+ so the length bit-stream plus one byte for size and
+ LEN_CHECK_SUM_WORD8 for the checksum should be less than or equal
+ to 255. */
+ if ((streamLenUB > (255 - (LEN_CHECK_SUM_WORD8 + 1))) ||
+ (streamLenUB == -ISAC_PAYLOAD_LARGER_THAN_LIMIT)) {
+ /* We have got a too long bit-stream we skip the upper-band
+ * bit-stream for this frame. */
+ streamLenUB = 0;
+ }
+
+ memcpy(encoded, instLB->ISACencLB_obj.bitstr_obj.stream, streamLenLB);
+ streamLen = streamLenLB;
+ if (streamLenUB > 0) {
+ encoded[streamLenLB] = (uint8_t)(streamLenUB + 1 + LEN_CHECK_SUM_WORD8);
+ memcpy(&encoded[streamLenLB + 1],
+ instUB->ISACencUB_obj.bitstr_obj.stream,
+ streamLenUB);
+ streamLen += encoded[streamLenLB];
+ } else {
+ encoded[streamLenLB] = 0;
+ }
+ } else {
+ if (streamLenLB == 0) {
+ return 0;
+ }
+ memcpy(encoded, instLB->ISACencLB_obj.bitstr_obj.stream, streamLenLB);
+ streamLenUB = 0;
+ streamLen = streamLenLB;
+ }
+
+ /* Add Garbage if required. */
+ bottleneck = WebRtcIsac_GetUplinkBandwidth(&instISAC->bwestimator_obj);
+ if (instISAC->codingMode == 0) {
+ int minBytes;
+ int limit;
+ uint8_t* ptrGarbage;
+
+ instISAC->MaxDelay = (double)WebRtcIsac_GetUplinkMaxDelay(
+ &instISAC->bwestimator_obj);
+
+ /* Update rate model and get minimum number of bytes in this packet. */
+ minBytes = WebRtcIsac_GetMinBytes(
+ &(instISAC->rate_data_obj), streamLen,
+ instISAC->instLB.ISACencLB_obj.current_framesamples, bottleneck,
+ instISAC->MaxDelay, instISAC->bandwidthKHz);
+
+ /* Make sure MinBytes does not exceed packet size limit. */
+ if (instISAC->bandwidthKHz == isac8kHz) {
+ if (instLB->ISACencLB_obj.current_framesamples == FRAMESAMPLES) {
+ limit = instLB->ISACencLB_obj.payloadLimitBytes30;
+ } else {
+ limit = instLB->ISACencLB_obj.payloadLimitBytes60;
+ }
+ } else {
+ limit = instUB->ISACencUB_obj.maxPayloadSizeBytes;
+ }
+ minBytes = (minBytes > limit) ? limit : minBytes;
+
+ /* Make sure we don't allow more than 255 bytes of garbage data.
+ * We store the length of the garbage data in 8 bits in the bitstream,
+ * 255 is the max garbage length we can signal using 8 bits. */
+ if ((instISAC->bandwidthKHz == isac8kHz) ||
+ (streamLenUB == 0)) {
+ ptrGarbage = &encoded[streamLenLB];
+ limit = streamLen + 255;
+ } else {
+ ptrGarbage = &encoded[streamLenLB + 1 + streamLenUB];
+ limit = streamLen + (255 - encoded[streamLenLB]);
+ }
+ minBytes = (minBytes > limit) ? limit : minBytes;
+
+ garbageLen = (minBytes > streamLen) ? (uint8_t)(minBytes - streamLen) : 0;
+
+ /* Save data for creation of multiple bit-streams. */
+ /* If bit-stream too short then add garbage at the end. */
+ if (garbageLen > 0) {
+ /* Overwrite the garbage area to avoid leaking possibly sensitive data
+ over the network. This also makes the output deterministic. */
+ memset(ptrGarbage, 0, garbageLen);
+
+ /* For a correct length of the upper-band bit-stream together
+ * with the garbage. Garbage is embeded in upper-band bit-stream.
+ * That is the only way to preserve backward compatibility. */
+ if ((instISAC->bandwidthKHz == isac8kHz) ||
+ (streamLenUB == 0)) {
+ encoded[streamLenLB] = garbageLen;
+ } else {
+ encoded[streamLenLB] += garbageLen;
+ /* Write the length of the garbage at the end of the upper-band
+ * bit-stream, if exists. This helps for sanity check. */
+ encoded[streamLenLB + 1 + streamLenUB] = garbageLen;
+
+ }
+ streamLen += garbageLen;
+ }
+ } else {
+ /* update rate model */
+ WebRtcIsac_UpdateRateModel(
+ &instISAC->rate_data_obj, streamLen,
+ instISAC->instLB.ISACencLB_obj.current_framesamples, bottleneck);
+ garbageLen = 0;
+ }
+
+ /* Generate CRC if required. */
+ if ((instISAC->bandwidthKHz != isac8kHz) && (streamLenUB > 0)) {
+ uint32_t crc;
+
+ WebRtcIsac_GetCrc((int16_t*)(&(encoded[streamLenLB + 1])),
+ streamLenUB + garbageLen, &crc);
+#ifndef WEBRTC_ARCH_BIG_ENDIAN
+ for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) {
+ encoded[streamLen - LEN_CHECK_SUM_WORD8 + k] =
+ (uint8_t)(crc >> (24 - k * 8));
+ }
+#else
+ memcpy(&encoded[streamLenLB + streamLenUB + 1], &crc, LEN_CHECK_SUM_WORD8);
+#endif
+ }
+ return streamLen;
+}
+
+
+/******************************************************************************
+ * WebRtcIsac_GetNewBitStream(...)
+ *
+ * This function returns encoded data, with the recieved bwe-index in the
+ * stream. If the rate is set to a value less than bottleneck of codec
+ * the new bistream will be re-encoded with the given target rate.
+ * It should always return a complete packet, i.e. only called once
+ * even for 60 msec frames.
+ *
+ * NOTE 1! This function does not write in the ISACStruct, it is not allowed.
+ * NOTE 2! Rates larger than the bottleneck of the codec will be limited
+ * to the current bottleneck.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - bweIndex : Index of bandwidth estimate to put in new
+ * bitstream
+ * - rate : target rate of the transcoder is bits/sec.
+ * Valid values are the accepted rate in iSAC,
+ * i.e. 10000 to 56000.
+ *
+ * Output:
+ * - encoded : The encoded data vector
+ *
+ * Return value : >0 - Length (in bytes) of coded data
+ * -1 - Error or called in SWB mode
+ * NOTE! No error code is written to
+ * the struct since it is only allowed to read
+ * the struct.
+ */
+int16_t WebRtcIsac_GetNewBitStream(ISACStruct* ISAC_main_inst,
+ int16_t bweIndex,
+ int16_t jitterInfo,
+ int32_t rate,
+ uint8_t* encoded,
+ int16_t isRCU) {
+ Bitstr iSACBitStreamInst; /* Local struct for bitstream handling */
+ int16_t streamLenLB;
+ int16_t streamLenUB;
+ int16_t totalStreamLen;
+ double gain2;
+ double gain1;
+ float scale;
+ enum ISACBandwidth bandwidthKHz;
+ double rateLB;
+ double rateUB;
+ int32_t currentBN;
+ uint32_t crc;
+#ifndef WEBRTC_ARCH_BIG_ENDIAN
+ int16_t k;
+#endif
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+
+ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
+ BIT_MASK_ENC_INIT) {
+ return -1;
+ }
+
+ /* Get the bottleneck of this iSAC and limit the
+ * given rate to the current bottleneck. */
+ WebRtcIsac_GetUplinkBw(ISAC_main_inst, &currentBN);
+ if (rate > currentBN) {
+ rate = currentBN;
+ }
+
+ if (WebRtcIsac_RateAllocation(rate, &rateLB, &rateUB, &bandwidthKHz) < 0) {
+ return -1;
+ }
+
+ /* Cannot transcode from 16 kHz to 12 kHz. */
+ if ((bandwidthKHz == isac12kHz) &&
+ (instISAC->bandwidthKHz == isac16kHz)) {
+ return -1;
+ }
+
+ /* A gain [dB] for the given rate. */
+ gain1 = WebRtcIsac_GetSnr(
+ rateLB, instISAC->instLB.ISACencLB_obj.current_framesamples);
+ /* The gain [dB] of this iSAC. */
+ gain2 = WebRtcIsac_GetSnr(
+ instISAC->instLB.ISACencLB_obj.bottleneck,
+ instISAC->instLB.ISACencLB_obj.current_framesamples);
+
+ /* Scale is the ratio of two gains in normal domain. */
+ scale = (float)pow(10, (gain1 - gain2) / 20.0);
+ /* Change the scale if this is a RCU bit-stream. */
+ scale = (isRCU) ? (scale * RCU_TRANSCODING_SCALE) : scale;
+
+ streamLenLB = WebRtcIsac_EncodeStoredDataLb(
+ &instISAC->instLB.ISACencLB_obj.SaveEnc_obj,
+ &iSACBitStreamInst, bweIndex, scale);
+
+ if (streamLenLB < 0) {
+ return -1;
+ }
+
+ /* Convert from bytes to int16_t. */
+ memcpy(encoded, iSACBitStreamInst.stream, streamLenLB);
+
+ if (bandwidthKHz == isac8kHz) {
+ return streamLenLB;
+ }
+
+ totalStreamLen = streamLenLB;
+ /* super-wideband is always at 30ms.
+ * These gains are in dB.
+ * Gain for the given rate. */
+ gain1 = WebRtcIsac_GetSnr(rateUB, FRAMESAMPLES);
+ /* Gain of this iSAC */
+ gain2 = WebRtcIsac_GetSnr(instISAC->instUB.ISACencUB_obj.bottleneck,
+ FRAMESAMPLES);
+
+ /* Scale is the ratio of two gains in normal domain. */
+ scale = (float)pow(10, (gain1 - gain2) / 20.0);
+
+ /* Change the scale if this is a RCU bit-stream. */
+ scale = (isRCU)? (scale * RCU_TRANSCODING_SCALE_UB) : scale;
+
+ streamLenUB = WebRtcIsac_EncodeStoredDataUb(
+ &(instISAC->instUB.ISACencUB_obj.SaveEnc_obj),
+ &iSACBitStreamInst, jitterInfo, scale,
+ instISAC->bandwidthKHz);
+
+ if (streamLenUB < 0) {
+ return -1;
+ }
+
+ if (streamLenUB + 1 + LEN_CHECK_SUM_WORD8 > 255) {
+ return streamLenLB;
+ }
+
+ totalStreamLen = streamLenLB + streamLenUB + 1 + LEN_CHECK_SUM_WORD8;
+ encoded[streamLenLB] = streamLenUB + 1 + LEN_CHECK_SUM_WORD8;
+
+ memcpy(&encoded[streamLenLB + 1], iSACBitStreamInst.stream,
+ streamLenUB);
+
+ WebRtcIsac_GetCrc((int16_t*)(&(encoded[streamLenLB + 1])),
+ streamLenUB, &crc);
+#ifndef WEBRTC_ARCH_BIG_ENDIAN
+ for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) {
+ encoded[totalStreamLen - LEN_CHECK_SUM_WORD8 + k] =
+ (uint8_t)((crc >> (24 - k * 8)) & 0xFF);
+ }
+#else
+ memcpy(&encoded[streamLenLB + streamLenUB + 1], &crc,
+ LEN_CHECK_SUM_WORD8);
+#endif
+ return totalStreamLen;
+}
+
+
+/****************************************************************************
+ * DecoderInitLb(...) - internal function for initialization of
+ * Lower Band
+ * DecoderInitUb(...) - internal function for initialization of
+ * Upper Band
+ * WebRtcIsac_DecoderInit(...) - API function
+ *
+ * This function initializes a ISAC instance prior to the decoder calls.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ */
+static void DecoderInitLb(ISACLBStruct* instISAC) {
+ int i;
+ /* Initialize stream vector to zero. */
+ for (i = 0; i < STREAM_SIZE_MAX_60; i++) {
+ instISAC->ISACdecLB_obj.bitstr_obj.stream[i] = 0;
+ }
+
+ WebRtcIsac_InitMasking(&instISAC->ISACdecLB_obj.maskfiltstr_obj);
+ WebRtcIsac_InitPostFilterbank(
+ &instISAC->ISACdecLB_obj.postfiltbankstr_obj);
+ WebRtcIsac_InitPitchFilter(&instISAC->ISACdecLB_obj.pitchfiltstr_obj);
+}
+
+static void DecoderInitUb(ISACUBStruct* instISAC) {
+ int i;
+ /* Init stream vector to zero */
+ for (i = 0; i < STREAM_SIZE_MAX_60; i++) {
+ instISAC->ISACdecUB_obj.bitstr_obj.stream[i] = 0;
+ }
+
+ WebRtcIsac_InitMasking(&instISAC->ISACdecUB_obj.maskfiltstr_obj);
+ WebRtcIsac_InitPostFilterbank(
+ &instISAC->ISACdecUB_obj.postfiltbankstr_obj);
+}
+
+void WebRtcIsac_DecoderInit(ISACStruct* ISAC_main_inst) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+
+ DecoderInitLb(&instISAC->instLB);
+ if (instISAC->decoderSamplingRateKHz == kIsacSuperWideband) {
+ memset(instISAC->synthesisFBState1, 0,
+ FB_STATE_SIZE_WORD32 * sizeof(int32_t));
+ memset(instISAC->synthesisFBState2, 0,
+ FB_STATE_SIZE_WORD32 * sizeof(int32_t));
+ DecoderInitUb(&(instISAC->instUB));
+ }
+ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) {
+ WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj,
+ instISAC->encoderSamplingRateKHz,
+ instISAC->decoderSamplingRateKHz);
+ }
+ instISAC->initFlag |= BIT_MASK_DEC_INIT;
+ instISAC->resetFlag_8kHz = 0;
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_UpdateBwEstimate(...)
+ *
+ * This function updates the estimate of the bandwidth.
+ *
+ * NOTE:
+ * The estimates of bandwidth is not valid if the sample rate of the far-end
+ * encoder is set to 48 kHz and send timestamps are increamented according to
+ * 48 kHz sampling rate.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - encoded : encoded ISAC frame(s).
+ * - packet_size : size of the packet.
+ * - rtp_seq_number : the RTP number of the packet.
+ * - arr_ts : the arrival time of the packet (from NetEq)
+ * in samples.
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int16_t WebRtcIsac_UpdateBwEstimate(ISACStruct* ISAC_main_inst,
+ const uint8_t* encoded,
+ size_t packet_size,
+ uint16_t rtp_seq_number,
+ uint32_t send_ts,
+ uint32_t arr_ts) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ Bitstr streamdata;
+#ifndef WEBRTC_ARCH_BIG_ENDIAN
+ int k;
+#endif
+ int16_t err;
+
+ /* Check if decoder initiated. */
+ if ((instISAC->initFlag & BIT_MASK_DEC_INIT) != BIT_MASK_DEC_INIT) {
+ instISAC->errorCode = ISAC_DECODER_NOT_INITIATED;
+ return -1;
+ }
+
+ /* Check that the size of the packet is valid, and if not return without
+ * updating the bandwidth estimate. A valid size is at least 10 bytes. */
+ if (packet_size < 10) {
+ /* Return error code if the packet length is null. */
+ instISAC->errorCode = ISAC_EMPTY_PACKET;
+ return -1;
+ }
+
+ WebRtcIsac_ResetBitstream(&(streamdata));
+
+#ifndef WEBRTC_ARCH_BIG_ENDIAN
+ for (k = 0; k < 10; k++) {
+ uint16_t ek = ((const uint16_t*)encoded)[k >> 1];
+ streamdata.stream[k] = (uint8_t)((ek >> ((k & 1) << 3)) & 0xff);
+ }
+#else
+ memcpy(streamdata.stream, encoded, 10);
+#endif
+
+ err = WebRtcIsac_EstimateBandwidth(&instISAC->bwestimator_obj, &streamdata,
+ packet_size, rtp_seq_number, send_ts,
+ arr_ts, instISAC->encoderSamplingRateKHz,
+ instISAC->decoderSamplingRateKHz);
+ if (err < 0) {
+ /* Return error code if something went wrong. */
+ instISAC->errorCode = -err;
+ return -1;
+ }
+ return 0;
+}
+
+static int Decode(ISACStruct* ISAC_main_inst,
+ const uint8_t* encoded,
+ size_t lenEncodedBytes,
+ int16_t* decoded,
+ int16_t* speechType,
+ int16_t isRCUPayload) {
+ /* Number of samples (480 or 960), output from decoder
+ that were actually used in the encoder/decoder
+ (determined on the fly). */
+ int16_t numSamplesLB;
+ int16_t numSamplesUB;
+ int16_t speechIdx;
+ float outFrame[MAX_FRAMESAMPLES];
+ int16_t outFrameLB[MAX_FRAMESAMPLES];
+ int16_t outFrameUB[MAX_FRAMESAMPLES];
+ int numDecodedBytesLBint;
+ size_t numDecodedBytesLB;
+ int numDecodedBytesUB;
+ size_t lenEncodedLBBytes;
+ int16_t validChecksum = 1;
+ int16_t k;
+ uint16_t numLayer;
+ size_t totSizeBytes;
+ int16_t err;
+
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ ISACUBDecStruct* decInstUB = &(instISAC->instUB.ISACdecUB_obj);
+ ISACLBDecStruct* decInstLB = &(instISAC->instLB.ISACdecLB_obj);
+
+ /* Check if decoder initiated. */
+ if ((instISAC->initFlag & BIT_MASK_DEC_INIT) !=
+ BIT_MASK_DEC_INIT) {
+ instISAC->errorCode = ISAC_DECODER_NOT_INITIATED;
+ return -1;
+ }
+
+ if (lenEncodedBytes == 0) {
+ /* return error code if the packet length is null. */
+ instISAC->errorCode = ISAC_EMPTY_PACKET;
+ return -1;
+ }
+
+ /* The size of the encoded lower-band is bounded by
+ * STREAM_SIZE_MAX. If a payload with the size larger than STREAM_SIZE_MAX
+ * is received, it is not considered erroneous. */
+ lenEncodedLBBytes = (lenEncodedBytes > STREAM_SIZE_MAX) ?
+ STREAM_SIZE_MAX : lenEncodedBytes;
+
+ /* Copy to lower-band bit-stream structure. */
+ memcpy(instISAC->instLB.ISACdecLB_obj.bitstr_obj.stream, encoded,
+ lenEncodedLBBytes);
+
+ /* We need to initialize numSamplesLB to something; otherwise, in the test
+ for whether we should return -1 below, the compiler might generate code
+ that fools Memcheck (Valgrind) into thinking that the control flow depends
+ on the uninitialized value in numSamplesLB (since WebRtcIsac_DecodeLb will
+ not fill it in if it fails and returns -1). */
+ numSamplesLB = 0;
+
+ /* Regardless of that the current codec is setup to work in
+ * wideband or super-wideband, the decoding of the lower-band
+ * has to be performed. */
+ numDecodedBytesLBint = WebRtcIsac_DecodeLb(&instISAC->transform_tables,
+ outFrame, decInstLB,
+ &numSamplesLB, isRCUPayload);
+ numDecodedBytesLB = (size_t)numDecodedBytesLBint;
+ if ((numDecodedBytesLBint < 0) ||
+ (numDecodedBytesLB > lenEncodedLBBytes) ||
+ (numSamplesLB > MAX_FRAMESAMPLES)) {
+ instISAC->errorCode = ISAC_LENGTH_MISMATCH;
+ return -1;
+ }
+
+ /* Error Check, we accept multi-layer bit-stream This will limit number
+ * of iterations of the while loop. Even without this the number
+ * of iterations is limited. */
+ numLayer = 1;
+ totSizeBytes = numDecodedBytesLB;
+ while (totSizeBytes != lenEncodedBytes) {
+ if ((totSizeBytes > lenEncodedBytes) ||
+ (encoded[totSizeBytes] == 0) ||
+ (numLayer > MAX_NUM_LAYERS)) {
+ instISAC->errorCode = ISAC_LENGTH_MISMATCH;
+ return -1;
+ }
+ totSizeBytes += encoded[totSizeBytes];
+ numLayer++;
+ }
+
+ if (instISAC->decoderSamplingRateKHz == kIsacWideband) {
+ for (k = 0; k < numSamplesLB; k++) {
+ if (outFrame[k] > 32767) {
+ decoded[k] = 32767;
+ } else if (outFrame[k] < -32768) {
+ decoded[k] = -32768;
+ } else {
+ decoded[k] = (int16_t)WebRtcIsac_lrint(outFrame[k]);
+ }
+ }
+ numSamplesUB = 0;
+ } else {
+ uint32_t crc;
+ /* We don't accept larger than 30ms (480 samples at lower-band)
+ * frame-size. */
+ for (k = 0; k < numSamplesLB; k++) {
+ if (outFrame[k] > 32767) {
+ outFrameLB[k] = 32767;
+ } else if (outFrame[k] < -32768) {
+ outFrameLB[k] = -32768;
+ } else {
+ outFrameLB[k] = (int16_t)WebRtcIsac_lrint(outFrame[k]);
+ }
+ }
+
+ /* Check for possible error, and if upper-band stream exists. */
+ if (numDecodedBytesLB == lenEncodedBytes) {
+ /* Decoding was successful. No super-wideband bit-stream exists. */
+ numSamplesUB = numSamplesLB;
+ memset(outFrameUB, 0, sizeof(int16_t) * numSamplesUB);
+
+ /* Prepare for the potential increase of signal bandwidth. */
+ instISAC->resetFlag_8kHz = 2;
+ } else {
+ /* This includes the checksum and the bytes that stores the length. */
+ int16_t lenNextStream = encoded[numDecodedBytesLB];
+
+ /* Is this garbage or valid super-wideband bit-stream?
+ * Check if checksum is valid. */
+ if (lenNextStream <= (LEN_CHECK_SUM_WORD8 + 1)) {
+ /* Such a small second layer cannot be super-wideband layer.
+ * It must be a short garbage. */
+ validChecksum = 0;
+ } else {
+ /* Run CRC to see if the checksum match. */
+ WebRtcIsac_GetCrc((int16_t*)(&encoded[numDecodedBytesLB + 1]),
+ lenNextStream - LEN_CHECK_SUM_WORD8 - 1, &crc);
+
+ validChecksum = 1;
+ for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) {
+ validChecksum &= (((crc >> (24 - k * 8)) & 0xFF) ==
+ encoded[numDecodedBytesLB + lenNextStream -
+ LEN_CHECK_SUM_WORD8 + k]);
+ }
+ }
+
+ if (!validChecksum) {
+ /* This is a garbage, we have received a wideband
+ * bit-stream with garbage. */
+ numSamplesUB = numSamplesLB;
+ memset(outFrameUB, 0, sizeof(int16_t) * numSamplesUB);
+ } else {
+ /* A valid super-wideband biststream exists. */
+ enum ISACBandwidth bandwidthKHz;
+ int32_t maxDelayBit;
+
+ /* If we have super-wideband bit-stream, we cannot
+ * have 60 ms frame-size. */
+ if (numSamplesLB > FRAMESAMPLES) {
+ instISAC->errorCode = ISAC_LENGTH_MISMATCH;
+ return -1;
+ }
+
+ /* The rest of the bit-stream contains the upper-band
+ * bit-stream curently this is the only thing there,
+ * however, we might add more layers. */
+
+ /* Have to exclude one byte where the length is stored
+ * and last 'LEN_CHECK_SUM_WORD8' bytes where the
+ * checksum is stored. */
+ lenNextStream -= (LEN_CHECK_SUM_WORD8 + 1);
+
+ memcpy(decInstUB->bitstr_obj.stream,
+ &encoded[numDecodedBytesLB + 1], lenNextStream);
+
+ /* Reset bit-stream object, this is the first decoding. */
+ WebRtcIsac_ResetBitstream(&(decInstUB->bitstr_obj));
+
+ /* Decode jitter information. */
+ err = WebRtcIsac_DecodeJitterInfo(&decInstUB->bitstr_obj, &maxDelayBit);
+ if (err < 0) {
+ instISAC->errorCode = -err;
+ return -1;
+ }
+
+ /* Update jitter info which is in the upper-band bit-stream
+ * only if the encoder is in super-wideband. Otherwise,
+ * the jitter info is already embedded in bandwidth index
+ * and has been updated. */
+ if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) {
+ err = WebRtcIsac_UpdateUplinkJitter(
+ &(instISAC->bwestimator_obj), maxDelayBit);
+ if (err < 0) {
+ instISAC->errorCode = -err;
+ return -1;
+ }
+ }
+
+ /* Decode bandwidth information. */
+ err = WebRtcIsac_DecodeBandwidth(&decInstUB->bitstr_obj,
+ &bandwidthKHz);
+ if (err < 0) {
+ instISAC->errorCode = -err;
+ return -1;
+ }
+
+ switch (bandwidthKHz) {
+ case isac12kHz: {
+ numDecodedBytesUB = WebRtcIsac_DecodeUb12(
+ &instISAC->transform_tables, outFrame, decInstUB, isRCUPayload);
+
+ /* Hang-over for transient alleviation -
+ * wait two frames to add the upper band going up from 8 kHz. */
+ if (instISAC->resetFlag_8kHz > 0) {
+ if (instISAC->resetFlag_8kHz == 2) {
+ /* Silence first and a half frame. */
+ memset(outFrame, 0, MAX_FRAMESAMPLES *
+ sizeof(float));
+ } else {
+ const float rampStep = 2.0f / MAX_FRAMESAMPLES;
+ float rampVal = 0;
+ memset(outFrame, 0, (MAX_FRAMESAMPLES >> 1) *
+ sizeof(float));
+
+ /* Ramp up second half of second frame. */
+ for (k = MAX_FRAMESAMPLES / 2; k < MAX_FRAMESAMPLES; k++) {
+ outFrame[k] *= rampVal;
+ rampVal += rampStep;
+ }
+ }
+ instISAC->resetFlag_8kHz -= 1;
+ }
+
+ break;
+ }
+ case isac16kHz: {
+ numDecodedBytesUB = WebRtcIsac_DecodeUb16(
+ &instISAC->transform_tables, outFrame, decInstUB, isRCUPayload);
+ break;
+ }
+ default:
+ return -1;
+ }
+
+ /* It might be less due to garbage. */
+ if ((numDecodedBytesUB != lenNextStream) &&
+ (numDecodedBytesUB != (lenNextStream -
+ encoded[numDecodedBytesLB + 1 + numDecodedBytesUB]))) {
+ instISAC->errorCode = ISAC_LENGTH_MISMATCH;
+ return -1;
+ }
+
+ /* If there is no error Upper-band always decodes
+ * 30 ms (480 samples). */
+ numSamplesUB = FRAMESAMPLES;
+
+ /* Convert to W16. */
+ for (k = 0; k < numSamplesUB; k++) {
+ if (outFrame[k] > 32767) {
+ outFrameUB[k] = 32767;
+ } else if (outFrame[k] < -32768) {
+ outFrameUB[k] = -32768;
+ } else {
+ outFrameUB[k] = (int16_t)WebRtcIsac_lrint(
+ outFrame[k]);
+ }
+ }
+ }
+ }
+
+ speechIdx = 0;
+ while (speechIdx < numSamplesLB) {
+ WebRtcSpl_SynthesisQMF(&outFrameLB[speechIdx], &outFrameUB[speechIdx],
+ FRAMESAMPLES_10ms, &decoded[(speechIdx << 1)],
+ instISAC->synthesisFBState1,
+ instISAC->synthesisFBState2);
+
+ speechIdx += FRAMESAMPLES_10ms;
+ }
+ }
+ *speechType = 0;
+ return (numSamplesLB + numSamplesUB);
+}
+
+
+
+
+
+
+
+/****************************************************************************
+ * WebRtcIsac_Decode(...)
+ *
+ * This function decodes a ISAC frame. Output speech length
+ * will be a multiple of 480 samples: 480 or 960 samples,
+ * depending on the frameSize (30 or 60 ms).
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - encoded : encoded ISAC frame(s)
+ * - len : bytes in encoded vector
+ *
+ * Output:
+ * - decoded : The decoded vector
+ *
+ * Return value : >0 - number of samples in decoded vector
+ * -1 - Error
+ */
+
+int WebRtcIsac_Decode(ISACStruct* ISAC_main_inst,
+ const uint8_t* encoded,
+ size_t lenEncodedBytes,
+ int16_t* decoded,
+ int16_t* speechType) {
+ int16_t isRCUPayload = 0;
+ return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded,
+ speechType, isRCUPayload);
+}
+
+/****************************************************************************
+ * WebRtcIsac_DecodeRcu(...)
+ *
+ * This function decodes a redundant (RCU) iSAC frame. Function is called in
+ * NetEq with a stored RCU payload in case of packet loss. Output speech length
+ * will be a multiple of 480 samples: 480 or 960 samples,
+ * depending on the framesize (30 or 60 ms).
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - encoded : encoded ISAC RCU frame(s)
+ * - len : bytes in encoded vector
+ *
+ * Output:
+ * - decoded : The decoded vector
+ *
+ * Return value : >0 - number of samples in decoded vector
+ * -1 - Error
+ */
+
+
+
+int WebRtcIsac_DecodeRcu(ISACStruct* ISAC_main_inst,
+ const uint8_t* encoded,
+ size_t lenEncodedBytes,
+ int16_t* decoded,
+ int16_t* speechType) {
+ int16_t isRCUPayload = 1;
+ return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded,
+ speechType, isRCUPayload);
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_DecodePlc(...)
+ *
+ * This function conducts PLC for ISAC frame(s). Output speech length
+ * will be a multiple of 480 samples: 480 or 960 samples,
+ * depending on the frameSize (30 or 60 ms).
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - noOfLostFrames : Number of PLC frames to produce
+ *
+ * Output:
+ * - decoded : The decoded vector
+ *
+ * Return value : Number of samples in decoded PLC vector
+ */
+size_t WebRtcIsac_DecodePlc(ISACStruct* ISAC_main_inst,
+ int16_t* decoded,
+ size_t noOfLostFrames) {
+ size_t numSamples = 0;
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+
+ /* Limit number of frames to two = 60 millisecond.
+ * Otherwise we exceed data vectors. */
+ if (noOfLostFrames > 2) {
+ noOfLostFrames = 2;
+ }
+
+ /* Get the number of samples per frame */
+ switch (instISAC->decoderSamplingRateKHz) {
+ case kIsacWideband: {
+ numSamples = 480 * noOfLostFrames;
+ break;
+ }
+ case kIsacSuperWideband: {
+ numSamples = 960 * noOfLostFrames;
+ break;
+ }
+ }
+
+ /* Set output samples to zero. */
+ memset(decoded, 0, numSamples * sizeof(int16_t));
+ return numSamples;
+}
+
+
+/****************************************************************************
+ * ControlLb(...) - Internal function for controlling Lower Band
+ * ControlUb(...) - Internal function for controlling Upper Band
+ * WebRtcIsac_Control(...) - API function
+ *
+ * This function sets the limit on the short-term average bit rate and the
+ * frame length. Should be used only in Instantaneous mode.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - rate : limit on the short-term average bit rate,
+ * in bits/second (between 10000 and 32000)
+ * - frameSize : number of milliseconds per frame (30 or 60)
+ *
+ * Return value : 0 - ok
+ * -1 - Error
+ */
+static int16_t ControlLb(ISACLBStruct* instISAC, double rate,
+ int16_t frameSize) {
+ if ((rate >= 10000) && (rate <= 32000)) {
+ instISAC->ISACencLB_obj.bottleneck = rate;
+ } else {
+ return -ISAC_DISALLOWED_BOTTLENECK;
+ }
+
+ if ((frameSize == 30) || (frameSize == 60)) {
+ instISAC->ISACencLB_obj.new_framelength = (FS / 1000) * frameSize;
+ } else {
+ return -ISAC_DISALLOWED_FRAME_LENGTH;
+ }
+
+ return 0;
+}
+
+static int16_t ControlUb(ISACUBStruct* instISAC, double rate) {
+ if ((rate >= 10000) && (rate <= 32000)) {
+ instISAC->ISACencUB_obj.bottleneck = rate;
+ } else {
+ return -ISAC_DISALLOWED_BOTTLENECK;
+ }
+ return 0;
+}
+
+int16_t WebRtcIsac_Control(ISACStruct* ISAC_main_inst,
+ int32_t bottleneckBPS,
+ int frameSize) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ int16_t status;
+ double rateLB;
+ double rateUB;
+ enum ISACBandwidth bandwidthKHz;
+
+ if (instISAC->codingMode == 0) {
+ /* In adaptive mode. */
+ instISAC->errorCode = ISAC_MODE_MISMATCH;
+ return -1;
+ }
+
+ /* Check if encoder initiated */
+ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
+ BIT_MASK_ENC_INIT) {
+ instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
+ return -1;
+ }
+
+ if (instISAC->encoderSamplingRateKHz == kIsacWideband) {
+ /* If the sampling rate is 16kHz then bandwith should be 8kHz,
+ * regardless of bottleneck. */
+ bandwidthKHz = isac8kHz;
+ rateLB = (bottleneckBPS > 32000) ? 32000 : bottleneckBPS;
+ rateUB = 0;
+ } else {
+ if (WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB,
+ &bandwidthKHz) < 0) {
+ return -1;
+ }
+ }
+
+ if ((instISAC->encoderSamplingRateKHz == kIsacSuperWideband) &&
+ (frameSize != 30) &&
+ (bandwidthKHz != isac8kHz)) {
+ /* Cannot have 60 ms in super-wideband. */
+ instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH;
+ return -1;
+ }
+
+ status = ControlLb(&instISAC->instLB, rateLB, (int16_t)frameSize);
+ if (status < 0) {
+ instISAC->errorCode = -status;
+ return -1;
+ }
+ if (bandwidthKHz != isac8kHz) {
+ status = ControlUb(&(instISAC->instUB), rateUB);
+ if (status < 0) {
+ instISAC->errorCode = -status;
+ return -1;
+ }
+ }
+
+
+ /* Check if bandwidth is changing from wideband to super-wideband
+ * then we have to synch data buffer of lower & upper-band. Also
+ * clean up the upper-band data buffer. */
+
+ if ((instISAC->bandwidthKHz == isac8kHz) && (bandwidthKHz != isac8kHz)) {
+ memset(instISAC->instUB.ISACencUB_obj.data_buffer_float, 0,
+ sizeof(float) * (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES));
+
+ if (bandwidthKHz == isac12kHz) {
+ instISAC->instUB.ISACencUB_obj.buffer_index =
+ instISAC->instLB.ISACencLB_obj.buffer_index;
+ } else {
+ instISAC->instUB.ISACencUB_obj.buffer_index =
+ LB_TOTAL_DELAY_SAMPLES + instISAC->instLB.ISACencLB_obj.buffer_index;
+
+ memcpy(&(instISAC->instUB.ISACencUB_obj.lastLPCVec),
+ WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER);
+ }
+ }
+
+ /* Update the payload limit if the bandwidth is changing. */
+ if (instISAC->bandwidthKHz != bandwidthKHz) {
+ instISAC->bandwidthKHz = bandwidthKHz;
+ UpdatePayloadSizeLimit(instISAC);
+ }
+ instISAC->bottleneck = bottleneckBPS;
+ return 0;
+}
+
+void WebRtcIsac_SetInitialBweBottleneck(ISACStruct* ISAC_main_inst,
+ int bottleneck_bits_per_second) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ assert(bottleneck_bits_per_second >= 10000 &&
+ bottleneck_bits_per_second <= 32000);
+ instISAC->bwestimator_obj.send_bw_avg = (float)bottleneck_bits_per_second;
+}
+
+/****************************************************************************
+ * WebRtcIsac_ControlBwe(...)
+ *
+ * This function sets the initial values of bottleneck and frame-size if
+ * iSAC is used in channel-adaptive mode. Through this API, users can
+ * enforce a frame-size for all values of bottleneck. Then iSAC will not
+ * automatically change the frame-size.
+ *
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - rateBPS : initial value of bottleneck in bits/second
+ * 10000 <= rateBPS <= 32000 is accepted
+ * For default bottleneck set rateBPS = 0
+ * - frameSizeMs : number of milliseconds per frame (30 or 60)
+ * - enforceFrameSize : 1 to enforce the given frame-size through out
+ * the adaptation process, 0 to let iSAC change
+ * the frame-size if required.
+ *
+ * Return value : 0 - ok
+ * -1 - Error
+ */
+int16_t WebRtcIsac_ControlBwe(ISACStruct* ISAC_main_inst,
+ int32_t bottleneckBPS,
+ int frameSizeMs,
+ int16_t enforceFrameSize) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ enum ISACBandwidth bandwidth;
+
+ /* Check if encoder initiated */
+ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
+ BIT_MASK_ENC_INIT) {
+ instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
+ return -1;
+ }
+
+ /* Check that we are in channel-adaptive mode, otherwise, return (-1) */
+ if (instISAC->codingMode != 0) {
+ instISAC->errorCode = ISAC_MODE_MISMATCH;
+ return -1;
+ }
+ if ((frameSizeMs != 30) &&
+ (instISAC->encoderSamplingRateKHz == kIsacSuperWideband)) {
+ return -1;
+ }
+
+ /* Set structure variable if enforceFrameSize is set. ISAC will then
+ * keep the chosen frame size. */
+ if (enforceFrameSize != 0) {
+ instISAC->instLB.ISACencLB_obj.enforceFrameSize = 1;
+ } else {
+ instISAC->instLB.ISACencLB_obj.enforceFrameSize = 0;
+ }
+
+ /* Set the initial rate. If the input value is zero then the default intial
+ * rate is used. Otehrwise, values between 10 to 32 kbps are accepted. */
+ if (bottleneckBPS != 0) {
+ double rateLB;
+ double rateUB;
+ if (WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB,
+ &bandwidth) < 0) {
+ return -1;
+ }
+ instISAC->bwestimator_obj.send_bw_avg = (float)bottleneckBPS;
+ instISAC->bandwidthKHz = bandwidth;
+ }
+
+ /* Set the initial frame-size. If 'enforceFrameSize' is set, the frame-size
+ * will not change */
+ if (frameSizeMs != 0) {
+ if ((frameSizeMs == 30) || (frameSizeMs == 60)) {
+ instISAC->instLB.ISACencLB_obj.new_framelength =
+ (int16_t)((FS / 1000) * frameSizeMs);
+ } else {
+ instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_GetDownLinkBwIndex(...)
+ *
+ * This function returns index representing the Bandwidth estimate from
+ * the other side to this side.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC structure
+ *
+ * Output:
+ * - bweIndex : Bandwidth estimate to transmit to other side.
+ *
+ */
+int16_t WebRtcIsac_GetDownLinkBwIndex(ISACStruct* ISAC_main_inst,
+ int16_t* bweIndex,
+ int16_t* jitterInfo) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+
+ /* Check if encoder initialized. */
+ if ((instISAC->initFlag & BIT_MASK_DEC_INIT) !=
+ BIT_MASK_DEC_INIT) {
+ instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
+ return -1;
+ }
+
+ /* Call function to get Bandwidth Estimate. */
+ WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj), bweIndex,
+ jitterInfo,
+ instISAC->decoderSamplingRateKHz);
+ return 0;
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_UpdateUplinkBw(...)
+ *
+ * This function takes an index representing the Bandwidth estimate from
+ * this side to other side and updates BWE.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC structure
+ * - rateIndex : Bandwidth estimate from other side.
+ *
+ * Return value : 0 - ok
+ * -1 - index out of range
+ */
+int16_t WebRtcIsac_UpdateUplinkBw(ISACStruct* ISAC_main_inst,
+ int16_t bweIndex) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ int16_t returnVal;
+
+ /* Check if encoder initiated. */
+ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
+ BIT_MASK_ENC_INIT) {
+ instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
+ return -1;
+ }
+
+ /* Call function to get Bandwidth Estimate. */
+ returnVal = WebRtcIsac_UpdateUplinkBwImpl(
+ &(instISAC->bwestimator_obj), bweIndex,
+ instISAC->encoderSamplingRateKHz);
+
+ if (returnVal < 0) {
+ instISAC->errorCode = -returnVal;
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_ReadBwIndex(...)
+ *
+ * This function returns the index of the Bandwidth estimate from the
+ * bit-stream.
+ *
+ * Input:
+ * - encoded : Encoded bit-stream
+ *
+ * Output:
+ * - frameLength : Length of frame in packet (in samples)
+ * - bweIndex : Bandwidth estimate in bit-stream
+ *
+ */
+int16_t WebRtcIsac_ReadBwIndex(const uint8_t* encoded,
+ int16_t* bweIndex) {
+ Bitstr streamdata;
+#ifndef WEBRTC_ARCH_BIG_ENDIAN
+ int k;
+#endif
+ int16_t err;
+
+ WebRtcIsac_ResetBitstream(&(streamdata));
+
+#ifndef WEBRTC_ARCH_BIG_ENDIAN
+ for (k = 0; k < 10; k++) {
+ int16_t ek2 = ((const int16_t*)encoded)[k >> 1];
+ streamdata.stream[k] = (uint8_t)((ek2 >> ((k & 1) << 3)) & 0xff);
+ }
+#else
+ memcpy(streamdata.stream, encoded, 10);
+#endif
+
+ /* Decode frame length. */
+ err = WebRtcIsac_DecodeFrameLen(&streamdata, bweIndex);
+ if (err < 0) {
+ return err;
+ }
+
+ /* Decode BW estimation. */
+ err = WebRtcIsac_DecodeSendBW(&streamdata, bweIndex);
+ if (err < 0) {
+ return err;
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_ReadFrameLen(...)
+ *
+ * This function returns the number of samples the decoder will generate if
+ * the given payload is decoded.
+ *
+ * Input:
+ * - encoded : Encoded bitstream
+ *
+ * Output:
+ * - frameLength : Length of frame in packet (in samples)
+ *
+ */
+int16_t WebRtcIsac_ReadFrameLen(ISACStruct* ISAC_main_inst,
+ const uint8_t* encoded,
+ int16_t* frameLength) {
+ Bitstr streamdata;
+#ifndef WEBRTC_ARCH_BIG_ENDIAN
+ int k;
+#endif
+ int16_t err;
+ ISACMainStruct* instISAC;
+
+ WebRtcIsac_ResetBitstream(&(streamdata));
+
+#ifndef WEBRTC_ARCH_BIG_ENDIAN
+ for (k = 0; k < 10; k++) {
+ int16_t ek2 = ((const int16_t*)encoded)[k >> 1];
+ streamdata.stream[k] = (uint8_t)((ek2 >> ((k & 1) << 3)) & 0xff);
+ }
+#else
+ memcpy(streamdata.stream, encoded, 10);
+#endif
+
+ /* Decode frame length. */
+ err = WebRtcIsac_DecodeFrameLen(&streamdata, frameLength);
+ if (err < 0) {
+ return -1;
+ }
+ instISAC = (ISACMainStruct*)ISAC_main_inst;
+
+ if (instISAC->decoderSamplingRateKHz == kIsacSuperWideband) {
+ /* The decoded frame length indicates the number of samples in
+ * lower-band in this case, multiply by 2 to get the total number
+ * of samples. */
+ *frameLength <<= 1;
+ }
+ return 0;
+}
+
+
+/*******************************************************************************
+ * WebRtcIsac_GetNewFrameLen(...)
+ *
+ * This function returns the frame length (in samples) of the next packet.
+ * In the case of channel-adaptive mode, iSAC decides on its frame length based
+ * on the estimated bottleneck, this AOI allows a user to prepare for the next
+ * packet (at the encoder).
+ *
+ * The primary usage is in CE to make the iSAC works in channel-adaptive mode
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC struct
+ *
+ * Return Value : frame lenght in samples
+ *
+ */
+int16_t WebRtcIsac_GetNewFrameLen(ISACStruct* ISAC_main_inst) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+
+ /* Return new frame length. */
+ if (instISAC->in_sample_rate_hz == 16000)
+ return (instISAC->instLB.ISACencLB_obj.new_framelength);
+ else /* 32000 Hz */
+ return ((instISAC->instLB.ISACencLB_obj.new_framelength) * 2);
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_GetErrorCode(...)
+ *
+ * This function can be used to check the error code of an iSAC instance.
+ * When a function returns -1 an error code will be set for that instance.
+ * The function below extracts the code of the last error that occurred in
+ * the specified instance.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance
+ *
+ * Return value : Error code
+ */
+int16_t WebRtcIsac_GetErrorCode(ISACStruct* ISAC_main_inst) {
+ return ((ISACMainStruct*)ISAC_main_inst)->errorCode;
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_GetUplinkBw(...)
+ *
+ * This function outputs the target bottleneck of the codec. In
+ * channel-adaptive mode, the target bottleneck is specified through an in-band
+ * signalling retrieved by bandwidth estimator.
+ * In channel-independent, also called instantaneous mode, the target
+ * bottleneck is provided to the encoder by calling xxx_control(...) (if
+ * xxx_control is never called, the default values are used.).
+ * Note that the output is the iSAC internal operating bottleneck which might
+ * differ slightly from the one provided through xxx_control().
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ *
+ * Output:
+ * - *bottleneck : bottleneck in bits/sec
+ *
+ * Return value : -1 if error happens
+ * 0 bit-rates computed correctly.
+ */
+int16_t WebRtcIsac_GetUplinkBw(ISACStruct* ISAC_main_inst,
+ int32_t* bottleneck) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+
+ if (instISAC->codingMode == 0) {
+ /* We are in adaptive mode then get the bottleneck from BWE. */
+ *bottleneck = (int32_t)instISAC->bwestimator_obj.send_bw_avg;
+ } else {
+ *bottleneck = instISAC->bottleneck;
+ }
+
+ if ((*bottleneck > 32000) && (*bottleneck < 38000)) {
+ *bottleneck = 32000;
+ } else if ((*bottleneck > 45000) && (*bottleneck < 50000)) {
+ *bottleneck = 45000;
+ } else if (*bottleneck > 56000) {
+ *bottleneck = 56000;
+ }
+ return 0;
+}
+
+
+/******************************************************************************
+ * WebRtcIsac_SetMaxPayloadSize(...)
+ *
+ * This function sets a limit for the maximum payload size of iSAC. The same
+ * value is used both for 30 and 60 ms packets. If the encoder sampling rate
+ * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the
+ * encoder sampling rate is 32 kHz the maximum payload size is between 120
+ * and 600 bytes.
+ *
+ * ---------------
+ * IMPORTANT NOTES
+ * ---------------
+ * The size of a packet is limited to the minimum of 'max-payload-size' and
+ * 'max-rate.' For instance, let's assume the max-payload-size is set to
+ * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
+ * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
+ * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
+ * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
+ * 170 bytes, i.e. min(170, 300).
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ * - maxPayloadBytes : maximum size of the payload in bytes
+ * valid values are between 100 and 400 bytes
+ * if encoder sampling rate is 16 kHz. For
+ * 32 kHz encoder sampling rate valid values
+ * are between 100 and 600 bytes.
+ *
+ * Return value : 0 if successful
+ * -1 if error happens
+ */
+int16_t WebRtcIsac_SetMaxPayloadSize(ISACStruct* ISAC_main_inst,
+ int16_t maxPayloadBytes) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ int16_t status = 0;
+
+ /* Check if encoder initiated */
+ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
+ BIT_MASK_ENC_INIT) {
+ instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
+ return -1;
+ }
+
+ if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) {
+ /* Sanity check. */
+ if (maxPayloadBytes < 120) {
+ /* 'maxRate' is out of valid range
+ * set to the acceptable value and return -1. */
+ maxPayloadBytes = 120;
+ status = -1;
+ }
+
+ /* sanity check */
+ if (maxPayloadBytes > STREAM_SIZE_MAX) {
+ /* maxRate is out of valid range,
+ * set to the acceptable value and return -1. */
+ maxPayloadBytes = STREAM_SIZE_MAX;
+ status = -1;
+ }
+ } else {
+ if (maxPayloadBytes < 120) {
+ /* Max payload-size is out of valid range
+ * set to the acceptable value and return -1. */
+ maxPayloadBytes = 120;
+ status = -1;
+ }
+ if (maxPayloadBytes > STREAM_SIZE_MAX_60) {
+ /* Max payload-size is out of valid range
+ * set to the acceptable value and return -1. */
+ maxPayloadBytes = STREAM_SIZE_MAX_60;
+ status = -1;
+ }
+ }
+ instISAC->maxPayloadSizeBytes = maxPayloadBytes;
+ UpdatePayloadSizeLimit(instISAC);
+ return status;
+}
+
+
+/******************************************************************************
+ * WebRtcIsac_SetMaxRate(...)
+ *
+ * This function sets the maximum rate which the codec may not exceed for
+ * any signal packet. The maximum rate is defined and payload-size per
+ * frame-size in bits per second.
+ *
+ * The codec has a maximum rate of 53400 bits per second (200 bytes per 30
+ * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms)
+ * if the encoder sampling rate is 32 kHz.
+ *
+ * It is possible to set a maximum rate between 32000 and 53400 bits/sec
+ * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode.
+ *
+ * ---------------
+ * IMPORTANT NOTES
+ * ---------------
+ * The size of a packet is limited to the minimum of 'max-payload-size' and
+ * 'max-rate.' For instance, let's assume the max-payload-size is set to
+ * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
+ * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
+ * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
+ * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
+ * 170 bytes, min(170, 300).
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ * - maxRate : maximum rate in bits per second,
+ * valid values are 32000 to 53400 bits/sec in
+ * wideband mode, and 32000 to 160000 bits/sec in
+ * super-wideband mode.
+ *
+ * Return value : 0 if successful
+ * -1 if error happens
+ */
+int16_t WebRtcIsac_SetMaxRate(ISACStruct* ISAC_main_inst,
+ int32_t maxRate) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ int16_t maxRateInBytesPer30Ms;
+ int16_t status = 0;
+
+ /* check if encoder initiated */
+ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) {
+ instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
+ return -1;
+ }
+ /* Calculate maximum number of bytes per 30 msec packets for the
+ given maximum rate. Multiply with 30/1000 to get number of
+ bits per 30 ms, divide by 8 to get number of bytes per 30 ms:
+ maxRateInBytes = floor((maxRate * 30/1000) / 8); */
+ maxRateInBytesPer30Ms = (int16_t)(maxRate * 3 / 800);
+
+ if (instISAC->encoderSamplingRateKHz == kIsacWideband) {
+ if (maxRate < 32000) {
+ /* 'maxRate' is out of valid range.
+ * Set to the acceptable value and return -1. */
+ maxRateInBytesPer30Ms = 120;
+ status = -1;
+ }
+
+ if (maxRate > 53400) {
+ /* 'maxRate' is out of valid range.
+ * Set to the acceptable value and return -1. */
+ maxRateInBytesPer30Ms = 200;
+ status = -1;
+ }
+ } else {
+ if (maxRateInBytesPer30Ms < 120) {
+ /* 'maxRate' is out of valid range
+ * Set to the acceptable value and return -1. */
+ maxRateInBytesPer30Ms = 120;
+ status = -1;
+ }
+
+ if (maxRateInBytesPer30Ms > STREAM_SIZE_MAX) {
+ /* 'maxRate' is out of valid range.
+ * Set to the acceptable value and return -1. */
+ maxRateInBytesPer30Ms = STREAM_SIZE_MAX;
+ status = -1;
+ }
+ }
+ instISAC->maxRateBytesPer30Ms = maxRateInBytesPer30Ms;
+ UpdatePayloadSizeLimit(instISAC);
+ return status;
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_GetRedPayload(...)
+ *
+ * This function populates "encoded" with the redundant payload of the recently
+ * encodedframe. This function has to be called once that WebRtcIsac_Encode(...)
+ * returns a positive value. Regardless of the frame-size this function will
+ * be called only once after encoding is completed. The bit-stream is
+ * targeted for 16000 bit/sec.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC struct
+ *
+ * Output:
+ * - encoded : the encoded data vector
+ *
+ *
+ * Return value : >0 - Length (in bytes) of coded data
+ * : -1 - Error
+ */
+int16_t WebRtcIsac_GetRedPayload(ISACStruct* ISAC_main_inst,
+ uint8_t* encoded) {
+ Bitstr iSACBitStreamInst;
+ int16_t streamLenLB;
+ int16_t streamLenUB;
+ int16_t streamLen;
+ int16_t totalLenUB;
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+#ifndef WEBRTC_ARCH_BIG_ENDIAN
+ int k;
+#endif
+
+ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
+ BIT_MASK_ENC_INIT) {
+ instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
+ }
+
+ WebRtcIsac_ResetBitstream(&(iSACBitStreamInst));
+
+ streamLenLB = WebRtcIsac_EncodeStoredDataLb(
+ &instISAC->instLB.ISACencLB_obj.SaveEnc_obj,
+ &iSACBitStreamInst,
+ instISAC->instLB.ISACencLB_obj.lastBWIdx,
+ RCU_TRANSCODING_SCALE);
+ if (streamLenLB < 0) {
+ return -1;
+ }
+
+ /* convert from bytes to int16_t. */
+ memcpy(encoded, iSACBitStreamInst.stream, streamLenLB);
+ streamLen = streamLenLB;
+ if (instISAC->bandwidthKHz == isac8kHz) {
+ return streamLenLB;
+ }
+
+ streamLenUB = WebRtcIsac_GetRedPayloadUb(
+ &instISAC->instUB.ISACencUB_obj.SaveEnc_obj,
+ &iSACBitStreamInst, instISAC->bandwidthKHz);
+ if (streamLenUB < 0) {
+ /* An error has happened but this is not the error due to a
+ * bit-stream larger than the limit. */
+ return -1;
+ }
+
+ /* We have one byte to write the total length of the upper-band.
+ * The length includes the bit-stream length, check-sum and the
+ * single byte where the length is written to. This is according to
+ * iSAC wideband and how the "garbage" is dealt. */
+ totalLenUB = streamLenUB + 1 + LEN_CHECK_SUM_WORD8;
+ if (totalLenUB > 255) {
+ streamLenUB = 0;
+ }
+
+ /* Generate CRC if required. */
+ if ((instISAC->bandwidthKHz != isac8kHz) &&
+ (streamLenUB > 0)) {
+ uint32_t crc;
+ streamLen += totalLenUB;
+ encoded[streamLenLB] = (uint8_t)totalLenUB;
+ memcpy(&encoded[streamLenLB + 1], iSACBitStreamInst.stream,
+ streamLenUB);
+
+ WebRtcIsac_GetCrc((int16_t*)(&(encoded[streamLenLB + 1])),
+ streamLenUB, &crc);
+#ifndef WEBRTC_ARCH_BIG_ENDIAN
+ for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) {
+ encoded[streamLen - LEN_CHECK_SUM_WORD8 + k] =
+ (uint8_t)((crc >> (24 - k * 8)) & 0xFF);
+ }
+#else
+ memcpy(&encoded[streamLenLB + streamLenUB + 1], &crc,
+ LEN_CHECK_SUM_WORD8);
+#endif
+ }
+ return streamLen;
+}
+
+
+/****************************************************************************
+ * WebRtcIsac_version(...)
+ *
+ * This function returns the version number.
+ *
+ * Output:
+ * - version : Pointer to character string
+ *
+ */
+void WebRtcIsac_version(char* version) {
+ strcpy(version, "4.3.0");
+}
+
+
+/******************************************************************************
+ * WebRtcIsac_SetEncSampRate()
+ * This function sets the sampling rate of the encoder. Initialization of the
+ * encoder WILL NOT overwrite the sampling rate of the encoder. The default
+ * value is 16 kHz which is set when the instance is created. The encoding-mode
+ * and the bottleneck remain unchanged by this call, however, the maximum rate
+ * and maximum payload-size will be reset to their default values.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ * - sample_rate_hz : sampling rate in Hertz, valid values are 16000
+ * and 32000.
+ *
+ * Return value : 0 if successful
+ * -1 if failed.
+ */
+int16_t WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst,
+ uint16_t sample_rate_hz) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ enum IsacSamplingRate encoder_operational_rate;
+
+ if ((sample_rate_hz != 16000) && (sample_rate_hz != 32000)) {
+ /* Sampling Frequency is not supported. */
+ instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY;
+ return -1;
+ }
+ if (sample_rate_hz == 16000) {
+ encoder_operational_rate = kIsacWideband;
+ } else {
+ encoder_operational_rate = kIsacSuperWideband;
+ }
+
+ if ((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
+ BIT_MASK_ENC_INIT) {
+ if (encoder_operational_rate == kIsacWideband) {
+ instISAC->bandwidthKHz = isac8kHz;
+ } else {
+ instISAC->bandwidthKHz = isac16kHz;
+ }
+ } else {
+ ISACUBStruct* instUB = &(instISAC->instUB);
+ ISACLBStruct* instLB = &(instISAC->instLB);
+ int32_t bottleneck = instISAC->bottleneck;
+ int16_t codingMode = instISAC->codingMode;
+ int16_t frameSizeMs = instLB->ISACencLB_obj.new_framelength /
+ (FS / 1000);
+
+ if ((encoder_operational_rate == kIsacWideband) &&
+ (instISAC->encoderSamplingRateKHz == kIsacSuperWideband)) {
+ /* Changing from super-wideband to wideband.
+ * we don't need to re-initialize the encoder of the lower-band. */
+ instISAC->bandwidthKHz = isac8kHz;
+ if (codingMode == 1) {
+ ControlLb(instLB,
+ (bottleneck > 32000) ? 32000 : bottleneck, FRAMESIZE);
+ }
+ instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60;
+ instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30;
+ } else if ((encoder_operational_rate == kIsacSuperWideband) &&
+ (instISAC->encoderSamplingRateKHz == kIsacWideband)) {
+ double bottleneckLB = 0;
+ double bottleneckUB = 0;
+ if (codingMode == 1) {
+ WebRtcIsac_RateAllocation(bottleneck, &bottleneckLB, &bottleneckUB,
+ &(instISAC->bandwidthKHz));
+ }
+
+ instISAC->bandwidthKHz = isac16kHz;
+ instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX;
+ instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX;
+
+ EncoderInitLb(instLB, codingMode, encoder_operational_rate);
+ EncoderInitUb(instUB, instISAC->bandwidthKHz);
+
+ memset(instISAC->analysisFBState1, 0,
+ FB_STATE_SIZE_WORD32 * sizeof(int32_t));
+ memset(instISAC->analysisFBState2, 0,
+ FB_STATE_SIZE_WORD32 * sizeof(int32_t));
+
+ if (codingMode == 1) {
+ instISAC->bottleneck = bottleneck;
+ ControlLb(instLB, bottleneckLB,
+ (instISAC->bandwidthKHz == isac8kHz) ? frameSizeMs:FRAMESIZE);
+ if (instISAC->bandwidthKHz > isac8kHz) {
+ ControlUb(instUB, bottleneckUB);
+ }
+ } else {
+ instLB->ISACencLB_obj.enforceFrameSize = 0;
+ instLB->ISACencLB_obj.new_framelength = FRAMESAMPLES;
+ }
+ }
+ }
+ instISAC->encoderSamplingRateKHz = encoder_operational_rate;
+ instISAC->in_sample_rate_hz = sample_rate_hz;
+ return 0;
+}
+
+
+/******************************************************************************
+ * WebRtcIsac_SetDecSampRate()
+ * This function sets the sampling rate of the decoder. Initialization of the
+ * decoder WILL NOT overwrite the sampling rate of the encoder. The default
+ * value is 16 kHz which is set when the instance is created.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ * - sample_rate_hz : sampling rate in Hertz, valid values are 16000
+ * and 32000.
+ *
+ * Return value : 0 if successful
+ * -1 if failed.
+ */
+int16_t WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst,
+ uint16_t sample_rate_hz) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ enum IsacSamplingRate decoder_operational_rate;
+
+ if (sample_rate_hz == 16000) {
+ decoder_operational_rate = kIsacWideband;
+ } else if (sample_rate_hz == 32000) {
+ decoder_operational_rate = kIsacSuperWideband;
+ } else {
+ /* Sampling Frequency is not supported. */
+ instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY;
+ return -1;
+ }
+
+ if ((instISAC->decoderSamplingRateKHz == kIsacWideband) &&
+ (decoder_operational_rate == kIsacSuperWideband)) {
+ /* Switching from wideband to super-wideband at the decoder
+ * we need to reset the filter-bank and initialize upper-band decoder. */
+ memset(instISAC->synthesisFBState1, 0,
+ FB_STATE_SIZE_WORD32 * sizeof(int32_t));
+ memset(instISAC->synthesisFBState2, 0,
+ FB_STATE_SIZE_WORD32 * sizeof(int32_t));
+
+ DecoderInitUb(&instISAC->instUB);
+ }
+ instISAC->decoderSamplingRateKHz = decoder_operational_rate;
+ return 0;
+}
+
+
+/******************************************************************************
+ * WebRtcIsac_EncSampRate()
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ *
+ * Return value : sampling rate in Hertz. The input to encoder
+ * is expected to be sampled in this rate.
+ *
+ */
+uint16_t WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ return instISAC->in_sample_rate_hz;
+}
+
+
+/******************************************************************************
+ * WebRtcIsac_DecSampRate()
+ * Return the sampling rate of the decoded audio.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ *
+ * Return value : sampling rate in Hertz. Decoder output is
+ * sampled at this rate.
+ *
+ */
+uint16_t WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+ return instISAC->decoderSamplingRateKHz == kIsacWideband ? 16000 : 32000;
+}
+
+void WebRtcIsac_GetBandwidthInfo(ISACStruct* inst,
+ IsacBandwidthInfo* bwinfo) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)inst;
+ assert(instISAC->initFlag & BIT_MASK_DEC_INIT);
+ WebRtcIsacBw_GetBandwidthInfo(&instISAC->bwestimator_obj,
+ instISAC->decoderSamplingRateKHz, bwinfo);
+}
+
+void WebRtcIsac_SetBandwidthInfo(ISACStruct* inst,
+ const IsacBandwidthInfo* bwinfo) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)inst;
+ assert(instISAC->initFlag & BIT_MASK_ENC_INIT);
+ WebRtcIsacBw_SetBandwidthInfo(&instISAC->bwestimator_obj, bwinfo);
+}
+
+void WebRtcIsac_SetEncSampRateInDecoder(ISACStruct* inst,
+ int sample_rate_hz) {
+ ISACMainStruct* instISAC = (ISACMainStruct*)inst;
+ assert(instISAC->initFlag & BIT_MASK_DEC_INIT);
+ assert(!(instISAC->initFlag & BIT_MASK_ENC_INIT));
+ assert(sample_rate_hz == 16000 || sample_rate_hz == 32000);
+ instISAC->encoderSamplingRateKHz = sample_rate_hz / 1000;
+}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h b/webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h
new file mode 100644
index 0000000..e150d39
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015 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_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
+
+#include "webrtc/modules/audio_coding/codecs/isac/main/include/isac.h"
+
+namespace webrtc {
+
+struct IsacFloat {
+ using instance_type = ISACStruct;
+ static const bool has_swb = true;
+ static inline int16_t Control(instance_type* inst,
+ int32_t rate,
+ int framesize) {
+ return WebRtcIsac_Control(inst, rate, framesize);
+ }
+ static inline int16_t ControlBwe(instance_type* inst,
+ int32_t rate_bps,
+ int frame_size_ms,
+ int16_t enforce_frame_size) {
+ return WebRtcIsac_ControlBwe(inst, rate_bps, frame_size_ms,
+ enforce_frame_size);
+ }
+ static inline int16_t Create(instance_type** inst) {
+ return WebRtcIsac_Create(inst);
+ }
+ static inline int DecodeInternal(instance_type* inst,
+ const uint8_t* encoded,
+ size_t len,
+ int16_t* decoded,
+ int16_t* speech_type) {
+ return WebRtcIsac_Decode(inst, encoded, len, decoded, speech_type);
+ }
+ static inline size_t DecodePlc(instance_type* inst,
+ int16_t* decoded,
+ size_t num_lost_frames) {
+ return WebRtcIsac_DecodePlc(inst, decoded, num_lost_frames);
+ }
+
+ static inline void DecoderInit(instance_type* inst) {
+ WebRtcIsac_DecoderInit(inst);
+ }
+ static inline int Encode(instance_type* inst,
+ const int16_t* speech_in,
+ uint8_t* encoded) {
+ return WebRtcIsac_Encode(inst, speech_in, encoded);
+ }
+ static inline int16_t EncoderInit(instance_type* inst, int16_t coding_mode) {
+ return WebRtcIsac_EncoderInit(inst, coding_mode);
+ }
+ static inline uint16_t EncSampRate(instance_type* inst) {
+ return WebRtcIsac_EncSampRate(inst);
+ }
+
+ static inline int16_t Free(instance_type* inst) {
+ return WebRtcIsac_Free(inst);
+ }
+ static inline void GetBandwidthInfo(instance_type* inst,
+ IsacBandwidthInfo* bwinfo) {
+ WebRtcIsac_GetBandwidthInfo(inst, bwinfo);
+ }
+ static inline int16_t GetErrorCode(instance_type* inst) {
+ return WebRtcIsac_GetErrorCode(inst);
+ }
+
+ static inline int16_t GetNewFrameLen(instance_type* inst) {
+ return WebRtcIsac_GetNewFrameLen(inst);
+ }
+ static inline void SetBandwidthInfo(instance_type* inst,
+ const IsacBandwidthInfo* bwinfo) {
+ WebRtcIsac_SetBandwidthInfo(inst, bwinfo);
+ }
+ static inline int16_t SetDecSampRate(instance_type* inst,
+ uint16_t sample_rate_hz) {
+ return WebRtcIsac_SetDecSampRate(inst, sample_rate_hz);
+ }
+ static inline int16_t SetEncSampRate(instance_type* inst,
+ uint16_t sample_rate_hz) {
+ return WebRtcIsac_SetEncSampRate(inst, sample_rate_hz);
+ }
+ static inline void SetEncSampRateInDecoder(instance_type* inst,
+ uint16_t sample_rate_hz) {
+ WebRtcIsac_SetEncSampRateInDecoder(inst, sample_rate_hz);
+ }
+ static inline void SetInitialBweBottleneck(instance_type* inst,
+ int bottleneck_bits_per_second) {
+ WebRtcIsac_SetInitialBweBottleneck(inst, bottleneck_bits_per_second);
+ }
+ static inline int16_t UpdateBwEstimate(instance_type* inst,
+ const uint8_t* encoded,
+ size_t packet_size,
+ uint16_t rtp_seq_number,
+ uint32_t send_ts,
+ uint32_t arr_ts) {
+ return WebRtcIsac_UpdateBwEstimate(inst, encoded, packet_size,
+ rtp_seq_number, send_ts, arr_ts);
+ }
+ static inline int16_t SetMaxPayloadSize(instance_type* inst,
+ int16_t max_payload_size_bytes) {
+ return WebRtcIsac_SetMaxPayloadSize(inst, max_payload_size_bytes);
+ }
+ static inline int16_t SetMaxRate(instance_type* inst, int32_t max_bit_rate) {
+ return WebRtcIsac_SetMaxRate(inst, max_bit_rate);
+ }
+};
+
+} // namespace webrtc
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c b/webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c
new file mode 100644
index 0000000..eabe708
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2011 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.
+ */
+
+/*
+ * lattice.c
+ *
+ * contains the normalized lattice filter routines (MA and AR) for iSAC codec
+ *
+ */
+#include "settings.h"
+#include "codec.h"
+
+#include <math.h>
+#include <memory.h>
+#include <string.h>
+#ifdef WEBRTC_ANDROID
+#include <stdlib.h>
+#endif
+
+/* filter the signal using normalized lattice filter */
+/* MA filter */
+void WebRtcIsac_NormLatticeFilterMa(int orderCoef,
+ float *stateF,
+ float *stateG,
+ float *lat_in,
+ double *filtcoeflo,
+ double *lat_out)
+{
+ int n,k,i,u,temp1;
+ int ord_1 = orderCoef+1;
+ float sth[MAX_AR_MODEL_ORDER];
+ float cth[MAX_AR_MODEL_ORDER];
+ float inv_cth[MAX_AR_MODEL_ORDER];
+ double a[MAX_AR_MODEL_ORDER+1];
+ float f[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN], g[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN];
+ float gain1;
+
+ for (u=0;u<SUBFRAMES;u++)
+ {
+ /* set the Direct Form coefficients */
+ temp1 = u*ord_1;
+ a[0] = 1;
+ memcpy(a+1, filtcoeflo+temp1+1, sizeof(double) * (ord_1-1));
+
+ /* compute lattice filter coefficients */
+ WebRtcIsac_Dir2Lat(a,orderCoef,sth,cth);
+
+ /* compute the gain */
+ gain1 = (float)filtcoeflo[temp1];
+ for (k=0;k<orderCoef;k++)
+ {
+ gain1 *= cth[k];
+ inv_cth[k] = 1/cth[k];
+ }
+
+ /* normalized lattice filter */
+ /*****************************/
+
+ /* initial conditions */
+ for (i=0;i<HALF_SUBFRAMELEN;i++)
+ {
+ f[0][i] = lat_in[i + u * HALF_SUBFRAMELEN];
+ g[0][i] = lat_in[i + u * HALF_SUBFRAMELEN];
+ }
+
+ /* get the state of f&g for the first input, for all orders */
+ for (i=1;i<ord_1;i++)
+ {
+ f[i][0] = inv_cth[i-1]*(f[i-1][0] + sth[i-1]*stateG[i-1]);
+ g[i][0] = cth[i-1]*stateG[i-1] + sth[i-1]* f[i][0];
+ }
+
+ /* filtering */
+ for(k=0;k<orderCoef;k++)
+ {
+ for(n=0;n<(HALF_SUBFRAMELEN-1);n++)
+ {
+ f[k+1][n+1] = inv_cth[k]*(f[k][n+1] + sth[k]*g[k][n]);
+ g[k+1][n+1] = cth[k]*g[k][n] + sth[k]* f[k+1][n+1];
+ }
+ }
+
+ for(n=0;n<HALF_SUBFRAMELEN;n++)
+ {
+ lat_out[n + u * HALF_SUBFRAMELEN] = gain1 * f[orderCoef][n];
+ }
+
+ /* save the states */
+ for (i=0;i<ord_1;i++)
+ {
+ stateF[i] = f[i][HALF_SUBFRAMELEN-1];
+ stateG[i] = g[i][HALF_SUBFRAMELEN-1];
+ }
+ /* process next frame */
+ }
+
+ return;
+}
+
+
+/*///////////////////AR filter ///////////////////////////////*/
+/* filter the signal using normalized lattice filter */
+void WebRtcIsac_NormLatticeFilterAr(int orderCoef,
+ float *stateF,
+ float *stateG,
+ double *lat_in,
+ double *lo_filt_coef,
+ float *lat_out)
+{
+ int n,k,i,u,temp1;
+ int ord_1 = orderCoef+1;
+ float sth[MAX_AR_MODEL_ORDER];
+ float cth[MAX_AR_MODEL_ORDER];
+ double a[MAX_AR_MODEL_ORDER+1];
+ float ARf[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN], ARg[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN];
+ float gain1,inv_gain1;
+
+ for (u=0;u<SUBFRAMES;u++)
+ {
+ /* set the denominator and numerator of the Direct Form */
+ temp1 = u*ord_1;
+ a[0] = 1;
+
+ memcpy(a+1, lo_filt_coef+temp1+1, sizeof(double) * (ord_1-1));
+
+ WebRtcIsac_Dir2Lat(a,orderCoef,sth,cth);
+
+ gain1 = (float)lo_filt_coef[temp1];
+ for (k=0;k<orderCoef;k++)
+ {
+ gain1 = cth[k]*gain1;
+ }
+
+ /* initial conditions */
+ inv_gain1 = 1/gain1;
+ for (i=0;i<HALF_SUBFRAMELEN;i++)
+ {
+ ARf[orderCoef][i] = (float)lat_in[i + u * HALF_SUBFRAMELEN]*inv_gain1;
+ }
+
+
+ for (i=orderCoef-1;i>=0;i--) //get the state of f&g for the first input, for all orders
+ {
+ ARf[i][0] = cth[i]*ARf[i+1][0] - sth[i]*stateG[i];
+ ARg[i+1][0] = sth[i]*ARf[i+1][0] + cth[i]* stateG[i];
+ }
+ ARg[0][0] = ARf[0][0];
+
+ for(n=0;n<(HALF_SUBFRAMELEN-1);n++)
+ {
+ for(k=orderCoef-1;k>=0;k--)
+ {
+ ARf[k][n+1] = cth[k]*ARf[k+1][n+1] - sth[k]*ARg[k][n];
+ ARg[k+1][n+1] = sth[k]*ARf[k+1][n+1] + cth[k]* ARg[k][n];
+ }
+ ARg[0][n+1] = ARf[0][n+1];
+ }
+
+ memcpy(lat_out+u * HALF_SUBFRAMELEN, &(ARf[0][0]), sizeof(float) * HALF_SUBFRAMELEN);
+
+ /* cannot use memcpy in the following */
+ for (i=0;i<ord_1;i++)
+ {
+ stateF[i] = ARf[i][HALF_SUBFRAMELEN-1];
+ stateG[i] = ARg[i][HALF_SUBFRAMELEN-1];
+ }
+
+ }
+
+ return;
+}
+
+
+/* compute the reflection coefficients using the step-down procedure*/
+/* converts the direct form parameters to lattice form.*/
+/* a and b are vectors which contain the direct form coefficients,
+ according to
+ A(z) = a(1) + a(2)*z + a(3)*z^2 + ... + a(M+1)*z^M
+ B(z) = b(1) + b(2)*z + b(3)*z^2 + ... + b(M+1)*z^M
+*/
+
+void WebRtcIsac_Dir2Lat(double *a,
+ int orderCoef,
+ float *sth,
+ float *cth)
+{
+ int m, k;
+ float tmp[MAX_AR_MODEL_ORDER];
+ float tmp_inv, cth2;
+
+ sth[orderCoef-1] = (float)a[orderCoef];
+ cth2 = 1.0f - sth[orderCoef-1] * sth[orderCoef-1];
+ cth[orderCoef-1] = (float)sqrt(cth2);
+ for (m=orderCoef-1; m>0; m--)
+ {
+ tmp_inv = 1.0f / cth2;
+ for (k=1; k<=m; k++)
+ {
+ tmp[k] = ((float)a[k] - sth[m] * (float)a[m-k+1]) * tmp_inv;
+ }
+
+ for (k=1; k<m; k++)
+ {
+ a[k] = tmp[k];
+ }
+
+ sth[m-1] = tmp[m];
+ cth2 = 1 - sth[m-1] * sth[m-1];
+ cth[m-1] = (float)sqrt(cth2);
+ }
+}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/transform.c b/webrtc/modules/audio_coding/codecs/isac/main/source/transform.c
new file mode 100644
index 0000000..8992897
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/transform.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2011 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 "settings.h"
+#include "fft.h"
+#include "codec.h"
+#include "os_specific_inline.h"
+#include <math.h>
+
+void WebRtcIsac_InitTransform(TransformTables* tables) {
+ int k;
+ double fact, phase;
+
+ fact = PI / (FRAMESAMPLES_HALF);
+ phase = 0.0;
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ tables->costab1[k] = cos(phase);
+ tables->sintab1[k] = sin(phase);
+ phase += fact;
+ }
+
+ fact = PI * ((double) (FRAMESAMPLES_HALF - 1)) / ((double) FRAMESAMPLES_HALF);
+ phase = 0.5 * fact;
+ for (k = 0; k < FRAMESAMPLES_QUARTER; k++) {
+ tables->costab2[k] = cos(phase);
+ tables->sintab2[k] = sin(phase);
+ phase += fact;
+ }
+}
+
+void WebRtcIsac_Time2Spec(const TransformTables* tables,
+ double* inre1,
+ double* inre2,
+ int16_t* outreQ7,
+ int16_t* outimQ7,
+ FFTstr* fftstr_obj) {
+ int k;
+ int dims[1];
+ double tmp1r, tmp1i, xr, xi, yr, yi, fact;
+ double tmpre[FRAMESAMPLES_HALF], tmpim[FRAMESAMPLES_HALF];
+
+
+ dims[0] = FRAMESAMPLES_HALF;
+
+
+ /* Multiply with complex exponentials and combine into one complex vector */
+ fact = 0.5 / sqrt(FRAMESAMPLES_HALF);
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ tmp1r = tables->costab1[k];
+ tmp1i = tables->sintab1[k];
+ tmpre[k] = (inre1[k] * tmp1r + inre2[k] * tmp1i) * fact;
+ tmpim[k] = (inre2[k] * tmp1r - inre1[k] * tmp1i) * fact;
+ }
+
+
+ /* Get DFT */
+ WebRtcIsac_Fftns(1, dims, tmpre, tmpim, -1, 1.0, fftstr_obj);
+
+ /* Use symmetry to separate into two complex vectors and center frames in time around zero */
+ for (k = 0; k < FRAMESAMPLES_QUARTER; k++) {
+ xr = tmpre[k] + tmpre[FRAMESAMPLES_HALF - 1 - k];
+ yi = -tmpre[k] + tmpre[FRAMESAMPLES_HALF - 1 - k];
+ xi = tmpim[k] - tmpim[FRAMESAMPLES_HALF - 1 - k];
+ yr = tmpim[k] + tmpim[FRAMESAMPLES_HALF - 1 - k];
+
+ tmp1r = tables->costab2[k];
+ tmp1i = tables->sintab2[k];
+ outreQ7[k] = (int16_t)WebRtcIsac_lrint((xr * tmp1r - xi * tmp1i) * 128.0);
+ outimQ7[k] = (int16_t)WebRtcIsac_lrint((xr * tmp1i + xi * tmp1r) * 128.0);
+ outreQ7[FRAMESAMPLES_HALF - 1 - k] = (int16_t)WebRtcIsac_lrint((-yr * tmp1i - yi * tmp1r) * 128.0);
+ outimQ7[FRAMESAMPLES_HALF - 1 - k] = (int16_t)WebRtcIsac_lrint((-yr * tmp1r + yi * tmp1i) * 128.0);
+ }
+}
+
+void WebRtcIsac_Spec2time(const TransformTables* tables,
+ double* inre,
+ double* inim,
+ double* outre1,
+ double* outre2,
+ FFTstr* fftstr_obj) {
+ int k;
+ double tmp1r, tmp1i, xr, xi, yr, yi, fact;
+
+ int dims;
+
+ dims = FRAMESAMPLES_HALF;
+
+ for (k = 0; k < FRAMESAMPLES_QUARTER; k++) {
+ /* Move zero in time to beginning of frames */
+ tmp1r = tables->costab2[k];
+ tmp1i = tables->sintab2[k];
+ xr = inre[k] * tmp1r + inim[k] * tmp1i;
+ xi = inim[k] * tmp1r - inre[k] * tmp1i;
+ yr = -inim[FRAMESAMPLES_HALF - 1 - k] * tmp1r - inre[FRAMESAMPLES_HALF - 1 - k] * tmp1i;
+ yi = -inre[FRAMESAMPLES_HALF - 1 - k] * tmp1r + inim[FRAMESAMPLES_HALF - 1 - k] * tmp1i;
+
+ /* Combine into one vector, z = x + j * y */
+ outre1[k] = xr - yi;
+ outre1[FRAMESAMPLES_HALF - 1 - k] = xr + yi;
+ outre2[k] = xi + yr;
+ outre2[FRAMESAMPLES_HALF - 1 - k] = -xi + yr;
+ }
+
+
+ /* Get IDFT */
+ WebRtcIsac_Fftns(1, &dims, outre1, outre2, 1, FRAMESAMPLES_HALF, fftstr_obj);
+
+
+ /* Demodulate and separate */
+ fact = sqrt(FRAMESAMPLES_HALF);
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ tmp1r = tables->costab1[k];
+ tmp1i = tables->sintab1[k];
+ xr = (outre1[k] * tmp1r - outre2[k] * tmp1i) * fact;
+ outre2[k] = (outre2[k] * tmp1r + outre1[k] * tmp1i) * fact;
+ outre1[k] = xr;
+ }
+}
diff --git a/webrtc/modules/audio_coding/meson.build b/webrtc/modules/audio_coding/meson.build
index 5975bfa..fb46df8 100644
--- a/webrtc/modules/audio_coding/meson.build
+++ b/webrtc/modules/audio_coding/meson.build
@@ -1,4 +1,4 @@
-audio_coding_sources = [
+webrtc_audio_coding_sources = [
'codecs/isac/main/source/arith_routines.c',
'codecs/isac/main/source/arith_routines_hist.c',
'codecs/isac/main/source/arith_routines_logist.c',
@@ -18,16 +18,45 @@ audio_coding_sources = [
'codecs/isac/main/source/pitch_gain_tables.c',
'codecs/isac/main/source/pitch_lag_tables.c',
'codecs/isac/main/source/spectrum_ar_model_tables.c',
+ 'codecs/audio_decoder.cc',
+ 'codecs/audio_encoder.cc',
+ 'codecs/isac/main/source/audio_decoder_isac.cc',
+ 'codecs/isac/main/source/audio_encoder_isac.cc',
+ 'codecs/isac/main/source/bandwidth_estimator.c',
+ 'codecs/isac/main/source/crc.c',
+ 'codecs/isac/main/source/decode.c',
+ 'codecs/isac/main/source/decode_bwe.c',
+ 'codecs/isac/main/source/encode.c',
+ 'codecs/isac/main/source/fft.c',
+ 'codecs/isac/main/source/isac.c',
+ 'codecs/isac/main/source/lattice.c',
+ 'codecs/isac/main/source/transform.c',
]
-libaudio_coding = static_library('audio_coding',
- audio_coding_sources,
- dependencies: common_deps,
+libwebrtc_audio_coding = library('webrtc_audio_coding',
+ webrtc_audio_coding_sources,
+ dependencies: [base_dep, common_audio_dep] + common_deps,
include_directories: webrtc_inc,
c_args: common_cflags,
- cpp_args: common_cxxflags
+ cpp_args: common_cxxflags,
+ soversion: soversion,
+ install: true
)
-audio_coding_dep = declare_dependency(
- link_with: libaudio_coding
+webrtc_audio_coding_dep = declare_dependency(
+ link_with: libwebrtc_audio_coding,
+ include_directories: webrtc_inc,
+ version: meson.project_version()
+)
+
+install_headers(['codecs/isac/bandwidth_info.h'],
+ subdir: 'webrtc_audio_processing/webrtc/modules/audio_coding/codecs/isac'
+)
+
+install_headers(['codecs/isac/main/source/settings.h'],
+ subdir: 'webrtc_audio_processing/webrtc/modules/audio_coding/codecs/isac/main/source'
+)
+
+install_headers(['codecs/isac/main/include/isac.h'],
+ subdir: 'webrtc_audio_processing/webrtc/modules/audio_coding/codecs/isac/main/include'
)
diff --git a/webrtc/modules/audio_processing/meson.build b/webrtc/modules/audio_processing/meson.build
index 5ce87a1..34e23e0 100644
--- a/webrtc/modules/audio_processing/meson.build
+++ b/webrtc/modules/audio_processing/meson.build
@@ -109,7 +109,7 @@ install_headers(webrtc_audio_processing_include_headers,
libwebrtc_audio_processing = library('webrtc_audio_processing',
webrtc_audio_processing_sources,
- dependencies: [base_dep, audio_coding_dep, system_wrappers_dep, common_audio_dep, audio_coding_dep, webrtc_dep] + common_deps,
+ dependencies: [base_dep, webrtc_audio_coding_dep, system_wrappers_dep, common_audio_dep, webrtc_dep] + common_deps,
link_with: extra_libs,
include_directories: webrtc_inc,
c_args: common_cflags,