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

Commit bdac7b1b authored by Joachim Eggers's avatar Joachim Eggers Committed by Jakub Pawlowski
Browse files

leaudio: LC3 encoder and decoder implementation.

Background: the fast MDCT (backward+forward) is implemented via the DCT-IV which
also needs a fast implementation. The initial approach of using directly the fast
DCT-IV from the fftw library has been extended by the alternative kissfft library.
The main purpose of using the kissfft library is a more simple integration into android.
Particularly with respect to license issues. On the other hand we needed to brake down
the DCT-IV into calling a complex fft, because the kissfft does not provide a specific
optimization for the DCT-IV. The approach via kissfft is now the default DCT-IV implementation.
It is self-contained within the lc3 module since the kissfft sources have been added completely.
There are no changes of the kissfft sources compared to the original library. The sources are taken from:

Bug: 150670922
Tag: #feature
Test: manual
Sponsor: jpawlowski@

Change-Id: I3bf6ca6e83b52ec1b70f091fb12d27744eff1424
parent a443689b
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