From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx> This changes endpoint.presets command to take codec as parameter. --- client/player.c | 240 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 175 insertions(+), 65 deletions(-) diff --git a/client/player.c b/client/player.c index 58e14654ffb0..a9f56fb94b9b 100644 --- a/client/player.c +++ b/client/player.c @@ -78,6 +78,7 @@ struct endpoint { uint8_t cis; char *transport; DBusMessage *msg; + struct preset *preset; }; static DBusConnection *dbus_conn; @@ -1166,7 +1167,7 @@ struct codec_qos { }; struct codec_preset { - const char *name; + char *name; const struct iovec data; const struct codec_qos qos; uint8_t target_latency; @@ -1410,9 +1411,10 @@ static struct codec_preset lc3_presets[] = { LC3_10_UNFRAMED(155u, 13u, 100u, 40000u)), }; -#define PRESET(_uuid, _presets, _default_index) \ +#define PRESET(_uuid, _codec, _presets, _default_index) \ { \ .uuid = _uuid, \ + .codec = _codec, \ .custom = { .name = "custom" }, \ .default_preset = &_presets[_default_index], \ .presets = _presets, \ @@ -1421,46 +1423,142 @@ static struct codec_preset lc3_presets[] = { static struct preset { const char *uuid; + uint8_t codec; + uint16_t cid; + uint16_t vid; struct codec_preset custom; struct codec_preset *default_preset; struct codec_preset *presets; size_t num_presets; } presets[] = { - PRESET(A2DP_SOURCE_UUID, sbc_presets, 6), - PRESET(A2DP_SINK_UUID, sbc_presets, 6), - PRESET(PAC_SINK_UUID, lc3_presets, 3), - PRESET(PAC_SOURCE_UUID, lc3_presets, 3), + PRESET(A2DP_SOURCE_UUID, A2DP_CODEC_SBC, sbc_presets, 6), + PRESET(A2DP_SINK_UUID, A2DP_CODEC_SBC, sbc_presets, 6), + PRESET(PAC_SINK_UUID, LC3_ID, lc3_presets, 3), + PRESET(PAC_SOURCE_UUID, LC3_ID, lc3_presets, 3), }; -static struct codec_preset *find_preset(const char *uuid, const char *name) +static void parse_vendor_codec(const char *codec, uint16_t *vid, uint16_t *cid) +{ + char **list; + char *endptr = NULL; + + if (!codec) + return; + + list = g_strsplit(codec, ":", 2); + + if (vid) + *vid = strtol(list[0], &endptr, 0); + + if (cid) + *cid = strtol(list[1], &endptr, 0); + + g_strfreev(list); +} + +static struct preset *find_presets(const char *uuid, uint8_t codec, + uint16_t vid, uint16_t cid) { size_t i; + if (codec == 0xff) { + GList *l; + + for (l = local_endpoints; l; l = g_list_next(l)) { + struct endpoint *ep = l->data; + + if (strcasecmp(ep->uuid, uuid) || ep->codec != codec) + continue; + + if (ep->codec == 0xff && (ep->vid != vid || + ep->cid != cid)) + continue; + + return ep->preset; + } + + return NULL; + } + for (i = 0; i < ARRAY_SIZE(presets); i++) { struct preset *preset = &presets[i]; - if (!strcasecmp(preset->uuid, uuid)) { - size_t j; + if (preset->codec != codec) + continue; - if (!name) - return preset->default_preset; - else if (!strcmp(name, "custom")) - return &preset->custom; - - for (j = 0; j < preset->num_presets; j++) { - struct codec_preset *p; - - p = &preset->presets[j]; - - if (!strcmp(p->name, name)) - return p; - } - } + if (!strcasecmp(preset->uuid, uuid)) + return preset; } return NULL; } +static struct preset *find_vendor_presets(const char *uuid, const char *codec) +{ + uint16_t cid; + uint16_t vid; + + if (!uuid || !codec) + return NULL; + + parse_vendor_codec(codec, &vid, &cid); + + return find_presets(uuid, 0xff, vid, cid); +} + +static struct preset *find_presets_name(const char *uuid, const char *codec) +{ + uint8_t id; + char *endptr = NULL; + + if (!uuid || !codec) + return NULL; + + if (strrchr(codec, ':')) + return find_vendor_presets(uuid, codec); + + id = strtol(codec, &endptr, 0); + + return find_presets(uuid, id, 0x0000, 0x0000); +} + +static struct codec_preset *preset_find_name(struct preset *preset, + const char *name) +{ + size_t i; + + if (!preset) + return NULL; + + if (!name) + return preset->default_preset; + else if (!strcmp(name, "custom")) + return &preset->custom; + + for (i = 0; i < preset->num_presets; i++) { + struct codec_preset *p; + + p = &preset->presets[i]; + + if (!strcmp(p->name, name)) + return p; + } + + return NULL; +} + +static struct codec_preset *find_preset(const char *uuid, const char *codec, + const char *name) +{ + struct preset *preset; + + preset = find_presets_name(uuid, codec); + if (!preset) + return NULL; + + return preset_find_name(preset, name); +} + static DBusMessage *endpoint_select_config_reply(DBusMessage *msg, uint8_t *data, size_t len) { @@ -1525,7 +1623,7 @@ static void select_config_response(const char *input, void *user_data) uint8_t *data; size_t len; - p = find_preset(ep->uuid, input); + p = preset_find_name(ep->preset, input); if (p) { data = p->data.iov_base; len = p->data.iov_len; @@ -1580,7 +1678,7 @@ static DBusMessage *endpoint_select_configuration(DBusConnection *conn, return NULL; } - p = find_preset(ep->uuid, NULL); + p = preset_find_name(ep->preset, NULL); if (!p) { reply = g_dbus_create_error(msg, "org.bluez.Error.Rejected", NULL); @@ -1755,7 +1853,7 @@ static void select_properties_response(const char *input, void *user_data) struct codec_preset *p; DBusMessage *reply; - p = find_preset(ep->uuid, input); + p = preset_find_name(ep->preset, input); if (p) { reply = endpoint_select_properties_reply(ep, ep->msg, p); goto done; @@ -1797,9 +1895,9 @@ static DBusMessage *endpoint_select_properties(DBusConnection *conn, return NULL; } - p = find_preset(ep->uuid, NULL); + p = preset_find_name(ep->preset, NULL); if (!p) - NULL; + return NULL; reply = endpoint_select_properties_reply(ep, msg, p); if (!reply) @@ -1903,6 +2001,11 @@ static void endpoint_free(void *data) if (ep->msg) dbus_message_unref(ep->msg); + if (ep->codec == 0xff) { + free(ep->preset->custom.name); + free(ep->preset); + } + g_free(ep->path); g_free(ep->uuid); g_free(ep); @@ -2312,7 +2415,6 @@ static void cmd_register_endpoint(int argc, char *argv[]) { struct endpoint *ep; char *endptr = NULL; - char **list; ep = g_new0(struct endpoint, 1); ep->uuid = g_strdup(argv[1]); @@ -2324,12 +2426,13 @@ static void cmd_register_endpoint(int argc, char *argv[]) local_endpoints = g_list_append(local_endpoints, ep); if (strrchr(argv[2], ':')) { - list = g_strsplit(argv[2], ":", 2); - ep->codec = 0xff; - ep->vid = strtol(list[0], &endptr, 0); - endptr = NULL; - ep->cid = strtol(list[1], &endptr, 0); + parse_vendor_codec(argv[2], &ep->cid, &ep->vid); + ep->preset = new0(struct preset, 1); + ep->preset->custom.name = strdup("custom"); + ep->preset->default_preset = &ep->preset->custom; + } else { + ep->preset = find_presets_name(ep->uuid, argv[2]); } if (argc > 3) @@ -2489,7 +2592,7 @@ static void cmd_config_endpoint(int argc, char *argv[]) } if (argc > 3) { - preset = find_preset(cfg->ep->uuid, argv[3]); + preset = preset_find_name(cfg->ep->preset, argv[3]); if (!preset) { bt_shell_printf("Preset %s not found\n", argv[3]); goto fail; @@ -2835,46 +2938,50 @@ static void custom_frequency(const char *input, void *user_data) custom_duration, user_data); } -static void cmd_presets_endpoint(int argc, char *argv[]) +static void print_presets(struct preset *preset) { size_t i; + struct codec_preset *p; + + p = &preset->custom; + + bt_shell_printf("%s%s\n", p == preset->default_preset ? "*" : "", + p->name); + + for (i = 0; i < preset->num_presets; i++) { + p = &preset->presets[i]; + bt_shell_printf("%s%s\n", p == preset->default_preset ? + "*" : "", p->name); + } +} + +static void cmd_presets_endpoint(int argc, char *argv[]) +{ + struct preset *preset; struct codec_preset *default_preset = NULL; - if (argc > 2) { - default_preset = find_preset(argv[1], argv[2]); + if (argc > 3) { + default_preset = find_preset(argv[1], argv[2], argv[3]); if (!default_preset) { - bt_shell_printf("Preset %s not found\n", argv[2]); + bt_shell_printf("Preset %s not found\n", argv[3]); return bt_shell_noninteractive_quit(EXIT_FAILURE); } } - for (i = 0; i < ARRAY_SIZE(presets); i++) { - struct preset *preset = &presets[i]; - - if (!strcasecmp(preset->uuid, argv[1])) { - size_t j; - struct codec_preset *p; - - if (default_preset) { - preset->default_preset = default_preset; - break; - } - - p = &preset->custom; - - bt_shell_printf("%s%s\n", p == preset->default_preset ? - "*" : "", p->name); - - for (j = 0; j < preset->num_presets; j++) { - p = &preset->presets[j]; - - bt_shell_printf("%s%s\n", - p == preset->default_preset ? - "*" : "", p->name); - } - } + preset = find_presets_name(argv[1], argv[2]); + if (!preset) { + bt_shell_printf("No preset found\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + if (default_preset) { + preset->default_preset = default_preset; + goto done; + } + + print_presets(preset); + +done: if (default_preset && !strcmp(default_preset->name, "custom")) { bt_shell_prompt_input("Codec", "Enter frequency (Khz):", custom_frequency, default_preset); @@ -2904,7 +3011,8 @@ static const struct bt_shell_menu endpoint_menu = { cmd_config_endpoint, "Configure Endpoint", endpoint_generator }, - { "presets", "<UUID> [default]", cmd_presets_endpoint, + { "presets", "<UUID> <codec[:company]> [default]", + cmd_presets_endpoint, "List available presets", uuid_generator }, {} }, @@ -2938,6 +3046,8 @@ static void register_endpoints(GDBusProxy *proxy) continue; ep = endpoint_new(cap); + ep->preset = find_presets(ep->uuid, ep->codec, ep->vid, + ep->cid); ep->max_transports = UINT8_MAX; ep->auto_accept = true; ep->cig = BT_ISO_QOS_CIG_UNSET; -- 2.40.0