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

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

Merge "leaudio: LC3 encoder and decoder implementation." am: c9ba708e am:...

Merge "leaudio: LC3 encoder and decoder implementation." am: c9ba708e am: 87a2340b am: ec0abef8

Original change: https://android-review.googlesource.com/c/platform/system/bt/+/1803977

Change-Id: I646338676d17f7cf9f3449cef2de0cb543922108
parents 8a13ef86 ec0abef8
Loading
Loading
Loading
Loading
+43 −0
Original line number Original line Diff line number Diff line
cc_library_static {
    name: "liblc3codec",
    host_supported: true,
    apex_available: [

        "//apex_available:platform",
        "com.android.bluetooth.updatable"
    ],
    defaults: ["fluoride_defaults"],
    srcs: [
        "Common/*.cpp",
        "Common/Tables/*.cpp",
        "Encoder/*.cpp",
        "Decoder/*.cpp",
        "TestSupport/DatapointsAndroid.cpp",
    ],
    cflags: [
        "-Werror",
        "-Wmissing-braces",
        "-Wno-unused-parameter",
        "-Wno-#warnings",
        "-Wuninitialized",
        "-Wno-self-assign",
        "-Wno-implicit-fallthrough",
    ],
    sanitize: {
        misc_undefined:[
           "unsigned-integer-overflow",
           "signed-integer-overflow",
           "bounds",
        ],
        cfi: true,
    },
    shared_libs: [
        "liblog",
    ],
    export_include_dirs: [
        "Api",
        "Common",
        "Common/Tables",
        "TestSupport",
    ],
}
+208 −0
Original line number Original line Diff line number Diff line
/*
 * Lc3Config.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 __LC3_CONFIG_HPP_
#define __LC3_CONFIG_HPP_

#include <cstdint>

/*
 * The LC3 encoder and decoder have a common set of essential session
 * configuration parameters - see LC3 specification Sections 2.2 "Encoder
 * interfaces" and Section 2.4 "Decoder interfaces" (dr09r07). The set of common
 * session configuration parameters is represented by an instance of class
 * Lc3Config.
 *
 * Lc3Config is designed such that all parameters need to be
 * providing when constructing an instance. Afterwards, success of creation,
 * the actual parameter values, and derived parameter values are provided
 * by corresponding const getter methods or public const fields.
 *
 * When parameters need to be changes, a new instance of Lc3Config has to be
 * created.
 *
 * Instances of Lc3Config are provided to instances of Lc3Encoder and Lc3Decoder
 * when constructing them.
 *
 * The main purpose of Lc3Config is to verify and handle common LC3 session
 * configuration parameters in a consistent way.
 *
 */
class Lc3Config {
 public:
  /*
   * Enumeration of supported frame durations N_ms = 7.5ms and N_ms = 10ms.
   *
   * Note: although the LC3 specification describes frame duration N_ms as
   *       a parameter with floating point values 7.5 and 10.0, we decided
   *       to make this parameter a discrete enumeration of supported
   *       frame durations. There are too many codec parts that need
   *       specifically listed constants dependent on the configured
   *       frame duration, so that it never will be possible to chose from a
   *       larger set of floating point values for N_ms.
   *         Making the data type of N_ms an enumeration supports
   *       straight forwards verification that meaningful parameters are given.
   */
  enum class FrameDuration { d10ms, d7p5ms };

  // configuration error (see "getErrorStatus")
  static const uint8_t ERROR_FREE = 0x00;
  static const uint8_t INVALID_SAMPLING_RATE = 0x01;
  static const uint8_t INVALID_FRAME_DURATION = 0x02;
  static const uint8_t INVALID_NUMBER_OF_CHANNELS = 0x04;

  /*
   * Constructor of an instance of Lc3Config
   * Parameters:
   *     (see also see LC3 specification Sections 2.2 "Encoder interfaces"
   *      and Section 2.4 "Decoder interfaces" (dr09r07) )
   *
   *  Fs_ : Sampling frequency in Hz -> defines public constant Fs
   *        Supported values are
   *           8000 Hz
   *          16000 Hz
   *          24000 Hz
   *          32000 Hz
   *          44100 Hz
   *          48000 Hz
   *
   *  N_ms_ : Frame duration given by value from enumeration FrameDuration (see
   * above)
   *          -> defines public constant N_ms
   *          Supported values see enumeration FrameDuration.
   *
   *  Nc_ : Number of channels -> defines public constant Nc
   *          Supported values are Nc > 0 and Nc < 256 such that device
   * resources are not exhausted. Notes:
   *            - Exhausting device resources can mean that there is not enough
   * memory to instantiate the corresponding number of encoders and/or decoders,
   * but also that computing the encoders and/or decoders in real-time is not
   * possible.
   *            - The parameter N_c_max described in the LC3 specifciation is
   * not given here, since there is too little knowledge on the target devices
   * where this code may be used.
   *
   */
  Lc3Config(uint16_t Fs_, FrameDuration N_ms_, uint8_t Nc_);

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

