From c8aa1f38df118173bab6a682adceae57285fe237 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 21 Nov 2018 15:51:44 +0100 Subject: [PATCH] bluez5: negotiate AAC if possible --- spa/plugins/bluez5/a2dp-sink.c | 21 +++++- spa/plugins/bluez5/bluez5-monitor.c | 102 ++++++++++++++++++++++++++-- 2 files changed, 116 insertions(+), 7 deletions(-) diff --git a/spa/plugins/bluez5/a2dp-sink.c b/spa/plugins/bluez5/a2dp-sink.c index 23941a86b..60faf9e36 100644 --- a/spa/plugins/bluez5/a2dp-sink.c +++ b/spa/plugins/bluez5/a2dp-sink.c @@ -970,7 +970,9 @@ impl_node_port_enum_params(struct spa_node *node, if (*index > 0) return 0; - if (this->transport->codec == 0) { + switch (this->transport->codec) { + case A2DP_CODEC_SBC: + { a2dp_sbc_t *config = this->transport->configuration; struct spa_audio_info_raw info = { 0, }; @@ -993,9 +995,22 @@ impl_node_port_enum_params(struct spa_node *node, } param = spa_format_audio_raw_build(&b, id, &info); + break; } - else + case A2DP_CODEC_MPEG24: + { + a2dp_aac_t *config = this->transport->configuration; + + param = spa_pod_builder_object(&b, + SPA_TYPE_OBJECT_Format, id, + SPA_FORMAT_mediaType, &SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, &SPA_POD_Id(SPA_MEDIA_SUBTYPE_aac), + 0); + break; + } + default: return -EIO; + } break; case SPA_PARAM_Format: @@ -1265,7 +1280,7 @@ static int impl_node_process(struct spa_node *node) input->status = SPA_STATUS_OK; } - return SPA_STATUS_OK; + return SPA_STATUS_HAVE_BUFFER; } static const struct spa_dict_item node_info_items[] = { diff --git a/spa/plugins/bluez5/bluez5-monitor.c b/spa/plugins/bluez5/bluez5-monitor.c index 139a3e144..125cd8f46 100644 --- a/spa/plugins/bluez5/bluez5-monitor.c +++ b/spa/plugins/bluez5/bluez5-monitor.c @@ -40,6 +40,9 @@ #include #include #include +#include + +#undef ENABLE_AAC #include "a2dp-codecs.h" #include "defs.h" @@ -223,17 +226,91 @@ static int select_configuration_sbc(struct spa_bt_monitor *monitor, void *capabi return 0; } +static int select_configuration_aac(struct spa_bt_monitor *monitor, void *capabilities, int size, void *config) +{ + a2dp_aac_t *cap, conf; + int freq; + + if (size < sizeof(conf)) { + spa_log_error(monitor->log, "Capabilities array has invalid size"); + return -ENOSPC; + } + cap = capabilities; + conf = *cap; + + if (conf.object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC) + conf.object_type = AAC_OBJECT_TYPE_MPEG2_AAC_LC; + else if (conf.object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC) + conf.object_type = AAC_OBJECT_TYPE_MPEG4_AAC_LC; + else if (conf.object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LTP) + conf.object_type = AAC_OBJECT_TYPE_MPEG4_AAC_LTP; + else if (conf.object_type & AAC_OBJECT_TYPE_MPEG4_AAC_SCA) + conf.object_type = AAC_OBJECT_TYPE_MPEG4_AAC_SCA; + else { + spa_log_error(monitor->log, "No supported object type: 0x%x", conf.object_type); + return -ENOTSUP; + } + + freq = AAC_GET_FREQUENCY(conf); + if (freq & AAC_SAMPLING_FREQ_48000) + freq = AAC_SAMPLING_FREQ_48000; + else if (freq & AAC_SAMPLING_FREQ_44100) + freq = AAC_SAMPLING_FREQ_44100; + else if (freq & AAC_SAMPLING_FREQ_64000) + freq = AAC_SAMPLING_FREQ_64000; + else if (freq & AAC_SAMPLING_FREQ_32000) + freq = AAC_SAMPLING_FREQ_32000; + else if (freq & AAC_SAMPLING_FREQ_88200) + freq = AAC_SAMPLING_FREQ_88200; + else if (freq & AAC_SAMPLING_FREQ_96000) + freq = AAC_SAMPLING_FREQ_96000; + else if (freq & AAC_SAMPLING_FREQ_24000) + freq = AAC_SAMPLING_FREQ_24000; + else if (freq & AAC_SAMPLING_FREQ_22050) + freq = AAC_SAMPLING_FREQ_22050; + else if (freq & AAC_SAMPLING_FREQ_16000) + freq = AAC_SAMPLING_FREQ_16000; + else if (freq & AAC_SAMPLING_FREQ_12000) + freq = AAC_SAMPLING_FREQ_12000; + else if (freq & AAC_SAMPLING_FREQ_11025) + freq = AAC_SAMPLING_FREQ_11025; + else if (freq & AAC_SAMPLING_FREQ_8000) + freq = AAC_SAMPLING_FREQ_8000; + else { + spa_log_error(monitor->log, "No supported sampling frequency: 0x%0x", freq); + return -ENOTSUP; + } + AAC_SET_FREQUENCY(conf, freq); + + if (conf.channels & AAC_CHANNELS_2) + conf.channels = AAC_CHANNELS_2; + else if (conf.channels & AAC_CHANNELS_1) + conf.channels = AAC_CHANNELS_1; + else { + spa_log_error(monitor->log, "No supported channels: 0x%0x", conf.channels); + return -ENOTSUP; + } + memcpy(config, &conf, size); + + spa_log_debug(monitor->log, "SelectConfiguration() %d %d %d", conf.object_type, freq, conf.channels); + + return 0; +} + static DBusHandlerResult endpoint_select_configuration(DBusConnection *conn, DBusMessage *m, void *userdata) { struct spa_bt_monitor *monitor = userdata; - a2dp_sbc_t *cap, config; - uint8_t *pconf = (uint8_t *) &config; + const char *path; + uint8_t *cap, config[16]; + uint8_t *pconf = (uint8_t *) config; DBusMessage *r; DBusError err; - int size; + int size, res; dbus_error_init(&err); + path = dbus_message_get_path(m); + if (!dbus_message_get_args(m, &err, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &cap, &size, DBUS_TYPE_INVALID)) { spa_log_error(monitor->log, "Endpoint SelectConfiguration(): %s", err.message); @@ -241,7 +318,14 @@ static DBusHandlerResult endpoint_select_configuration(DBusConnection *conn, DBu return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - if (select_configuration_sbc(monitor, cap, size, &config) < 0) { + if (strstr(path, "/A2DP/SBC/") == path) { + res = select_configuration_sbc(monitor, cap, size, config); + } else if (strstr(path, "/A2DP/MPEG24/") == path) { + res = select_configuration_aac(monitor, cap, size, config); + } else + res = -ENOTSUP; + + if (res < 0) { if ((r = dbus_message_new_error(m, "org.bluez.Error.InvalidArguments", "Unable to select configuration")) == NULL) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -965,6 +1049,9 @@ static int register_a2dp_endpoint(struct spa_bt_monitor *monitor, case A2DP_CODEC_SBC: profile_path = "/A2DP/SBC/Source"; break; + case A2DP_CODEC_MPEG24: + profile_path = "/A2DP/MPEG24/Source"; + break; default: return -ENOTSUP; } @@ -1033,6 +1120,13 @@ static int adapter_register_endpoints(struct spa_bt_adapter *a) { struct spa_bt_monitor *monitor = a->monitor; +#ifdef ENABLE_AAC + register_a2dp_endpoint(monitor, a->path, + SPA_BT_UUID_A2DP_SOURCE, + SPA_BT_PROFILE_A2DP_SOURCE, + A2DP_CODEC_MPEG24, + &bluez_a2dp_aac, sizeof(bluez_a2dp_aac)); +#endif register_a2dp_endpoint(monitor, a->path, SPA_BT_UUID_A2DP_SOURCE, SPA_BT_PROFILE_A2DP_SOURCE,