From 87843366cecc935ede11bda6e23fada33b4fde23 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Sat, 14 Jun 2025 18:52:55 +0300 Subject: [PATCH] bluez5: add PLC for MSBC using spandsp Use spandsp as optional dependency for MSBC codec, for providing PLC. --- meson_options.txt | 4 ++++ spa/meson.build | 3 +++ spa/plugins/bluez5/hfp-codec-msbc.c | 35 ++++++++++++++++++++++++++--- spa/plugins/bluez5/meson.build | 2 +- spa/plugins/bluez5/plc.h | 26 +++++++++++++++++++++ 5 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 spa/plugins/bluez5/plc.h diff --git a/meson_options.txt b/meson_options.txt index cd2c839f7..e55fe22a1 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -153,6 +153,10 @@ option('bluez5-codec-g722', description: 'Enable G722 open source codec implementation', type: 'feature', value: 'auto') +option('bluez5-plc-spandsp', + description: 'Enable SpanDSP for packet loss concealment', + type: 'feature', + value: 'auto') option('control', description: 'Enable control spa plugin integration', type: 'feature', diff --git a/spa/meson.build b/spa/meson.build index 637aeb8d4..1f749757c 100644 --- a/spa/meson.build +++ b/spa/meson.build @@ -111,6 +111,9 @@ if get_option('spa-plugins').allowed() endif g722_codec_option = get_option('bluez5-codec-g722') summary({'G722': g722_codec_option.allowed()}, bool_yn: true, section: 'Bluetooth audio codecs') + + spandsp_dep = dependency('spandsp', required : get_option('bluez5-plc-spandsp')) + cdata.set('HAVE_SPANDSP', spandsp_dep.found()) endif have_vulkan = false diff --git a/spa/plugins/bluez5/hfp-codec-msbc.c b/spa/plugins/bluez5/hfp-codec-msbc.c index 2e6f838eb..d2aabe2b0 100644 --- a/spa/plugins/bluez5/hfp-codec-msbc.c +++ b/spa/plugins/bluez5/hfp-codec-msbc.c @@ -3,6 +3,8 @@ /* SPDX-FileCopyrightText: Copyright © 2025 Pauli Virtanen */ /* SPDX-License-Identifier: MIT */ +#include "config.h" + #include #include #include @@ -24,10 +26,12 @@ #include "media-codecs.h" #include "hfp-h2.h" +#include "plc.h" + #define MSBC_BLOCK_SIZE 240 -static struct spa_log *log; +static struct spa_log *log_; struct impl { sbc_t msbc; @@ -36,6 +40,8 @@ struct impl { void *data; size_t avail; + + plc_state_t *plc; }; static int codec_enum_config(const struct media_codec *codec, uint32_t flags, @@ -104,6 +110,10 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags, h2_reader_init(&this->h2, true); + this->plc = plc_init(NULL); + if (!this->plc) + return NULL; + return spa_steal_ptr(this); } @@ -112,6 +122,7 @@ static void codec_deinit(void *data) struct impl *this = data; sbc_finish(&this->msbc); + plc_free(this->plc); free(this); } @@ -198,13 +209,30 @@ static int codec_decode(void *data, return consumed; } + plc_rx(this->plc, dst, *dst_out / sizeof(int16_t)); + return consumed; } +static int codec_produce_plc(void *data, void *dst, size_t dst_size) +{ + struct impl *this = data; + int res; + + if (dst_size < MSBC_BLOCK_SIZE) + return -EINVAL; + + res = plc_fillin(this->plc, dst, MSBC_BLOCK_SIZE / sizeof(int16_t)); + if (res < 0) + return res; + + return MSBC_BLOCK_SIZE; +} + static void codec_set_log(struct spa_log *global_log) { - log = global_log; - spa_log_topic_init(log, &codec_plugin_log_topic); + log_ = global_log; + spa_log_topic_init(log_, &codec_plugin_log_topic); } const struct media_codec hfp_codec_msbc = { @@ -221,6 +249,7 @@ const struct media_codec hfp_codec_msbc = { .set_log = codec_set_log, .start_decode = codec_start_decode, .decode = codec_decode, + .produce_plc = codec_produce_plc, .name = "msbc", .description = "MSBC", .stream_pkt = true, diff --git a/spa/plugins/bluez5/meson.build b/spa/plugins/bluez5/meson.build index bf9c6374b..01c5f3ac1 100644 --- a/spa/plugins/bluez5/meson.build +++ b/spa/plugins/bluez5/meson.build @@ -110,7 +110,7 @@ bluez_codec_hfp_msbc = shared_library('spa-codec-bluez5-hfp-msbc', [ 'hfp-codec-msbc.c', 'media-codecs.c' ], include_directories : [ configinc ], c_args : codec_args, - dependencies : [ spa_dep, sbc_dep ], + dependencies : [ spa_dep, sbc_dep, spandsp_dep ], install : true, install_dir : spa_plugindir / 'bluez5') diff --git a/spa/plugins/bluez5/plc.h b/spa/plugins/bluez5/plc.h new file mode 100644 index 000000000..7ad23697d --- /dev/null +++ b/spa/plugins/bluez5/plc.h @@ -0,0 +1,26 @@ +/* Spa PLC */ +/* SPDX-FileCopyrightText: Copyright © 2025 Pauli Virtanen */ +/* SPDX-License-Identifier: MIT */ + +#ifndef SPA_BLUEZ5_PLC_H +#define SPA_BLUEZ5_PLC_H + +#include +#include +#include + +#ifdef HAVE_SPANDSP +#include +#else +typedef struct { char dummy; } plc_state_t; +static inline int plc_rx(plc_state_t *s, int16_t *data, int len) { return -ENOTSUP; } +static inline int plc_fillin(plc_state_t *s, int16_t *data, int len) { return -ENOTSUP; } +static inline plc_state_t *plc_init(plc_state_t *s) +{ + static plc_state_t state; + return &state; +} +static inline int plc_free(plc_state_t *s) { return 0; } +#endif + +#endif