  // Destructor
  virtual ~Lc3Config();

  /*
   * Getter "isValid" provides a convenience function that returns true when an
   * instance of Lc3Config could be created without error.
   */
  bool isValid() const;

  /*
   * Getter "getErrorStatus" provides details on the success of instantiating
   * Lc3Config. The possible return values are listed as constants in this class
   * (see configuration error constants above)
   */
  uint8_t getErrorStatus() const;

  /*
   * Getter "getByteCountFromBitrate" provides the number of bytes available in
   * one encoded frame of one channel (see "nbytes" as described in
   * Section 3.2.5 "Bit budget and bitrate" (dr09r07) )
   *
   * The number of bytes "nbytes" to use for encoding a single channel is a
   * required external input to each single channel LC3 encoder. The same number
   * of bytes (now to be used for decoding) is also a required external input to
   * each single channel LC3 decoder. The corresponding number of bits available
   * in one frame is thus "nbits  8*nbytes". The codec works on a byte boundary,
   * i.e. the variable "nbytes" shall be an integer number. A certain "bitrate"
   * can be converted to a number of bytes "nbytes" where the number of bytes is
   * rounded towards the nearest lower integer.
   *
   * The algorithm is verified from the bitrate corresponding to
   *  nbytes = 20 up to the bitrate corresponding to
   *  nbytes = 400 per channel for all sampling rates.
   * The LC3 specification does not specify or recommend what bitrate to use for
   * encoding a frame of audio samples. This is specified by the profiles making
   * use of the LC3.
   */
  uint16_t getByteCountFromBitrate(
      uint32_t bitrate) const;  // meant for a single channel

  /*
   * Getter "getBitrateFromByteCount" provides the bitrate of the codec in bits
   * per second of one channel (see Section 3.2.5 "Bit budget and bitrate"
   * (dr1.0r03) )
   *
   * This is a convenience utility and not directly used by the LC3
   * implementation.
   *
   * The bitrate of the codec in bits per second is
   * "bitrate = ceil(nbits / frame_duration) = ceil(nbits*Fs/NF) =
   * ceil(8*nbytes*Fs/NF)".
   *
   * The LC3 specification does not specify or recommend what bitrate to use for
   * encoding a frame of audio samples. This is specified by the profiles making
   * use of the LC3.
   */
  uint32_t getBitrateFromByteCount(uint16_t nbytes) const;

  /*
   * Getter "getFscal" provides a utility used within the LC3 implementation
   * for easier parameter mapping when Fs == 44100
   * (see Section 3.2.2 "Sampling rates" (dr1.0r03) )
   */
  double getFscal() const;

  /*
   * Getter "getNmsValue" provides a utility used within the LC3 implementation
   * that converts FrameDuration N_ms enumeration values to duration values in
   * milliseconds.
   */
  double getNmsValue() const;

 private:
  // internal utilities used for verifying the given input parameters and
  // computing derived parameters
  uint8_t getFs_ind(uint16_t Fs);
  uint16_t getNF(uint16_t Fs, FrameDuration N_ms);
  uint16_t getNE(uint16_t NF, FrameDuration N_ms);

  // errors status set during construction and returned by getErrorStatus()
  uint8_t errorStatus;

 public:
  // configuration details -> see also Section 3.1.2 "Mathematical symbols"
  // (dr09r07)
  const uint16_t Fs;         // Sampling rate (in Hz)
  const uint8_t Fs_ind;      // Sampling rate index (see also Section 3.2.2
                             // "Sampling rates" (dr09r07)
  const FrameDuration N_ms;  // Frame duration -> see Lc3Config constructor
                             // documentation Note: that the actual frame
                             // duration is longer by a factor of 480/441
                             //       if the sampling rate is 44100 Hz
  const uint16_t NF;  // Number of samples processed in one frame of one channel
                      // (also known as frame size)
  const uint16_t
      NE;            // Number of encoded spectral lines (per frame and channel)
  const uint16_t Z;  // Number of leading zeros in MDCT window
  const uint8_t Nc;  // Number of channels
  const uint8_t N_b;  // Number of bands
};

