diff options
author | Antoine Soulier <asoulier@google.com> | 2023-12-28 10:14:57 -0800 |
---|---|---|
committer | Antoine Soulier <asoulier@google.com> | 2023-12-28 10:16:57 -0800 |
commit | 125c68269617f63efac9c05745637633f6a581c8 (patch) | |
tree | 1202cafd0e88e84bf1e409a55fdc3a46318ccdda | |
parent | 6c99421bac3272bc347c2bb528548ca99fc4fea8 (diff) | |
download | liblc3-125c68269617f63efac9c05745637633f6a581c8.tar.gz |
Documents LC3 Plus feature
-rw-r--r-- | README.md | 25 | ||||
-rw-r--r-- | include/lc3.h | 152 | ||||
-rw-r--r-- | include/lc3_cpp.h | 12 | ||||
-rw-r--r-- | tools/dlc3.c | 8 | ||||
-rw-r--r-- | tools/elc3.c | 8 |
5 files changed, 136 insertions, 69 deletions
@@ -1,8 +1,15 @@ # Low Complexity Communication Codec (LC3) -The LC3 is an efficient low latency audio codec. +LC3 and LC3 Plus are audio codecs designed for low-latency audio transport. -[_Low Complexity Communication Codec_](https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=502107&vId=542963) +- LC3 is specified by [_the Bluetooth Special Interset Group for the LE Audio + protocol_](https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=502107&vId=542963) + +- LC3 Plus is defined by [_ETSI TS 103 634_](https://www.etsi.org/deliver/etsi_ts/103600_103699/103634/01.04.01_60/ts_103634v010401p.pdf) + +In addition to LC3, following features of LC3 Plus are proposed: +- Frame duration of 2.5 and 5ms. +- High-Resolution mode, 48 KHz, and 96 kHz sampling rates. ## Overview @@ -10,7 +17,7 @@ The directory layout is as follows : - include: Library interface - src: Source files - tools: Standalone encoder/decoder tools -- test: Python implentation, used as reference for unit testing +- test: Unit testing framework - fuzz: Roundtrip fuzz testing harness - build: Building outputs - bin: Compilation output @@ -25,6 +32,16 @@ $ make -j Compiled library `liblc3.a` will be found in `bin` directory. +LC3 Plus features can be selectively disabled : +- `LC3_PLUS=0` disable the support of 2.5ms and 5ms frame durations. +- `LC3_PLUS_HR=0` turns off the support of the High-Resolution mode. + +Only Bluetooth LC3 features will be included using the following command: + +```sh +$ make LC3_PLUS=0 LC3_PLUS_HR=0 -j +``` + #### Cross compilation The cc, as, ld and ar can be selected with respective Makefile variables `CC`, @@ -77,7 +94,7 @@ $ ./elc3 <in.wav> -b <bitrate> | ./dlc3 | aplay A python implementation of the encoder is provided in `test` diretory. The C implementation is unitary validated against this implementation and -intermediate values given in Appendix C of the specification. +intermediate values given in Appendix C of the LC3 specification. #### Prerequisite diff --git a/include/lc3.h b/include/lc3.h index c49f0a9..614a58a 100644 --- a/include/lc3.h +++ b/include/lc3.h @@ -20,11 +20,15 @@ * Low Complexity Communication Codec (LC3) * * This implementation conforms to : - * Low Complexity Communication Codec (LC3) - * Bluetooth Specification v1.0 * + * - Low Complexity Communication Codec (LC3) + * Bluetooth Specification v1.0 * - * The LC3 is an efficient low latency audio codec. + * - ETSI TS 103 634 v1.4.1 + * Digital Enhanced Cordless Telecommunications (DECT) + * Low Complexity Communication Codec plus (LC3plus) + * + * LC3 and LC3 Plus are audio codecs designed for low-latency audio transport. * * - Unlike most other codecs, the LC3 codec is focused on audio streaming * in constrained (on packet sizes and interval) tranport layer. @@ -40,19 +44,65 @@ * * - Unlike classic codecs, the LC3 codecs does not run on fixed amount * of samples as input. It operates only on fixed frame duration, for - * any supported samplerates (8 to 48 KHz). Two frames duration are + * any supported sample rates (8 to 48 KHz). Two frames duration are * available 7.5ms and 10ms. * * - * --- About 44.1 KHz samplerate --- + * --- LC3 Plus features --- + * + * In addition to LC3, following features of LC3 Plus are proposed: + * - Frame duration of 2.5 and 5ms. + * - High-Resolution mode, 48 KHz, and 96 kHz sampling rates. + * + * The distinction between LC3 and LC3 plus is made according to : + * + * Frame Duration | 2.5ms | 5ms | 7.5ms | 10 ms | + * ---------------- | ----- | ----- | ----- | ----- | + * LC3 | | | X | X | + * LC3 Plus | X | X | | X | + * + * The 10 ms frame duration is available in LC3 and LC3 plus standard. + * In this mode, the produced bitstream can be referenced either + * as LC3 or LC3 plus. + * + * The LC3 Plus high-resolution mode should be preferred at high bitrates + * and larger audio bandwidth. In this mode, the audio bandwidth is always + * up to the Nyquist frequency, compared to LC3 at 48 KHz, which limits + * the bandwidth to 20 KHz. + * + * + * --- Bit rate --- + * + * The proposed implementation accepts any frame sizes between 20 and 400 Bytes + * for non-high-resolution mode. Mind that the LC3 Plus standard defines + * smaller sizes for frame durations shorter than 10 ms and/or sampling rates + * less than 48 kHz. + * + * In High-Resolution mode, the frame sizes (and bitrates) are restricted + * as follows: + * + * HR Configuration | Frame sizes | Bitrate (kbps) | + * ------------------ | ------------- | -------------- | + * 10 ms - 48 KHz | 156 to 625 | 124.8 - 500 | + * 10 ms - 96 KHz | 187 to 625 | 149.6 - 500 | + * ------------------ | ------------- | -------------- | + * 5 ms - 48 KHz | 93 to 375 | 148.8 - 600 | + * 5 ms - 96 KHz | 109 to 375 | 174.4 - 600 | + * ------------------ | ------------- | -------------- | + * 2.5 ms - 48 KHz | 54 to 210 | 172.8 - 672 | + * 2.5 ms - 96 KHz | 62 to 210 | 198.4 - 672 | + * + * + * --- About 44.1 KHz sample rate --- * - * The Bluetooth specification reference the 44.1 KHz samplerate, although - * there is no support in the core algorithm of the codec of 44.1 KHz. - * We can summarize the 44.1 KHz support by "you can put any samplerate - * around the defined base samplerates". Please mind the following items : + * The Bluetooth specification and the ETSI TS 103 634 standard references + * the 44.1 KHz sample rate, although there is no support in the core algorithm + * of the codec. + * We can summarize the 44.1 KHz support by "You can put any sample rate around + * the defined base sample rates." Please mind the following items : * - * 1. The frame size will not be 7.5 ms or 10 ms, but is scaled - * by 'supported samplerate' / 'input samplerate' + * 1. The frame size will not be 2.5ms, 5ms, 7.5 ms or 10 ms, but is scaled + * by 'supported sample rate' / 'input sample rate' * * 2. The bandwidth will be hard limited (to 20 KHz) if you select 48 KHz. * The encoded bandwidth will also be affected by the above inverse @@ -84,8 +134,8 @@ * space must be aligned to a pointer size. As an example, you can setup * encoder like this : * - * | enc = lc3_setup_encoder(frame_us, samplerate, - * | malloc(lc3_encoder_size(frame_us, samplerate))); + * | enc = lc3_setup_encoder(frame_us, sample rate, + * | malloc(lc3_encoder_size(frame_us, sample rate))); * | ... * | free(enc); * @@ -124,31 +174,31 @@ extern "C" { /** * Limitations - * - On the bitrate, in bps (48 KHz, 10ms frame size) + * - On the bitrate, in bps * - On the size of the frames in bytes * - On the number of samples by frames */ #define LC3_MIN_BITRATE 16000 #define LC3_MAX_BITRATE 320000 -#define LC3_MAX_HR_BITRATE 500000 +#define LC3_HR_MAX_BITRATE 672000 #define LC3_MIN_FRAME_BYTES 20 #define LC3_MAX_FRAME_BYTES 400 -#define LC3_MAX_HR_FRAME_BYTES 625 +#define LC3_HR_MAX_FRAME_BYTES 625 #define LC3_MIN_FRAME_SAMPLES LC3_NS( 2500, 8000) #define LC3_MAX_FRAME_SAMPLES LC3_NS(10000, 48000) -#define LC3_MAX_HR_FRAME_SAMPLES LC3_NS(10000, 96000) +#define LC3_HR_MAX_FRAME_SAMPLES LC3_NS(10000, 96000) /** * Parameters check * LC3_CHECK_DT_US(us) True when frame duration in us is suitable - * LC3_CHECK_SR_HZ(sr) True when samplerate in Hz is suitable + * LC3_CHECK_SR_HZ(sr) True when sample rate in Hz is suitable * - * LC3_CHECK_HR_SR_HZ(hrmode, sr) - * True when samplerate in Hz is suitable, according to the + * LC3_HR_CHECK_SR_HZ(hrmode, sr) + * True when sample rate in Hz is suitable, according to the * selection of the high-resolution mode `hrmode`. */ @@ -160,7 +210,7 @@ extern "C" { ( ((sr) == 8000) || ((sr) == 16000) || ((sr) == 24000) || \ ((sr) == 32000) || ((sr) == 48000) ) -#define LC3_CHECK_HR_SR_HZ(hrmode, sr) \ +#define LC3_HR_CHECK_SR_HZ(hrmode, sr) \ ( (hrmode) ? ((sr) == 48000) || ((sr) == 96000) : LC3_CHECK_SR_HZ(sr) ) @@ -190,10 +240,10 @@ typedef struct lc3_decoder *lc3_decoder_t; /** - * Static memory of encoder context + * Static memory of encoder/decoder contexts * * Propose types suitable for static memory allocation, supporting - * any frame duration, and maximum samplerates 16k and 48k respectively + * any frame duration, and maximum sample rates 16k and 48k respectively * You can customize your type using the `LC3_ENCODER_MEM_T` or * `LC3_DECODER_MEM_T` macro. */ @@ -207,9 +257,9 @@ typedef LC3_DECODER_MEM_T(10000, 48000) lc3_decoder_mem_48k_t; /** * Return the number of PCM samples in a frame - * hrmode Enable High-Resolution mode (48000 and 96000 samplerates) + * hrmode Enable High-Resolution mode (48000 and 96000 sample rates) * dt_us Frame duration in us, 2500, 5000, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 + * sr_hz Sample rate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 * return Number of PCM samples, -1 on bad parameters */ int lc3_hr_frame_samples(bool hrmode, int dt_us, int sr_hz); @@ -218,9 +268,9 @@ int lc3_frame_samples(int dt_us, int sr_hz); /** * Return the size of frames, from bitrate - * hrmode Enable High-Resolution mode (48000 and 96000 samplerates) + * hrmode Enable High-Resolution mode (48000 and 96000 sample rates) * dt_us Frame duration in us, 2500, 5000, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 + * sr_hz Sample rate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 * bitrate Target bitrate in bit per second, 0 or `INT_MAX` returns * respectively the minimum and maximum allowed size. * return The floor size in bytes of the frames, -1 on bad parameters @@ -231,9 +281,9 @@ int lc3_frame_bytes(int dt_us, int bitrate); /** * Resolve the bitrate, from the size of frames - * hrmode Enable High-Resolution mode (48000 and 96000 samplerates) + * hrmode Enable High-Resolution mode (48000 and 96000 sample rates) * dt_us Frame duration in us, 2500, 5000, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 + * sr_hz Sample rate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 * nbytes Size in bytes of the frames, 0 or `INT_MAX` returns * respectively the minimum and maximum allowed bitrate. * return The according bitrate in bps, -1 on bad parameters @@ -244,9 +294,9 @@ int lc3_resolve_bitrate(int dt_us, int nbytes); /** * Return algorithmic delay, as a number of samples - * hrmode Enable High-Resolution mode (48000 and 96000 samplerates) + * hrmode Enable High-Resolution mode (48000 and 96000 sample rates) * dt_us Frame duration in us, 2500, 5000, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 + * sr_hz Sample rate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 * return Number of algorithmic delay samples, -1 on bad parameters */ int lc3_hr_delay_samples(bool hrmode, int dt_us, int sr_hz); @@ -255,12 +305,12 @@ int lc3_delay_samples(int dt_us, int sr_hz); /** * Return size needed for an encoder - * hrmode Enable High-Resolution mode (48000 and 96000 samplerates) + * hrmode Enable High-Resolution mode (48000 and 96000 sample rates) * dt_us Frame duration in us, 2500, 5000, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 + * sr_hz Sample rate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 * return Size of then encoder in bytes, 0 on bad parameters * - * The `sr_hz` parameter is the samplerate of the PCM input stream, + * The `sr_hz` parameter is the sample rate of the PCM input stream, * and will match `sr_pcm_hz` of `lc3_hr_setup_encoder()`. */ unsigned lc3_hr_encoder_size(bool hrmode, int dt_us, int sr_hz); @@ -269,18 +319,18 @@ unsigned lc3_encoder_size(int dt_us, int sr_hz); /** * Setup encoder - * hrmode Enable High-Resolution mode (48000 and 96000 samplerates) + * hrmode Enable High-Resolution mode (48000 and 96000 sample rates) * dt_us Frame duration in us, 2500, 5000, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 - * sr_pcm_hz Input samplerate, downsampling option of input, or 0 + * sr_hz Sample rate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 + * sr_pcm_hz Input sample rate, downsampling option of input, or 0 * mem Encoder memory space, aligned to pointer type * return Encoder as an handle, NULL on bad parameters * * The `sr_pcm_hz` parameter is a downsampling option of PCM input, - * the value `0` fallback to the samplerate of the encoded stream `sr_hz`. + * the value `0` fallback to the sample rate of the encoded stream `sr_hz`. * When used, `sr_pcm_hz` is intended to be higher or equal to the encoder - * samplerate `sr_hz`. The size of the context needed, given by - * `lc3_encoder_size()` will be set accordingly to `sr_pcm_hz`. + * sample rate `sr_hz`. The size of the context needed, given by + * `lc3_hr_encoder_size()` will be set accordingly to `sr_pcm_hz`. */ lc3_encoder_t lc3_hr_setup_encoder(bool hrmode, int dt_us, int sr_hz, int sr_pcm_hz, void *mem); @@ -293,7 +343,7 @@ lc3_encoder_t lc3_setup_encoder( * encoder Handle of the encoder * fmt PCM input format * pcm, stride Input PCM samples, and count between two consecutives - * nbytes Target size, in bytes, of the frame (20 to 400) + * nbytes Target size, in bytes, of the frame * out Output buffer of `nbytes` size * return 0: On success -1: Wrong parameters */ @@ -302,13 +352,13 @@ int lc3_encode(lc3_encoder_t encoder, enum lc3_pcm_format fmt, /** * Return size needed for an decoder - * hrmode Enable High-Resolution mode (48000 and 96000 samplerates) + * hrmode Enable High-Resolution mode (48000 and 96000 sample rates) * dt_us Frame duration in us, 2500, 5000, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 + * sr_hz Sample rate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 * return Size of then decoder in bytes, 0 on bad parameters * - * The `sr_hz` parameter is the samplerate of the PCM output stream, - * and will match `sr_pcm_hz` of `lc3_setup_decoder()`. + * The `sr_hz` parameter is the sample rate of the PCM output stream, + * and will match `sr_pcm_hz` of `lc3_hr_setup_decoder()`. */ unsigned lc3_hr_decoder_size(bool hrmode, int dt_us, int sr_hz); @@ -316,18 +366,18 @@ unsigned lc3_decoder_size(int dt_us, int sr_hz); /** * Setup decoder - * hrmode Enable High-Resolution mode (48000 and 96000 samplerates) + * hrmode Enable High-Resolution mode (48000 and 96000 sample rates) * dt_us Frame duration in us, 2500, 5000, 7500 or 10000 - * sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 - * sr_pcm_hz Output samplerate, upsampling option of output (or 0) + * sr_hz Sample rate in Hz, 8000, 16000, 24000, 32000, 48000 or 96000 + * sr_pcm_hz Output sample rate, upsampling option of output (or 0) * mem Decoder memory space, aligned to pointer type * return Decoder as an handle, NULL on bad parameters * * The `sr_pcm_hz` parameter is an upsampling option of PCM output, - * the value `0` fallback to the samplerate of the decoded stream `sr_hz`. + * the value `0` fallback to the sample rate of the decoded stream `sr_hz`. * When used, `sr_pcm_hz` is intended to be higher or equal to the decoder - * samplerate `sr_hz`. The size of the context needed, given by - * `lc3_decoder_size()` will be set accordingly to `sr_pcm_hz`. + * sample rate `sr_hz`. The size of the context needed, given by + * `lc3_hr_decoder_size()` will be set accordingly to `sr_pcm_hz`. */ lc3_decoder_t lc3_hr_setup_decoder(bool hrmode, int dt_us, int sr_hz, int sr_pcm_hz, void *mem); diff --git a/include/lc3_cpp.h b/include/lc3_cpp.h index 660f527..3900b9b 100644 --- a/include/lc3_cpp.h +++ b/include/lc3_cpp.h @@ -108,14 +108,14 @@ class Encoder : public Base<struct lc3_encoder> { // Encoder construction / destruction // // The frame duration `dt_us` is 2500, 5000, 7500 or 10000 us. - // The samplerate `sr_hz` is 8000, 16000, 24000, 32000 or 48000 Hz. + // The sample rate `sr_hz` is 8000, 16000, 24000, 32000 or 48000 Hz. // The `hrmode` flag enables the high-resolution mode, in which case // the sample rate is 48000 or 96000 Hz. // // The `sr_pcm_hz` parameter is a downsampling option of PCM input, - // the value 0 fallback to the samplerate of the encoded stream `sr_hz`. + // the value 0 fallback to the sample rate of the encoded stream `sr_hz`. // When used, `sr_pcm_hz` is intended to be higher or equal to the encoder - // samplerate `sr_hz`. + // sample rate `sr_hz`. Encoder(int dt_us, int sr_hz, int sr_pcm_hz = 0, size_t nchannels = 1, bool hrmode = false) @@ -209,14 +209,14 @@ class Decoder : public Base<struct lc3_decoder> { // Decoder construction / destruction // // The frame duration `dt_us` is 2500, 5000, 7500 or 10000 us. - // The samplerate `sr_hz` is 8000, 16000, 24000, 32000 or 48000 Hz. + // The sample rate `sr_hz` is 8000, 16000, 24000, 32000 or 48000 Hz. // The `hrmode` flag enables the high-resolution mode, in which case // the sample rate is 48000 or 96000 Hz. // // The `sr_pcm_hz` parameter is an downsampling option of PCM output, - // the value 0 fallback to the samplerate of the decoded stream `sr_hz`. + // the value 0 fallback to the sample rate of the decoded stream `sr_hz`. // When used, `sr_pcm_hz` is intended to be higher or equal to the decoder - // samplerate `sr_hz`. + // sample rate `sr_hz`. Decoder(int dt_us, int sr_hz, int sr_pcm_hz = 0, size_t nchannels = 1, bool hrmode = false) diff --git a/tools/dlc3.c b/tools/dlc3.c index 69760be..d351324 100644 --- a/tools/dlc3.c +++ b/tools/dlc3.c @@ -171,10 +171,10 @@ int main(int argc, char *argv[]) if (!LC3_CHECK_DT_US(frame_us)) error(EINVAL, "Frame duration"); - if (!LC3_CHECK_HR_SR_HZ(hrmode, srate_hz)) + if (!LC3_HR_CHECK_SR_HZ(hrmode, srate_hz)) error(EINVAL, "Samplerate %d Hz", srate_hz); - if (p.srate_hz && (!LC3_CHECK_HR_SR_HZ(hrmode, p.srate_hz) || + if (p.srate_hz && (!LC3_HR_CHECK_SR_HZ(hrmode, p.srate_hz) || p.srate_hz < srate_hz )) error(EINVAL, "Output samplerate %d Hz", p.srate_hz); @@ -190,8 +190,8 @@ int main(int argc, char *argv[]) /* --- Setup decoding --- */ - uint8_t in[2 * LC3_MAX_HR_FRAME_BYTES]; - int8_t alignas(int32_t) pcm[2 * LC3_MAX_HR_FRAME_SAMPLES*4]; + uint8_t in[2 * LC3_HR_MAX_FRAME_BYTES]; + int8_t alignas(int32_t) pcm[2 * LC3_HR_MAX_FRAME_SAMPLES*4]; lc3_decoder_t dec[2]; int frame_samples = lc3_hr_frame_samples(hrmode, frame_us, pcm_srate_hz); diff --git a/tools/elc3.c b/tools/elc3.c index af7dfbc..4d7b010 100644 --- a/tools/elc3.c +++ b/tools/elc3.c @@ -171,7 +171,7 @@ int main(int argc, char *argv[]) if (!LC3_CHECK_DT_US(frame_us)) error(EINVAL, "Frame duration"); - if (!LC3_CHECK_HR_SR_HZ(p.hrmode, srate_hz)) + if (!LC3_HR_CHECK_SR_HZ(p.hrmode, srate_hz)) error(EINVAL, "Samplerate %d Hz", srate_hz); if (pcm_sbits != 16 && pcm_sbits != 24) @@ -184,7 +184,7 @@ int main(int argc, char *argv[]) if (nch < 1 || nch > 2) error(EINVAL, "Number of channels %d", nch); - if (p.srate_hz && (!LC3_CHECK_HR_SR_HZ(p.hrmode, p.srate_hz) || + if (p.srate_hz && (!LC3_HR_CHECK_SR_HZ(p.hrmode, p.srate_hz) || p.srate_hz > srate_hz )) error(EINVAL, "Encoder samplerate %d Hz", p.srate_hz); @@ -198,8 +198,8 @@ int main(int argc, char *argv[]) /* --- Setup encoding --- */ - int8_t alignas(int32_t) pcm[2 * LC3_MAX_HR_FRAME_SAMPLES*4]; - uint8_t out[2 * LC3_MAX_HR_FRAME_BYTES]; + int8_t alignas(int32_t) pcm[2 * LC3_HR_MAX_FRAME_SAMPLES*4]; + uint8_t out[2 * LC3_HR_MAX_FRAME_BYTES]; lc3_encoder_t enc[2]; int frame_bytes = lc3_hr_frame_bytes( |