From abfa04caa4bd55a4fdc711bf06f45042a2aebc02 Mon Sep 17 00:00:00 2001 From: Huang-Huang Bao Date: Sat, 20 Mar 2021 15:10:42 +0800 Subject: [PATCH] a2dp: add props param support for LDAC LDAC quality can now be set with SPA_PROP_quality on a2dp-sink node. Also fix a NULL reference if device setting is empty. --- spa/plugins/bluez5/a2dp-codec-ldac.c | 92 ++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/spa/plugins/bluez5/a2dp-codec-ldac.c b/spa/plugins/bluez5/a2dp-codec-ldac.c index afb14eed3..431863646 100644 --- a/spa/plugins/bluez5/a2dp-codec-ldac.c +++ b/spa/plugins/bluez5/a2dp-codec-ldac.c @@ -27,6 +27,8 @@ #include #include +#include +#include #include #include @@ -75,6 +77,8 @@ struct impl { int frame_length; int frame_count; int frame_count_factor; + + const struct props *props; }; enum { @@ -354,6 +358,65 @@ static void codec_clear_props(void *props) free(props); } +static int codec_enum_props(void *props, const struct spa_dict *settings, uint32_t id, uint32_t idx, + struct spa_pod_builder *b, struct spa_pod **param) +{ + struct props *p = props; + switch (id) { + case SPA_PARAM_PropInfo: + { + switch (idx) { + case 0: + *param = spa_pod_builder_add_object(b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_quality), + SPA_PROP_INFO_name, SPA_POD_String("LDAC quality"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_ENUM_Int(5, + p->eqmid, + LDACBT_EQMID_AUTO, + LDACBT_EQMID_HQ, + LDACBT_EQMID_SQ, + LDACBT_EQMID_MQ)); + break; + default: + return 0; + } + break; + } + case SPA_PARAM_Props: + { + switch (idx) { + case 0: + *param = spa_pod_builder_add_object(b, + SPA_TYPE_OBJECT_Props, id, + SPA_PROP_quality, SPA_POD_Int(p->eqmid)); + break; + default: + return 0; + } + break; + } + default: + return -ENOENT; + } + return 1; +} + +static int codec_set_props(void *props, const struct spa_pod *param) +{ + struct props *p = props; + const int prev_eqmid = p->eqmid; + if (param == NULL) { + p->eqmid = LDACBT_EQMID_AUTO; + } else { + spa_pod_parse_object(param, + SPA_TYPE_OBJECT_Props, NULL, + SPA_PROP_quality, SPA_POD_OPT_Int(&p->eqmid)); + } + + return prev_eqmid != p->eqmid; +} + static void *codec_init(const struct a2dp_codec *codec, uint32_t flags, void *config, size_t config_len, const struct spa_audio_info *info, void *props, size_t mtu) @@ -480,6 +543,32 @@ static void codec_deinit(void *data) free(this); } +static int codec_update_props(void *data, void *props) +{ + struct impl *this = data; + struct props *p = props; + int res; + + if (p == NULL) + return 0; + + if (p->eqmid == LDACBT_EQMID_AUTO) { + this->eqmid = LDACBT_EQMID_SQ; + this->enable_abr = true; + } else { + this->eqmid = p->eqmid; + this->enable_abr = false; + } + + if ((res = ldacBT_set_eqmid(this->ldac, this->eqmid)) < 0) + goto error; + if ((res = update_frame_info(this)) < 0) + goto error; + return 0; +error: + return res; +} + static int codec_abr_process(void *data, size_t unsent) { #ifdef ENABLE_LDAC_ABR @@ -547,9 +636,12 @@ const struct a2dp_codec a2dp_codec_ldac = { .select_config = codec_select_config, .enum_config = codec_enum_config, .init_props = codec_init_props, + .enum_props = codec_enum_props, + .set_props = codec_set_props, .clear_props = codec_clear_props, .init = codec_init, .deinit = codec_deinit, + .update_props = codec_update_props, .get_block_size = codec_get_block_size, .get_num_blocks = codec_get_num_blocks, .abr_process = codec_abr_process,