Skip to content

Commit ca95526

Browse files
libsbc: sbc: implement SBC codec
Use the Android Bluetooth SBC encoder and decoder. The Android Bluetooth SBC is put as external library (libsbc). sbc.c/sbc.h implement the interface that is compliant with Zephyr style and can be used by Zephyr's other modules ( like A2DP). Signed-off-by: Mark Wang <yichang.wang@nxp.com>
1 parent f52d71c commit ca95526

File tree

5 files changed

+371
-0
lines changed

5 files changed

+371
-0
lines changed

include/zephyr/libsbc/sbc.h

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2024 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <stdint.h>
8+
#include <stdbool.h>
9+
#include <string.h>
10+
#if defined(CONFIG_LIBSBC_ENCODER)
11+
#include "sbc_encoder.h"
12+
#endif
13+
#if defined(CONFIG_LIBSBC_DECODER)
14+
#include "oi_codec_sbc.h"
15+
#include "oi_status.h"
16+
#endif
17+
18+
enum __packed sbc_ch_mode {
19+
SBC_CH_MODE_MONO,
20+
SBC_CH_MODE_DUAL_CHANNEL,
21+
SBC_CH_MODE_STEREO,
22+
SBC_CH_MODE_JOINT_STEREO,
23+
};
24+
25+
enum __packed sbc_alloc_mthd {
26+
SBC_ALLOC_MTHD_LOUDNESS,
27+
SBC_ALLOC_MTHD_SNR,
28+
};
29+
30+
#if defined(CONFIG_LIBSBC_ENCODER)
31+
32+
struct sbc_encoder {
33+
SBC_ENC_PARAMS sbc_encoder_params;
34+
};
35+
36+
struct sbc_encoder_init_param {
37+
uint32_t bit_rate;
38+
uint32_t samp_freq;
39+
uint8_t blk_len;
40+
uint8_t subband;
41+
enum sbc_alloc_mthd alloc_mthd;
42+
enum sbc_ch_mode ch_mode;
43+
uint8_t ch_num;
44+
uint8_t min_bitpool;
45+
uint8_t max_bitpool;
46+
};
47+
48+
/**
49+
* Setup encoder
50+
* param The init parameters.
51+
* return Zero on success or (negative) error code otherwise.
52+
*/
53+
int sbc_setup_encoder(struct sbc_encoder *encoder, struct sbc_encoder_init_param *param);
54+
55+
/**
56+
* Encode a frame
57+
* encoder Handle of the encoder
58+
* in_data Input PCM samples
59+
* nbytes Target size, in bytes, of the frame
60+
* out_data Output buffer of `nbytes` size
61+
* return Return number of bytes output
62+
*/
63+
uint32_t sbc_encode(struct sbc_encoder *encoder, const void *in_data, void *out_data);
64+
65+
/**
66+
* Return the number of PCM samples in a frame
67+
* encoder Handle of the encoder.
68+
* return Number of PCM samples or (negative) error code otherwise
69+
*/
70+
int sbc_frame_samples(struct sbc_encoder *encoder);
71+
72+
/**
73+
* Return the number of PCM bytes in a frame
74+
* encoder Handle of the encoder.
75+
* return Number of PCM bytes or (negative) error code otherwise
76+
*/
77+
int sbc_frame_bytes(struct sbc_encoder *encoder);
78+
79+
/**
80+
* Return the encoded size of one frame
81+
* encoder Handle of the encoder.
82+
* return The encoded size of one frame in bytes or (negative) error code otherwise
83+
*/
84+
int sbc_frame_encoded_bytes(struct sbc_encoder *encoder);
85+
#endif
86+
87+
#if defined(CONFIG_LIBSBC_DECODER)
88+
89+
struct sbc_decoder {
90+
OI_CODEC_SBC_DECODER_CONTEXT context;
91+
uint32_t context_data[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
92+
};
93+
94+
/**
95+
* Setup the SBC decoder.
96+
* decoder Handle of the decoder
97+
*
98+
* return Zero on success or (negative) error code otherwise.
99+
*/
100+
int sbc_setup_decoder(struct sbc_decoder *decoder);
101+
102+
/**
103+
* Decode a frame
104+
* decoder Handle of the decoder
105+
* in_data Input bitstream, it is increased after decode one frame
106+
* in_size Input data size in bytes, it is decreased after decode one frame
107+
* out_data Output PCM samples
108+
* out_size Output data size in bytes
109+
* return Zero on success or (negative) error code otherwise.
110+
*/
111+
int sbc_decode(struct sbc_decoder *decoder, const void **in_data, uint32_t *in_size,
112+
void *out_data, uint32_t *out_size);
113+
#endif

modules/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ comment "hal_nxp module not available."
7878
comment "liblc3 module not available."
7979
depends on !ZEPHYR_LIBLC3_MODULE
8080

81+
comment "libsbc module not available."
82+
depends on !ZEPHYR_LIBSBC_MODULE
83+
8184
comment "LittleFS module not available."
8285
depends on !ZEPHYR_LITTLEFS_MODULE
8386

modules/libsbc/CMakeLists.txt

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
if(CONFIG_LIBSBC_ENCODER OR CONFIG_LIBSBC_DECODER)
2+
3+
zephyr_library_named(libsbc)
4+
zephyr_library_compile_options(-O3 -std=c11 -ffast-math -Wno-array-bounds)
5+
6+
zephyr_compile_definitions(SBC_FOR_EMBEDDED_LINUX)
7+
zephyr_compile_definitions(SBC_NO_PCM_CPY_OPTION)
8+
zephyr_library_sources(sbc.c)
9+
10+
if(CONFIG_LIBSBC_ENCODER)
11+
zephyr_library_sources(
12+
${ZEPHYR_LIBSBC_MODULE_DIR}/encoder/srce/sbc_analysis.c
13+
${ZEPHYR_LIBSBC_MODULE_DIR}/encoder/srce/sbc_dct.c
14+
${ZEPHYR_LIBSBC_MODULE_DIR}/encoder/srce/sbc_dct_coeffs.c
15+
${ZEPHYR_LIBSBC_MODULE_DIR}/encoder/srce/sbc_enc_bit_alloc_mono.c
16+
${ZEPHYR_LIBSBC_MODULE_DIR}/encoder/srce/sbc_enc_bit_alloc_ste.c
17+
${ZEPHYR_LIBSBC_MODULE_DIR}/encoder/srce/sbc_enc_coeffs.c
18+
${ZEPHYR_LIBSBC_MODULE_DIR}/encoder/srce/sbc_encoder.c
19+
${ZEPHYR_LIBSBC_MODULE_DIR}/encoder/srce/sbc_packing.c
20+
)
21+
zephyr_include_directories(
22+
${ZEPHYR_LIBSBC_MODULE_DIR}/encoder/include
23+
)
24+
endif()
25+
26+
if(CONFIG_LIBSBC_DECODER)
27+
zephyr_library_sources(
28+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/alloc.c
29+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/bitalloc.c
30+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/bitalloc-sbc.c
31+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/bitstream-decode.c
32+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/decoder-oina.c
33+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/decoder-private.c
34+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/decoder-sbc.c
35+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/dequant.c
36+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/framing.c
37+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/framing-sbc.c
38+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/oi_codec_version.c
39+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/readsamplesjoint.inc
40+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/synthesis-8-generated.c
41+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/synthesis-dct8.c
42+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce/synthesis-sbc.c
43+
)
44+
zephyr_include_directories(
45+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/include
46+
${ZEPHYR_LIBSBC_MODULE_DIR}/decoder/srce
47+
)
48+
endif()
49+
endif()

modules/libsbc/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) 2024 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config ZEPHYR_LIBSBC_MODULE
5+
bool
6+
7+
config LIBSBC_ENCODER
8+
bool "libsbc encoder Support"
9+
help
10+
This option enables the Android SBC encoder library for Bluetooth A2DP
11+
12+
config LIBSBC_DECODER
13+
bool "libsbc decoder Support"
14+
help
15+
This option enables the Android SBC decoder library for Bluetooth A2DP