#endif  // __LC3_CONFIG_HPP_
+346 −0
Original line number Original line Diff line number Diff line
/*
 * Lc3Decoder.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_LC3DECODER_HPP_
#define API_LC3DECODER_HPP_

#include <cstdint>
#include <vector>

#include "Lc3Config.hpp"

/*
 * Forward declaration of the "internal" class DecoderTop, so
 * that the private vector of single channel decoders can be declared in
 * Lc3Decoder.
 */
namespace Lc3Dec {
class DecoderTop;
}

/*
 * The LC3 decoder interface is specified in
 * LC3 specification Sections 2.4 "Decoder interfaces" (dr09r07).
 *
 * Lc3Decoder is designed such that all specified features are provided.
 *
 * In contrast to the Lc3Encoder, even 24bit and 32bit decoded audio
 * data can be provided - however in one fix byte arrangement which will
 * not meet all meaningful options. Providing 24bit and 32bit decoded audio
 * data makes the API more complex but does not increase the needed
 * resources when basic 16bit/sample audio data is desired only.
 *
 * Instantiating Lc3Decoder 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 Lc3Decoder
 * instance.
 *
 * There is no possibility of changing Lc3Config within Lc3Decoder. When session
 * parameters have to be changed, the calling application has to create a new
 * instance of Lc3Decoder.
 *
 * 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 bitrate 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"). LC3 specification Sections 2.4
 * "Decoder interfaces" specifies "byte_count_max" of the decoder to allow
 * pre-allocation of resources. This parameter is provided here for completeness
 * and used for verifying the byte_count value of individual frames only. The
 * needed memory has to be provided by the calling application anyway, so that
 * it is up to the application whether a pre-allocation of memory is useful.
 *
 */

class Lc3Decoder {
 public:
  /*
   * Convenience constructor of Lc3Decoder with two simple parameter only.
   * Note that this constructor instantiated Lc3Config implicitly with
   *  Lc3Decoder(Lc3Config(Fs,frameDuration, 1)) that means that this
   * constructor provides processing of one channel (mono) and 16bit/sample
   * PCM output only.
   *
   * Parameters:
   *  Fs : Sampling frequency in Hz -> see Lc3Config.hpp for supported values
   *
   *  frameDuration : frame duration of 10ms (default) or 7.5ms
   *                    -> see Lc3Config.hpp for more details
   */
  Lc3Decoder(uint16_t Fs, Lc3Config::FrameDuration frameDuration =
                              Lc3Config::FrameDuration::d10ms);

  /*
   * General constructor of Lc3Decoder.
   *
   * 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_dec_ : Bits per audio sample for the output PCM
   * signal. See LC3 specification Section 2.4 "Decoder 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 encoder input
   * PCM setting "bits_per_audio_sample_enc".
   *
   *  byte_count_max_dec_ : Maximum allowed payload byte_count for a single
   * channel. When using and allowing external rate control, the maximum byte
   *                        count for the session may be used to configure the
   * session buffers without a need to dynamically reallocate memory during the
   * session.
   *
   * 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"
   */
  Lc3Decoder(Lc3Config lc3Config_, uint8_t bits_per_audio_sample_dec_ = 16,
             uint16_t byte_count_max_dec_ = 400, void* datapoints = nullptr);

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

  // Destructor
  virtual ~Lc3Decoder();

