146 lines
7.8 KiB
Plaintext
146 lines
7.8 KiB
Plaintext
/*
|
|
* Readme.txt
|
|
*
|
|
* Copyright 2019 HIMSA II K/S - www.himsa.dk. 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.
|