modules/libsbc/sbc.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
* Copyright 2024 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <errno.h>
8+
#include <zephyr/libsbc/sbc.h>
9+
10+
#if defined(CONFIG_LIBSBC_ENCODER)
11+
12+
int sbc_setup_encoder(struct sbc_encoder *encoder, struct sbc_encoder_init_param *param)
13+
{
14+
SBC_ENC_PARAMS *encoder_params;
15+
16+
if (encoder == NULL) {
17+
return -EINVAL;
18+
}
19+
20+
memset(encoder, 0, sizeof(struct sbc_encoder));
21+
22+
encoder_params = &encoder->sbc_encoder_params;
23+
24+
encoder_params->s16ChannelMode = (int16_t)param->ch_mode;
25+
encoder_params->s16NumOfSubBands = (int16_t)param->subband;
26+
if (!encoder_params->s16NumOfSubBands) {
27+
return -EINVAL;
28+
}
29+
encoder_params->s16NumOfBlocks = (int16_t)param->blk_len;
30+
if (!encoder_params->s16NumOfBlocks) {
31+
return -EINVAL;
32+
}
33+
encoder_params->s16AllocationMethod = (int16_t)param->alloc_mthd;
34+
encoder_params->s16NumOfChannels = param->ch_num;
35+
if (!encoder_params->s16NumOfChannels) {
36+
return -EINVAL;
37+
}
38+
39+
switch (param->samp_freq) {
40+
case 16000u:
41+
encoder_params->s16SamplingFreq = 0;
42+
break;
43+
case 32000u:
44+
encoder_params->s16SamplingFreq = 1;
45+
break;
46+
case 44100u:
47+
encoder_params->s16SamplingFreq = 2;
48+
break;
49+
case 48000u:
50+
encoder_params->s16SamplingFreq = 3;
51+
break;
52+
default:
53+
return -EINVAL;
54+
}
55+
56+
encoder_params->u16BitRate = param->bit_rate;
57+
58+
SBC_Encoder_Init(encoder_params);
59+
60+
if (encoder_params->s16BitPool < param->min_bitpool) {
61+
/* need to increase the `param->bit_rate` */
62+
return -EINVAL;
63+
} else if (encoder_params->s16BitPool > param->max_bitpool) {
64+
/* need to decrease the `param->bit_rate` */
65+
return -EOVERFLOW;
66+
}
67+
68+
return 0;
69+
}
70+
71+
/**
72+
* Encode a SBC frame
73+
*/
74+
uint32_t sbc_encode(struct sbc_encoder *encoder, const void *in_data, void *out_data)
75+
{
76+
uint32_t ret;
77+
78+
if ((encoder == NULL) || (in_data == NULL) || (out_data == NULL)) {
79+
return 0;
80+
}
81+
82+
ret = SBC_Encode(&encoder->sbc_encoder_params, (int16_t *)in_data, out_data);
83+
84+
return ret;
85+
}
86+
87+
int sbc_frame_samples(struct sbc_encoder *encoder)
88+
{
89+
if (encoder == NULL) {
90+
return -EINVAL;
91+
}
92+
93+
return encoder->sbc_encoder_params.s16NumOfSubBands *
94+
encoder->sbc_encoder_params.s16NumOfBlocks;
95+
}
96+
97+
int sbc_frame_bytes(struct sbc_encoder *encoder)
98+
{
99+
if (encoder == NULL) {
100+
return -EINVAL;
101+
}
102+
103+
return sbc_frame_samples(encoder) * 2 *
104+
(encoder->sbc_encoder_params.s16ChannelMode == SBC_CH_MODE_MONO ? 1 : 2);
105+
}
106+
107+
int sbc_frame_encoded_bytes(struct sbc_encoder *encoder)
108+
{
109+
int size = 4;
110+
int channel_num = 2;
111+
SBC_ENC_PARAMS *encoder_params;
112+
113+
if (encoder == NULL) {
114+
return -EINVAL;
115+
}
116+
117+
encoder_params = &encoder->sbc_encoder_params;
118+
119+
if (encoder_params->s16ChannelMode == SBC_CH_MODE_MONO) {
120+
channel_num = 1;
121+
}
122+
123+
size += (4 * encoder_params->s16NumOfSubBands * channel_num) / 8;
124+
if ((encoder_params->s16ChannelMode == SBC_CH_MODE_MONO) ||
125+
(encoder_params->s16ChannelMode == SBC_CH_MODE_DUAL_CHANNEL)) {
126+
size += ((encoder_params->s16NumOfBlocks * channel_num *
127+
encoder_params->s16BitPool + 7) / 8);
128+
} else if (encoder_params->s16ChannelMode == SBC_CH_MODE_STEREO) {
129+
size += ((encoder_params->s16NumOfBlocks *
130+
encoder_params->s16BitPool + 7) / 8);
131+
} else {
132+
size += ((encoder_params->s16NumOfSubBands +
133+
encoder_params->s16NumOfBlocks *
134+
encoder_params->s16BitPool + 7) / 8);
135+
}
136+
137+
return size;
138+
}
139+
#endif
140+
141+
#if defined(CONFIG_LIBSBC_DECODER)
142+
/**
143+
* Setup decoder
144+
*/
145+
int sbc_setup_decoder(struct sbc_decoder *decoder)
146+
{
147+
OI_STATUS status;
148+
149+
if (decoder == NULL) {
150+
return -EINVAL;
151+
}
152+
153+
memset(decoder, 0, sizeof(struct sbc_decoder));
154+
155+
status = OI_CODEC_SBC_DecoderReset(
156+
&decoder->context,
157+
&decoder->context_data[0],
158+
sizeof(decoder->context_data),
159+
2, 2, FALSE);
160+
if (!OI_SUCCESS(status)) {
161+
return -EIO;
162+
}
163+
164+
return 0;
165+
}
166+
167+
/**
168+
* Decode a frame
169+
*/
170+
int sbc_decode(struct sbc_decoder *decoder, const void **in_data, uint32_t *in_size,
171+
void *out_data, uint32_t *out_size)
172+
{
173+
OI_STATUS status;
174+
175+
if (decoder == NULL || in_data == NULL || in_size == NULL ||
176+
out_data == NULL || out_size == NULL) {
177+
return -EINVAL;
178+
}
179+
180+
status = OI_CODEC_SBC_DecodeFrame(&decoder->context,
181+
(const OI_BYTE**)in_data,
182+
in_size,
183+
out_data,
184+
out_size);
185+
if (!OI_SUCCESS(status)) {
186+
return -EIO;
187+
} else {
188+
return 0;
189+
}
190+
}
191+
#endif

0 commit comments

Comments
 (0)