  /*
   * 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_dec;
  const uint16_t byte_count_max_dec;

  // encoding error (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_X_OUT_SIZE = 0x03;
  static const uint8_t INVALID_BITS_PER_AUDIO_SAMPLE = 0x04;
  static const uint8_t DECODER_ALLOCATION_ERROR = 0x05;

  /*
   * Decoding one 16 bit/sample output frame for one channel
   *
   * Note that this methods returns the error INVALID_BITS_PER_AUDIO_SAMPLE
   * when the session has been configured for any bits_per_audio_sample_dec
   * != 16.
   *
   * Further, note that this method can be used for multi-channel configurations
   * as well, particularly when the provided multi-channel "run" (see below) is
   * not supporting the kind of byte stream concatenation existing in the
   * calling application.
   *
   * Parameters:
   *   bytes : pointer to byte array holding the input LC3 encoded byte stream
   *           of the given channel.
   *           The size of this memory is given by the byte_count parameter.
   *
   *   byte_count : number of encoded bytes; byte count to be used for decoding
   *                the received frame payload.
   *                Supported values are 20 bytes to byte_count_max_dec bytes.
   *
   *   BFI : Bad Frame Indication flags
   *         "0" signifies that no bit errors where detected in given "bytes"
   *         "1" signifies a corrupt payload packet was detected in given
   * "bytes"
   *
   *   x_out : pointer to output PCM data (16 bit/sample), where the memory
   *           has to be provided by the calling application.
   *
   *   x_out_size : number of 16 bit values supported by x_out
   *                Note: this parameter has been introduced for clarity and
   *                      verification purpose only. The method will return
   *                      the error INVALID_X_OUT_SIZE when x_out_size !=
   * lc3Config.NF.
   *
   *   BEC_detect : flag indication bit errors detected during decoding of input
   * bytes Note: a basic packet loss concealment (PLC) will be applied when
   *                      BEC_detect!=0, so that the returned audio data stays
   *                      somewhat acceptable.
   *
   *  channelNr : index of channel to be processed (default=0), where channelNr
   * < lc3Config.Nc
   *
   *
   * Return value: error code as listed above.
   */
  uint8_t run(const uint8_t* bytes, uint16_t byte_count, uint8_t BFI,
              int16_t* x_out, uint16_t x_out_size, uint8_t& BEC_detect,
              uint8_t channelNr = 0);

  /*
   * Decoding one 16, 24, or 32 bit/sample output frame for one channel
   *
   * Note that every output PCM sample will need one 32 bit memory place in the
   * output stream independently from the configured bits_per_audio_sample_dec.
   *
   * Further, note that this method can be used for multi-channel configurations
   * as well, particularly when the provided multi-channel "run" (see below) is
   * not supporting the kind of byte stream concatenation existing in the
   * calling application.
   *
   * Parameters:
   *   bytes : pointer to byte array holding the input LC3 encoded byte stream
   *           of the given channel.
   *           The size of this memory is given by the byte_count parameter.
   *
   *   byte_count : number of encoded bytes; byte count to be used for decoding
   *                the received frame payload.
   *                Supported values are 20 bytes to byte_count_max_dec bytes.
   *
   *   BFI : Bad Frame Indication flags
   *         "0" signifies that no bit errors where detected in given "bytes"
   *         "1" signifies a corrupt payload packet was detected in given
   * "bytes"
   *
   *   x_out : pointer to output PCM data (memory 32 bit/sample, precision 16
   * bit/sample, 24 bit/sample or 32 bit/sample), where the memory has to be
   * provided by the calling application.
   *
   *   x_out_size : number of 32 bit values supported by x_out
   *                Note: this parameter has been introduced for clarity and
   *                      verification purpose only. The method will return
   *                      the error INVALID_X_OUT_SIZE when x_out_size !=
   * lc3Config.NF.
   *
   *   BEC_detect : flag indication bit errors detected during decoding of input
   * bytes Note: a basic packet loss concealment (PLC) will be applied when
   *                      BEC_detect!=0, so that the returned audio data stays
   *                      somewhat acceptable.
   *
   *  channelNr : index of channel to be processed (default=0), where channelNr
   * < lc3Config.Nc
   *
   *
   * Return value: error code as listed above.
   */
  uint8_t run(const uint8_t* bytes, uint16_t byte_count, uint8_t BFI,
              int32_t* x_out, uint16_t x_out_size, uint8_t& BEC_detect,
              uint8_t channelNr = 0);

