blob: 859d9bb49cf29a107d8c0e4121872f2a9c5e25f7 [file] [log] [blame]
/*
* Readme.txt
*
* 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.
*/
Contents
========
(1) Introduction
(2) Directory Structure
(3) Naming Conventions
(4) General Code Structure
(5) Test and Debug Support
(1) Introduction
================
(derived from Bluetooth SIG LC3 specification dr09r06)
The Low Complexity Communication Codec (LC3) is an efficient Bluetooth Audio Codec for use in
audio profiles. This codec can encode speech and music at a variety of bitrates. The LC3 can
be incorporated in any Bluetooth audio profile.
The LC3 specification allows floating point and fixed point implementations as long as the
resulting decoded audio signals are sufficiently close in quality. The given implementation
exploits floating point operation in the majority of the code.
To deliver satisfactory audio quality under all channel conditions, it is strongly recommended
that some form of Packet Loss Concealment (PLC) should be implemented on the receiving ends of
audio connections. The purpose of packet loss concealment is to conceal the effect of unavailable
or corrupted frame data for decoding. The given code implements the example PLC algorithm provided
in the informative Appendix B of the LC3 specification. Alternative PLC schemes are possible, but have
to meet or exceed the performance of the given implementation.
The initial implementation of this codec has been made in year 2019 in parallel to final
improvements and extensions to the LC3 specification. The final implementation has been matched
to the specification, however, references in the code to the specification are not adapted to
the latest formal changes in the specification. Thus, the revision of the specification referenced
is given with each reference, so that it should be possible to track the links to the specification.
(2) Directory Structure
=======================
|- Api -> include files needed by calling application code
|- Common | -> implementation needed by LC3 encoder and decoder
| |-- KissFft -> source code of kissfft library used for fast transforms
| |-- Tables -> tables as given in Section 3.7 "Tables and constants" (dr09r06)
|- Decoder -> implementation of LC3 decoder (*.hpp and *.cpp)
|- Encoder -> implementation of LC3 encoder (*.hpp and *.cpp)
|- TestSupport -> interface and dummy/demo implementation of "datapoint" access
for test and debug support
(3) Naming Conventions and Coding Style
=======================================
Names of variables/objects have been chosen to be as close as possible
to the naming within the LC3 specification. This applies not only to the
selected wording, but also to the chosen case and concatenation of words.
Thus, variable naming may appear somewhat unorthodox to a standard C/C++ developer
and is not always consistent in style. Nevertheless, the close link to the specification
document is considered most valuable so that this approach has been followed.
The LC3 specification contains textual descriptions, equations, pseudo-code, tables
and reference intermediate outputs. The naming of variables is not perfectly consistent,
particularly in the case of names for intermediate outputs in relation to the
specification text. Thus, there are situations where we had to select one name out of
different options or had to choose different names for internal variables and
"datapoints" provided for test and debug support.
Some parts of the code are directly converted from pseudo-code given in
the specification document. Changes compared to the specification are made only
when supported by technical arguments. Again, the close link to the specification
is considered most valuable. Note that this implies in some situations that code
is not optimized in terms of computation effort, memory usage and/or clarity of its structure.
Further Conventions:
- indentation using 4 spaces; no TABS at all
- directory, file and class names are camel-case starting with a capital letter
(4) General Code Structure
==========================
The implementation is in C++ where object oriented programming is mainly used to
formulate the relations of higher level modules/classes. The code of the lower level
modules is syntactically C++, but the style is more like plain old procedural
programming. The latter is mainly due to the goal of formulating the code very close
to the specification - not only with respect to its overall behaviour but also with
respect to the organization. This is particularly true for the modules depending
heavily on converted pseudo-code from the LC3 specification.
A brief overview on the main class relationships is summarized in the following
basic diagrams.
Encoder:
--------
Lc3Encoder : main API and handling of multi-channel sessions
| |(1)------(1) Lc3Config : configuration instance
|
|(1)-------(lc3Config.Nc) EncoderTop : toplevel class for single channel session;
| | dynamically reallocates EncoderFrame instance in case
| | of bitrate changes
| |
| |--- holds all sub-modules directly that are not dependent
| on variable bitrate;
|
|(1)-----(1) EncoderFrame : toplevel processing per frame and
reallocation of sub-modules in case
of bitrate changes
Decoder:
--------
Lc3Decoder : main API and handling of multi-channel sessions
| |(1)------(1) Lc3Config : configuration instance
|
|(1)-------(lc3Config.Nc) DecoderTop : toplevel class for single channel session;
| | dynamically reallocates DecoderFrame instance in case
| | of bitrate changes
| |
| |--- holds all sub-modules directly that are not dependent
| on variable bitrate;
|
|(1)-----(1) DecoderFrame : toplevel processing per frame and
reallocation of sub-modules in case
of bitrate changes
(5) Test and Debug Support
==========================
The development of the codec implementation has been strongly based on close match of
intermediate values with specified reference values. To be able to access the proper
values in a standardized manner a simple "datapoint" API has been created.
Note: this API is not fully optimized for usage within in android but may be extended
for this purpose in future.
The given API can be found in "TestSupport/Datapoints.hpp" with a basic (mainly dummy) implementation
given in "TestSupport/DatapointsAndroid.cpp".
To use this API an instance of "DatapointContainer" has to be created and provided to the
Lc3Encoder and Lc3Decoder constructors when needed. Note: that this is not intended for final releases
due to the additional resources needed.