summaryrefslogtreecommitdiff
path: root/webrtc/modules/audio_coding
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/modules/audio_coding')
-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
28 files changed, 8033 insertions, 7 deletions
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'
)