  /*
   * Decoding one 16 bit/sample output frame for multiple channels.
   *
   * Note that this methods returns the error INVALID_BITS_PER_AUDIO_SAMPLE
   * when the session has been configured for any bits_per_audio_sample_dec
   * != 16.
   *
   * Parameters:
   *   bytes : pointer to byte array holding the input LC3 encoded byte stream
   *           of all given channels.
   *           The size of this memory is given by the sum of all
   * byte_count_per_channel values (see parameter byte_count_per_channel). Note
   * that the encoded values of all channels are expected to be concatenated
   * without any stuffing bytes of meta data in between.
   *
   *   byte_count_per_channel : number of encoded bytes; byte count to be used
   * for decoding the received frame payload per channel. Thus,
   * byte_count_per_channel is an array of byte_count values with length
   * lc3Conig.Nc Supported values are 20 bytes to byte_count_max_dec bytes per
   *                            channel.
   *
   *   BFI_per_channel : lc3Conig.Nc length array of Bad Frame Indication flags
   *                     "0" signifies that no bit errors where detected in
   * given "bytes" "1" signifies a corrupt payload packet was detected in given
   * "bytes"
   *
   *   x_out : pointer to output 16 bit/sample PCM data, where the memory
   *           has to be provided by the calling application.
   *
   *   x_out_size : number of 16 bit values supported by x_out
   *                Note: this parameter has been introduced for clarity and
   *                      verification purpose only. The method will return
   *                      the error INVALID_X_OUT_SIZE when x_out_size !=
   * lc3Config.NF * lc3Conig.Nc.
   *
   *   BEC_detect_per_channel : lc3Conig.Nc length array of flags indicating bit
   * errors detected during decoding of input bytes of a certain channel. Note:
   * a basic packet loss concealment (PLC) will be applied when BEC_detect!=0,
   * so that the returned audio data stays somewhat acceptable.
   *
   *
   * Return value: error code via "or" concatenation of the error codes of
   * processing the individual channels. Note: this "or" concatenation make
   * specific error diagnosis impossible. Thus only checking != ERROR_FREE is
   * meaningful. When more specific information is needed, the single channel
   * call (see above) need to be called.
   */
  uint8_t run(const uint8_t* bytes, const uint16_t* byte_count_per_channel,
              const uint8_t* BFI_per_channel, int16_t* x_out,
              uint32_t x_out_size, uint8_t* BEC_detect_per_channel);

  /*
   * Decoding one 16, 24, or 32 bit/sample output frame for multiple channels
   *
   * Note that every output PCM sample will need one 32 bit memory place in the
   * output stream independently from the configured bits_per_audio_sample_dec.
   *
   * Parameters:
   *   bytes : pointer to byte array holding the input LC3 encoded byte stream
   *           of all given channels.
   *           The size of this memory is given by the sum of all
   * byte_count_per_channel values (see parameter byte_count_per_channel). Note
   * that the encoded values of all channels are expected to be concatenated
   * without any stuffing bytes of meta data in between.
   *
   *   byte_count_per_channel : number of encoded bytes; byte count to be used
   * for decoding the received frame payload per channel. Thus,
   * byte_count_per_channel is an array of byte_count values with length
   * lc3Conig.Nc Supported values are 20 bytes to byte_count_max_dec bytes per
   *                            channel.
   *
   *   BFI_per_channel : lc3Conig.Nc length array of Bad Frame Indication flags
   *                     "0" signifies that no bit errors where detected in
   * given "bytes" "1" signifies a corrupt payload packet was detected in given
   * "bytes"
   *
   *   x_out : pointer to output 16, 24, or 32 bit/sample PCM data, where the
   * memory has to be provided by the calling application.
   *
   *   x_out_size : number of 32 bit values supported by x_out
   *                Note: this parameter has been introduced for clarity and
   *                      verification purpose only. The method will return
   *                      the error INVALID_X_OUT_SIZE when x_out_size !=
   * lc3Config.NF * lc3Conig.Nc.
   *
   *   BEC_detect_per_channel : lc3Conig.Nc length array of flags indicating bit
   * errors detected during decoding of input bytes of a certain channel. Note:
   * a basic packet loss concealment (PLC) will be applied when BEC_detect!=0,
   * so that the returned audio data stays somewhat acceptable.
   *
   *
   * Return value: error code via "or" concatenation of the error codes of
   * processing the individual channels. Note: this "or" concatenation make
   * specific error diagnosis impossible. Thus only checking != ERROR_FREE is
   * meaningful. When more specific information is needed, the single channel
   * call (see above) need to be called.
   */
  uint8_t run(const uint8_t* bytes, const uint16_t* byte_count_per_channel,
              const uint8_t* BFI_per_channel, int32_t* x_out,
              uint32_t x_out_size, uint8_t* BEC_detect_per_channel);

 private:
  std::vector<Lc3Dec::DecoderTop*> decoderList;
};

#endif /* API_LC3DECODER_HPP_ */
+198 −0

File added.

Preview size limit exceeded, changes collapsed.

+238 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading