Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 87d3c8cd authored by Jakub Pawlowski's avatar Jakub Pawlowski Committed by Automerger Merge Worker
Browse files

Delete previous LC3 encoder implementation am: 111ff202 am: 427b3990 am: b5ee37e8

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Bluetooth/+/1934968

Change-Id: I26c5ee935400a18c280f80ec919056f1d5a7286e
parents 3db8180a b5ee37e8
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -34,7 +34,6 @@
#include "device/include/controller.h"
#include "device/include/controller.h"
#include "devices.h"
#include "devices.h"
#include "embdrv/lc3/Api/Lc3Decoder.hpp"
#include "embdrv/lc3/Api/Lc3Decoder.hpp"
#include "embdrv/lc3/Api/Lc3Encoder.hpp"
#include "embdrv/lc3_enc/include/lc3.h"
#include "embdrv/lc3_enc/include/lc3.h"
#include "gatt/bta_gattc_int.h"
#include "gatt/bta_gattc_int.h"
#include "le_audio_types.h"
#include "le_audio_types.h"
+0 −2
Original line number Original line Diff line number Diff line
@@ -16,8 +16,6 @@


#include <memory>
#include <memory>


#include "embdrv/lc3/Api/Lc3Encoder.hpp"

namespace bluetooth {
namespace bluetooth {
namespace audio {
namespace audio {
class HalVersionManager {
class HalVersionManager {
+0 −13
Original line number Original line Diff line number Diff line
@@ -20,7 +20,6 @@ cc_library_static {
        "Common/*.cpp",
        "Common/*.cpp",
        "Common/fft/*.c",
        "Common/fft/*.c",
        "Common/Tables/*.cpp",
        "Common/Tables/*.cpp",
        "Encoder/*.cpp",
        "Decoder/*.cpp",
        "Decoder/*.cpp",
        "TestSupport/DatapointsAndroid.cpp",
        "TestSupport/DatapointsAndroid.cpp",
    ],
    ],
@@ -57,18 +56,6 @@ cc_library_static {
    ],
    ],
}
}


cc_fuzz {
  name: "liblc3codec_encoder_fuzzer",

  srcs: [
    "fuzzer/liblc3codec_encoder_fuzzer.cpp",
  ],

  static_libs: [
    "liblc3codec",
  ],
}

cc_fuzz {
cc_fuzz {
  name: "liblc3codec_decoder_fuzzer",
  name: "liblc3codec_decoder_fuzzer",


+0 −198
Original line number Original line Diff line number Diff line
/*
 * Lc3Encoder.hpp
 *
 * Copyright 2021 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
 * www.ehima.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef API_LC3ENCODER_HPP_
#define API_LC3ENCODER_HPP_

#include <cstdint>
#include <vector>

#include "Lc3Config.hpp"

/*
 * Forward declaration of the "internal" class EncoderTop, so
 * that the private vector of single channel encoders can be declared in
 * Lc3Encoder.
 */
namespace Lc3Enc {
class EncoderTop;
}

/*
 * The LC3 encoder interface is specified in
 * LC3 specification Sections 2.2 "Encoder interfaces" (dr09r07).
 *
 * Lc3Encoder is designed such that all specified features are provided
 * with the (current) exception of not providing other input bit depth
 * than 16 bit/sample. At the time of writing, the main purpose of the
 * implementation was to handle 16bit audio data provided within android
 * smartphones. Providing the specified 24bit and 32 bit audio data input,
 * would make the API more complex. However, the main argument to not support
 * these sample rates right now, is that internal operations and memory
 * consumption would have to be increased measurable otherwise.
 *
 * Instantiating Lc3Encoder implies providing a Lc3Config instance. A copy of
 * this instance is available as public const member so that all essential
 * session parameters can be obtained throughout the lifetime of the Lc3Encoder
 * instance.
 *
 * There is no possibility of changing Lc3Config within Lc3Encoder. When session
 * parameters have to be changed, the calling application has to create a new
 * instance of Lc3Encoder.
 *
 * Lc3 supports operation with variable encoded bitrate. It is possible to
 * change the bitrate from frame to frame, where for preciseness the parameter
 * is not given as bit rate directly but in terms of the byte_count per frame.
 * This parameter has to be in the range of 20 to 400 (see LC3 specification
 * Section 3.2.5 "Bit budget and bitrate")
 *
 */

class Lc3Encoder {
 public:
  /*
   * Convenience constructor of Lc3Encoder with one simple parameter only.
   * Note that this constructor instantiated Lc3Config implicitly with
   *  Lc3Config(Fs, Lc3Config::FrameDuration::d10ms, 1) that means that this
   * constructor provides processing of one channel (mono) with 10ms frame
   * duration.
   *
   * Parameters:
   *  Fs : Sampling frequency in Hz -> see Lc3Config.hpp for supported values
   */
  Lc3Encoder(uint16_t Fs);

  /*
   * General constructor of Lc3Encoder.
   *
   * Parameters:
   *  lc3Config_ : instance of Lc3Config. See documentation of Lc3Config for
   * more details. Note: providing an invalid instance of Lc3Config will result
   *                     in skipping any processing later.
   *               The provided instance of Lc3Config will be copied to the
   *               public field "lc3Config" (see below).
   *
   *  bits_per_audio_sample_enc_ : The bits per audio sample for the input PCM
   * signal. See LC3 specification Section 2.2 "Encoder interfaces" and
   * Section 3.2.3 "Bits per sample" for the general LC3 requirement to support
   * 16, 24 and 32 bit. Note: This parameter may differ from the decoder output
   * PCM setting "bits_per_audio_sample_dec".
   *
   *                                However, the current implementation allows
   * 16 bit only and will return an error INVALID_BITS_PER_AUDIO_SAMPLE for
   * run() when configured with any other value. (see reasoning for this
   * constraint in the general class descripton above)
   *
   * datapoints : pointer to an instance of a class allowing to collect internal
   * data. Note: this feature is used and prepared for testing of the codec
   *                    implementation only. See general "Readme.txt"
   */
  Lc3Encoder(Lc3Config lc3Config_, uint8_t bits_per_audio_sample_enc_ = 16,
             void* datapoints = nullptr);

  // no default constructor supported
  Lc3Encoder() = delete;

  // Destructor
  virtual ~Lc3Encoder();

  /*
   * Configuration provided during instantiation accessible as public const
   * fields. Note: Lc3Config provides a getter to check whether the
   * configuration is valid.
   */
  const Lc3Config lc3Config;
  const uint8_t bits_per_audio_sample_enc;

  // encoding errors (see return values of "run" methods)
  static const uint8_t ERROR_FREE = 0x00;
  static const uint8_t INVALID_CONFIGURATION = 0x01;
  static const uint8_t INVALID_BYTE_COUNT = 0x02;
  static const uint8_t INVALID_BITS_PER_AUDIO_SAMPLE = 0x03;
  static const uint8_t ENCODER_ALLOCATION_ERROR = 0x04;

  /*
   * Encoding of one input frame for one channel.
   *
   * Note that this method can be used for multi-channel configurations as well,
   * particularly when the provided multi-channel "run" (see below) is not
   * providing the kind of byte stream concatenation desired by a specific
   * application.
   *
   * Parameters:
   *  x          : pointer to input signal array with 16bit/sample.
   *               The length of the signal to be provided depends on the given
   *               session configuration and can be obtained via
   *               lc3Config.NF
   *
   *  byte_count : determines the compression strength (-> bitrate) to be used
   *               for this specific frame. Supported values are 20 bytes to 400
   * bytes, where values well below 40 bytes typically give rather poor audio
   * quality. Note: in case of having an application targeting a given bitrate,
   * the helper method "lc3Config.getByteCountFromBitrate(.)" can be used to
   * compute the proper setting for this byte_count parameter.
   *
   *  bytes      : pointer to byte array (memory) provided by the application,
   * where the encoded byte stream will be placed. The size of this memory is
   * given by the byte_count parameter.
   *
   *  channelNr  : index of channel to be processed (default=0), where channelNr
   * < lc3Config.Nc
   *
   * Return value: error code as listed above.
   */
  uint8_t run(const int16_t* x, uint16_t byte_count, uint8_t* bytes,
              uint8_t channelNr = 0);

  /*
   * Encoding of one multi-channel frame.
   *
   * Note that this call always processes all channels configured in the given
   * session.
   *
   * Parameters:
   *  x          : pointer to input signal array with 16bit/sample.
   *               The length of the signal to be provided depends on the given
   *               session configuration and can be obtained via
   *               lc3Config.NF * lc3Config.Nc
   *
   *  byte_count_per_channel : determines the compression strength (-> bitrate)
   * to be used for each channel individually of this specific frame. Thus,
   * byte_count_per_channel is an array of byte_count values with length
   * lc3Conig.Nc Supported values per channel are 20 bytes to 400 bytes. See
   * also the documentation for the single channel "run" above.
   *
   *  bytes      : pointer to byte array (memory) provided by the application,
   * where the encoded byte stream will be placed. The size of this memory is
   * given by the byte_count_per_channel parameter, specifically by the sum of
   * all channel-wise byte_count values (byte_count_per_channel[0] + ... +
   * byte_count_per_channel[lc3Config.Nc]) This implies that the encoded bytes
   * from the individual channels are concatenated directly (without any
   * stuffing bytes or meta information).
   *
   * Return value: error code as listed above.
   */
  uint8_t run(const int16_t* x, const uint16_t* byte_count_per_channel,
              uint8_t* bytes);

 private:
  std::vector<Lc3Enc::EncoderTop*> encoderList;
};

#endif /* API_LC3ENCODER_HPP_ */
+0 −120
Original line number Original line Diff line number Diff line
/*
 * AttackDetector.cpp
 *
 * Copyright 2021 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
 * www.ehima.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "AttackDetector.hpp"

#include <cmath>

namespace Lc3Enc {

AttackDetector::AttackDetector(const Lc3Config& lc3Config_)
    : lc3Config(lc3Config_),
      M_F((lc3Config.N_ms == Lc3Config::FrameDuration::d10ms)
              ? 160
              : 120),  // 16*N_ms
      F_att(0),
      E_att_last(0),
      A_att_last(0),
      P_att_last(-1) {
  // make sure these states are initially zero as demanded by the specification
  x_att_last[0] = 0;
  x_att_last[1] = 0;
}

AttackDetector::~AttackDetector() {}

void AttackDetector::run(const int16_t* const x_s, uint16_t nbytes) {
  // 3.3.6.1 Overview (d09r06_FhG)
  // -> attack detection active only for higher bitrates and fs>=32000;
  // otherwise defaults are set
  F_att = 0;
  if (lc3Config.Fs < 32000) {
    return;
  }
  bool isActive =
      ((lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) &&
       (lc3Config.Fs == 32000) && (nbytes > 80)) ||
      ((lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) &&
       (lc3Config.Fs >= 44100) && (nbytes >= 100)) ||
      ((lc3Config.N_ms == Lc3Config::FrameDuration::d7p5ms) &&
       (lc3Config.Fs == 32000) && (nbytes >= 61) && (nbytes < 150)) ||
      ((lc3Config.N_ms == Lc3Config::FrameDuration::d7p5ms) &&
       (lc3Config.Fs >= 44100) && (nbytes >= 75) && (nbytes < 150));
  if (!isActive) {
    // Note: in bitrate switching situations we have to set proper states
    E_att_last = 0;
    A_att_last = 0;
    P_att_last = -1;
    return;
  }

  // 3.3.6.2 Downsampling and filtering of input signal (d09r02_F2F)
  // Note: the following section might be converted to int32 instead
  //       of double computation (maybe something for optimization)
  double x_att_extended[M_F + 2];
  x_att_extended[0] = x_att_last[0];
  x_att_extended[1] = x_att_last[1];
  double* x_att = &x_att_extended[2];
  for (uint8_t n = 0; n < M_F; n++)  // downsampling
  {
    x_att[n] = 0;
    for (uint8_t m = 0; m < lc3Config.NF / M_F; m++) {
      x_att[n] += x_s[lc3Config.NF / M_F * n + m];
    }
  }
  x_att_last[0] = x_att[M_F - 2];
  x_att_last[1] = x_att[M_F - 1];
  double* x_hp = x_att_extended;     // just for improve readability
  for (uint8_t n = 0; n < M_F; n++)  // highpass-filtering (in-place!)
  {
    x_hp[n] = 0.375 * x_att[n] - 0.5 * x_att[n - 1] + 0.125 * x_att[n - 2];
  }

  // 3.3.6.3 Energy calculation & 3.3.6.4 Attack detection (d09r06_FhG)
  int8_t P_att = -1;
  const uint8_t N_blocks =
      (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) ? 4 : 3;  // N_ms/2.5
  for (uint8_t n = 0; n < N_blocks; n++) {
    double E_att = 0;
    for (uint8_t l = 40 * n; l <= (40 * n + 39); l++) {
      E_att += x_hp[l] * x_hp[l];
    }
    double A_att =
        (0.25 * A_att_last > E_att_last) ? 0.25 * A_att_last : E_att_last;
    if (E_att > 8.5 * A_att) {
      // attack detected
      P_att = n;
    }
    E_att_last = E_att;
    A_att_last = A_att;
  }
  const uint8_t T_att = (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms)
                            ? 2
                            : 1;  // floor(N_blocks/2)
  F_att = (P_att >= 0) || (P_att_last >= T_att);
  P_att_last = P_att;  // prepare next frame
}

void AttackDetector::registerDatapoints(DatapointContainer* datapoints) {
  if (nullptr != datapoints) {
    datapoints->addDatapoint("F_att", &F_att, sizeof(F_att));
  }
}

}  // namespace Lc3Enc
Loading