From b4b7cd2725478e0cf0fc26b7333bdeaecf422bc189fd62bfed75cd1952e30a68 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Fri, 20 Sep 2019 20:37:21 +0000 Subject: [PATCH] Accepting request 732242 from home:seife:testing update to version 5.51 OBS-URL: https://build.opensuse.org/request/show/732242 OBS-URL: https://build.opensuse.org/package/show/Base:System/bluez?expand=0&rev=271 --- 0001-obexd-use-AM_LDFLAGS-for-linking.patch | 26 - 0001-policy-Add-logic-to-connect-a-Sink.patch | 77 - ...x-build-after-y2038-changes-in-glibc.patch | 67 - bluez-5.45-disable-broken-tests.diff | 22 - bluez-5.50-a2dp-backports.patch | 4714 ----------------- bluez-5.50-gcc9.patch | 321 -- bluez-5.50.tar.xz | 3 - bluez-5.51-disable-broken-tests.diff | 24 + bluez-5.51.tar.xz | 3 + bluez-cups-libexec.patch | 22 +- bluez.changes | 29 + bluez.spec | 29 +- disable_some_obex_tests.patch | 28 - temporary-rpmlintrc | 1 + 14 files changed, 75 insertions(+), 5291 deletions(-) delete mode 100644 0001-obexd-use-AM_LDFLAGS-for-linking.patch delete mode 100644 0001-policy-Add-logic-to-connect-a-Sink.patch delete mode 100644 0001-tools-Fix-build-after-y2038-changes-in-glibc.patch delete mode 100644 bluez-5.45-disable-broken-tests.diff delete mode 100644 bluez-5.50-a2dp-backports.patch delete mode 100644 bluez-5.50-gcc9.patch delete mode 100644 bluez-5.50.tar.xz create mode 100644 bluez-5.51-disable-broken-tests.diff create mode 100644 bluez-5.51.tar.xz delete mode 100644 disable_some_obex_tests.patch create mode 100644 temporary-rpmlintrc diff --git a/0001-obexd-use-AM_LDFLAGS-for-linking.patch b/0001-obexd-use-AM_LDFLAGS-for-linking.patch deleted file mode 100644 index d723ffc..0000000 --- a/0001-obexd-use-AM_LDFLAGS-for-linking.patch +++ /dev/null @@ -1,26 +0,0 @@ -From b912306ae756eaf75caa1ab7e04e3112fac4a01c Mon Sep 17 00:00:00 2001 -From: Stefan Seyfried -Date: Mon, 11 Dec 2017 22:52:28 +0100 -Subject: [PATCH] obexd: use AM_LDFLAGS for linking - -without this, --enable-pie does not work for obexd ---- - Makefile.obexd | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Makefile.obexd b/Makefile.obexd -index 2e33cbc72..86c395305 100644 ---- a/Makefile.obexd -+++ b/Makefile.obexd -@@ -83,7 +83,7 @@ obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \ - gdbus/libgdbus-internal.la \ - @ICAL_LIBS@ @DBUS_LIBS@ @GLIB_LIBS@ -ldl - --obexd_src_obexd_LDFLAGS = -Wl,--export-dynamic -+obexd_src_obexd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic - - obexd_src_obexd_CFLAGS = $(AM_CFLAGS) @GLIB_CFLAGS@ @DBUS_CFLAGS@ \ - @ICAL_CFLAGS@ -DOBEX_PLUGIN_BUILTIN \ --- -2.15.1 - diff --git a/0001-policy-Add-logic-to-connect-a-Sink.patch b/0001-policy-Add-logic-to-connect-a-Sink.patch deleted file mode 100644 index 7d8424f..0000000 --- a/0001-policy-Add-logic-to-connect-a-Sink.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 477ecca127c529611adbc53f08039cefaf86305d Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Tue, 26 Jun 2018 13:37:33 +0300 -Subject: [PATCH] policy: Add logic to connect a Sink - -References: boo#1131772 -Patch-mainline: 5.51 -Git-commit: 477ecca127c529611adbc53f08039cefaf86305d - -If HFP/HSP HS connects and the device also supports a Sink connect it -as well since some devices (e.g. Sony MW600) may not connect it -automatically. -Acked-by: Michal Suchanek ---- - plugins/policy.c | 39 +++++++++++++++++++++++++++++++++++++++ - 1 file changed, 39 insertions(+) - -diff --git a/plugins/policy.c b/plugins/policy.c -index 1f5a506a2c2f..de51e58b91dc 100644 ---- a/plugins/policy.c -+++ b/plugins/policy.c -@@ -297,6 +297,42 @@ static void sink_cb(struct btd_service *service, btd_service_state_t old_state, - } - } - -+static void hs_cb(struct btd_service *service, btd_service_state_t old_state, -+ btd_service_state_t new_state) -+{ -+ struct btd_device *dev = btd_service_get_device(service); -+ struct policy_data *data; -+ struct btd_service *sink; -+ -+ /* If the device supports Sink set a timer to connect it as well */ -+ sink = btd_device_get_service(dev, A2DP_SINK_UUID); -+ if (sink == NULL) -+ return; -+ -+ data = policy_get_data(dev); -+ -+ switch (new_state) { -+ case BTD_SERVICE_STATE_UNAVAILABLE: -+ break; -+ case BTD_SERVICE_STATE_DISCONNECTED: -+ break; -+ case BTD_SERVICE_STATE_CONNECTING: -+ break; -+ case BTD_SERVICE_STATE_CONNECTED: -+ /* Check if service initiate the connection then proceed -+ * immediately otherwise set timer -+ */ -+ if (old_state == BTD_SERVICE_STATE_CONNECTING) -+ policy_connect(data, sink); -+ else if (btd_service_get_state(sink) != -+ BTD_SERVICE_STATE_CONNECTED) -+ policy_set_sink_timer(data); -+ break; -+ case BTD_SERVICE_STATE_DISCONNECTING: -+ break; -+ } -+} -+ - static gboolean policy_connect_tg(gpointer user_data) - { - struct policy_data *data = user_data; -@@ -615,6 +651,9 @@ static void service_cb(struct btd_service *service, - controller_cb(service, old_state, new_state); - else if (g_str_equal(profile->remote_uuid, AVRCP_TARGET_UUID)) - target_cb(service, old_state, new_state); -+ else if (g_str_equal(profile->remote_uuid, HFP_HS_UUID) || -+ g_str_equal(profile->remote_uuid, HSP_HS_UUID)) -+ hs_cb(service, old_state, new_state); - - /* - * Return if the reconnection feature is not enabled (all --- -2.20.1 - diff --git a/0001-tools-Fix-build-after-y2038-changes-in-glibc.patch b/0001-tools-Fix-build-after-y2038-changes-in-glibc.patch deleted file mode 100644 index d46fd49..0000000 --- a/0001-tools-Fix-build-after-y2038-changes-in-glibc.patch +++ /dev/null @@ -1,67 +0,0 @@ -From: Bastien Nocera -Date: Fri, 7 Jun 2019 09:51:33 +0200 -Subject: tools: Fix build after y2038 changes in glibc -Git-repo: git://git.kernel.org/pub/scm/bluetooth/bluez.git -Git-commit: f36f71f60b1e68c0f12e615b9b128d089ec3dd19 -Patch-mainline: yes - -The 32-bit SIOCGSTAMP has been deprecated. Use the deprecated name -to fix the build. - -Signed-off-by: Jiri Slaby ---- - tools/l2test.c | 6 +++++- - tools/rctest.c | 6 +++++- - 2 files changed, 10 insertions(+), 2 deletions(-) - -diff --git a/tools/l2test.c b/tools/l2test.c -index e755ac881..e787c2ce2 100644 ---- a/tools/l2test.c -+++ b/tools/l2test.c -@@ -55,6 +55,10 @@ - #define BREDR_DEFAULT_PSM 0x1011 - #define LE_DEFAULT_PSM 0x0080 - -+#ifndef SIOCGSTAMP_OLD -+#define SIOCGSTAMP_OLD SIOCGSTAMP -+#endif -+ - /* Test modes */ - enum { - SEND, -@@ -907,7 +911,7 @@ static void recv_mode(int sk) - if (timestamp) { - struct timeval tv; - -- if (ioctl(sk, SIOCGSTAMP, &tv) < 0) { -+ if (ioctl(sk, SIOCGSTAMP_OLD, &tv) < 0) { - timestamp = 0; - memset(ts, 0, sizeof(ts)); - } else { -diff --git a/tools/rctest.c b/tools/rctest.c -index 94490f462..bc8ed875d 100644 ---- a/tools/rctest.c -+++ b/tools/rctest.c -@@ -50,6 +50,10 @@ - - #include "src/shared/util.h" - -+#ifndef SIOCGSTAMP_OLD -+#define SIOCGSTAMP_OLD SIOCGSTAMP -+#endif -+ - /* Test modes */ - enum { - SEND, -@@ -505,7 +509,7 @@ static void recv_mode(int sk) - if (timestamp) { - struct timeval tv; - -- if (ioctl(sk, SIOCGSTAMP, &tv) < 0) { -+ if (ioctl(sk, SIOCGSTAMP_OLD, &tv) < 0) { - timestamp = 0; - memset(ts, 0, sizeof(ts)); - } else { --- -2.21.0 - diff --git a/bluez-5.45-disable-broken-tests.diff b/bluez-5.45-disable-broken-tests.diff deleted file mode 100644 index eb5214f..0000000 --- a/bluez-5.45-disable-broken-tests.diff +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/Makefile.am b/Makefile.am -index 84e67a4..cac5283 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -395,7 +395,7 @@ unit_test_lib_SOURCES = unit/test-lib.c - unit_test_lib_LDADD = src/libshared-glib.la \ - lib/libbluetooth-internal.la @GLIB_LIBS@ - --unit_tests += unit/test-gatt -+#unit_tests += unit/test-gatt - - unit_test_gatt_SOURCES = unit/test-gatt.c - unit_test_gatt_LDADD = src/libshared-glib.la \ -@@ -424,7 +424,7 @@ unit_test_gattrib_LDADD = lib/libbluetooth-internal.la \ - @GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt - - if MIDI --unit_tests += unit/test-midi -+#unit_tests += unit/test-midi - unit_test_midi_CFLAGS = $(AM_CFLAGS) @ALSA_CFLAGS@ -DMIDI_TEST - unit_test_midi_SOURCES = unit/test-midi.c \ - profiles/midi/libmidi.h \ diff --git a/bluez-5.50-a2dp-backports.patch b/bluez-5.50-a2dp-backports.patch deleted file mode 100644 index 33e10d8..0000000 --- a/bluez-5.50-a2dp-backports.patch +++ /dev/null @@ -1,4714 +0,0 @@ -From 1e9dafa0dd062f6773481074d4a426ae4c6e2aea Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 23 Dec 2018 11:40:12 +0100 -Subject: [PATCH 01/31] avinfo: Fix buffer overflow when parsing - broken/malicious data - -Check size of buffer prior casting it to struct. ---- - tools/avinfo.c | 91 +++++++++++++++++++++++++++++++++++++++----------- - 1 file changed, 71 insertions(+), 20 deletions(-) - -diff --git a/tools/avinfo.c b/tools/avinfo.c -index 31c4e106e..47fa1d2c5 100644 ---- a/tools/avinfo.c -+++ b/tools/avinfo.c -@@ -167,10 +167,15 @@ struct avdtp_content_protection_capability { - uint8_t data[0]; - } __attribute__ ((packed)); - --static void print_aptx(a2dp_aptx_t *aptx) -+static void print_aptx(a2dp_aptx_t *aptx, uint8_t size) - { - printf("\t\tVendor Specific Value (aptX)"); - -+ if (size < sizeof(*aptx)) { -+ printf(" (broken)\n"); -+ return; -+ } -+ - printf("\n\t\t\tFrequencies: "); - if (aptx->frequency & APTX_SAMPLING_FREQ_16000) - printf("16kHz "); -@@ -190,20 +195,33 @@ static void print_aptx(a2dp_aptx_t *aptx) - printf("\n"); - } - --static void print_ldac(a2dp_ldac_t *ldac) -+static void print_ldac(a2dp_ldac_t *ldac, uint8_t size) - { - printf("\t\tVendor Specific Value (LDAC)"); - -+ if (size < sizeof(*ldac)) { -+ printf(" (broken)\n"); -+ return; -+ } -+ - printf("\n\t\t\tUnknown: %02x %02x", ldac->unknown[0], - ldac->unknown[1]); - - printf("\n"); - } - --static void print_vendor(a2dp_vendor_codec_t *vendor) -+static void print_vendor(a2dp_vendor_codec_t *vendor, uint8_t size) - { -- uint32_t vendor_id = btohl(vendor->vendor_id); -- uint16_t codec_id = btohs(vendor->codec_id); -+ uint32_t vendor_id; -+ uint16_t codec_id; -+ -+ if (size < sizeof(*vendor)) { -+ printf("\tMedia Codec: Vendor Specific A2DP Codec (broken)"); -+ return; -+ } -+ -+ vendor_id = btohl(vendor->vendor_id); -+ codec_id = btohs(vendor->codec_id); - - printf("\tMedia Codec: Vendor Specific A2DP Codec"); - -@@ -212,15 +230,22 @@ static void print_vendor(a2dp_vendor_codec_t *vendor) - printf("\n\t\tVendor Specific Codec ID 0x%04x\n", codec_id); - - if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) -- print_aptx((void *) vendor); -+ print_aptx((void *) vendor, size); - else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID) -- print_ldac((void *) vendor); -+ print_ldac((void *) vendor, size); - } - --static void print_mpeg24(a2dp_aac_t *aac) -+static void print_mpeg24(a2dp_aac_t *aac, uint8_t size) - { -- unsigned freq = AAC_GET_FREQUENCY(*aac); -- unsigned bitrate = AAC_GET_BITRATE(*aac); -+ unsigned int freq, bitrate; -+ -+ if (size < sizeof(*aac)) { -+ printf("\tMedia Codec: MPEG24 (broken)\n"); -+ return; -+ } -+ -+ freq = AAC_GET_FREQUENCY(*aac); -+ bitrate = AAC_GET_BITRATE(*aac); - - printf("\tMedia Codec: MPEG24\n\t\tObject Types: "); - -@@ -270,8 +295,13 @@ static void print_mpeg24(a2dp_aac_t *aac) - printf("\n\t\tVBR: %s", aac->vbr ? "Yes\n" : "No\n"); - } - --static void print_mpeg12(a2dp_mpeg_t *mpeg) -+static void print_mpeg12(a2dp_mpeg_t *mpeg, uint8_t size) - { -+ if (size < sizeof(*mpeg)) { -+ printf("\tMedia Codec: MPEG12 (broken)\n"); -+ return; -+ } -+ - printf("\tMedia Codec: MPEG12\n\t\tChannel Modes: "); - - if (mpeg->channel_mode & MPEG_CHANNEL_MODE_MONO) -@@ -351,8 +381,13 @@ static void print_mpeg12(a2dp_mpeg_t *mpeg) - printf("RFC-2250\n"); - } - --static void print_sbc(a2dp_sbc_t *sbc) -+static void print_sbc(a2dp_sbc_t *sbc, uint8_t size) - { -+ if (size < sizeof(*sbc)) { -+ printf("\tMedia Codec: SBC (broken)\n"); -+ return; -+ } -+ - printf("\tMedia Codec: SBC\n\t\tChannel Modes: "); - - if (sbc->channel_mode & SBC_CHANNEL_MODE_MONO) -@@ -394,20 +429,27 @@ static void print_sbc(a2dp_sbc_t *sbc) - sbc->min_bitpool, sbc->max_bitpool); - } - --static void print_media_codec(struct avdtp_media_codec_capability *cap) -+static void print_media_codec( -+ struct avdtp_media_codec_capability *cap, -+ uint8_t size) - { -+ if (size < sizeof(*cap)) { -+ printf("\tMedia Codec: Unknown (broken)\n"); -+ return; -+ } -+ - switch (cap->media_codec_type) { - case A2DP_CODEC_SBC: -- print_sbc((void *) cap->data); -+ print_sbc((void *) cap->data, size - 2); - break; - case A2DP_CODEC_MPEG12: -- print_mpeg12((void *) cap->data); -+ print_mpeg12((void *) cap->data, size - 2); - break; - case A2DP_CODEC_MPEG24: -- print_mpeg24((void *) cap->data); -+ print_mpeg24((void *) cap->data, size - 2); - break; - case A2DP_CODEC_VENDOR: -- print_vendor((void *) cap->data); -+ print_vendor((void *) cap->data, size - 2); - break; - default: - printf("\tMedia Codec: Unknown\n"); -@@ -415,10 +457,16 @@ static void print_media_codec(struct avdtp_media_codec_capability *cap) - } - - static void print_content_protection( -- struct avdtp_content_protection_capability *cap) -+ struct avdtp_content_protection_capability *cap, -+ uint8_t size) - { - printf("\tContent Protection: "); - -+ if (size < sizeof(*cap)) { -+ printf("Unknown (broken)\n"); -+ return; -+ } -+ - switch (btohs(cap->content_protection_type)) { - case AVDTP_CONTENT_PROTECTION_TYPE_DTCP: - printf("DTCP"); -@@ -452,13 +500,16 @@ static void print_caps(void *data, int size) - case AVDTP_REPORTING: - case AVDTP_RECOVERY: - case AVDTP_MULTIPLEXING: -+ default: - /* FIXME: Add proper functions */ -+ printf("\tUnknown category: %d\n", cap->category); - break; - case AVDTP_MEDIA_CODEC: -- print_media_codec((void *) cap->data); -+ print_media_codec((void *) cap->data, cap->length); - break; - case AVDTP_CONTENT_PROTECTION: -- print_content_protection((void *) cap->data); -+ print_content_protection((void *) cap->data, -+ cap->length); - break; - } - --- -2.21.0 - - -From 5ac3a1beaffcd184767fb767b131375976e7a5d9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 23 Dec 2018 11:40:13 +0100 -Subject: [PATCH 02/31] avinfo: Show Vendor Specific Data - ---- - tools/avinfo.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/tools/avinfo.c b/tools/avinfo.c -index 47fa1d2c5..61bcdab0b 100644 ---- a/tools/avinfo.c -+++ b/tools/avinfo.c -@@ -214,6 +214,7 @@ static void print_vendor(a2dp_vendor_codec_t *vendor, uint8_t size) - { - uint32_t vendor_id; - uint16_t codec_id; -+ int i; - - if (size < sizeof(*vendor)) { - printf("\tMedia Codec: Vendor Specific A2DP Codec (broken)"); -@@ -227,7 +228,12 @@ static void print_vendor(a2dp_vendor_codec_t *vendor, uint8_t size) - - printf("\n\t\tVendor ID 0x%08x", vendor_id); - -- printf("\n\t\tVendor Specific Codec ID 0x%04x\n", codec_id); -+ printf("\n\t\tVendor Specific Codec ID 0x%04x", codec_id); -+ -+ printf("\n\t\tVendor Specific Data:"); -+ for (i = 6; i < size; ++i) -+ printf(" 0x%.02x", ((unsigned char *)vendor)[i]); -+ printf("\n"); - - if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) - print_aptx((void *) vendor, size); --- -2.21.0 - - -From 51da4ed2a5b7cd05032faf5d7a695eecaf79f0f0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 23 Dec 2018 11:40:14 +0100 -Subject: [PATCH 03/31] a2dp-codecs: Add SBC prefix for MIN/MAX_BITPOOL - constants - -Those two constants are SBC codec specific. ---- - android/hal-audio-sbc.c | 12 ++++++------ - profiles/audio/a2dp-codecs.h | 4 ++-- - 2 files changed, 8 insertions(+), 8 deletions(-) - -diff --git a/android/hal-audio-sbc.c b/android/hal-audio-sbc.c -index 7ad3a6a51..fd6c61b95 100644 ---- a/android/hal-audio-sbc.c -+++ b/android/hal-audio-sbc.c -@@ -90,8 +90,8 @@ static const a2dp_sbc_t sbc_presets[] = { - SBC_ALLOCATION_LOUDNESS, - .block_length = SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 | - SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16, -- .min_bitpool = MIN_BITPOOL, -- .max_bitpool = MAX_BITPOOL -+ .min_bitpool = SBC_MIN_BITPOOL, -+ .max_bitpool = SBC_MAX_BITPOOL - }, - { - .frequency = SBC_SAMPLING_FREQ_44100, -@@ -99,8 +99,8 @@ static const a2dp_sbc_t sbc_presets[] = { - .subbands = SBC_SUBBANDS_8, - .allocation_method = SBC_ALLOCATION_LOUDNESS, - .block_length = SBC_BLOCK_LENGTH_16, -- .min_bitpool = MIN_BITPOOL, -- .max_bitpool = MAX_BITPOOL -+ .min_bitpool = SBC_MIN_BITPOOL, -+ .max_bitpool = SBC_MAX_BITPOOL - }, - { - .frequency = SBC_SAMPLING_FREQ_48000, -@@ -108,8 +108,8 @@ static const a2dp_sbc_t sbc_presets[] = { - .subbands = SBC_SUBBANDS_8, - .allocation_method = SBC_ALLOCATION_LOUDNESS, - .block_length = SBC_BLOCK_LENGTH_16, -- .min_bitpool = MIN_BITPOOL, -- .max_bitpool = MAX_BITPOOL -+ .min_bitpool = SBC_MIN_BITPOOL, -+ .max_bitpool = SBC_MAX_BITPOOL - }, - }; - -diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h -index 4fb5c0cc9..205491939 100644 ---- a/profiles/audio/a2dp-codecs.h -+++ b/profiles/audio/a2dp-codecs.h -@@ -49,8 +49,8 @@ - #define SBC_ALLOCATION_SNR (1 << 1) - #define SBC_ALLOCATION_LOUDNESS 1 - --#define MAX_BITPOOL 64 --#define MIN_BITPOOL 2 -+#define SBC_MAX_BITPOOL 64 -+#define SBC_MIN_BITPOOL 2 - - #define MPEG_CHANNEL_MODE_MONO (1 << 3) - #define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2) --- -2.21.0 - - -From b199f360f0c99337544fb6f5479c006f377988db Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 23 Dec 2018 11:40:15 +0100 -Subject: [PATCH 04/31] a2dp-codecs: Fix codec id for ATRAC - -According to Bluetooth Assigned Numbers for Audio/Video ATRAC has codec id 0x04. -See: https://www.bluetooth.com/specifications/assigned-numbers/audio-video ---- - profiles/audio/a2dp-codecs.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h -index 205491939..25959902c 100644 ---- a/profiles/audio/a2dp-codecs.h -+++ b/profiles/audio/a2dp-codecs.h -@@ -25,7 +25,7 @@ - #define A2DP_CODEC_SBC 0x00 - #define A2DP_CODEC_MPEG12 0x01 - #define A2DP_CODEC_MPEG24 0x02 --#define A2DP_CODEC_ATRAC 0x03 -+#define A2DP_CODEC_ATRAC 0x04 - #define A2DP_CODEC_VENDOR 0xFF - - #define SBC_SAMPLING_FREQ_16000 (1 << 3) --- -2.21.0 - - -From dfa516c37d8ab07e4ba0f85289e2fa3246e89f36 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 23 Dec 2018 11:40:16 +0100 -Subject: [PATCH 05/31] a2dp-codecs & avinfo: Fix parsing MPEG bit rate values - -Redefine bitrate field in a2dp_mpeg_t struct in endian neutral way and -separate vbr field according to A2DP specification. Define new macros -MPEG_GET_BITRATE() and MPEG_SET_BITRATE() for manipulating with bitrate -like for a2dp_aac_t struct. - -And fix meaning of bitrate field. According to A2DP specification, it is -bitrate index, not bitrate itself. According to MPEG specification, each -MPEG layer have different bitrates for bitrate indexes. Therefore define -correctly bitrates for Layers 1, 2 and 3. - -This fixes problems with parsing bitrate field in a2dp_mpeg_t struct as it -was broken due to endianity and it was broken for Layer 1 and 2 as bitrate -definitions was for Layer 3. ---- - profiles/audio/a2dp-codecs.h | 93 +++++++++++++++++++----- - tools/avinfo.c | 135 ++++++++++++++++++++++++++--------- - 2 files changed, 176 insertions(+), 52 deletions(-) - -diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h -index 25959902c..47030bcc1 100644 ---- a/profiles/audio/a2dp-codecs.h -+++ b/profiles/audio/a2dp-codecs.h -@@ -68,22 +68,75 @@ - #define MPEG_SAMPLING_FREQ_44100 (1 << 1) - #define MPEG_SAMPLING_FREQ_48000 1 - --#define MPEG_BIT_RATE_VBR 0x8000 --#define MPEG_BIT_RATE_320000 0x4000 --#define MPEG_BIT_RATE_256000 0x2000 --#define MPEG_BIT_RATE_224000 0x1000 --#define MPEG_BIT_RATE_192000 0x0800 --#define MPEG_BIT_RATE_160000 0x0400 --#define MPEG_BIT_RATE_128000 0x0200 --#define MPEG_BIT_RATE_112000 0x0100 --#define MPEG_BIT_RATE_96000 0x0080 --#define MPEG_BIT_RATE_80000 0x0040 --#define MPEG_BIT_RATE_64000 0x0020 --#define MPEG_BIT_RATE_56000 0x0010 --#define MPEG_BIT_RATE_48000 0x0008 --#define MPEG_BIT_RATE_40000 0x0004 --#define MPEG_BIT_RATE_32000 0x0002 --#define MPEG_BIT_RATE_FREE 0x0001 -+#define MPEG_BIT_RATE_INDEX_0 (1 << 0) -+#define MPEG_BIT_RATE_INDEX_1 (1 << 1) -+#define MPEG_BIT_RATE_INDEX_2 (1 << 2) -+#define MPEG_BIT_RATE_INDEX_3 (1 << 3) -+#define MPEG_BIT_RATE_INDEX_4 (1 << 4) -+#define MPEG_BIT_RATE_INDEX_5 (1 << 5) -+#define MPEG_BIT_RATE_INDEX_6 (1 << 6) -+#define MPEG_BIT_RATE_INDEX_7 (1 << 7) -+#define MPEG_BIT_RATE_INDEX_8 (1 << 8) -+#define MPEG_BIT_RATE_INDEX_9 (1 << 9) -+#define MPEG_BIT_RATE_INDEX_10 (1 << 10) -+#define MPEG_BIT_RATE_INDEX_11 (1 << 11) -+#define MPEG_BIT_RATE_INDEX_12 (1 << 12) -+#define MPEG_BIT_RATE_INDEX_13 (1 << 13) -+#define MPEG_BIT_RATE_INDEX_14 (1 << 14) -+ -+#define MPEG_MP1_BIT_RATE_32000 MPEG_BIT_RATE_INDEX_1 -+#define MPEG_MP1_BIT_RATE_64000 MPEG_BIT_RATE_INDEX_2 -+#define MPEG_MP1_BIT_RATE_96000 MPEG_BIT_RATE_INDEX_3 -+#define MPEG_MP1_BIT_RATE_128000 MPEG_BIT_RATE_INDEX_4 -+#define MPEG_MP1_BIT_RATE_160000 MPEG_BIT_RATE_INDEX_5 -+#define MPEG_MP1_BIT_RATE_192000 MPEG_BIT_RATE_INDEX_6 -+#define MPEG_MP1_BIT_RATE_224000 MPEG_BIT_RATE_INDEX_7 -+#define MPEG_MP1_BIT_RATE_256000 MPEG_BIT_RATE_INDEX_8 -+#define MPEG_MP1_BIT_RATE_288000 MPEG_BIT_RATE_INDEX_9 -+#define MPEG_MP1_BIT_RATE_320000 MPEG_BIT_RATE_INDEX_10 -+#define MPEG_MP1_BIT_RATE_352000 MPEG_BIT_RATE_INDEX_11 -+#define MPEG_MP1_BIT_RATE_384000 MPEG_BIT_RATE_INDEX_12 -+#define MPEG_MP1_BIT_RATE_416000 MPEG_BIT_RATE_INDEX_13 -+#define MPEG_MP1_BIT_RATE_448000 MPEG_BIT_RATE_INDEX_14 -+ -+#define MPEG_MP2_BIT_RATE_32000 MPEG_BIT_RATE_INDEX_1 -+#define MPEG_MP2_BIT_RATE_48000 MPEG_BIT_RATE_INDEX_2 -+#define MPEG_MP2_BIT_RATE_56000 MPEG_BIT_RATE_INDEX_3 -+#define MPEG_MP2_BIT_RATE_64000 MPEG_BIT_RATE_INDEX_4 -+#define MPEG_MP2_BIT_RATE_80000 MPEG_BIT_RATE_INDEX_5 -+#define MPEG_MP2_BIT_RATE_96000 MPEG_BIT_RATE_INDEX_6 -+#define MPEG_MP2_BIT_RATE_112000 MPEG_BIT_RATE_INDEX_7 -+#define MPEG_MP2_BIT_RATE_128000 MPEG_BIT_RATE_INDEX_8 -+#define MPEG_MP2_BIT_RATE_160000 MPEG_BIT_RATE_INDEX_9 -+#define MPEG_MP2_BIT_RATE_192000 MPEG_BIT_RATE_INDEX_10 -+#define MPEG_MP2_BIT_RATE_224000 MPEG_BIT_RATE_INDEX_11 -+#define MPEG_MP2_BIT_RATE_256000 MPEG_BIT_RATE_INDEX_12 -+#define MPEG_MP2_BIT_RATE_320000 MPEG_BIT_RATE_INDEX_13 -+#define MPEG_MP2_BIT_RATE_384000 MPEG_BIT_RATE_INDEX_14 -+ -+#define MPEG_MP3_BIT_RATE_32000 MPEG_BIT_RATE_INDEX_1 -+#define MPEG_MP3_BIT_RATE_40000 MPEG_BIT_RATE_INDEX_2 -+#define MPEG_MP3_BIT_RATE_48000 MPEG_BIT_RATE_INDEX_3 -+#define MPEG_MP3_BIT_RATE_56000 MPEG_BIT_RATE_INDEX_4 -+#define MPEG_MP3_BIT_RATE_64000 MPEG_BIT_RATE_INDEX_5 -+#define MPEG_MP3_BIT_RATE_80000 MPEG_BIT_RATE_INDEX_6 -+#define MPEG_MP3_BIT_RATE_96000 MPEG_BIT_RATE_INDEX_7 -+#define MPEG_MP3_BIT_RATE_112000 MPEG_BIT_RATE_INDEX_8 -+#define MPEG_MP3_BIT_RATE_128000 MPEG_BIT_RATE_INDEX_9 -+#define MPEG_MP3_BIT_RATE_160000 MPEG_BIT_RATE_INDEX_10 -+#define MPEG_MP3_BIT_RATE_192000 MPEG_BIT_RATE_INDEX_11 -+#define MPEG_MP3_BIT_RATE_224000 MPEG_BIT_RATE_INDEX_12 -+#define MPEG_MP3_BIT_RATE_256000 MPEG_BIT_RATE_INDEX_13 -+#define MPEG_MP3_BIT_RATE_320000 MPEG_BIT_RATE_INDEX_14 -+ -+#define MPEG_BIT_RATE_FREE MPEG_BIT_RATE_INDEX_0 -+ -+#define MPEG_GET_BITRATE(a) ((uint16_t)(a).bitrate1 << 8 | (a).bitrate2) -+#define MPEG_SET_BITRATE(a, b) \ -+ do { \ -+ (a).bitrate1 = ((b) >> 8) & 0x7f; \ -+ (a).bitrate2 = (b) & 0xff; \ -+ } while (0) - - #define AAC_OBJECT_TYPE_MPEG2_AAC_LC 0x80 - #define AAC_OBJECT_TYPE_MPEG4_AAC_LC 0x40 -@@ -168,7 +221,9 @@ typedef struct { - uint8_t frequency:6; - uint8_t mpf:1; - uint8_t rfa:1; -- uint16_t bitrate; -+ uint8_t bitrate1:7; -+ uint8_t vbr:1; -+ uint8_t bitrate2; - } __attribute__ ((packed)) a2dp_mpeg_t; - - typedef struct { -@@ -213,7 +268,9 @@ typedef struct { - uint8_t rfa:1; - uint8_t mpf:1; - uint8_t frequency:6; -- uint16_t bitrate; -+ uint8_t vbr:1; -+ uint8_t bitrate1:7; -+ uint8_t bitrate2; - } __attribute__ ((packed)) a2dp_mpeg_t; - - typedef struct { -diff --git a/tools/avinfo.c b/tools/avinfo.c -index 61bcdab0b..2398cc5e0 100644 ---- a/tools/avinfo.c -+++ b/tools/avinfo.c -@@ -303,11 +303,15 @@ static void print_mpeg24(a2dp_aac_t *aac, uint8_t size) - - static void print_mpeg12(a2dp_mpeg_t *mpeg, uint8_t size) - { -+ uint16_t bitrate; -+ - if (size < sizeof(*mpeg)) { - printf("\tMedia Codec: MPEG12 (broken)\n"); - return; - } - -+ bitrate = MPEG_GET_BITRATE(*mpeg); -+ - printf("\tMedia Codec: MPEG12\n\t\tChannel Modes: "); - - if (mpeg->channel_mode & MPEG_CHANNEL_MODE_MONO) -@@ -343,42 +347,105 @@ static void print_mpeg12(a2dp_mpeg_t *mpeg, uint8_t size) - if (mpeg->layer & MPEG_LAYER_MP3) - printf("3 "); - -- printf("\n\t\tBit Rate: "); -- if (mpeg->bitrate & MPEG_BIT_RATE_FREE) -- printf("Free format"); -- else { -- if (mpeg->bitrate & MPEG_BIT_RATE_32000) -- printf("32kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_40000) -- printf("40kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_48000) -- printf("48kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_56000) -- printf("56kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_64000) -- printf("64kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_80000) -- printf("80kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_96000) -- printf("96kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_112000) -- printf("112kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_128000) -- printf("128kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_160000) -- printf("160kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_192000) -- printf("192kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_224000) -- printf("224kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_256000) -- printf("256kbps "); -- if (mpeg->bitrate & MPEG_BIT_RATE_320000) -- printf("320kbps "); -+ if (bitrate & MPEG_BIT_RATE_FREE) { -+ printf("\n\t\tBit Rate: Free format"); -+ } else { -+ if (mpeg->layer & MPEG_LAYER_MP1) { -+ printf("\n\t\tLayer 1 Bit Rate: "); -+ if (bitrate & MPEG_MP1_BIT_RATE_32000) -+ printf("32kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_64000) -+ printf("64kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_96000) -+ printf("96kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_128000) -+ printf("128kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_160000) -+ printf("160kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_192000) -+ printf("192kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_224000) -+ printf("224kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_256000) -+ printf("256kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_320000) -+ printf("320kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_352000) -+ printf("352kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_384000) -+ printf("384kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_416000) -+ printf("416kbps "); -+ if (bitrate & MPEG_MP1_BIT_RATE_448000) -+ printf("448kbps "); -+ } -+ -+ if (mpeg->layer & MPEG_LAYER_MP2) { -+ printf("\n\t\tLayer 2 Bit Rate: "); -+ if (bitrate & MPEG_MP2_BIT_RATE_32000) -+ printf("32kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_48000) -+ printf("48kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_56000) -+ printf("56kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_64000) -+ printf("64kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_80000) -+ printf("80kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_96000) -+ printf("96kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_112000) -+ printf("112kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_128000) -+ printf("128kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_160000) -+ printf("160kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_192000) -+ printf("192kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_224000) -+ printf("224kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_256000) -+ printf("256kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_320000) -+ printf("320kbps "); -+ if (bitrate & MPEG_MP2_BIT_RATE_384000) -+ printf("384kbps "); -+ } -+ -+ if (mpeg->layer & MPEG_LAYER_MP3) { -+ printf("\n\t\tLayer 3 Bit Rate: "); -+ if (bitrate & MPEG_MP3_BIT_RATE_32000) -+ printf("32kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_40000) -+ printf("40kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_48000) -+ printf("48kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_56000) -+ printf("56kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_64000) -+ printf("64kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_80000) -+ printf("80kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_96000) -+ printf("96kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_112000) -+ printf("112kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_128000) -+ printf("128kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_160000) -+ printf("160kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_192000) -+ printf("192kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_224000) -+ printf("224kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_256000) -+ printf("256kbps "); -+ if (bitrate & MPEG_MP3_BIT_RATE_320000) -+ printf("320kbps "); -+ } - } - -- printf("\n\t\tVBR: %s", mpeg->bitrate & MPEG_BIT_RATE_VBR ? "Yes" : -- "No"); -+ printf("\n\t\tVBR: %s", mpeg->vbr ? "Yes" : "No"); - - printf("\n\t\tPayload Format: "); - if (mpeg->mpf) --- -2.21.0 - - -From 70874281220368ed24bb99e916b765608c01a44a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 23 Dec 2018 11:40:17 +0100 -Subject: [PATCH 06/31] a2dp-codecs: Define a2dp_vendor_codec_t struct in - endian neutral way - -And define new macros A2DP_GET_VENDOR_ID(), A2DP_GET_CODEC_ID() and -A2DP_SET_VENDOR_ID_CODEC_ID() for easily filling a2dp_vendor_codec_t -struct. ---- - android/a2dp.c | 8 ++++---- - android/avdtp.c | 6 ++++-- - android/hal-audio-aptx.c | 18 ++++++------------ - profiles/audio/a2dp-codecs.h | 24 ++++++++++++++++++++++-- - profiles/audio/a2dp.c | 9 +++++---- - tools/avinfo.c | 4 ++-- - 6 files changed, 43 insertions(+), 26 deletions(-) - -diff --git a/android/a2dp.c b/android/a2dp.c -index f21904208..8bcdfd20f 100644 ---- a/android/a2dp.c -+++ b/android/a2dp.c -@@ -417,8 +417,8 @@ static int check_capabilities(struct a2dp_preset *preset, - preset->len); - case A2DP_CODEC_VENDOR: - vndcodec = (void *) codec->data; -- if (btohl(vndcodec->vendor_id) == APTX_VENDOR_ID && -- btohs(vndcodec->codec_id) == APTX_CODEC_ID) -+ if (A2DP_GET_VENDOR_ID(*vndcodec) == APTX_VENDOR_ID && -+ A2DP_GET_CODEC_ID(*vndcodec) == APTX_CODEC_ID) - return aptx_check_config(codec->data, codec_len, - preset->data, preset->len); - return -EINVAL; -@@ -1344,8 +1344,8 @@ static uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec, - a2dp_vendor_codec_t *vndcodec = (void *) endpoint->caps->data; - - avdtp_sep_set_vendor_codec(endpoint->sep, -- btohl(vndcodec->vendor_id), -- btohs(vndcodec->codec_id)); -+ A2DP_GET_VENDOR_ID(*vndcodec), -+ A2DP_GET_CODEC_ID(*vndcodec)); - } - - endpoints = g_slist_append(endpoints, endpoint); -diff --git a/android/avdtp.c b/android/avdtp.c -index 34caf3db5..7fb8cb731 100644 ---- a/android/avdtp.c -+++ b/android/avdtp.c -@@ -1103,10 +1103,12 @@ struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session, - a2dp_vendor_codec_t *vndcodec = - (void *) codec_data->data; - -- if (btohl(vndcodec->vendor_id) != lsep->vndcodec_vendor) -+ if (A2DP_GET_VENDOR_ID(*vndcodec) != -+ lsep->vndcodec_vendor) - continue; - -- if (btohs(vndcodec->codec_id) != lsep->vndcodec_codec) -+ if (A2DP_GET_CODEC_ID(*vndcodec) != -+ lsep->vndcodec_codec) - continue; - } - -diff --git a/android/hal-audio-aptx.c b/android/hal-audio-aptx.c -index a8000759b..4707f593e 100644 ---- a/android/hal-audio-aptx.c -+++ b/android/hal-audio-aptx.c -@@ -36,27 +36,21 @@ struct aptx_data { - - static const a2dp_aptx_t aptx_presets[] = { - { -- .info = { -- .vendor_id = APTX_VENDOR_ID, -- .codec_id = APTX_CODEC_ID, -- }, -+ .info = -+ A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID), - .frequency = APTX_SAMPLING_FREQ_44100 | - APTX_SAMPLING_FREQ_48000, - .channel_mode = APTX_CHANNEL_MODE_STEREO, - }, - { -- .info = { -- .vendor_id = APTX_VENDOR_ID, -- .codec_id = APTX_CODEC_ID, -- }, -+ .info = -+ A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID), - .frequency = APTX_SAMPLING_FREQ_48000, - .channel_mode = APTX_CHANNEL_MODE_STEREO, - }, - { -- .info = { -- .vendor_id = APTX_VENDOR_ID, -- .codec_id = APTX_CODEC_ID, -- }, -+ .info = -+ A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID), - .frequency = APTX_SAMPLING_FREQ_44100, - .channel_mode = APTX_CHANNEL_MODE_STEREO, - }, -diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h -index 47030bcc1..a310efe49 100644 ---- a/profiles/audio/a2dp-codecs.h -+++ b/profiles/audio/a2dp-codecs.h -@@ -198,10 +198,30 @@ - #define LDAC_CODEC_ID 0x00aa - - typedef struct { -- uint32_t vendor_id; -- uint16_t codec_id; -+ uint8_t vendor_id4; -+ uint8_t vendor_id3; -+ uint8_t vendor_id2; -+ uint8_t vendor_id1; -+ uint8_t codec_id2; -+ uint8_t codec_id1; - } __attribute__ ((packed)) a2dp_vendor_codec_t; - -+#define A2DP_GET_VENDOR_ID(a) ( \ -+ (((uint32_t)(a).vendor_id4) << 0) | \ -+ (((uint32_t)(a).vendor_id3) << 8) | \ -+ (((uint32_t)(a).vendor_id2) << 16) | \ -+ (((uint32_t)(a).vendor_id1) << 24) \ -+ ) -+#define A2DP_GET_CODEC_ID(a) ((a).codec_id2 | (((uint16_t)(a).codec_id1) << 8)) -+#define A2DP_SET_VENDOR_ID_CODEC_ID(v, c) ((a2dp_vendor_codec_t){ \ -+ .vendor_id4 = (((v) >> 0) & 0xff), \ -+ .vendor_id3 = (((v) >> 8) & 0xff), \ -+ .vendor_id2 = (((v) >> 16) & 0xff), \ -+ .vendor_id1 = (((v) >> 24) & 0xff), \ -+ .codec_id2 = (((c) >> 0) & 0xff), \ -+ .codec_id1 = (((c) >> 8) & 0xff), \ -+ }) -+ - #if __BYTE_ORDER == __LITTLE_ENDIAN - - typedef struct { -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index fc98bb264..344459332 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -523,14 +523,15 @@ static gboolean endpoint_match_codec_ind(struct avdtp *session, - local_codec = (a2dp_vendor_codec_t *) capabilities; - remote_codec = (a2dp_vendor_codec_t *) codec->data; - -- if (remote_codec->vendor_id != local_codec->vendor_id) -+ if (A2DP_GET_VENDOR_ID(*remote_codec) != -+ A2DP_GET_VENDOR_ID(*local_codec)) - return FALSE; - -- if (remote_codec->codec_id != local_codec->codec_id) -+ if (A2DP_GET_CODEC_ID(*remote_codec) != A2DP_GET_CODEC_ID(*local_codec)) - return FALSE; - -- DBG("vendor 0x%08x codec 0x%04x", btohl(remote_codec->vendor_id), -- btohs(remote_codec->codec_id)); -+ DBG("vendor 0x%08x codec 0x%04x", A2DP_GET_VENDOR_ID(*remote_codec), -+ A2DP_GET_CODEC_ID(*remote_codec)); - return TRUE; - } - -diff --git a/tools/avinfo.c b/tools/avinfo.c -index 2398cc5e0..424221f8d 100644 ---- a/tools/avinfo.c -+++ b/tools/avinfo.c -@@ -221,8 +221,8 @@ static void print_vendor(a2dp_vendor_codec_t *vendor, uint8_t size) - return; - } - -- vendor_id = btohl(vendor->vendor_id); -- codec_id = btohs(vendor->codec_id); -+ vendor_id = A2DP_GET_VENDOR_ID(*vendor); -+ codec_id = A2DP_GET_CODEC_ID(*vendor); - - printf("\tMedia Codec: Vendor Specific A2DP Codec"); - --- -2.21.0 - - -From f20550833ec0a3fee5930cc25db0b51f8492f65a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 23 Dec 2018 11:40:18 +0100 -Subject: [PATCH 07/31] a2dp-codecs: Add needed includes and properly check for - endian macros - -Without stdint.h type uint8_t cannot be used. - -And without endian.h macros __BYTE_ORDER, __LITTLE_ENDIAN and __BIG_ENDIAN -are not defined. - -When both __BYTE_ORDER and __LITTLE_ENDIAN macros are not defined, then -condition #if __BYTE_ORDER == __LITTLE_ENDIAN is true. ---- - profiles/audio/a2dp-codecs.h | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h -index a310efe49..649e2411b 100644 ---- a/profiles/audio/a2dp-codecs.h -+++ b/profiles/audio/a2dp-codecs.h -@@ -22,6 +22,9 @@ - * - */ - -+#include -+#include -+ - #define A2DP_CODEC_SBC 0x00 - #define A2DP_CODEC_MPEG12 0x01 - #define A2DP_CODEC_MPEG24 0x02 -@@ -222,7 +225,8 @@ typedef struct { - .codec_id1 = (((c) >> 8) & 0xff), \ - }) - --#if __BYTE_ORDER == __LITTLE_ENDIAN -+#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ -+ __BYTE_ORDER == __LITTLE_ENDIAN - - typedef struct { - uint8_t channel_mode:4; -@@ -269,7 +273,8 @@ typedef struct { - uint8_t unknown[2]; - } __attribute__ ((packed)) a2dp_ldac_t; - --#elif __BYTE_ORDER == __BIG_ENDIAN -+#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ -+ __BYTE_ORDER == __BIG_ENDIAN - - typedef struct { - uint8_t frequency:4; --- -2.21.0 - - -From 99c71523e1d4b33885d2e095f3a7539764edbce8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 23 Dec 2018 11:40:19 +0100 -Subject: [PATCH 08/31] a2dp-codecs: Properly define macros and struct for LDAC - codec - ---- - profiles/audio/a2dp-codecs.h | 27 +++++++++++++++++---------- - tools/avinfo.c | 4 ++-- - 2 files changed, 19 insertions(+), 12 deletions(-) - -diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h -index 649e2411b..6f667d3aa 100644 ---- a/profiles/audio/a2dp-codecs.h -+++ b/profiles/audio/a2dp-codecs.h -@@ -200,6 +200,17 @@ - #define LDAC_VENDOR_ID 0x0000012d - #define LDAC_CODEC_ID 0x00aa - -+#define LDAC_SAMPLING_FREQ_44100 0x20 -+#define LDAC_SAMPLING_FREQ_48000 0x10 -+#define LDAC_SAMPLING_FREQ_88200 0x08 -+#define LDAC_SAMPLING_FREQ_96000 0x04 -+#define LDAC_SAMPLING_FREQ_176400 0x02 -+#define LDAC_SAMPLING_FREQ_192000 0x01 -+ -+#define LDAC_CHANNEL_MODE_MONO 0x04 -+#define LDAC_CHANNEL_MODE_DUAL 0x02 -+#define LDAC_CHANNEL_MODE_STEREO 0x01 -+ - typedef struct { - uint8_t vendor_id4; - uint8_t vendor_id3; -@@ -225,6 +236,12 @@ typedef struct { - .codec_id1 = (((c) >> 8) & 0xff), \ - }) - -+typedef struct { -+ a2dp_vendor_codec_t info; -+ uint8_t frequency; -+ uint8_t channel_mode; -+} __attribute__ ((packed)) a2dp_ldac_t; -+ - #if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ - __BYTE_ORDER == __LITTLE_ENDIAN - -@@ -268,11 +285,6 @@ typedef struct { - uint8_t frequency:4; - } __attribute__ ((packed)) a2dp_aptx_t; - --typedef struct { -- a2dp_vendor_codec_t info; -- uint8_t unknown[2]; --} __attribute__ ((packed)) a2dp_ldac_t; -- - #elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ - __BYTE_ORDER == __BIG_ENDIAN - -@@ -316,11 +328,6 @@ typedef struct { - uint8_t channel_mode:4; - } __attribute__ ((packed)) a2dp_aptx_t; - --typedef struct { -- a2dp_vendor_codec_t info; -- uint8_t unknown[2]; --} __attribute__ ((packed)) a2dp_ldac_t; -- - #else - #error "Unknown byte order" - #endif -diff --git a/tools/avinfo.c b/tools/avinfo.c -index 424221f8d..1852b2473 100644 ---- a/tools/avinfo.c -+++ b/tools/avinfo.c -@@ -204,8 +204,8 @@ static void print_ldac(a2dp_ldac_t *ldac, uint8_t size) - return; - } - -- printf("\n\t\t\tUnknown: %02x %02x", ldac->unknown[0], -- ldac->unknown[1]); -+ printf("\n\t\t\tUnknown: %02x %02x", ldac->frequency, -+ ldac->channel_mode); - - printf("\n"); - } --- -2.21.0 - - -From 8e119a083b931a53d19ba218973c31bdda56138d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 23 Dec 2018 11:40:20 +0100 -Subject: [PATCH 09/31] a2dp-codecs: Add macros and structures for new codecs - -Add additional codecs: FastStream, aptX Low Latency and aptX HD codecs. ---- - profiles/audio/a2dp-codecs.h | 120 +++++++++++++++++++++++++++++++++++ - 1 file changed, 120 insertions(+) - -diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h -index 6f667d3aa..0bdd29110 100644 ---- a/profiles/audio/a2dp-codecs.h -+++ b/profiles/audio/a2dp-codecs.h -@@ -4,6 +4,7 @@ - * - * Copyright (C) 2006-2010 Nokia Corporation - * Copyright (C) 2004-2010 Marcel Holtmann -+ * Copyright (C) 2018 Pali Rohár - * - * - * This library is free software; you can redistribute it and/or -@@ -197,6 +198,59 @@ - #define APTX_SAMPLING_FREQ_44100 0x02 - #define APTX_SAMPLING_FREQ_48000 0x01 - -+#define FASTSTREAM_VENDOR_ID 0x0000000a -+#define FASTSTREAM_CODEC_ID 0x0001 -+ -+#define FASTSTREAM_DIRECTION_SINK 0x1 -+#define FASTSTREAM_DIRECTION_SOURCE 0x2 -+ -+#define FASTSTREAM_SINK_SAMPLING_FREQ_44100 0x2 -+#define FASTSTREAM_SINK_SAMPLING_FREQ_48000 0x1 -+ -+#define FASTSTREAM_SOURCE_SAMPLING_FREQ_16000 0x2 -+ -+#define APTX_LL_VENDOR_ID 0x0000000a -+#define APTX_LL_CODEC_ID 0x0002 -+ -+#define APTX_LL_CHANNEL_MODE_MONO 0x01 -+#define APTX_LL_CHANNEL_MODE_STEREO 0x02 -+ -+#define APTX_LL_SAMPLING_FREQ_16000 0x08 -+#define APTX_LL_SAMPLING_FREQ_32000 0x04 -+#define APTX_LL_SAMPLING_FREQ_44100 0x02 -+#define APTX_LL_SAMPLING_FREQ_48000 0x01 -+ -+/* Default parameters for aptX Low Latency encoder */ -+ -+/* Target codec buffer level = 180 */ -+#define APTX_LL_TARGET_LEVEL2 0xb4 -+#define APTX_LL_TARGET_LEVEL1 0x00 -+ -+/* Initial codec buffer level = 360 */ -+#define APTX_LL_INITIAL_LEVEL2 0x68 -+#define APTX_LL_INITIAL_LEVEL1 0x01 -+ -+/* SRA max rate 0.005 * 10000 = 50 */ -+#define APTX_LL_SRA_MAX_RATE 0x32 -+ -+/* SRA averaging time = 1s */ -+#define APTX_LL_SRA_AVG_TIME 0x01 -+ -+/* Good working codec buffer level = 180 */ -+#define APTX_LL_GOOD_WORKING_LEVEL2 0xB4 -+#define APTX_LL_GOOD_WORKING_LEVEL1 0x00 -+ -+#define APTX_HD_VENDOR_ID 0x000000D7 -+#define APTX_HD_CODEC_ID 0x0024 -+ -+#define APTX_HD_CHANNEL_MODE_MONO 0x1 -+#define APTX_HD_CHANNEL_MODE_STEREO 0x2 -+ -+#define APTX_HD_SAMPLING_FREQ_16000 0x8 -+#define APTX_HD_SAMPLING_FREQ_32000 0x4 -+#define APTX_HD_SAMPLING_FREQ_44100 0x2 -+#define APTX_HD_SAMPLING_FREQ_48000 0x1 -+ - #define LDAC_VENDOR_ID 0x0000012d - #define LDAC_CODEC_ID 0x00aa - -@@ -236,6 +290,18 @@ typedef struct { - .codec_id1 = (((c) >> 8) & 0xff), \ - }) - -+typedef struct { -+ uint8_t reserved; -+ uint8_t target_level2; -+ uint8_t target_level1; -+ uint8_t initial_level2; -+ uint8_t initial_level1; -+ uint8_t sra_max_rate; -+ uint8_t sra_avg_time; -+ uint8_t good_working_level2; -+ uint8_t good_working_level1; -+} __attribute__ ((packed)) a2dp_aptx_ll_new_caps_t; -+ - typedef struct { - a2dp_vendor_codec_t info; - uint8_t frequency; -@@ -285,6 +351,33 @@ typedef struct { - uint8_t frequency:4; - } __attribute__ ((packed)) a2dp_aptx_t; - -+typedef struct { -+ a2dp_vendor_codec_t info; -+ uint8_t direction; -+ uint8_t sink_frequency:4; -+ uint8_t source_frequency:4; -+} __attribute__ ((packed)) a2dp_faststream_t; -+ -+typedef struct { -+ a2dp_vendor_codec_t info; -+ uint8_t channel_mode:4; -+ uint8_t frequency:4; -+ uint8_t bidirect_link:1; -+ uint8_t has_new_caps:1; -+ uint8_t reserved:6; -+ a2dp_aptx_ll_new_caps_t new_caps[0]; -+} __attribute__ ((packed)) a2dp_aptx_ll_t; -+ -+typedef struct { -+ a2dp_vendor_codec_t info; -+ uint8_t channel_mode:4; -+ uint8_t frequency:4; -+ uint8_t reserved0; -+ uint8_t reserved1; -+ uint8_t reserved2; -+ uint8_t reserved3; -+} __attribute__ ((packed)) a2dp_aptx_hd_t; -+ - #elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ - __BYTE_ORDER == __BIG_ENDIAN - -@@ -328,6 +421,33 @@ typedef struct { - uint8_t channel_mode:4; - } __attribute__ ((packed)) a2dp_aptx_t; - -+typedef struct { -+ a2dp_vendor_codec_t info; -+ uint8_t direction; -+ uint8_t source_frequency:4; -+ uint8_t sink_frequency:4; -+} __attribute__ ((packed)) a2dp_faststream_t; -+ -+typedef struct { -+ a2dp_vendor_codec_t info; -+ uint8_t frequency:4; -+ uint8_t channel_mode:4; -+ uint8_t reserved:6; -+ uint8_t has_new_caps:1; -+ uint8_t bidirect_link:1; -+ a2dp_aptx_ll_new_caps_t new_caps[0]; -+} __attribute__ ((packed)) a2dp_aptx_ll_t; -+ -+typedef struct { -+ a2dp_vendor_codec_t info; -+ uint8_t frequency:4; -+ uint8_t channel_mode:4; -+ uint8_t reserved0; -+ uint8_t reserved1; -+ uint8_t reserved2; -+ uint8_t reserved3; -+} __attribute__ ((packed)) a2dp_aptx_hd_t; -+ - #else - #error "Unknown byte order" - #endif --- -2.21.0 - - -From 7a2ea44b4c9929507a679debf0cf74416146a5d0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 23 Dec 2018 11:40:21 +0100 -Subject: [PATCH 10/31] avinfo: Parse new A2DP codecs - -Parse information about additional A2DP codecs: FastStream, aptX Low -Latency, aptX HD and LDAC. ---- - tools/avinfo.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 144 insertions(+), 2 deletions(-) - -diff --git a/tools/avinfo.c b/tools/avinfo.c -index 1852b2473..02fc1f233 100644 ---- a/tools/avinfo.c -+++ b/tools/avinfo.c -@@ -4,6 +4,7 @@ - * - * Copyright (C) 2006-2010 Nokia Corporation - * Copyright (C) 2004-2010 Marcel Holtmann -+ * Copyright (C) 2018 Pali Rohár - * - * - * This program is free software; you can redistribute it and/or modify -@@ -195,6 +196,121 @@ static void print_aptx(a2dp_aptx_t *aptx, uint8_t size) - printf("\n"); - } - -+static void print_faststream(a2dp_faststream_t *faststream, uint8_t size) -+{ -+ printf("\t\tVendor Specific Value (FastStream)"); -+ -+ if (size < sizeof(*faststream)) { -+ printf(" (broken)\n"); -+ return; -+ } -+ -+ printf("\n\t\t\tDirections: "); -+ if (faststream->direction & FASTSTREAM_DIRECTION_SINK) -+ printf("sink "); -+ if (faststream->direction & FASTSTREAM_DIRECTION_SOURCE) -+ printf("source "); -+ -+ if (faststream->direction & FASTSTREAM_DIRECTION_SINK) { -+ printf("\n\t\t\tSink Frequencies: "); -+ if (faststream->sink_frequency & -+ FASTSTREAM_SINK_SAMPLING_FREQ_44100) -+ printf("44.1kHz "); -+ if (faststream->sink_frequency & -+ FASTSTREAM_SINK_SAMPLING_FREQ_48000) -+ printf("48kHz "); -+ } -+ -+ if (faststream->direction & FASTSTREAM_DIRECTION_SOURCE) { -+ printf("\n\t\t\tSource Frequencies: "); -+ if (faststream->source_frequency & -+ FASTSTREAM_SOURCE_SAMPLING_FREQ_16000) -+ printf("16kHz "); -+ } -+ -+ printf("\n"); -+} -+ -+static void print_aptx_ll(a2dp_aptx_ll_t *aptx_ll, uint8_t size) -+{ -+ a2dp_aptx_ll_new_caps_t *aptx_ll_new; -+ -+ printf("\t\tVendor Specific Value (aptX Low Latency)"); -+ -+ if (size < sizeof(*aptx_ll)) { -+ printf(" (broken)\n"); -+ return; -+ } -+ -+ printf("\n\t\t\tFrequencies: "); -+ if (aptx_ll->frequency & APTX_LL_SAMPLING_FREQ_16000) -+ printf("16kHz "); -+ if (aptx_ll->frequency & APTX_LL_SAMPLING_FREQ_32000) -+ printf("32kHz "); -+ if (aptx_ll->frequency & APTX_LL_SAMPLING_FREQ_44100) -+ printf("44.1kHz "); -+ if (aptx_ll->frequency & APTX_LL_SAMPLING_FREQ_48000) -+ printf("48kHz "); -+ -+ printf("\n\t\t\tChannel modes: "); -+ if (aptx_ll->channel_mode & APTX_LL_CHANNEL_MODE_MONO) -+ printf("Mono "); -+ if (aptx_ll->channel_mode & APTX_LL_CHANNEL_MODE_STEREO) -+ printf("Stereo "); -+ -+ printf("\n\t\tBidirectional link: %s", -+ aptx_ll->bidirect_link ? "Yes" : "No"); -+ -+ aptx_ll_new = &aptx_ll->new_caps[0]; -+ if (aptx_ll->has_new_caps && -+ size >= sizeof(*aptx_ll) + sizeof(*aptx_ll_new)) { -+ printf("\n\t\tTarget codec buffer level: %u", -+ (unsigned int)aptx_ll_new->target_level2 | -+ ((unsigned int)(aptx_ll_new->target_level1) << 8)); -+ printf("\n\t\tInitial codec buffer level: %u", -+ (unsigned int)aptx_ll_new->initial_level2 | -+ ((unsigned int)(aptx_ll_new->initial_level1) << 8)); -+ printf("\n\t\tSRA max rate: %g", -+ aptx_ll_new->sra_max_rate / 10000.0); -+ printf("\n\t\tSRA averaging time: %us", -+ (unsigned int)aptx_ll_new->sra_avg_time); -+ printf("\n\t\tGood working codec buffer level: %u", -+ (unsigned int)aptx_ll_new->good_working_level2 | -+ ((unsigned int)(aptx_ll_new->good_working_level1) << 8) -+ ); -+ } -+ -+ printf("\n"); -+} -+ -+static void print_aptx_hd(a2dp_aptx_hd_t *aptx_hd, uint8_t size) -+{ -+ printf("\t\tVendor Specific Value (aptX HD)"); -+ -+ if (size < sizeof(*aptx_hd)) { -+ printf(" (broken)\n"); -+ return; -+ } -+ -+ printf("\n\t\t\tFrequencies: "); -+ if (aptx_hd->frequency & APTX_HD_SAMPLING_FREQ_16000) -+ printf("16kHz "); -+ if (aptx_hd->frequency & APTX_HD_SAMPLING_FREQ_32000) -+ printf("32kHz "); -+ if (aptx_hd->frequency & APTX_HD_SAMPLING_FREQ_44100) -+ printf("44.1kHz "); -+ if (aptx_hd->frequency & APTX_HD_SAMPLING_FREQ_48000) -+ printf("48kHz "); -+ -+ printf("\n\t\t\tChannel modes: "); -+ if (aptx_hd->channel_mode & APTX_HD_CHANNEL_MODE_MONO) -+ printf("Mono "); -+ if (aptx_hd->channel_mode & APTX_HD_CHANNEL_MODE_STEREO) -+ printf("Stereo "); -+ -+ printf("\n"); -+} -+ - static void print_ldac(a2dp_ldac_t *ldac, uint8_t size) - { - printf("\t\tVendor Specific Value (LDAC)"); -@@ -204,8 +320,27 @@ static void print_ldac(a2dp_ldac_t *ldac, uint8_t size) - return; - } - -- printf("\n\t\t\tUnknown: %02x %02x", ldac->frequency, -- ldac->channel_mode); -+ printf("\n\t\t\tFrequencies: "); -+ if (ldac->frequency & LDAC_SAMPLING_FREQ_44100) -+ printf("44.1kHz "); -+ if (ldac->frequency & LDAC_SAMPLING_FREQ_48000) -+ printf("48kHz "); -+ if (ldac->frequency & LDAC_SAMPLING_FREQ_88200) -+ printf("88.2kHz "); -+ if (ldac->frequency & LDAC_SAMPLING_FREQ_96000) -+ printf("96kHz "); -+ if (ldac->frequency & LDAC_SAMPLING_FREQ_176400) -+ printf("176.4kHz "); -+ if (ldac->frequency & LDAC_SAMPLING_FREQ_192000) -+ printf("192kHz "); -+ -+ printf("\n\t\t\tChannel modes: "); -+ if (ldac->channel_mode & LDAC_CHANNEL_MODE_MONO) -+ printf("Mono "); -+ if (ldac->channel_mode & LDAC_CHANNEL_MODE_DUAL) -+ printf("Dual "); -+ if (ldac->channel_mode & LDAC_CHANNEL_MODE_STEREO) -+ printf("Stereo "); - - printf("\n"); - } -@@ -237,6 +372,13 @@ static void print_vendor(a2dp_vendor_codec_t *vendor, uint8_t size) - - if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) - print_aptx((void *) vendor, size); -+ else if (vendor_id == FASTSTREAM_VENDOR_ID && -+ codec_id == FASTSTREAM_CODEC_ID) -+ print_faststream((void *) vendor, size); -+ else if (vendor_id == APTX_LL_VENDOR_ID && codec_id == APTX_LL_CODEC_ID) -+ print_aptx_ll((void *) vendor, size); -+ else if (vendor_id == APTX_HD_VENDOR_ID && codec_id == APTX_HD_CODEC_ID) -+ print_aptx_hd((void *) vendor, size); - else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID) - print_ldac((void *) vendor, size); - } --- -2.21.0 - - -From 61bc87a7702f0ed544d190444938ebece135547d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 23 Dec 2018 11:00:43 +0100 -Subject: [PATCH 11/31] btmon: Parse new A2DP codecs - -Parse information about additional A2DP codecs: FastStream, aptX Low -Latency and aptX HD. ---- - monitor/a2dp.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 284 insertions(+), 12 deletions(-) - -diff --git a/monitor/a2dp.c b/monitor/a2dp.c -index 94f9758aa..3e798a7ee 100644 ---- a/monitor/a2dp.c -+++ b/monitor/a2dp.c -@@ -3,6 +3,7 @@ - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2015 Andrzej Kaczmarek -+ * Copyright (C) 2018 Pali Rohár - * - * - * This library is free software; you can redistribute it and/or -@@ -50,6 +51,12 @@ - /* Vendor Specific A2DP Codecs */ - #define APTX_VENDOR_ID 0x0000004f - #define APTX_CODEC_ID 0x0001 -+#define FASTSTREAM_VENDOR_ID 0x0000000a -+#define FASTSTREAM_CODEC_ID 0x0001 -+#define APTX_LL_VENDOR_ID 0x0000000a -+#define APTX_LL_CODEC_ID 0x0002 -+#define APTX_HD_VENDOR_ID 0x000000D7 -+#define APTX_HD_CODEC_ID 0x0024 - #define LDAC_VENDOR_ID 0x0000012d - #define LDAC_CODEC_ID 0x00aa - -@@ -186,6 +193,23 @@ static const struct bit_desc aptx_channel_mode_table[] = { - { } - }; - -+static const struct bit_desc faststream_direction_table[] = { -+ { 0, "Sink" }, -+ { 1, "Source" }, -+ { } -+}; -+ -+static const struct bit_desc faststream_sink_frequency_table[] = { -+ { 1, "44100" }, -+ { 0, "48000" }, -+ { } -+}; -+ -+static const struct bit_desc faststream_source_frequency_table[] = { -+ { 5, "16000" }, -+ { } -+}; -+ - static void print_value_bits(uint8_t indent, uint32_t value, - const struct bit_desc *table) - { -@@ -210,12 +234,49 @@ static const char *find_value_bit(uint32_t value, - return "Unknown"; - } - -+struct vndcodec { -+ uint32_t vendor_id; -+ uint16_t codec_id; -+ char *codec_name; -+ bool (*codec_vendor_cap)(uint8_t losc, struct l2cap_frame *frame); -+ bool (*codec_vendor_cfg)(uint8_t losc, struct l2cap_frame *frame); -+}; -+ -+static bool codec_vendor_aptx_cap(uint8_t losc, struct l2cap_frame *frame); -+static bool codec_vendor_aptx_cfg(uint8_t losc, struct l2cap_frame *frame); -+static bool codec_vendor_faststream_cap(uint8_t losc, -+ struct l2cap_frame *frame); -+static bool codec_vendor_faststream_cfg(uint8_t losc, -+ struct l2cap_frame *frame); -+static bool codec_vendor_aptx_ll_cap(uint8_t losc, struct l2cap_frame *frame); -+static bool codec_vendor_aptx_ll_cfg(uint8_t losc, struct l2cap_frame *frame); -+static bool codec_vendor_aptx_hd_cap(uint8_t losc, struct l2cap_frame *frame); -+static bool codec_vendor_aptx_hd_cfg(uint8_t losc, struct l2cap_frame *frame); -+static bool codec_vendor_ldac(uint8_t losc, struct l2cap_frame *frame); -+ -+static const struct vndcodec vndcodecs[] = { -+ { APTX_VENDOR_ID, APTX_CODEC_ID, "aptX", -+ codec_vendor_aptx_cap, codec_vendor_aptx_cfg }, -+ { FASTSTREAM_VENDOR_ID, FASTSTREAM_CODEC_ID, "FastStream", -+ codec_vendor_faststream_cap, codec_vendor_faststream_cfg }, -+ { APTX_LL_VENDOR_ID, APTX_LL_CODEC_ID, "aptX Low Latency", -+ codec_vendor_aptx_ll_cap, codec_vendor_aptx_ll_cfg }, -+ { APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID, "aptX HD", -+ codec_vendor_aptx_hd_cap, codec_vendor_aptx_hd_cfg }, -+ { LDAC_VENDOR_ID, LDAC_CODEC_ID, "LDAC", -+ codec_vendor_ldac, codec_vendor_ldac }, -+ { } -+}; -+ - static const char *vndcodec2str(uint32_t vendor_id, uint16_t codec_id) - { -- if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) -- return "aptX"; -- else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID) -- return "LDAC"; -+ size_t i; -+ -+ for (i = 0; i < sizeof(vndcodecs)/sizeof(*vndcodecs); i++) { -+ if (vndcodecs[i].vendor_id == vendor_id && -+ vndcodecs[i].codec_id == codec_id) -+ return vndcodecs[i].codec_name; -+ } - - return "Unknown"; - } -@@ -507,6 +568,108 @@ static bool codec_vendor_aptx_cap(uint8_t losc, struct l2cap_frame *frame) - return true; - } - -+static bool codec_vendor_faststream_cap(uint8_t losc, struct l2cap_frame *frame) -+{ -+ uint8_t cap = 0; -+ -+ if (losc != 2) -+ return false; -+ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ print_field("%*cDirection: 0x%02x", BASE_INDENT + 2, ' ', cap); -+ print_value_bits(BASE_INDENT + 2, cap, faststream_direction_table); -+ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ print_field("%*cSink Frequency: 0x%02x", BASE_INDENT + 2, ' ', -+ cap & 0x0f); -+ print_value_bits(BASE_INDENT + 2, cap & 0x0f, -+ faststream_sink_frequency_table); -+ -+ print_field("%*cSource Frequency: 0x%02x", BASE_INDENT + 2, ' ', -+ cap & 0xf0); -+ print_value_bits(BASE_INDENT + 2, cap & 0xf0, -+ faststream_source_frequency_table); -+ -+ return true; -+} -+ -+static bool codec_vendor_aptx_ll_cap(uint8_t losc, struct l2cap_frame *frame) -+{ -+ uint8_t cap = 0; -+ uint16_t level = 0; -+ -+ if (losc != 2 && losc != 11) -+ return false; -+ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ print_field("%*cFrequency: 0x%02x", BASE_INDENT + 2, ' ', cap & 0xf0); -+ print_value_bits(BASE_INDENT + 2, cap & 0xf0, aptx_frequency_table); -+ -+ print_field("%*cChannel Mode: 0x%02x", BASE_INDENT + 2, ' ', -+ cap & 0x0f); -+ print_value_bits(BASE_INDENT + 2, cap & 0x0f, aptx_channel_mode_table); -+ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ print_field("%*cBidirectional link: %s", BASE_INDENT, ' ', -+ (cap & 1) ? "Yes" : "No"); -+ -+ if ((cap & 2) && losc == 11) { -+ /* reserved */ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ l2cap_frame_get_le16(frame, &level); -+ print_field("%*cTarget codec buffer level: %u (0x%02x)", -+ BASE_INDENT + 2, ' ', level, level); -+ -+ l2cap_frame_get_le16(frame, &level); -+ print_field("%*cInitial codec buffer level: %u (0x%02x)", -+ BASE_INDENT + 2, ' ', level, level); -+ -+ l2cap_frame_get_u8(frame, &cap); -+ print_field("%*cSRA max rate: %g (0x%02x)", -+ BASE_INDENT + 2, ' ', cap / 10000.0, cap); -+ -+ l2cap_frame_get_u8(frame, &cap); -+ print_field("%*cSRA averaging time: %us (0x%02x)", -+ BASE_INDENT + 2, ' ', cap, cap); -+ -+ l2cap_frame_get_le16(frame, &level); -+ print_field("%*cGood working codec buffer level: %u (0x%02x)", -+ BASE_INDENT + 2, ' ', level, level); -+ } -+ -+ return true; -+} -+ -+static bool codec_vendor_aptx_hd_cap(uint8_t losc, struct l2cap_frame *frame) -+{ -+ uint8_t cap = 0; -+ -+ if (losc != 5) -+ return false; -+ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ print_field("%*cFrequency: 0x%02x", BASE_INDENT + 2, ' ', cap & 0xf0); -+ print_value_bits(BASE_INDENT + 2, cap & 0xf0, aptx_frequency_table); -+ -+ print_field("%*cChannel Mode: 0x%02x", BASE_INDENT + 2, ' ', -+ cap & 0x0f); -+ print_value_bits(BASE_INDENT + 2, cap & 0x0f, aptx_channel_mode_table); -+ -+ /* reserved */ -+ l2cap_frame_get_u8(frame, &cap); -+ l2cap_frame_get_u8(frame, &cap); -+ l2cap_frame_get_u8(frame, &cap); -+ l2cap_frame_get_u8(frame, &cap); -+ -+ return true; -+} -+ - static bool codec_vendor_ldac(uint8_t losc, struct l2cap_frame *frame) - { - uint16_t cap = 0; -@@ -525,6 +688,7 @@ static bool codec_vendor_cap(uint8_t losc, struct l2cap_frame *frame) - { - uint32_t vendor_id = 0; - uint16_t codec_id = 0; -+ size_t i; - - if (losc < 6) - return false; -@@ -540,10 +704,11 @@ static bool codec_vendor_cap(uint8_t losc, struct l2cap_frame *frame) - print_field("%*cVendor Specific Codec ID: %s (0x%04x)", BASE_INDENT, - ' ', vndcodec2str(vendor_id, codec_id), codec_id); - -- if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) -- return codec_vendor_aptx_cap(losc, frame); -- else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID) -- return codec_vendor_ldac(losc, frame); -+ for (i = 0; i < sizeof(vndcodecs)/sizeof(*vndcodecs); i++) { -+ if (vndcodecs[i].vendor_id == vendor_id && -+ vndcodecs[i].codec_id == codec_id) -+ return vndcodecs[i].codec_vendor_cap(losc, frame); -+ } - - packet_hexdump(frame->data, losc); - l2cap_frame_pull(frame, frame, losc); -@@ -571,10 +736,116 @@ static bool codec_vendor_aptx_cfg(uint8_t losc, struct l2cap_frame *frame) - return true; - } - -+static bool codec_vendor_faststream_cfg(uint8_t losc, struct l2cap_frame *frame) -+{ -+ uint8_t cap = 0; -+ -+ if (losc != 2) -+ return false; -+ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ print_field("%*cDirection: %s (0x%02x)", BASE_INDENT + 2, ' ', -+ find_value_bit(cap, faststream_direction_table), -+ cap); -+ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ print_field("%*cSink Frequency: %s (0x%02x)", BASE_INDENT + 2, ' ', -+ find_value_bit(cap & 0x0f, -+ faststream_sink_frequency_table), -+ cap & 0x0f); -+ -+ print_field("%*cSource Frequency: %s (0x%02x)", BASE_INDENT + 2, ' ', -+ find_value_bit(cap & 0xf0, -+ faststream_source_frequency_table), -+ cap & 0xf0); -+ -+ return true; -+} -+ -+static bool codec_vendor_aptx_ll_cfg(uint8_t losc, struct l2cap_frame *frame) -+{ -+ uint8_t cap = 0; -+ uint16_t level = 0; -+ -+ if (losc != 2 && losc != 11) -+ return false; -+ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT + 2, ' ', -+ find_value_bit(cap & 0xf0, aptx_frequency_table), -+ cap & 0xf0); -+ -+ print_field("%*cChannel Mode: %s (0x%02x)", BASE_INDENT + 2, ' ', -+ find_value_bit(cap & 0x0f, aptx_channel_mode_table), -+ cap & 0x0f); -+ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ print_field("%*cBidirectional link: %s", BASE_INDENT, ' ', -+ (cap & 1) ? "Yes" : "No"); -+ -+ if ((cap & 2) && losc == 11) { -+ /* reserved */ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ l2cap_frame_get_le16(frame, &level); -+ print_field("%*cTarget codec buffer level: %u (0x%02x)", -+ BASE_INDENT + 2, ' ', level, level); -+ -+ l2cap_frame_get_le16(frame, &level); -+ print_field("%*cInitial codec buffer level: %u (0x%02x)", -+ BASE_INDENT + 2, ' ', level, level); -+ -+ l2cap_frame_get_u8(frame, &cap); -+ print_field("%*cSRA max rate: %g (0x%02x)", -+ BASE_INDENT + 2, ' ', cap / 10000.0, cap); -+ -+ l2cap_frame_get_u8(frame, &cap); -+ print_field("%*cSRA averaging time: %us (0x%02x)", -+ BASE_INDENT + 2, ' ', cap, cap); -+ -+ l2cap_frame_get_le16(frame, &level); -+ print_field("%*cGood working codec buffer level: %u (0x%02x)", -+ BASE_INDENT + 2, ' ', level, level); -+ } -+ -+ return true; -+} -+ -+static bool codec_vendor_aptx_hd_cfg(uint8_t losc, struct l2cap_frame *frame) -+{ -+ uint8_t cap = 0; -+ -+ if (losc != 5) -+ return false; -+ -+ l2cap_frame_get_u8(frame, &cap); -+ -+ print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT + 2, ' ', -+ find_value_bit(cap & 0xf0, aptx_frequency_table), -+ cap & 0xf0); -+ -+ print_field("%*cChannel Mode: %s (0x%02x)", BASE_INDENT + 2, ' ', -+ find_value_bit(cap & 0x0f, aptx_channel_mode_table), -+ cap & 0x0f); -+ -+ /* reserved */ -+ l2cap_frame_get_u8(frame, &cap); -+ l2cap_frame_get_u8(frame, &cap); -+ l2cap_frame_get_u8(frame, &cap); -+ l2cap_frame_get_u8(frame, &cap); -+ -+ return true; -+} -+ - static bool codec_vendor_cfg(uint8_t losc, struct l2cap_frame *frame) - { - uint32_t vendor_id = 0; - uint16_t codec_id = 0; -+ size_t i; - - if (losc < 6) - return false; -@@ -590,10 +861,11 @@ static bool codec_vendor_cfg(uint8_t losc, struct l2cap_frame *frame) - print_field("%*cVendor Specific Codec ID: %s (0x%04x)", BASE_INDENT, - ' ', vndcodec2str(vendor_id, codec_id), codec_id); - -- if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) -- return codec_vendor_aptx_cfg(losc, frame); -- else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID) -- return codec_vendor_ldac(losc, frame); -+ for (i = 0; i < sizeof(vndcodecs)/sizeof(*vndcodecs); i++) { -+ if (vndcodecs[i].vendor_id == vendor_id && -+ vndcodecs[i].codec_id == codec_id) -+ return vndcodecs[i].codec_vendor_cfg(losc, frame); -+ } - - packet_hexdump(frame->data, losc); - l2cap_frame_pull(frame, frame, losc); --- -2.21.0 - - -From fcad924159d772586fe9e402985fee64ae29b70a Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Thu, 3 Jan 2019 13:45:43 -0300 -Subject: [PATCH 12/31] a2dp: Expose remote SEP - -This implements MediaEndpoint for remote SEP which can be used by -clients to switch configuration on demand. ---- - profiles/audio/a2dp.c | 351 ++++++++++++++++++++++++++++++++++++++++- - profiles/audio/a2dp.h | 1 + - profiles/audio/avdtp.c | 10 ++ - profiles/audio/avdtp.h | 4 + - profiles/audio/media.c | 8 + - 5 files changed, 367 insertions(+), 7 deletions(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index 344459332..4025776aa 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -27,7 +27,10 @@ - #include - #endif - -+#define _GNU_SOURCE -+ - #include -+#include - #include - - #include -@@ -38,14 +41,19 @@ - #include "lib/sdp_lib.h" - #include "lib/uuid.h" - -+#include "gdbus/gdbus.h" -+ - #include "src/plugin.h" - #include "src/adapter.h" - #include "src/device.h" -+#include "src/dbus-common.h" -+#include "src/error.h" - #include "src/profile.h" - #include "src/service.h" - #include "src/log.h" - #include "src/sdpd.h" - #include "src/shared/queue.h" -+#include "src/shared/util.h" - - #include "btio/btio.h" - -@@ -63,6 +71,8 @@ - - #define AVDTP_PSM 25 - -+#define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1" -+ - struct a2dp_sep { - struct a2dp_server *server; - struct a2dp_endpoint *endpoint; -@@ -93,6 +103,7 @@ struct a2dp_setup_cb { - }; - - struct a2dp_setup { -+ struct a2dp_channel *chan; - struct avdtp *session; - struct a2dp_sep *sep; - struct avdtp_remote_sep *rsep; -@@ -121,6 +132,12 @@ struct a2dp_server { - struct queue *channels; - }; - -+struct a2dp_remote_sep { -+ struct a2dp_channel *chan; -+ char *path; -+ struct avdtp_remote_sep *sep; -+}; -+ - struct a2dp_channel { - struct a2dp_server *server; - struct btd_device *device; -@@ -129,6 +146,7 @@ struct a2dp_channel { - unsigned int state_id; - unsigned int auth_id; - struct avdtp *session; -+ struct queue *seps; - }; - - static GSList *servers = NULL; -@@ -144,12 +162,42 @@ static struct a2dp_setup *setup_ref(struct a2dp_setup *setup) - return setup; - } - -+static bool match_by_session(const void *data, const void *user_data) -+{ -+ const struct a2dp_channel *chan = data; -+ const struct avdtp *session = user_data; -+ -+ return chan->session == session; -+} -+ -+static struct a2dp_channel *find_channel(struct avdtp *session) -+{ -+ GSList *l; -+ -+ for (l = servers; l; l = g_slist_next(l)) { -+ struct a2dp_server *server = l->data; -+ struct a2dp_channel *chan; -+ -+ chan = queue_find(server->channels, match_by_session, session); -+ if (chan) -+ return chan; -+ } -+ -+ return NULL; -+} -+ - static struct a2dp_setup *setup_new(struct avdtp *session) - { - struct a2dp_setup *setup; -+ struct a2dp_channel *chan; -+ -+ chan = find_channel(session); -+ if (!chan) -+ return NULL; - - setup = g_new0(struct a2dp_setup, 1); - setup->session = avdtp_ref(session); -+ setup->chan = find_channel(session); - setups = g_slist_append(setups, setup); - - return setup; -@@ -1299,6 +1347,14 @@ static struct a2dp_server *find_server(GSList *list, struct btd_adapter *a) - return NULL; - } - -+static void remove_remote_sep(void *data) -+{ -+ struct a2dp_remote_sep *sep = data; -+ -+ g_dbus_unregister_interface(btd_get_dbus_connection(), sep->path, -+ MEDIA_ENDPOINT_INTERFACE); -+} -+ - static void channel_free(void *data) - { - struct a2dp_channel *chan = data; -@@ -1316,6 +1372,7 @@ static void channel_free(void *data) - - avdtp_remove_state_cb(chan->state_id); - -+ queue_destroy(chan->seps, remove_remote_sep); - g_free(chan); - } - -@@ -1371,6 +1428,7 @@ static struct a2dp_channel *channel_new(struct a2dp_server *server, - chan = g_new0(struct a2dp_channel, 1); - chan->server = server; - chan->device = device; -+ chan->seps = queue_new(); - chan->state_id = avdtp_add_state_cb(device, avdtp_state_cb, chan); - - if (!queue_push_tail(server->channels, chan)) { -@@ -1805,16 +1863,11 @@ void a2dp_remove_sep(struct a2dp_sep *sep) - a2dp_unregister_sep(sep); - } - --static void select_cb(struct a2dp_setup *setup, void *ret, int size) -+static void setup_add_caps(struct a2dp_setup *setup, uint8_t *caps, size_t size) - { - struct avdtp_service_capability *media_transport, *media_codec; - struct avdtp_media_codec_capability *cap; - -- if (size < 0) { -- DBG("Endpoint replied an invalid configuration"); -- goto done; -- } -- - media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, - NULL, 0); - -@@ -1823,13 +1876,23 @@ static void select_cb(struct a2dp_setup *setup, void *ret, int size) - cap = g_malloc0(sizeof(*cap) + size); - cap->media_type = AVDTP_MEDIA_TYPE_AUDIO; - cap->media_codec_type = setup->sep->codec; -- memcpy(cap->data, ret, size); -+ memcpy(cap->data, caps, size); - - media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, cap, - sizeof(*cap) + size); - - setup->caps = g_slist_append(setup->caps, media_codec); - g_free(cap); -+} -+ -+static void select_cb(struct a2dp_setup *setup, void *ret, int size) -+{ -+ if (size < 0) { -+ DBG("Endpoint replied an invalid configuration"); -+ goto done; -+ } -+ -+ setup_add_caps(setup, ret, size); - - done: - finalize_select(setup); -@@ -1885,6 +1948,277 @@ static struct a2dp_sep *a2dp_select_sep(struct avdtp *session, uint8_t type, - return a2dp_find_sep(session, l, NULL); - } - -+struct client { -+ const char *sender; -+ const char *path; -+}; -+ -+static int match_client(const void *data, const void *user_data) -+{ -+ struct a2dp_sep *sep = (void *) data; -+ const struct a2dp_endpoint *endpoint = sep->endpoint; -+ const struct client *client = user_data; -+ -+ if (strcmp(client->sender, endpoint->get_name(sep, sep->user_data))) -+ return -1; -+ -+ return strcmp(client->path, endpoint->get_path(sep, sep->user_data)); -+} -+ -+static struct a2dp_sep *find_sep(struct a2dp_server *server, const char *sender, -+ const char *path) -+{ -+ GSList *l; -+ struct client client = { sender, path }; -+ -+ l = g_slist_find_custom(server->sources, &client, match_client); -+ if (l) -+ return l->data; -+ -+ l = g_slist_find_custom(server->sinks, &client, match_client); -+ if (l) -+ return l->data; -+ -+ return NULL; -+} -+ -+static int parse_properties(DBusMessageIter *props, uint8_t **caps, int *size) -+{ -+ while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) { -+ const char *key; -+ DBusMessageIter value, entry; -+ int var; -+ -+ dbus_message_iter_recurse(props, &entry); -+ dbus_message_iter_get_basic(&entry, &key); -+ -+ dbus_message_iter_next(&entry); -+ dbus_message_iter_recurse(&entry, &value); -+ -+ var = dbus_message_iter_get_arg_type(&value); -+ if (strcasecmp(key, "Capabilities") == 0) { -+ DBusMessageIter array; -+ -+ if (var != DBUS_TYPE_ARRAY) -+ return -EINVAL; -+ -+ dbus_message_iter_recurse(&value, &array); -+ dbus_message_iter_get_fixed_array(&array, caps, size); -+ return 0; -+ } -+ -+ dbus_message_iter_next(props); -+ } -+ -+ return -EINVAL; -+} -+ -+static int a2dp_reconfig(struct a2dp_channel *chan, const char *sender, -+ struct a2dp_sep *lsep, struct a2dp_remote_sep *rsep, -+ uint8_t *caps, int size) -+{ -+ struct a2dp_setup *setup; -+ const struct queue_entry *entry; -+ int err; -+ -+ setup = a2dp_setup_get(chan->session); -+ if (!setup) -+ return -ENOMEM; -+ -+ setup->sep = lsep; -+ setup->rsep = rsep->sep; -+ -+ setup_add_caps(setup, caps, size); -+ -+ /* Check for existing stream and close it */ -+ for (entry = queue_get_entries(chan->server->seps); entry; -+ entry = entry->next) { -+ struct a2dp_sep *tmp = entry->data; -+ -+ /* Attempt to reconfigure if a stream already exists */ -+ if (tmp->stream) { -+ /* Only allow switching sep from the same sender */ -+ if (strcmp(sender, tmp->endpoint->get_name(tmp, -+ tmp->user_data))) -+ return -EPERM; -+ -+ err = avdtp_close(chan->session, tmp->stream, FALSE); -+ if (err < 0) { -+ error("avdtp_close: %s", strerror(-err)); -+ return err; -+ } -+ -+ setup->reconfigure = TRUE; -+ -+ return 0; -+ } -+ } -+ -+ err = avdtp_set_configuration(setup->session, setup->rsep, -+ lsep->lsep, -+ setup->caps, -+ &setup->stream); -+ if (err < 0) { -+ error("avdtp_set_configuration: %s", strerror(-err)); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg, -+ void *data) -+{ -+ struct a2dp_remote_sep *rsep = data; -+ struct a2dp_channel *chan = rsep->chan; -+ struct a2dp_sep *lsep; -+ struct avdtp_service_capability *service; -+ struct avdtp_media_codec_capability *codec; -+ DBusMessageIter args, props; -+ const char *sender, *path; -+ uint8_t *caps; -+ int err, size = 0; -+ -+ sender = dbus_message_get_sender(msg); -+ -+ dbus_message_iter_init(msg, &args); -+ -+ dbus_message_iter_get_basic(&args, &path); -+ dbus_message_iter_next(&args); -+ -+ lsep = find_sep(chan->server, sender, path); -+ if (!lsep) -+ return btd_error_invalid_args(msg); -+ -+ /* Check if SEPs are no the same role */ -+ if (avdtp_get_type(rsep->sep) == lsep->type) -+ return btd_error_invalid_args(msg); -+ -+ service = avdtp_get_codec(rsep->sep); -+ codec = (struct avdtp_media_codec_capability *) service->data; -+ -+ /* Check if codec match */ -+ if (!endpoint_match_codec_ind(chan->session, codec, lsep)) -+ return btd_error_invalid_args(msg); -+ -+ dbus_message_iter_recurse(&args, &props); -+ if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY) -+ return btd_error_invalid_args(msg); -+ -+ if (parse_properties(&props, &caps, &size) < 0) -+ return btd_error_invalid_args(msg); -+ -+ err = a2dp_reconfig(chan, sender, lsep, rsep, caps, size); -+ if (err < 0) -+ return btd_error_failed(msg, strerror(-err)); -+ -+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); -+} -+ -+static const GDBusMethodTable sep_methods[] = { -+ { GDBUS_EXPERIMENTAL_ASYNC_METHOD("SetConfiguration", -+ GDBUS_ARGS({ "endpoint", "o" }, -+ { "properties", "a{sv}" } ), -+ NULL, set_configuration) }, -+ { }, -+}; -+ -+static gboolean get_uuid(const GDBusPropertyTable *property, -+ DBusMessageIter *iter, void *data) -+{ -+ struct a2dp_remote_sep *sep = data; -+ const char *uuid; -+ -+ switch (avdtp_get_type(sep->sep)) { -+ case AVDTP_SEP_TYPE_SOURCE: -+ uuid = A2DP_SOURCE_UUID; -+ break; -+ case AVDTP_SEP_TYPE_SINK: -+ uuid = A2DP_SOURCE_UUID; -+ break; -+ default: -+ uuid = ""; -+ } -+ -+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid); -+ -+ return TRUE; -+} -+ -+static gboolean get_codec(const GDBusPropertyTable *property, -+ DBusMessageIter *iter, void *data) -+{ -+ struct a2dp_remote_sep *sep = data; -+ struct avdtp_service_capability *cap = avdtp_get_codec(sep->sep); -+ struct avdtp_media_codec_capability *codec = (void *) cap->data; -+ -+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, -+ &codec->media_codec_type); -+ -+ return TRUE; -+} -+ -+static gboolean get_capabilities(const GDBusPropertyTable *property, -+ DBusMessageIter *iter, void *data) -+{ -+ struct a2dp_remote_sep *sep = data; -+ struct avdtp_service_capability *service = avdtp_get_codec(sep->sep); -+ struct avdtp_media_codec_capability *codec = (void *) service->data; -+ uint8_t *caps = codec->data; -+ DBusMessageIter array; -+ -+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, -+ DBUS_TYPE_BYTE_AS_STRING, &array); -+ -+ dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, &caps, -+ service->length - sizeof(*codec)); -+ -+ dbus_message_iter_close_container(iter, &array); -+ -+ return TRUE; -+} -+ -+static const GDBusPropertyTable sep_properties[] = { -+ { "UUID", "s", get_uuid, NULL, NULL, -+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, -+ { "Codec", "y", get_codec, NULL, NULL, -+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, -+ { "Capabilities", "ay", get_capabilities, NULL, NULL, -+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, -+ { } -+}; -+ -+static void remote_sep_free(void *data) -+{ -+ struct a2dp_remote_sep *sep = data; -+ -+ free(sep->path); -+ free(sep); -+} -+ -+static void register_remote_sep(void *data, void *user_data) -+{ -+ struct avdtp_remote_sep *rsep = data; -+ struct a2dp_setup *setup = user_data; -+ struct a2dp_remote_sep *sep; -+ -+ sep = new0(struct a2dp_remote_sep, 1); -+ sep->chan = setup->chan; -+ sep->sep = rsep; -+ asprintf(&sep->path, "%s/sep%d", device_get_path(setup->chan->device), -+ avdtp_get_seid(rsep)); -+ -+ if (g_dbus_register_interface(btd_get_dbus_connection(), -+ sep->path, MEDIA_ENDPOINT_INTERFACE, -+ sep_methods, NULL, sep_properties, -+ sep, remote_sep_free) == FALSE) { -+ error("Could not register remote sep %s", sep->path); -+ remote_sep_free(sep); -+ } -+ -+ queue_push_tail(setup->chan->seps, sep); -+} -+ - static void discover_cb(struct avdtp *session, GSList *seps, - struct avdtp_error *err, void *user_data) - { -@@ -1895,6 +2229,9 @@ static void discover_cb(struct avdtp *session, GSList *seps, - setup->seps = seps; - setup->err = err; - -+ if (!err && queue_isempty(setup->chan->seps)) -+ g_slist_foreach(seps, register_remote_sep, setup); -+ - finalize_discover(setup); - } - -diff --git a/profiles/audio/a2dp.h b/profiles/audio/a2dp.h -index 2c388bb68..7f38c75f3 100644 ---- a/profiles/audio/a2dp.h -+++ b/profiles/audio/a2dp.h -@@ -32,6 +32,7 @@ typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, gboolean ret); - - struct a2dp_endpoint { - const char *(*get_name) (struct a2dp_sep *sep, void *user_data); -+ const char *(*get_path) (struct a2dp_sep *sep, void *user_data); - size_t (*get_capabilities) (struct a2dp_sep *sep, - uint8_t **capabilities, - void *user_data); -diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c -index 2cb3c8a00..cc4322d10 100644 ---- a/profiles/audio/avdtp.c -+++ b/profiles/audio/avdtp.c -@@ -3161,6 +3161,16 @@ static int process_queue(struct avdtp *session) - return send_req(session, FALSE, req); - } - -+uint8_t avdtp_get_seid(struct avdtp_remote_sep *sep) -+{ -+ return sep->seid; -+} -+ -+uint8_t avdtp_get_type(struct avdtp_remote_sep *sep) -+{ -+ return sep->type; -+} -+ - struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep) - { - return sep->codec; -diff --git a/profiles/audio/avdtp.h b/profiles/audio/avdtp.h -index 621a6e3cf..e5fc40c89 100644 ---- a/profiles/audio/avdtp.h -+++ b/profiles/audio/avdtp.h -@@ -223,6 +223,10 @@ struct avdtp *avdtp_ref(struct avdtp *session); - struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category, - void *data, int size); - -+uint8_t avdtp_get_seid(struct avdtp_remote_sep *sep); -+ -+uint8_t avdtp_get_type(struct avdtp_remote_sep *sep); -+ - struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep); - - int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb, -diff --git a/profiles/audio/media.c b/profiles/audio/media.c -index 23d15611b..9b833b6aa 100644 ---- a/profiles/audio/media.c -+++ b/profiles/audio/media.c -@@ -488,6 +488,13 @@ static const char *get_name(struct a2dp_sep *sep, void *user_data) - return endpoint->sender; - } - -+static const char *get_path(struct a2dp_sep *sep, void *user_data) -+{ -+ struct media_endpoint *endpoint = user_data; -+ -+ return endpoint->path; -+} -+ - static size_t get_capabilities(struct a2dp_sep *sep, uint8_t **capabilities, - void *user_data) - { -@@ -578,6 +585,7 @@ static void set_delay(struct a2dp_sep *sep, uint16_t delay, void *user_data) - - static struct a2dp_endpoint a2dp_endpoint = { - .get_name = get_name, -+ .get_path = get_path, - .get_capabilities = get_capabilities, - .select_configuration = select_config, - .set_configuration = set_config, --- -2.21.0 - - -From dc9b175cc89621a2abbae5b661bfc61c68191abe Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Fri, 4 Jan 2019 16:22:05 -0300 -Subject: [PATCH 13/31] doc/media-api: Add Endpoint property to MediaTransport - -Adds endpoint object to MediaTransport so application can resolve which -MediaEndpoint is in use. ---- - doc/media-api.txt | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/doc/media-api.txt b/doc/media-api.txt -index b5ad2db12..93c3490b6 100644 ---- a/doc/media-api.txt -+++ b/doc/media-api.txt -@@ -604,3 +604,8 @@ Properties object Device [readonly] - acquired by the sender. - - Possible Values: 0-127 -+ -+ object Endpoint [readonly, optional, experimental] -+ -+ Endpoint object which the transport is associated -+ with. --- -2.21.0 - - -From e7795ccbc1810a7a398fb059638f289644447ab1 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Fri, 4 Jan 2019 16:24:18 -0300 -Subject: [PATCH 14/31] a2dp: Implement MediaTransport.Endpoint - -This implements MediaTransport.Endpoint property which exposes what -endpoint is being used by the transport. ---- - profiles/audio/a2dp.c | 91 +++++++++++++++++++++++++++++--------- - profiles/audio/a2dp.h | 1 + - profiles/audio/media.c | 5 ++- - profiles/audio/transport.c | 28 +++++++++++- - profiles/audio/transport.h | 1 + - 5 files changed, 102 insertions(+), 24 deletions(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index 4025776aa..4fa01894a 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -106,7 +106,7 @@ struct a2dp_setup { - struct a2dp_channel *chan; - struct avdtp *session; - struct a2dp_sep *sep; -- struct avdtp_remote_sep *rsep; -+ struct a2dp_remote_sep *rsep; - struct avdtp_stream *stream; - struct avdtp_error *err; - avdtp_set_configuration_cb setconf_cb; -@@ -1065,6 +1065,24 @@ static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep, - return TRUE; - } - -+static bool match_remote_sep(const void *data, const void *user_data) -+{ -+ const struct a2dp_remote_sep *sep = data; -+ const struct avdtp_remote_sep *rsep = user_data; -+ -+ return sep->sep == rsep; -+} -+ -+static struct a2dp_remote_sep *find_remote_sep(struct a2dp_channel *chan, -+ struct a2dp_sep *sep) -+{ -+ struct avdtp_remote_sep *rsep; -+ -+ rsep = avdtp_find_remote_sep(chan->session, sep->lsep); -+ -+ return queue_find(chan->seps, match_remote_sep, rsep); -+} -+ - static gboolean a2dp_reconfigure(gpointer data) - { - struct a2dp_setup *setup = data; -@@ -1074,14 +1092,14 @@ static gboolean a2dp_reconfigure(gpointer data) - struct avdtp_service_capability *cap; - - if (setup->rsep) { -- cap = avdtp_get_codec(setup->rsep); -+ cap = avdtp_get_codec(setup->rsep->sep); - rsep_codec = (struct avdtp_media_codec_capability *) cap->data; - } - - if (!setup->rsep || sep->codec != rsep_codec->media_codec_type) -- setup->rsep = avdtp_find_remote_sep(setup->session, sep->lsep); -+ setup->rsep = find_remote_sep(setup->chan, sep); - -- posix_err = avdtp_set_configuration(setup->session, setup->rsep, -+ posix_err = avdtp_set_configuration(setup->session, setup->rsep->sep, - sep->lsep, - setup->caps, - &setup->stream); -@@ -1097,6 +1115,16 @@ failed: - return FALSE; - } - -+static struct a2dp_remote_sep *get_remote_sep(struct a2dp_channel *chan, -+ struct avdtp_stream *stream) -+{ -+ struct avdtp_remote_sep *rsep; -+ -+ rsep = avdtp_stream_get_remote_sep(stream); -+ -+ return queue_find(chan->seps, match_remote_sep, rsep); -+} -+ - static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep, - struct avdtp_stream *stream, struct avdtp_error *err, - void *user_data) -@@ -1121,7 +1149,7 @@ static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep, - } - - if (!setup->rsep) -- setup->rsep = avdtp_stream_get_remote_sep(stream); -+ setup->rsep = get_remote_sep(setup->chan, stream); - - if (setup->reconfigure) - g_timeout_add(RECONFIGURE_TIMEOUT, a2dp_reconfigure, setup); -@@ -1347,10 +1375,23 @@ static struct a2dp_server *find_server(GSList *list, struct btd_adapter *a) - return NULL; - } - -+static void remote_sep_free(void *data) -+{ -+ struct a2dp_remote_sep *sep = data; -+ -+ free(sep->path); -+ free(sep); -+} -+ - static void remove_remote_sep(void *data) - { - struct a2dp_remote_sep *sep = data; - -+ if (!sep->path) { -+ remote_sep_free(sep); -+ return; -+ } -+ - g_dbus_unregister_interface(btd_get_dbus_connection(), sep->path, - MEDIA_ENDPOINT_INTERFACE); - } -@@ -2026,7 +2067,7 @@ static int a2dp_reconfig(struct a2dp_channel *chan, const char *sender, - return -ENOMEM; - - setup->sep = lsep; -- setup->rsep = rsep->sep; -+ setup->rsep = rsep; - - setup_add_caps(setup, caps, size); - -@@ -2054,7 +2095,7 @@ static int a2dp_reconfig(struct a2dp_channel *chan, const char *sender, - } - } - -- err = avdtp_set_configuration(setup->session, setup->rsep, -+ err = avdtp_set_configuration(setup->session, setup->rsep->sep, - lsep->lsep, - setup->caps, - &setup->stream); -@@ -2188,14 +2229,6 @@ static const GDBusPropertyTable sep_properties[] = { - { } - }; - --static void remote_sep_free(void *data) --{ -- struct a2dp_remote_sep *sep = data; -- -- free(sep->path); -- free(sep); --} -- - static void register_remote_sep(void *data, void *user_data) - { - struct avdtp_remote_sep *rsep = data; -@@ -2205,6 +2238,10 @@ static void register_remote_sep(void *data, void *user_data) - sep = new0(struct a2dp_remote_sep, 1); - sep->chan = setup->chan; - sep->sep = rsep; -+ -+ if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) -+ goto done; -+ - asprintf(&sep->path, "%s/sep%d", device_get_path(setup->chan->device), - avdtp_get_seid(rsep)); - -@@ -2213,9 +2250,13 @@ static void register_remote_sep(void *data, void *user_data) - sep_methods, NULL, sep_properties, - sep, remote_sep_free) == FALSE) { - error("Could not register remote sep %s", sep->path); -- remote_sep_free(sep); -+ free(sep->path); -+ sep->path = NULL; - } - -+ DBG("Found remote SEP: %s", sep->path); -+ -+done: - queue_push_tail(setup->chan->seps, sep); - } - -@@ -2283,14 +2324,14 @@ unsigned int a2dp_select_capabilities(struct avdtp *session, - cb_data->user_data = user_data; - - setup->sep = sep; -- setup->rsep = avdtp_find_remote_sep(session, sep->lsep); -+ setup->rsep = find_remote_sep(setup->chan, sep); - - if (setup->rsep == NULL) { - error("Could not find remote sep"); - goto fail; - } - -- service = avdtp_get_codec(setup->rsep); -+ service = avdtp_get_codec(setup->rsep->sep); - codec = (struct avdtp_media_codec_capability *) service->data; - - err = sep->endpoint->select_configuration(sep, codec->data, -@@ -2384,13 +2425,13 @@ unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep, - break; - } - -- setup->rsep = avdtp_find_remote_sep(session, sep->lsep); -+ setup->rsep = find_remote_sep(setup->chan, sep); - if (setup->rsep == NULL) { - error("No matching ACP and INT SEPs found"); - goto failed; - } - -- posix_err = avdtp_set_configuration(session, setup->rsep, -+ posix_err = avdtp_set_configuration(session, setup->rsep->sep, - sep->lsep, caps, - &setup->stream); - if (posix_err < 0) { -@@ -2632,6 +2673,16 @@ struct btd_device *a2dp_setup_get_device(struct a2dp_setup *setup) - return avdtp_get_device(setup->session); - } - -+const char *a2dp_setup_remote_path(struct a2dp_setup *setup) -+{ -+ if (setup->rsep) { -+ if (setup->rsep->path) -+ return setup->rsep->path; -+ } -+ -+ return NULL; -+} -+ - static int a2dp_source_probe(struct btd_service *service) - { - struct btd_device *dev = btd_service_get_device(service); -diff --git a/profiles/audio/a2dp.h b/profiles/audio/a2dp.h -index 7f38c75f3..19466a428 100644 ---- a/profiles/audio/a2dp.h -+++ b/profiles/audio/a2dp.h -@@ -91,4 +91,5 @@ gboolean a2dp_sep_lock(struct a2dp_sep *sep, struct avdtp *session); - gboolean a2dp_sep_unlock(struct a2dp_sep *sep, struct avdtp *session); - struct avdtp_stream *a2dp_sep_get_stream(struct a2dp_sep *sep); - struct btd_device *a2dp_setup_get_device(struct a2dp_setup *setup); -+const char *a2dp_setup_remote_path(struct a2dp_setup *setup); - struct avdtp *a2dp_avdtp_get(struct btd_device *device); -diff --git a/profiles/audio/media.c b/profiles/audio/media.c -index 9b833b6aa..e651275b4 100644 ---- a/profiles/audio/media.c -+++ b/profiles/audio/media.c -@@ -429,8 +429,9 @@ static gboolean set_configuration(struct media_endpoint *endpoint, - if (transport != NULL) - return FALSE; - -- transport = media_transport_create(device, configuration, size, -- endpoint); -+ transport = media_transport_create(device, -+ a2dp_setup_remote_path(data->setup), -+ configuration, size, endpoint); - if (transport == NULL) - return FALSE; - -diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c -index b9d357ec2..7eb115fc6 100644 ---- a/profiles/audio/transport.c -+++ b/profiles/audio/transport.c -@@ -91,6 +91,7 @@ struct a2dp_transport { - struct media_transport { - char *path; /* Transport object path */ - struct btd_device *device; /* Transport device */ -+ const char *remote_endpoint; /* Transport remote SEP */ - struct media_endpoint *endpoint; /* Transport endpoint */ - struct media_owner *owner; /* Transport owner */ - uint8_t *configuration; /* Transport configuration */ -@@ -688,6 +689,24 @@ static void set_volume(const GDBusPropertyTable *property, - avrcp_set_volume(transport->device, volume, notify); - } - -+static gboolean endpoint_exists(const GDBusPropertyTable *property, void *data) -+{ -+ struct media_transport *transport = data; -+ -+ return transport->remote_endpoint != NULL; -+} -+ -+static gboolean get_endpoint(const GDBusPropertyTable *property, -+ DBusMessageIter *iter, void *data) -+{ -+ struct media_transport *transport = data; -+ -+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, -+ &transport->remote_endpoint); -+ -+ return TRUE; -+} -+ - static const GDBusMethodTable transport_methods[] = { - { GDBUS_ASYNC_METHOD("Acquire", - NULL, -@@ -711,6 +730,8 @@ static const GDBusPropertyTable transport_properties[] = { - { "State", "s", get_state }, - { "Delay", "q", get_delay, NULL, delay_exists }, - { "Volume", "q", get_volume, set_volume, volume_exists }, -+ { "Endpoint", "o", get_endpoint, NULL, endpoint_exists, -+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, - { } - }; - -@@ -835,6 +856,7 @@ static int media_transport_init_sink(struct media_transport *transport) - } - - struct media_transport *media_transport_create(struct btd_device *device, -+ const char *remote_endpoint, - uint8_t *configuration, - size_t size, void *data) - { -@@ -849,8 +871,10 @@ struct media_transport *media_transport_create(struct btd_device *device, - transport->configuration = g_new(uint8_t, size); - memcpy(transport->configuration, configuration, size); - transport->size = size; -- transport->path = g_strdup_printf("%s/fd%d", device_get_path(device), -- fd++); -+ transport->remote_endpoint = remote_endpoint; -+ transport->path = g_strdup_printf("%s/fd%d", -+ remote_endpoint ? remote_endpoint : -+ device_get_path(device), fd++); - transport->fd = -1; - - uuid = media_endpoint_get_uuid(endpoint); -diff --git a/profiles/audio/transport.h b/profiles/audio/transport.h -index 505ad5c54..ac542bf6c 100644 ---- a/profiles/audio/transport.h -+++ b/profiles/audio/transport.h -@@ -25,6 +25,7 @@ - struct media_transport; - - struct media_transport *media_transport_create(struct btd_device *device, -+ const char *remote_endpoint, - uint8_t *configuration, - size_t size, void *data); - --- -2.21.0 - - -From 7ba5782208069a27ed8207b6b43e5ba1b4a5c9c6 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Tue, 8 Jan 2019 10:34:42 -0300 -Subject: [PATCH 15/31] a2dp: Cache remote endpoints - -In order to always have the Endpoint interface available the remote -endpoints needs to be cached since the remote stack may config a stream -on its own there may not be a chance to discover the endpoits available -which would make it impossible to switch endpoints. ---- - profiles/audio/a2dp.c | 724 +++++++++++++++++++++++++---------------- - profiles/audio/avdtp.c | 46 ++- - profiles/audio/avdtp.h | 5 + - 3 files changed, 492 insertions(+), 283 deletions(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index 4fa01894a..6975682c9 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -1441,6 +1441,410 @@ static gboolean disconnect_cb(GIOChannel *io, GIOCondition cond, gpointer data) - return FALSE; - } - -+static void caps_add_codec(GSList **l, uint8_t codec, uint8_t *caps, -+ size_t size) -+{ -+ struct avdtp_service_capability *media_transport, *media_codec; -+ struct avdtp_media_codec_capability *cap; -+ -+ media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, -+ NULL, 0); -+ -+ *l = g_slist_append(*l, media_transport); -+ -+ cap = g_malloc0(sizeof(*cap) + size); -+ cap->media_type = AVDTP_MEDIA_TYPE_AUDIO; -+ cap->media_codec_type = codec; -+ memcpy(cap->data, caps, size); -+ -+ media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, cap, -+ sizeof(*cap) + size); -+ -+ *l = g_slist_append(*l, media_codec); -+ g_free(cap); -+} -+ -+struct client { -+ const char *sender; -+ const char *path; -+}; -+ -+static int match_client(const void *data, const void *user_data) -+{ -+ struct a2dp_sep *sep = (void *) data; -+ const struct a2dp_endpoint *endpoint = sep->endpoint; -+ const struct client *client = user_data; -+ -+ if (strcmp(client->sender, endpoint->get_name(sep, sep->user_data))) -+ return -1; -+ -+ return strcmp(client->path, endpoint->get_path(sep, sep->user_data)); -+} -+ -+static struct a2dp_sep *find_sep(struct a2dp_server *server, uint8_t type, -+ const char *sender, const char *path) -+{ -+ GSList *l; -+ struct client client = { sender, path }; -+ -+ l = type == AVDTP_SEP_TYPE_SINK ? server->sources : server->sinks; -+ -+ l = g_slist_find_custom(l, &client, match_client); -+ if (l) -+ return l->data; -+ -+ return NULL; -+} -+ -+static int parse_properties(DBusMessageIter *props, uint8_t **caps, int *size) -+{ -+ while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) { -+ const char *key; -+ DBusMessageIter value, entry; -+ int var; -+ -+ dbus_message_iter_recurse(props, &entry); -+ dbus_message_iter_get_basic(&entry, &key); -+ -+ dbus_message_iter_next(&entry); -+ dbus_message_iter_recurse(&entry, &value); -+ -+ var = dbus_message_iter_get_arg_type(&value); -+ if (strcasecmp(key, "Capabilities") == 0) { -+ DBusMessageIter array; -+ -+ if (var != DBUS_TYPE_ARRAY) -+ return -EINVAL; -+ -+ dbus_message_iter_recurse(&value, &array); -+ dbus_message_iter_get_fixed_array(&array, caps, size); -+ return 0; -+ } -+ -+ dbus_message_iter_next(props); -+ } -+ -+ return -EINVAL; -+} -+ -+static void reconfig_cb(struct avdtp *session, struct a2dp_sep *sep, -+ struct avdtp_stream *stream, int err, void *user_data) -+{ -+ DBusMessage *msg = user_data; -+ -+ if (err) -+ g_dbus_send_message(btd_get_dbus_connection(), -+ btd_error_failed(msg, strerror(-err))); -+ else -+ g_dbus_send_reply(btd_get_dbus_connection(), msg, -+ DBUS_TYPE_INVALID); -+ -+ dbus_message_unref(msg); -+} -+ -+static int a2dp_reconfig(struct a2dp_channel *chan, const char *sender, -+ struct a2dp_sep *lsep, struct a2dp_remote_sep *rsep, -+ uint8_t *caps, int size, void *user_data) -+{ -+ struct a2dp_setup *setup; -+ struct a2dp_setup_cb *cb_data; -+ GSList *l; -+ int err; -+ -+ setup = a2dp_setup_get(chan->session); -+ if (!setup) -+ return -ENOMEM; -+ -+ cb_data = setup_cb_new(setup); -+ cb_data->config_cb = reconfig_cb; -+ cb_data->user_data = user_data; -+ -+ setup->sep = lsep; -+ setup->rsep = rsep; -+ -+ caps_add_codec(&setup->caps, setup->sep->codec, caps, size); -+ -+ l = avdtp_get_type(rsep->sep) == AVDTP_SEP_TYPE_SINK ? -+ chan->server->sources : -+ chan->server->sinks; -+ -+ /* Check for existing stream and close it */ -+ for (; l; l = g_slist_next(l)) { -+ struct a2dp_sep *tmp = l->data; -+ -+ /* Attempt to reconfigure if a stream already exists */ -+ if (tmp->stream) { -+ /* Only allow switching sep from the same sender */ -+ if (strcmp(sender, tmp->endpoint->get_name(tmp, -+ tmp->user_data))) -+ return -EPERM; -+ -+ err = avdtp_close(chan->session, tmp->stream, FALSE); -+ if (err < 0) { -+ error("avdtp_close: %s", strerror(-err)); -+ goto fail; -+ } -+ -+ setup->reconfigure = TRUE; -+ -+ return 0; -+ } -+ } -+ -+ err = avdtp_set_configuration(setup->session, setup->rsep->sep, -+ lsep->lsep, -+ setup->caps, -+ &setup->stream); -+ if (err < 0) { -+ error("avdtp_set_configuration: %s", strerror(-err)); -+ goto fail; -+ } -+ -+ return 0; -+ -+fail: -+ setup_unref(setup); -+ return err; -+} -+ -+static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg, -+ void *data) -+{ -+ struct a2dp_remote_sep *rsep = data; -+ struct a2dp_channel *chan = rsep->chan; -+ struct a2dp_sep *lsep = NULL; -+ struct avdtp_service_capability *service; -+ struct avdtp_media_codec_capability *codec; -+ DBusMessageIter args, props; -+ const char *sender, *path; -+ uint8_t *caps; -+ int err, size = 0; -+ -+ sender = dbus_message_get_sender(msg); -+ -+ dbus_message_iter_init(msg, &args); -+ -+ dbus_message_iter_get_basic(&args, &path); -+ dbus_message_iter_next(&args); -+ -+ lsep = find_sep(chan->server, avdtp_get_type(rsep->sep), sender, path); -+ if (!lsep) -+ return btd_error_invalid_args(msg); -+ -+ service = avdtp_get_codec(rsep->sep); -+ codec = (struct avdtp_media_codec_capability *) service->data; -+ -+ /* Check if codec really matches */ -+ if (!endpoint_match_codec_ind(chan->session, codec, lsep)) -+ return btd_error_invalid_args(msg); -+ -+ dbus_message_iter_recurse(&args, &props); -+ if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY) -+ return btd_error_invalid_args(msg); -+ -+ if (parse_properties(&props, &caps, &size) < 0) -+ return btd_error_invalid_args(msg); -+ -+ err = a2dp_reconfig(chan, sender, lsep, rsep, caps, size, -+ dbus_message_ref(msg)); -+ if (err < 0) { -+ dbus_message_unref(msg); -+ return btd_error_failed(msg, strerror(-err)); -+ } -+ -+ return NULL; -+} -+ -+static const GDBusMethodTable sep_methods[] = { -+ { GDBUS_EXPERIMENTAL_ASYNC_METHOD("SetConfiguration", -+ GDBUS_ARGS({ "endpoint", "o" }, -+ { "properties", "a{sv}" } ), -+ NULL, set_configuration) }, -+ { }, -+}; -+ -+static gboolean get_uuid(const GDBusPropertyTable *property, -+ DBusMessageIter *iter, void *data) -+{ -+ struct a2dp_remote_sep *sep = data; -+ const char *uuid; -+ -+ switch (avdtp_get_type(sep->sep)) { -+ case AVDTP_SEP_TYPE_SOURCE: -+ uuid = A2DP_SOURCE_UUID; -+ break; -+ case AVDTP_SEP_TYPE_SINK: -+ uuid = A2DP_SOURCE_UUID; -+ break; -+ default: -+ uuid = ""; -+ } -+ -+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid); -+ -+ return TRUE; -+} -+ -+static gboolean get_codec(const GDBusPropertyTable *property, -+ DBusMessageIter *iter, void *data) -+{ -+ struct a2dp_remote_sep *sep = data; -+ struct avdtp_service_capability *cap = avdtp_get_codec(sep->sep); -+ struct avdtp_media_codec_capability *codec = (void *) cap->data; -+ -+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, -+ &codec->media_codec_type); -+ -+ return TRUE; -+} -+ -+static gboolean get_capabilities(const GDBusPropertyTable *property, -+ DBusMessageIter *iter, void *data) -+{ -+ struct a2dp_remote_sep *sep = data; -+ struct avdtp_service_capability *service = avdtp_get_codec(sep->sep); -+ struct avdtp_media_codec_capability *codec = (void *) service->data; -+ uint8_t *caps = codec->data; -+ DBusMessageIter array; -+ -+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, -+ DBUS_TYPE_BYTE_AS_STRING, &array); -+ -+ dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, &caps, -+ service->length - sizeof(*codec)); -+ -+ dbus_message_iter_close_container(iter, &array); -+ -+ return TRUE; -+} -+ -+static const GDBusPropertyTable sep_properties[] = { -+ { "UUID", "s", get_uuid, NULL, NULL, -+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, -+ { "Codec", "y", get_codec, NULL, NULL, -+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, -+ { "Capabilities", "ay", get_capabilities, NULL, NULL, -+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, -+ { } -+}; -+ -+static void register_remote_sep(void *data, void *user_data) -+{ -+ struct avdtp_remote_sep *rsep = data; -+ struct a2dp_channel *chan = user_data; -+ struct a2dp_remote_sep *sep; -+ -+ sep = queue_find(chan->seps, match_remote_sep, rsep); -+ if (sep) -+ return; -+ -+ sep = new0(struct a2dp_remote_sep, 1); -+ sep->chan = chan; -+ sep->sep = rsep; -+ -+ if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) -+ goto done; -+ -+ asprintf(&sep->path, "%s/sep%d", device_get_path(chan->device), -+ avdtp_get_seid(rsep)); -+ -+ if (g_dbus_register_interface(btd_get_dbus_connection(), -+ sep->path, MEDIA_ENDPOINT_INTERFACE, -+ sep_methods, NULL, sep_properties, -+ sep, remote_sep_free) == FALSE) { -+ error("Could not register remote sep %s", sep->path); -+ free(sep->path); -+ sep->path = NULL; -+ goto done; -+ } -+ -+ DBG("Found remote SEP: %s", sep->path); -+ -+done: -+ queue_push_tail(chan->seps, sep); -+} -+ -+static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file, -+ char **seids) -+{ -+ struct avdtp_remote_sep *sep; -+ -+ if (!seids) -+ return; -+ -+ for (; *seids; seids++) { -+ uint8_t seid; -+ uint8_t type; -+ uint8_t codec; -+ char *value, caps[256]; -+ uint8_t data[128]; -+ int i, size; -+ GSList *l = NULL; -+ -+ if (sscanf(*seids, "%02hhx", &seid) != 1) -+ continue; -+ -+ value = g_key_file_get_string(key_file, "Endpoints", *seids, -+ NULL); -+ if (!value) -+ continue; -+ -+ if (sscanf(value, "%02hhx:%02hhx:%s", &type, &codec, -+ caps) != 3) { -+ warn("Unable to load Endpoint: seid %u", seid); -+ g_free(value); -+ continue; -+ } -+ -+ for (i = 0, size = strlen(caps); i < size; i += 2) { -+ uint8_t *tmp = data + i / 2; -+ -+ if (sscanf(caps + i, "%02hhx", tmp) != 1) { -+ warn("Unable to load Endpoint: seid %u", seid); -+ break; -+ } -+ } -+ -+ g_free(value); -+ -+ if (i != size) -+ continue; -+ -+ caps_add_codec(&l, codec, data, size / 2); -+ -+ sep = avdtp_register_remote_sep(chan->session, seid, type, l); -+ if (!sep) { -+ warn("Unable to register Endpoint: seid %u", seid); -+ continue; -+ } -+ -+ register_remote_sep(sep, chan); -+ } -+} -+ -+static void load_remote_seps(struct a2dp_channel *chan) -+{ -+ struct btd_device *device = chan->device; -+ char filename[PATH_MAX]; -+ char dst_addr[18]; -+ char **keys; -+ GKeyFile *key_file; -+ -+ ba2str(device_get_address(device), dst_addr); -+ -+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", -+ btd_adapter_get_storage_dir(device_get_adapter(device)), -+ dst_addr); -+ key_file = g_key_file_new(); -+ g_key_file_load_from_file(key_file, filename, 0, NULL); -+ keys = g_key_file_get_keys(key_file, "Endpoints", NULL, NULL); -+ -+ load_remote_sep(chan, key_file, keys); -+ -+ g_strfreev(keys); -+ g_key_file_free(key_file); -+} -+ - static void avdtp_state_cb(struct btd_device *dev, struct avdtp *session, - avdtp_session_state_t old_state, - avdtp_session_state_t new_state, -@@ -1456,6 +1860,9 @@ static void avdtp_state_cb(struct btd_device *dev, struct avdtp *session, - case AVDTP_SESSION_STATE_CONNECTING: - break; - case AVDTP_SESSION_STATE_CONNECTED: -+ if (!chan->session) -+ chan->session = session; -+ load_remote_seps(chan); - break; - } - } -@@ -1904,28 +2311,6 @@ void a2dp_remove_sep(struct a2dp_sep *sep) - a2dp_unregister_sep(sep); - } - --static void setup_add_caps(struct a2dp_setup *setup, uint8_t *caps, size_t size) --{ -- struct avdtp_service_capability *media_transport, *media_codec; -- struct avdtp_media_codec_capability *cap; -- -- media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, -- NULL, 0); -- -- setup->caps = g_slist_append(setup->caps, media_transport); -- -- cap = g_malloc0(sizeof(*cap) + size); -- cap->media_type = AVDTP_MEDIA_TYPE_AUDIO; -- cap->media_codec_type = setup->sep->codec; -- memcpy(cap->data, caps, size); -- -- media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, cap, -- sizeof(*cap) + size); -- -- setup->caps = g_slist_append(setup->caps, media_codec); -- g_free(cap); --} -- - static void select_cb(struct a2dp_setup *setup, void *ret, int size) - { - if (size < 0) { -@@ -1933,7 +2318,7 @@ static void select_cb(struct a2dp_setup *setup, void *ret, int size) - goto done; - } - -- setup_add_caps(setup, ret, size); -+ caps_add_codec(&setup->caps, setup->sep->codec, ret, size); - - done: - finalize_select(setup); -@@ -1989,275 +2374,58 @@ static struct a2dp_sep *a2dp_select_sep(struct avdtp *session, uint8_t type, - return a2dp_find_sep(session, l, NULL); - } - --struct client { -- const char *sender; -- const char *path; --}; -- --static int match_client(const void *data, const void *user_data) --{ -- struct a2dp_sep *sep = (void *) data; -- const struct a2dp_endpoint *endpoint = sep->endpoint; -- const struct client *client = user_data; -- -- if (strcmp(client->sender, endpoint->get_name(sep, sep->user_data))) -- return -1; -- -- return strcmp(client->path, endpoint->get_path(sep, sep->user_data)); --} -- --static struct a2dp_sep *find_sep(struct a2dp_server *server, const char *sender, -- const char *path) --{ -- GSList *l; -- struct client client = { sender, path }; -- -- l = g_slist_find_custom(server->sources, &client, match_client); -- if (l) -- return l->data; -- -- l = g_slist_find_custom(server->sinks, &client, match_client); -- if (l) -- return l->data; -- -- return NULL; --} -- --static int parse_properties(DBusMessageIter *props, uint8_t **caps, int *size) --{ -- while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) { -- const char *key; -- DBusMessageIter value, entry; -- int var; -- -- dbus_message_iter_recurse(props, &entry); -- dbus_message_iter_get_basic(&entry, &key); -- -- dbus_message_iter_next(&entry); -- dbus_message_iter_recurse(&entry, &value); -- -- var = dbus_message_iter_get_arg_type(&value); -- if (strcasecmp(key, "Capabilities") == 0) { -- DBusMessageIter array; -- -- if (var != DBUS_TYPE_ARRAY) -- return -EINVAL; -- -- dbus_message_iter_recurse(&value, &array); -- dbus_message_iter_get_fixed_array(&array, caps, size); -- return 0; -- } -- -- dbus_message_iter_next(props); -- } -- -- return -EINVAL; --} -- --static int a2dp_reconfig(struct a2dp_channel *chan, const char *sender, -- struct a2dp_sep *lsep, struct a2dp_remote_sep *rsep, -- uint8_t *caps, int size) --{ -- struct a2dp_setup *setup; -- const struct queue_entry *entry; -- int err; -- -- setup = a2dp_setup_get(chan->session); -- if (!setup) -- return -ENOMEM; -- -- setup->sep = lsep; -- setup->rsep = rsep; -- -- setup_add_caps(setup, caps, size); -- -- /* Check for existing stream and close it */ -- for (entry = queue_get_entries(chan->server->seps); entry; -- entry = entry->next) { -- struct a2dp_sep *tmp = entry->data; -- -- /* Attempt to reconfigure if a stream already exists */ -- if (tmp->stream) { -- /* Only allow switching sep from the same sender */ -- if (strcmp(sender, tmp->endpoint->get_name(tmp, -- tmp->user_data))) -- return -EPERM; -- -- err = avdtp_close(chan->session, tmp->stream, FALSE); -- if (err < 0) { -- error("avdtp_close: %s", strerror(-err)); -- return err; -- } -- -- setup->reconfigure = TRUE; -- -- return 0; -- } -- } -- -- err = avdtp_set_configuration(setup->session, setup->rsep->sep, -- lsep->lsep, -- setup->caps, -- &setup->stream); -- if (err < 0) { -- error("avdtp_set_configuration: %s", strerror(-err)); -- return err; -- } -- -- return 0; --} -- --static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg, -- void *data) --{ -- struct a2dp_remote_sep *rsep = data; -- struct a2dp_channel *chan = rsep->chan; -- struct a2dp_sep *lsep; -- struct avdtp_service_capability *service; -- struct avdtp_media_codec_capability *codec; -- DBusMessageIter args, props; -- const char *sender, *path; -- uint8_t *caps; -- int err, size = 0; -- -- sender = dbus_message_get_sender(msg); -- -- dbus_message_iter_init(msg, &args); -- -- dbus_message_iter_get_basic(&args, &path); -- dbus_message_iter_next(&args); -- -- lsep = find_sep(chan->server, sender, path); -- if (!lsep) -- return btd_error_invalid_args(msg); -- -- /* Check if SEPs are no the same role */ -- if (avdtp_get_type(rsep->sep) == lsep->type) -- return btd_error_invalid_args(msg); -- -- service = avdtp_get_codec(rsep->sep); -- codec = (struct avdtp_media_codec_capability *) service->data; -- -- /* Check if codec match */ -- if (!endpoint_match_codec_ind(chan->session, codec, lsep)) -- return btd_error_invalid_args(msg); -- -- dbus_message_iter_recurse(&args, &props); -- if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY) -- return btd_error_invalid_args(msg); -- -- if (parse_properties(&props, &caps, &size) < 0) -- return btd_error_invalid_args(msg); -- -- err = a2dp_reconfig(chan, sender, lsep, rsep, caps, size); -- if (err < 0) -- return btd_error_failed(msg, strerror(-err)); -- -- return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); --} -- --static const GDBusMethodTable sep_methods[] = { -- { GDBUS_EXPERIMENTAL_ASYNC_METHOD("SetConfiguration", -- GDBUS_ARGS({ "endpoint", "o" }, -- { "properties", "a{sv}" } ), -- NULL, set_configuration) }, -- { }, --}; -- --static gboolean get_uuid(const GDBusPropertyTable *property, -- DBusMessageIter *iter, void *data) --{ -- struct a2dp_remote_sep *sep = data; -- const char *uuid; -- -- switch (avdtp_get_type(sep->sep)) { -- case AVDTP_SEP_TYPE_SOURCE: -- uuid = A2DP_SOURCE_UUID; -- break; -- case AVDTP_SEP_TYPE_SINK: -- uuid = A2DP_SOURCE_UUID; -- break; -- default: -- uuid = ""; -- } -- -- dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid); -- -- return TRUE; --} -- --static gboolean get_codec(const GDBusPropertyTable *property, -- DBusMessageIter *iter, void *data) --{ -- struct a2dp_remote_sep *sep = data; -- struct avdtp_service_capability *cap = avdtp_get_codec(sep->sep); -- struct avdtp_media_codec_capability *codec = (void *) cap->data; -- -- dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, -- &codec->media_codec_type); -- -- return TRUE; --} -- --static gboolean get_capabilities(const GDBusPropertyTable *property, -- DBusMessageIter *iter, void *data) -+static void store_remote_sep(void *data, void *user_data) - { - struct a2dp_remote_sep *sep = data; -+ GKeyFile *key_file = (void *) user_data; -+ char seid[4], value[256]; - struct avdtp_service_capability *service = avdtp_get_codec(sep->sep); - struct avdtp_media_codec_capability *codec = (void *) service->data; -- uint8_t *caps = codec->data; -- DBusMessageIter array; -+ unsigned int i; -+ ssize_t offset; - -- dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, -- DBUS_TYPE_BYTE_AS_STRING, &array); -+ sprintf(seid, "%02hhx", avdtp_get_seid(sep->sep)); - -- dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, &caps, -- service->length - sizeof(*codec)); -+ offset = sprintf(value, "%02hhx:%02hhx:", avdtp_get_type(sep->sep), -+ codec->media_codec_type); - -- dbus_message_iter_close_container(iter, &array); -+ for (i = 0; i < service->length - sizeof(*codec); i++) -+ offset += sprintf(value + offset, "%02hhx", codec->data[i]); - -- return TRUE; --} - --static const GDBusPropertyTable sep_properties[] = { -- { "UUID", "s", get_uuid, NULL, NULL, -- G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, -- { "Codec", "y", get_codec, NULL, NULL, -- G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, -- { "Capabilities", "ay", get_capabilities, NULL, NULL, -- G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, -- { } --}; -+ g_key_file_set_string(key_file, "Endpoints", seid, value); -+} - --static void register_remote_sep(void *data, void *user_data) -+static void store_remote_seps(struct a2dp_channel *chan) - { -- struct avdtp_remote_sep *rsep = data; -- struct a2dp_setup *setup = user_data; -- struct a2dp_remote_sep *sep; -+ struct btd_device *device = chan->device; -+ char filename[PATH_MAX]; -+ char dst_addr[18]; -+ GKeyFile *key_file; -+ char *data; -+ gsize length = 0; - -- sep = new0(struct a2dp_remote_sep, 1); -- sep->chan = setup->chan; -- sep->sep = rsep; -+ if (queue_isempty(chan->seps)) -+ return; - -- if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) -- goto done; -+ ba2str(device_get_address(device), dst_addr); - -- asprintf(&sep->path, "%s/sep%d", device_get_path(setup->chan->device), -- avdtp_get_seid(rsep)); -+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", -+ btd_adapter_get_storage_dir(device_get_adapter(device)), -+ dst_addr); -+ key_file = g_key_file_new(); -+ g_key_file_load_from_file(key_file, filename, 0, NULL); - -- if (g_dbus_register_interface(btd_get_dbus_connection(), -- sep->path, MEDIA_ENDPOINT_INTERFACE, -- sep_methods, NULL, sep_properties, -- sep, remote_sep_free) == FALSE) { -- error("Could not register remote sep %s", sep->path); -- free(sep->path); -- sep->path = NULL; -- } -+ /* Remove current endpoints since it might have changed */ -+ g_key_file_remove_group(key_file, "Endpoints", NULL); - -- DBG("Found remote SEP: %s", sep->path); -+ queue_foreach(chan->seps, store_remote_sep, key_file); - --done: -- queue_push_tail(setup->chan->seps, sep); -+ data = g_key_file_to_data(key_file, &length, NULL); -+ g_file_set_contents(filename, data, length, NULL); -+ -+ g_free(data); -+ g_key_file_free(key_file); - } - - static void discover_cb(struct avdtp *session, GSList *seps, -@@ -2270,8 +2438,10 @@ static void discover_cb(struct avdtp *session, GSList *seps, - setup->seps = seps; - setup->err = err; - -- if (!err && queue_isempty(setup->chan->seps)) -- g_slist_foreach(seps, register_remote_sep, setup); -+ if (!err) { -+ g_slist_foreach(seps, register_remote_sep, setup->chan); -+ store_remote_seps(setup->chan); -+ } - - finalize_discover(setup); - } -diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c -index cc4322d10..4f964feb5 100644 ---- a/profiles/audio/avdtp.c -+++ b/profiles/audio/avdtp.c -@@ -2638,12 +2638,15 @@ static gboolean avdtp_discover_resp(struct avdtp *session, - stream = find_stream_by_rseid(session, resp->seps[i].seid); - - sep = find_remote_sep(session->seps, resp->seps[i].seid); -- if (!sep) { -- if (resp->seps[i].inuse && !stream) -- continue; -- sep = g_new0(struct avdtp_remote_sep, 1); -- session->seps = g_slist_append(session->seps, sep); -- } -+ if (sep && sep->type == resp->seps[i].type && -+ sep->media_type == resp->seps[i].media_type) -+ continue; -+ -+ if (resp->seps[i].inuse && !stream) -+ continue; -+ -+ sep = g_new0(struct avdtp_remote_sep, 1); -+ session->seps = g_slist_append(session->seps, sep); - - sep->stream = stream; - sep->seid = resp->seps[i].seid; -@@ -3192,6 +3195,37 @@ struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category, - return cap; - } - -+struct avdtp_remote_sep *avdtp_register_remote_sep(struct avdtp *session, -+ uint8_t seid, -+ uint8_t type, -+ GSList *caps) -+{ -+ struct avdtp_remote_sep *sep; -+ GSList *l; -+ -+ sep = find_remote_sep(session->seps, seid); -+ if (sep) -+ return sep; -+ -+ sep = g_new0(struct avdtp_remote_sep, 1); -+ session->seps = g_slist_append(session->seps, sep); -+ sep->seid = seid; -+ sep->type = type; -+ sep->media_type = AVDTP_MEDIA_TYPE_AUDIO; -+ sep->caps = caps; -+ -+ for (l = caps; l; l = g_slist_next(l)) { -+ struct avdtp_service_capability *cap = l->data; -+ -+ if (cap->category == AVDTP_MEDIA_CODEC) -+ sep->codec = cap; -+ } -+ -+ DBG("seid %d type %d media %d", sep->seid, sep->type, sep->media_type); -+ -+ return sep; -+} -+ - static gboolean process_discover(gpointer data) - { - struct avdtp *session = data; -diff --git a/profiles/audio/avdtp.h b/profiles/audio/avdtp.h -index e5fc40c89..b03ca9030 100644 ---- a/profiles/audio/avdtp.h -+++ b/profiles/audio/avdtp.h -@@ -223,6 +223,11 @@ struct avdtp *avdtp_ref(struct avdtp *session); - struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category, - void *data, int size); - -+struct avdtp_remote_sep *avdtp_register_remote_sep(struct avdtp *session, -+ uint8_t seid, -+ uint8_t type, -+ GSList *caps); -+ - uint8_t avdtp_get_seid(struct avdtp_remote_sep *sep); - - uint8_t avdtp_get_type(struct avdtp_remote_sep *sep); --- -2.21.0 - - -From 50d87b05b3322f3678b6dda97e4c26ef186f63ac Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Tue, 15 Jan 2019 11:06:04 -0300 -Subject: [PATCH 16/31] doc/media-api: Add Device property to MediaEndpoint - -This adds Device property which indicates which device the endpoint -belongs to. ---- - doc/media-api.txt | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/doc/media-api.txt b/doc/media-api.txt -index 93c3490b6..b909d8e73 100644 ---- a/doc/media-api.txt -+++ b/doc/media-api.txt -@@ -533,6 +533,10 @@ Methods void SetConfiguration(object transport, dict properties) - already been unregistered. - - -+ object Device [readonly, optional]: -+ -+ Device object which the endpoint is belongs to. -+ - MediaTransport1 hierarchy - ========================= - --- -2.21.0 - - -From 394b06e7f706de581a4aa50d20232081bceaa824 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Tue, 15 Jan 2019 11:07:13 -0300 -Subject: [PATCH 17/31] a2dp: Add implementation of MediaEndpoint.Device - -This adds the implementation of MediaEndpoint.Device property so the -clints don't need to guess what device the endpoint belongs. ---- - profiles/audio/a2dp.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index 6975682c9..ff384cd23 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -1718,6 +1718,19 @@ static gboolean get_capabilities(const GDBusPropertyTable *property, - return TRUE; - } - -+static gboolean get_device(const GDBusPropertyTable *property, -+ DBusMessageIter *iter, void *data) -+{ -+ struct a2dp_remote_sep *sep = data; -+ const char *path; -+ -+ path = device_get_path(sep->chan->device); -+ -+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); -+ -+ return TRUE; -+} -+ - static const GDBusPropertyTable sep_properties[] = { - { "UUID", "s", get_uuid, NULL, NULL, - G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, -@@ -1725,6 +1738,8 @@ static const GDBusPropertyTable sep_properties[] = { - G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, - { "Capabilities", "ay", get_capabilities, NULL, NULL, - G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, -+ { "Device", "o", get_device, NULL, NULL, -+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, - { } - }; - --- -2.21.0 - - -From 4222cbdd5909043c7f903bbca9bb377ba7aeb7bb Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Tue, 22 Jan 2019 15:28:12 +0200 -Subject: [PATCH 18/31] a2dp: Add reverse discovery - -Now that remote endpoints are exposed there is a chance that a -configured device will reconnect and initiate SetConfiguration skipping -the discovery phase which is now required in order to be able to switch -endpoints, so this introduces the reverse discovery logic in order to -find out about remote endpoints capabilities if they have not been -found yet. ---- - profiles/audio/a2dp.c | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index ff384cd23..4001ea0ea 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -583,6 +583,12 @@ static gboolean endpoint_match_codec_ind(struct avdtp *session, - return TRUE; - } - -+static void reverse_discover(struct avdtp *session, GSList *seps, int err, -+ void *user_data) -+{ -+ DBG("err %d", err); -+} -+ - static gboolean endpoint_setconf_ind(struct avdtp *session, - struct avdtp_local_sep *sep, - struct avdtp_stream *stream, -@@ -638,8 +644,14 @@ static gboolean endpoint_setconf_ind(struct avdtp *session, - setup_ref(setup), - endpoint_setconf_cb, - a2dp_sep->user_data); -- if (ret == 0) -+ if (ret == 0) { -+ /* Attempt to reverve discover if there are no remote -+ * SEPs. -+ */ -+ if (queue_isempty(setup->chan->seps)) -+ a2dp_discover(session, reverse_discover, NULL); - return TRUE; -+ } - - setup_unref(setup); - setup->err = g_new(struct avdtp_error, 1); --- -2.21.0 - - -From 18495cf34e6412af10da2632289cf0c07b5e23ab Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sat, 26 Jan 2019 11:46:06 +0100 -Subject: [PATCH 19/31] a2dp-codecs & avinfo: Simplify defintions and parsing - of aptX family - -Reuse whole a2dp_aptx_t structure and defines as they are same for aptX Low -Latency and aptX HD. ---- - profiles/audio/a2dp-codecs.h | 46 +++++-------------------------- - tools/avinfo.c | 53 ++++++++++-------------------------- - 2 files changed, 22 insertions(+), 77 deletions(-) - -diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h -index 0bdd29110..16088dc26 100644 ---- a/profiles/audio/a2dp-codecs.h -+++ b/profiles/audio/a2dp-codecs.h -@@ -212,14 +212,6 @@ - #define APTX_LL_VENDOR_ID 0x0000000a - #define APTX_LL_CODEC_ID 0x0002 - --#define APTX_LL_CHANNEL_MODE_MONO 0x01 --#define APTX_LL_CHANNEL_MODE_STEREO 0x02 -- --#define APTX_LL_SAMPLING_FREQ_16000 0x08 --#define APTX_LL_SAMPLING_FREQ_32000 0x04 --#define APTX_LL_SAMPLING_FREQ_44100 0x02 --#define APTX_LL_SAMPLING_FREQ_48000 0x01 -- - /* Default parameters for aptX Low Latency encoder */ - - /* Target codec buffer level = 180 */ -@@ -243,14 +235,6 @@ - #define APTX_HD_VENDOR_ID 0x000000D7 - #define APTX_HD_CODEC_ID 0x0024 - --#define APTX_HD_CHANNEL_MODE_MONO 0x1 --#define APTX_HD_CHANNEL_MODE_STEREO 0x2 -- --#define APTX_HD_SAMPLING_FREQ_16000 0x8 --#define APTX_HD_SAMPLING_FREQ_32000 0x4 --#define APTX_HD_SAMPLING_FREQ_44100 0x2 --#define APTX_HD_SAMPLING_FREQ_48000 0x1 -- - #define LDAC_VENDOR_ID 0x0000012d - #define LDAC_CODEC_ID 0x00aa - -@@ -359,25 +343,13 @@ typedef struct { - } __attribute__ ((packed)) a2dp_faststream_t; - - typedef struct { -- a2dp_vendor_codec_t info; -- uint8_t channel_mode:4; -- uint8_t frequency:4; -+ a2dp_aptx_t aptx; - uint8_t bidirect_link:1; - uint8_t has_new_caps:1; - uint8_t reserved:6; - a2dp_aptx_ll_new_caps_t new_caps[0]; - } __attribute__ ((packed)) a2dp_aptx_ll_t; - --typedef struct { -- a2dp_vendor_codec_t info; -- uint8_t channel_mode:4; -- uint8_t frequency:4; -- uint8_t reserved0; -- uint8_t reserved1; -- uint8_t reserved2; -- uint8_t reserved3; --} __attribute__ ((packed)) a2dp_aptx_hd_t; -- - #elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ - __BYTE_ORDER == __BIG_ENDIAN - -@@ -429,25 +401,21 @@ typedef struct { - } __attribute__ ((packed)) a2dp_faststream_t; - - typedef struct { -- a2dp_vendor_codec_t info; -- uint8_t frequency:4; -- uint8_t channel_mode:4; -+ a2dp_aptx_t aptx; - uint8_t reserved:6; - uint8_t has_new_caps:1; - uint8_t bidirect_link:1; - a2dp_aptx_ll_new_caps_t new_caps[0]; - } __attribute__ ((packed)) a2dp_aptx_ll_t; - -+#else -+#error "Unknown byte order" -+#endif -+ - typedef struct { -- a2dp_vendor_codec_t info; -- uint8_t frequency:4; -- uint8_t channel_mode:4; -+ a2dp_aptx_t aptx; - uint8_t reserved0; - uint8_t reserved1; - uint8_t reserved2; - uint8_t reserved3; - } __attribute__ ((packed)) a2dp_aptx_hd_t; -- --#else --#error "Unknown byte order" --#endif -diff --git a/tools/avinfo.c b/tools/avinfo.c -index 02fc1f233..ea7a93ed2 100644 ---- a/tools/avinfo.c -+++ b/tools/avinfo.c -@@ -168,15 +168,8 @@ struct avdtp_content_protection_capability { - uint8_t data[0]; - } __attribute__ ((packed)); - --static void print_aptx(a2dp_aptx_t *aptx, uint8_t size) -+static void print_aptx_common(a2dp_aptx_t *aptx) - { -- printf("\t\tVendor Specific Value (aptX)"); -- -- if (size < sizeof(*aptx)) { -- printf(" (broken)\n"); -- return; -- } -- - printf("\n\t\t\tFrequencies: "); - if (aptx->frequency & APTX_SAMPLING_FREQ_16000) - printf("16kHz "); -@@ -192,6 +185,18 @@ static void print_aptx(a2dp_aptx_t *aptx, uint8_t size) - printf("Mono "); - if (aptx->channel_mode & APTX_CHANNEL_MODE_STEREO) - printf("Stereo "); -+} -+ -+static void print_aptx(a2dp_aptx_t *aptx, uint8_t size) -+{ -+ printf("\t\tVendor Specific Value (aptX)"); -+ -+ if (size < sizeof(*aptx)) { -+ printf(" (broken)\n"); -+ return; -+ } -+ -+ print_aptx_common(aptx); - - printf("\n"); - } -@@ -242,21 +247,7 @@ static void print_aptx_ll(a2dp_aptx_ll_t *aptx_ll, uint8_t size) - return; - } - -- printf("\n\t\t\tFrequencies: "); -- if (aptx_ll->frequency & APTX_LL_SAMPLING_FREQ_16000) -- printf("16kHz "); -- if (aptx_ll->frequency & APTX_LL_SAMPLING_FREQ_32000) -- printf("32kHz "); -- if (aptx_ll->frequency & APTX_LL_SAMPLING_FREQ_44100) -- printf("44.1kHz "); -- if (aptx_ll->frequency & APTX_LL_SAMPLING_FREQ_48000) -- printf("48kHz "); -- -- printf("\n\t\t\tChannel modes: "); -- if (aptx_ll->channel_mode & APTX_LL_CHANNEL_MODE_MONO) -- printf("Mono "); -- if (aptx_ll->channel_mode & APTX_LL_CHANNEL_MODE_STEREO) -- printf("Stereo "); -+ print_aptx_common(&aptx_ll->aptx); - - printf("\n\t\tBidirectional link: %s", - aptx_ll->bidirect_link ? "Yes" : "No"); -@@ -292,21 +283,7 @@ static void print_aptx_hd(a2dp_aptx_hd_t *aptx_hd, uint8_t size) - return; - } - -- printf("\n\t\t\tFrequencies: "); -- if (aptx_hd->frequency & APTX_HD_SAMPLING_FREQ_16000) -- printf("16kHz "); -- if (aptx_hd->frequency & APTX_HD_SAMPLING_FREQ_32000) -- printf("32kHz "); -- if (aptx_hd->frequency & APTX_HD_SAMPLING_FREQ_44100) -- printf("44.1kHz "); -- if (aptx_hd->frequency & APTX_HD_SAMPLING_FREQ_48000) -- printf("48kHz "); -- -- printf("\n\t\t\tChannel modes: "); -- if (aptx_hd->channel_mode & APTX_HD_CHANNEL_MODE_MONO) -- printf("Mono "); -- if (aptx_hd->channel_mode & APTX_HD_CHANNEL_MODE_STEREO) -- printf("Stereo "); -+ print_aptx_common(&aptx_hd->aptx); - - printf("\n"); - } --- -2.21.0 - - -From 5861b20c6bd9c4f82c7b20de1101d9eebc90345b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sat, 26 Jan 2019 11:24:50 +0100 -Subject: [PATCH 20/31] avinfo: Dump unknown codecs and unknown categories - ---- - tools/avinfo.c | 15 ++++++++++++++- - 1 file changed, 14 insertions(+), 1 deletion(-) - -diff --git a/tools/avinfo.c b/tools/avinfo.c -index ea7a93ed2..6f9f2763b 100644 ---- a/tools/avinfo.c -+++ b/tools/avinfo.c -@@ -625,6 +625,8 @@ static void print_media_codec( - struct avdtp_media_codec_capability *cap, - uint8_t size) - { -+ int i; -+ - if (size < sizeof(*cap)) { - printf("\tMedia Codec: Unknown (broken)\n"); - return; -@@ -645,6 +647,10 @@ static void print_media_codec( - break; - default: - printf("\tMedia Codec: Unknown\n"); -+ printf("\t\tCodec Data:"); -+ for (i = 0; i < size - 2; ++i) -+ printf(" 0x%.02x", ((unsigned char *)cap->data)[i]); -+ printf("\n"); - } - } - -@@ -676,6 +682,7 @@ static void print_content_protection( - static void print_caps(void *data, int size) - { - int processed; -+ int i; - - for (processed = 0; processed + 2 < size;) { - struct avdtp_service_capability *cap; -@@ -692,9 +699,15 @@ static void print_caps(void *data, int size) - case AVDTP_REPORTING: - case AVDTP_RECOVERY: - case AVDTP_MULTIPLEXING: -- default: - /* FIXME: Add proper functions */ -+ break; -+ default: - printf("\tUnknown category: %d\n", cap->category); -+ printf("\t\tData:"); -+ for (i = 0; i < cap->length; ++i) -+ printf(" 0x%.02x", -+ ((unsigned char *)cap->data)[i]); -+ printf("\n"); - break; - case AVDTP_MEDIA_CODEC: - print_media_codec((void *) cap->data, cap->length); --- -2.21.0 - - -From e6ad4cbe20f3e66c77fa27c2d8b721a4ccdef58f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sat, 26 Jan 2019 11:24:15 +0100 -Subject: [PATCH 21/31] avinfo: Fix parsing capabilities - -Function print_caps() expects capabilities buffer without AVDTP header. -Previously avinfo somehow worked, because AVDTP header looks like -capability header with unknown category which was skipped. ---- - tools/avinfo.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/avinfo.c b/tools/avinfo.c -index 6f9f2763b..e45b50918 100644 ---- a/tools/avinfo.c -+++ b/tools/avinfo.c -@@ -799,7 +799,7 @@ static ssize_t avdtp_get_caps(int sk, int seid) - return -1; - } - -- print_caps(caps, ret); -+ print_caps(caps->caps, ret - sizeof(struct getcap_resp)); - - return 0; - } --- -2.21.0 - - -From 87805eea93c451aa1b438a2b01967a96f53dce1f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Tue, 29 Jan 2019 18:12:07 +0100 -Subject: [PATCH 22/31] a2dp-codecs: Fix SBC_MAX_BITPOOL and add SBC quality - modes - -According to A2DP specification; section SBC; Codec Specific Information -Elements; Minimum / Maximum Bitpool Value, range for Bitpool value is from -2 to 250. - -A2DP specification also defines bitpool values for two SBC modes: Middle -Quality and High Quality. They depends on channel mode and frequency. So -add definitions for them into a2dp-codecs file too. - -File android/hal-audio-sbc.c was updated to use High Quality mode for -chosen frequency. ---- - android/hal-audio-sbc.c | 6 +++--- - profiles/audio/a2dp-codecs.h | 16 +++++++++++++++- - 2 files changed, 18 insertions(+), 4 deletions(-) - -diff --git a/android/hal-audio-sbc.c b/android/hal-audio-sbc.c -index fd6c61b95..4df4ec7ff 100644 ---- a/android/hal-audio-sbc.c -+++ b/android/hal-audio-sbc.c -@@ -91,7 +91,7 @@ static const a2dp_sbc_t sbc_presets[] = { - .block_length = SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 | - SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16, - .min_bitpool = SBC_MIN_BITPOOL, -- .max_bitpool = SBC_MAX_BITPOOL -+ .max_bitpool = SBC_BITPOOL_HQ_JOINT_STEREO_44100, - }, - { - .frequency = SBC_SAMPLING_FREQ_44100, -@@ -100,7 +100,7 @@ static const a2dp_sbc_t sbc_presets[] = { - .allocation_method = SBC_ALLOCATION_LOUDNESS, - .block_length = SBC_BLOCK_LENGTH_16, - .min_bitpool = SBC_MIN_BITPOOL, -- .max_bitpool = SBC_MAX_BITPOOL -+ .max_bitpool = SBC_BITPOOL_HQ_JOINT_STEREO_44100, - }, - { - .frequency = SBC_SAMPLING_FREQ_48000, -@@ -109,7 +109,7 @@ static const a2dp_sbc_t sbc_presets[] = { - .allocation_method = SBC_ALLOCATION_LOUDNESS, - .block_length = SBC_BLOCK_LENGTH_16, - .min_bitpool = SBC_MIN_BITPOOL, -- .max_bitpool = SBC_MAX_BITPOOL -+ .max_bitpool = SBC_BITPOOL_HQ_JOINT_STEREO_48000, - }, - }; - -diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h -index 16088dc26..93e9d3523 100644 ---- a/profiles/audio/a2dp-codecs.h -+++ b/profiles/audio/a2dp-codecs.h -@@ -53,8 +53,22 @@ - #define SBC_ALLOCATION_SNR (1 << 1) - #define SBC_ALLOCATION_LOUDNESS 1 - --#define SBC_MAX_BITPOOL 64 - #define SBC_MIN_BITPOOL 2 -+#define SBC_MAX_BITPOOL 250 -+ -+/* Other settings: -+ * Block length = 16 -+ * Allocation method = Loudness -+ * Subbands = 8 -+ */ -+#define SBC_BITPOOL_MQ_MONO_44100 19 -+#define SBC_BITPOOL_MQ_MONO_48000 18 -+#define SBC_BITPOOL_MQ_JOINT_STEREO_44100 35 -+#define SBC_BITPOOL_MQ_JOINT_STEREO_48000 33 -+#define SBC_BITPOOL_HQ_MONO_44100 31 -+#define SBC_BITPOOL_HQ_MONO_48000 29 -+#define SBC_BITPOOL_HQ_JOINT_STEREO_44100 53 -+#define SBC_BITPOOL_HQ_JOINT_STEREO_48000 51 - - #define MPEG_CHANNEL_MODE_MONO (1 << 3) - #define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2) --- -2.21.0 - - -From d23b245146678847d4afa87d8ea9d859935a5a37 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Mon, 8 Apr 2019 12:41:39 +0300 -Subject: [PATCH 23/31] a2dp: Fix UUID of remote Sinks - -Sinks were being reported as Sources. ---- - profiles/audio/a2dp.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index 4001ea0ea..8f141739c 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -1686,7 +1686,7 @@ static gboolean get_uuid(const GDBusPropertyTable *property, - uuid = A2DP_SOURCE_UUID; - break; - case AVDTP_SEP_TYPE_SINK: -- uuid = A2DP_SOURCE_UUID; -+ uuid = A2DP_SINK_UUID; - break; - default: - uuid = ""; --- -2.21.0 - - -From 44257aa797796ac3ddc0e01de68df596b6ebf858 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Fri, 3 May 2019 14:49:22 +0300 -Subject: [PATCH 24/31] a2dp: Fix useless statement - -Checking for NULL path doesn't really matter since NULL is returned -anyway. ---- - profiles/audio/a2dp.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index 8f141739c..1c9473887 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -2873,8 +2873,7 @@ struct btd_device *a2dp_setup_get_device(struct a2dp_setup *setup) - const char *a2dp_setup_remote_path(struct a2dp_setup *setup) - { - if (setup->rsep) { -- if (setup->rsep->path) -- return setup->rsep->path; -+ return setup->rsep->path; - } - - return NULL; --- -2.21.0 - - -From 12e91430886546160f6131c1622a4923adedf3d2 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Tue, 23 Apr 2019 18:46:36 +0300 -Subject: [PATCH 25/31] a2dp: Store last used endpoint - -This stores the last used endpoint whenever it is considered open and -then prefer to use it when attempting to reconnect. ---- - profiles/audio/a2dp.c | 105 ++++++++++++++++++++++++++++++++++++------ - 1 file changed, 92 insertions(+), 13 deletions(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index 1c9473887..d1ed82243 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -147,6 +147,7 @@ struct a2dp_channel { - unsigned int auth_id; - struct avdtp *session; - struct queue *seps; -+ struct a2dp_remote_sep *last_used; - }; - - static GSList *servers = NULL; -@@ -860,6 +861,60 @@ static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep, - return TRUE; - } - -+static bool match_remote_sep(const void *data, const void *user_data) -+{ -+ const struct a2dp_remote_sep *sep = data; -+ const struct avdtp_remote_sep *rsep = user_data; -+ -+ return sep->sep == rsep; -+} -+ -+static void store_last_used(struct a2dp_channel *chan, -+ struct avdtp_remote_sep *rsep) -+{ -+ GKeyFile *key_file; -+ char filename[PATH_MAX]; -+ char dst_addr[18]; -+ char value[4]; -+ char *data; -+ size_t len = 0; -+ -+ ba2str(device_get_address(chan->device), dst_addr); -+ -+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", -+ btd_adapter_get_storage_dir(device_get_adapter(chan->device)), -+ dst_addr); -+ key_file = g_key_file_new(); -+ g_key_file_load_from_file(key_file, filename, 0, NULL); -+ -+ sprintf(value, "%02hhx", avdtp_get_seid(rsep)); -+ -+ g_key_file_set_string(key_file, "Endpoints", "LastUsed", value); -+ -+ data = g_key_file_to_data(key_file, &len, NULL); -+ g_file_set_contents(filename, data, len, NULL); -+ -+ g_free(data); -+ g_key_file_free(key_file); -+} -+ -+static void update_last_used(struct a2dp_channel *chan, -+ struct avdtp_stream *stream) -+{ -+ struct avdtp_remote_sep *rsep; -+ struct a2dp_remote_sep *sep; -+ -+ rsep = avdtp_stream_get_remote_sep(stream); -+ -+ /* Update last used */ -+ sep = queue_find(chan->seps, match_remote_sep, rsep); -+ if (chan->last_used == sep) -+ return; -+ -+ chan->last_used = sep; -+ store_last_used(chan, rsep); -+} -+ - static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep, - struct avdtp_stream *stream, struct avdtp_error *err, - void *user_data) -@@ -884,7 +939,8 @@ static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep, - setup->err = err; - if (setup->start) - finalize_resume(setup); -- } -+ } else if (setup->chan) -+ update_last_used(setup->chan, stream); - - finalize_config(setup); - -@@ -1077,14 +1133,6 @@ static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep, - return TRUE; - } - --static bool match_remote_sep(const void *data, const void *user_data) --{ -- const struct a2dp_remote_sep *sep = data; -- const struct avdtp_remote_sep *rsep = user_data; -- -- return sep->sep == rsep; --} -- - static struct a2dp_remote_sep *find_remote_sep(struct a2dp_channel *chan, - struct a2dp_sep *sep) - { -@@ -1791,19 +1839,28 @@ done: - queue_push_tail(chan->seps, sep); - } - -+static bool match_seid(const void *data, const void *user_data) -+{ -+ const struct a2dp_remote_sep *sep = data; -+ const uint8_t *seid = user_data; -+ -+ return avdtp_get_seid(sep->sep) == *seid; -+} -+ - static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file, - char **seids) - { - struct avdtp_remote_sep *sep; -+ uint8_t seid; -+ char *value; - - if (!seids) - return; - - for (; *seids; seids++) { -- uint8_t seid; - uint8_t type; - uint8_t codec; -- char *value, caps[256]; -+ char caps[256]; - uint8_t data[128]; - int i, size; - GSList *l = NULL; -@@ -1847,6 +1904,15 @@ static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file, - - register_remote_sep(sep, chan); - } -+ -+ value = g_key_file_get_string(key_file, "Endpoints", "LastUsed", NULL); -+ if (!value) -+ return; -+ -+ if (sscanf(value, "%02hhx", &seid) != 1) -+ return; -+ -+ chan->last_used = queue_find(chan->seps, match_seid, &seid); - } - - static void load_remote_seps(struct a2dp_channel *chan) -@@ -2355,8 +2421,12 @@ done: - static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list, - const char *sender) - { -+ struct a2dp_sep *first = NULL; -+ struct a2dp_channel *chan = find_channel(session); -+ - for (; list; list = list->next) { - struct a2dp_sep *sep = list->data; -+ struct avdtp_remote_sep *rsep; - - /* Use sender's endpoint if available */ - if (sender) { -@@ -2370,14 +2440,23 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list, - continue; - } - -- if (avdtp_find_remote_sep(session, sep->lsep) == NULL) -+ rsep = avdtp_find_remote_sep(session, sep->lsep); -+ if (!rsep) - continue; - -+ /* Locate last used if set */ -+ if (chan->last_used) { -+ if (chan->last_used->sep == rsep) -+ return sep; -+ first = sep; -+ continue; -+ } -+ - return sep; - - } - -- return NULL; -+ return first; - } - - static struct a2dp_sep *a2dp_select_sep(struct avdtp *session, uint8_t type, --- -2.21.0 - - -From 2934144ad10e7d6988cbfd4e3642be275d41c450 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Mon, 29 Apr 2019 13:30:34 +0300 -Subject: [PATCH 26/31] a2dp: Fix not calling SelectConfiguration on other - available endpoints - -Endpoint may not be able to select a valid configuration but there could -be other endpoints available that could be used, so instead of just -using the first match this collects all the matching endpoints and put -them into a queue (ordered by priority) then proceed to next endpoint -only failing if none of the available endpoits can select a valid -configuration. ---- - profiles/audio/a2dp.c | 77 ++++++++++++++++++++++++++++--------------- - 1 file changed, 50 insertions(+), 27 deletions(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index d1ed82243..f10ba6c81 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -105,6 +105,7 @@ struct a2dp_setup_cb { - struct a2dp_setup { - struct a2dp_channel *chan; - struct avdtp *session; -+ struct queue *eps; - struct a2dp_sep *sep; - struct a2dp_remote_sep *rsep; - struct avdtp_stream *stream; -@@ -2406,23 +2407,44 @@ void a2dp_remove_sep(struct a2dp_sep *sep) - - static void select_cb(struct a2dp_setup *setup, void *ret, int size) - { -- if (size < 0) { -- DBG("Endpoint replied an invalid configuration"); -+ struct avdtp_service_capability *service; -+ struct avdtp_media_codec_capability *codec; -+ int err; -+ -+ if (size) { -+ caps_add_codec(&setup->caps, setup->sep->codec, ret, size); - goto done; - } - -- caps_add_codec(&setup->caps, setup->sep->codec, ret, size); -+ setup->sep = queue_pop_head(setup->eps); -+ if (!setup->sep) { -+ error("Unable to select a valid configuration"); -+ queue_destroy(setup->eps, NULL); -+ goto done; -+ } -+ -+ setup->rsep = find_remote_sep(setup->chan, setup->sep); -+ service = avdtp_get_codec(setup->rsep->sep); -+ codec = (struct avdtp_media_codec_capability *) service->data; -+ -+ err = setup->sep->endpoint->select_configuration(setup->sep, -+ codec->data, -+ service->length - sizeof(*codec), -+ setup_ref(setup), -+ select_cb, setup->sep->user_data); -+ if (err == 0) -+ return; - - done: - finalize_select(setup); - setup_unref(setup); - } - --static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list, -+static struct queue *a2dp_find_eps(struct avdtp *session, GSList *list, - const char *sender) - { -- struct a2dp_sep *first = NULL; - struct a2dp_channel *chan = find_channel(session); -+ struct queue *seps = NULL; - - for (; list; list = list->next) { - struct a2dp_sep *sep = list->data; -@@ -2444,26 +2466,25 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list, - if (!rsep) - continue; - -- /* Locate last used if set */ -- if (chan->last_used) { -- if (chan->last_used->sep == rsep) -- return sep; -- first = sep; -- continue; -- } -+ if (!seps) -+ seps = queue_new(); - -- return sep; -+ /* Prepend last used so it is preferred over others */ -+ if (chan->last_used && chan->last_used->sep == rsep) -+ queue_push_head(seps, sep); -+ else -+ queue_push_tail(seps, sep); - - } - -- return first; -+ return seps; - } - --static struct a2dp_sep *a2dp_select_sep(struct avdtp *session, uint8_t type, -+static struct queue *a2dp_select_eps(struct avdtp *session, uint8_t type, - const char *sender) - { - struct a2dp_server *server; -- struct a2dp_sep *sep; -+ struct queue *seps; - GSList *l; - - server = find_server(servers, avdtp_get_adapter(session)); -@@ -2473,11 +2494,11 @@ static struct a2dp_sep *a2dp_select_sep(struct avdtp *session, uint8_t type, - l = type == AVDTP_SEP_TYPE_SINK ? server->sources : server->sinks; - - /* Check sender's seps first */ -- sep = a2dp_find_sep(session, l, sender); -- if (sep != NULL) -- return sep; -+ seps = a2dp_find_eps(session, l, sender); -+ if (seps != NULL) -+ return seps; - -- return a2dp_find_sep(session, l, NULL); -+ return a2dp_find_eps(session, l, NULL); - } - - static void store_remote_sep(void *data, void *user_data) -@@ -2580,13 +2601,13 @@ unsigned int a2dp_select_capabilities(struct avdtp *session, - { - struct a2dp_setup *setup; - struct a2dp_setup_cb *cb_data; -- struct a2dp_sep *sep; -+ struct queue *eps; - struct avdtp_service_capability *service; - struct avdtp_media_codec_capability *codec; - int err; - -- sep = a2dp_select_sep(session, type, sender); -- if (!sep) { -+ eps = a2dp_select_eps(session, type, sender); -+ if (!eps) { - error("Unable to select SEP"); - return 0; - } -@@ -2599,8 +2620,9 @@ unsigned int a2dp_select_capabilities(struct avdtp *session, - cb_data->select_cb = cb; - cb_data->user_data = user_data; - -- setup->sep = sep; -- setup->rsep = find_remote_sep(setup->chan, sep); -+ setup->eps = eps; -+ setup->sep = queue_pop_head(eps); -+ setup->rsep = find_remote_sep(setup->chan, setup->sep); - - if (setup->rsep == NULL) { - error("Could not find remote sep"); -@@ -2610,10 +2632,11 @@ unsigned int a2dp_select_capabilities(struct avdtp *session, - service = avdtp_get_codec(setup->rsep->sep); - codec = (struct avdtp_media_codec_capability *) service->data; - -- err = sep->endpoint->select_configuration(sep, codec->data, -+ err = setup->sep->endpoint->select_configuration(setup->sep, -+ codec->data, - service->length - sizeof(*codec), - setup_ref(setup), -- select_cb, sep->user_data); -+ select_cb, setup->sep->user_data); - if (err == 0) - return cb_data->id; - --- -2.21.0 - - -From 05e8894f97f09a2d17f3c9e8f398424218712ba8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Micha=C5=82=20Lowas-Rzechonek?= - -Date: Tue, 30 Apr 2019 12:30:00 +0200 -Subject: [PATCH 27/31] a2dp: Fixed warn_unused_result warning -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This used to break builds when using maintainer mode via -./bootstrap-configure: - -profiles/audio/a2dp.c:1775:2: error: ignoring return value of - ‘asprintf’, declared with attribute warn_unused_result - [-Werror=unused-result] - asprintf(&sep->path, "%s/sep%d", - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---- - profiles/audio/a2dp.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index f10ba6c81..11afe0d05 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -1821,8 +1821,15 @@ static void register_remote_sep(void *data, void *user_data) - if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) - goto done; - -- asprintf(&sep->path, "%s/sep%d", device_get_path(chan->device), -- avdtp_get_seid(rsep)); -+ if (asprintf(&sep->path, "%s/sep%d", -+ device_get_path(chan->device), -+ avdtp_get_seid(rsep)) < 0) { -+ error("Could not allocate path for remote sep %s/sep%d", -+ device_get_path(chan->device), -+ avdtp_get_seid(rsep)); -+ sep->path = NULL; -+ goto done; -+ } - - if (g_dbus_register_interface(btd_get_dbus_connection(), - sep->path, MEDIA_ENDPOINT_INTERFACE, --- -2.21.0 - - -From 722eeec6864c1f84207431dfcdf4ef2321543d54 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Fri, 3 May 2019 10:51:34 +0300 -Subject: [PATCH 28/31] a2dp: Fix crash when endpoint respond with an error - -If endpoint respond with an error the callback will be called with size -set to -1 not 0. ---- - profiles/audio/a2dp.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index 11afe0d05..24587b450 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -2418,7 +2418,7 @@ static void select_cb(struct a2dp_setup *setup, void *ret, int size) - struct avdtp_media_codec_capability *codec; - int err; - -- if (size) { -+ if (size >= 0) { - caps_add_codec(&setup->caps, setup->sep->codec, ret, size); - goto done; - } --- -2.21.0 - - -From 0c97c4ecbedd0378c88899bc393f299fac048a48 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Fri, 3 May 2019 11:22:40 +0300 -Subject: [PATCH 29/31] a2dp: Try aborting when switching endpoints - -If ongoing stream cannot be closed try aborting since the setup may -still be ongoing. ---- - profiles/audio/a2dp.c | 13 +++++++++++-- - 1 file changed, 11 insertions(+), 2 deletions(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index 24587b450..36cc55da5 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -1257,6 +1257,11 @@ static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep, - if (!setup) - return; - -+ if (setup->reconfigure) { -+ g_timeout_add(RECONFIGURE_TIMEOUT, a2dp_reconfigure, setup); -+ return; -+ } -+ - setup_unref(setup); - } - -@@ -1642,8 +1647,12 @@ static int a2dp_reconfig(struct a2dp_channel *chan, const char *sender, - - err = avdtp_close(chan->session, tmp->stream, FALSE); - if (err < 0) { -- error("avdtp_close: %s", strerror(-err)); -- goto fail; -+ err = avdtp_abort(chan->session, tmp->stream); -+ if (err < 0) { -+ error("avdtp_abort: %s", -+ strerror(-err)); -+ goto fail; -+ } - } - - setup->reconfigure = TRUE; --- -2.21.0 - - -From a71f4e02625f470f2bf5512caec6f157aef12d7e Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Fri, 3 May 2019 11:24:57 +0300 -Subject: [PATCH 30/31] a2dp: Update last used on open indication - -This updates the last used endpoint also when receiving an open -request from the remote end. ---- - profiles/audio/a2dp.c | 55 +++++++++++++++++++++++-------------------- - 1 file changed, 29 insertions(+), 26 deletions(-) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index 36cc55da5..6d9c26b3d 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -836,32 +836,6 @@ static void getconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep, - DBG("Source %p: Set_Configuration_Cfm", sep); - } - --static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep, -- struct avdtp_stream *stream, uint8_t *err, -- void *user_data) --{ -- struct a2dp_sep *a2dp_sep = user_data; -- struct a2dp_setup *setup; -- -- if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) -- DBG("Sink %p: Open_Ind", sep); -- else -- DBG("Source %p: Open_Ind", sep); -- -- setup = a2dp_setup_get(session); -- if (!setup) -- return FALSE; -- -- setup->stream = stream; -- -- if (setup->reconfigure) -- setup->reconfigure = FALSE; -- -- finalize_config(setup); -- -- return TRUE; --} -- - static bool match_remote_sep(const void *data, const void *user_data) - { - const struct a2dp_remote_sep *sep = data; -@@ -916,6 +890,35 @@ static void update_last_used(struct a2dp_channel *chan, - store_last_used(chan, rsep); - } - -+static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep, -+ struct avdtp_stream *stream, uint8_t *err, -+ void *user_data) -+{ -+ struct a2dp_sep *a2dp_sep = user_data; -+ struct a2dp_setup *setup; -+ -+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) -+ DBG("Sink %p: Open_Ind", sep); -+ else -+ DBG("Source %p: Open_Ind", sep); -+ -+ setup = a2dp_setup_get(session); -+ if (!setup) -+ return FALSE; -+ -+ setup->stream = stream; -+ -+ if (!err && setup->chan) -+ update_last_used(setup->chan, stream); -+ -+ if (setup->reconfigure) -+ setup->reconfigure = FALSE; -+ -+ finalize_config(setup); -+ -+ return TRUE; -+} -+ - static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep, - struct avdtp_stream *stream, struct avdtp_error *err, - void *user_data) --- -2.21.0 - - -From fe6895ac63e37894ccaf17d4bec12e496d547c55 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Fri, 3 May 2019 12:41:15 +0300 -Subject: [PATCH 31/31] a2dp: Fix reconfiguring when there multiple devices - connected - -When there are multiple devices connected streams need to be matched -with the sessions they belong. ---- - profiles/audio/a2dp.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c -index 6d9c26b3d..b54c50315 100644 ---- a/profiles/audio/a2dp.c -+++ b/profiles/audio/a2dp.c -@@ -1648,6 +1648,10 @@ static int a2dp_reconfig(struct a2dp_channel *chan, const char *sender, - tmp->user_data))) - return -EPERM; - -+ /* Check if stream is for the channel */ -+ if (!avdtp_has_stream(chan->session, tmp->stream)) -+ continue; -+ - err = avdtp_close(chan->session, tmp->stream, FALSE); - if (err < 0) { - err = avdtp_abort(chan->session, tmp->stream); --- -2.21.0 - diff --git a/bluez-5.50-gcc9.patch b/bluez-5.50-gcc9.patch deleted file mode 100644 index 824d273..0000000 --- a/bluez-5.50-gcc9.patch +++ /dev/null @@ -1,321 +0,0 @@ -From 0be5246170f76a476101aa2dd7e748937363a1dc Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Fri, 11 Jan 2019 10:16:17 -0300 -Subject: unit: Fix fsanitize-address-use-after-scope with GCC 9 - -Raw data payload must be copied since the declaration goes out of -scope: - -Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=202213 - ---- -From: Antoine Belvire - -Trivial rebase to apply on bluez 5.50 (only test-gatt.c hunk #4 modified). - ---- - unit/test-avctp.c | 9 +++++++-- - unit/test-avdtp.c | 13 +++++++++---- - unit/test-avrcp.c | 15 ++++++++++----- - unit/test-gatt.c | 11 +++++++++-- - unit/test-hfp.c | 13 +++++++++---- - unit/test-hog.c | 10 +++++----- - unit/test-sdp.c | 6 +++--- - 7 files changed, 52 insertions(+), 25 deletions(-) - -diff --git a/unit/test-avctp.c b/unit/test-avctp.c -index 60fd6ad71..c92618bab 100644 ---- a/unit/test-avctp.c -+++ b/unit/test-avctp.c -@@ -43,7 +43,7 @@ - - struct test_pdu { - bool valid; -- const uint8_t *data; -+ uint8_t *data; - size_t size; - }; - -@@ -66,7 +66,7 @@ struct context { - #define raw_pdu(args...) \ - { \ - .valid = true, \ -- .data = data(args), \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ - .size = sizeof(data(args)), \ - } - -@@ -84,6 +84,11 @@ struct context { - static void test_free(gconstpointer user_data) - { - const struct test_data *data = user_data; -+ struct test_pdu *pdu; -+ int i; -+ -+ for (i = 0; (pdu = &data->pdu_list[i]) && pdu->valid; i++) -+ g_free(pdu->data); - - g_free(data->test_name); - g_free(data->pdu_list); -diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c -index 176852ae7..13c03d037 100644 ---- a/unit/test-avdtp.c -+++ b/unit/test-avdtp.c -@@ -47,7 +47,7 @@ - struct test_pdu { - bool valid; - bool fragmented; -- const uint8_t *data; -+ uint8_t *data; - size_t size; - }; - -@@ -61,7 +61,7 @@ struct test_data { - #define raw_pdu(args...) \ - { \ - .valid = true, \ -- .data = data(args), \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ - .size = sizeof(data(args)), \ - } - -@@ -69,7 +69,7 @@ struct test_data { - { \ - .valid = true, \ - .fragmented = true, \ -- .data = data(args), \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ - .size = sizeof(data(args)), \ - } - -@@ -81,7 +81,7 @@ struct test_data { - static struct test_data data; \ - data.test_name = g_strdup(name); \ - data.pdu_list = g_memdup(pdus, sizeof(pdus)); \ -- tester_add(name, &data, NULL, function, NULL); \ -+ tester_add(name, &data, NULL, function, NULL); \ - } while (0) - - struct context { -@@ -102,6 +102,11 @@ struct context { - static void test_free(gconstpointer user_data) - { - const struct test_data *data = user_data; -+ struct test_pdu *pdu; -+ int i; -+ -+ for (i = 0; (pdu = &data->pdu_list[i]) && pdu->valid; i++) -+ g_free(pdu->data); - - g_free(data->test_name); - g_free(data->pdu_list); -diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c -index 9ffd44cfd..adf25f002 100644 ---- a/unit/test-avrcp.c -+++ b/unit/test-avrcp.c -@@ -49,7 +49,7 @@ struct test_pdu { - bool fragmented; - bool continuing; - bool browse; -- const uint8_t *data; -+ uint8_t *data; - size_t size; - }; - -@@ -74,7 +74,7 @@ struct context { - #define raw_pdu(args...) \ - { \ - .valid = true, \ -- .data = data(args), \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ - .size = sizeof(data(args)), \ - } - -@@ -82,7 +82,7 @@ struct context { - { \ - .valid = true, \ - .browse = true, \ -- .data = data(args), \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ - .size = sizeof(data(args)), \ - } - -@@ -90,7 +90,7 @@ struct context { - { \ - .valid = true, \ - .fragmented = true, \ -- .data = data(args), \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ - .size = sizeof(data(args)), \ - } - -@@ -98,7 +98,7 @@ struct context { - { \ - .valid = true, \ - .continuing = true, \ -- .data = data(args), \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ - .size = sizeof(data(args)), \ - } - -@@ -116,6 +116,11 @@ struct context { - static void test_free(gconstpointer user_data) - { - const struct test_data *data = user_data; -+ struct test_pdu *pdu; -+ int i; -+ -+ for (i = 0; (pdu = &data->pdu_list[i]) && pdu->valid; i++) -+ g_free(pdu->data); - - g_free(data->test_name); - g_free(data->pdu_list); -diff --git a/unit/test-gatt.c b/unit/test-gatt.c -index d8d007386..e35271b61 100644 ---- a/unit/test-gatt.c -+++ b/unit/test-gatt.c -@@ -48,7 +48,7 @@ - - struct test_pdu { - bool valid; -- const uint8_t *data; -+ uint8_t *data; - size_t size; - }; - -@@ -86,7 +86,7 @@ struct context { - #define raw_pdu(args...) \ - { \ - .valid = true, \ -- .data = data(args), \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ - .size = sizeof(data(args)), \ - } - -@@ -306,6 +306,11 @@ static bt_uuid_t uuid_char_128 = { - static void test_free(gconstpointer user_data) - { - const struct test_data *data = user_data; -+ struct test_pdu *pdu; -+ int i; -+ -+ for (i = 0; (pdu = &data->pdu_list[i]) && pdu->valid; i++) -+ g_free(pdu->data); - - g_free(data->test_name); - g_free(data->pdu_list); -@@ -1911,6 +1916,8 @@ static void test_server(gconstpointer data) - g_assert_cmpint(len, ==, pdu.size); - - util_hexdump('<', pdu.data, len, test_debug, "GATT: "); -+ -+ g_free(pdu.data); - } - - static void test_search_primary(gconstpointer data) -diff --git a/unit/test-hfp.c b/unit/test-hfp.c -index f2b9622c2..890eee659 100644 ---- a/unit/test-hfp.c -+++ b/unit/test-hfp.c -@@ -43,7 +43,7 @@ struct context { - - struct test_pdu { - bool valid; -- const uint8_t *data; -+ uint8_t *data; - size_t size; - enum hfp_gw_cmd_type type; - bool fragmented; -@@ -63,7 +63,7 @@ struct test_data { - #define raw_pdu(args...) \ - { \ - .valid = true, \ -- .data = data(args), \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ - .size = sizeof(data(args)), \ - } - -@@ -75,7 +75,7 @@ struct test_data { - #define type_pdu(cmd_type, args...) \ - { \ - .valid = true, \ -- .data = data(args), \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ - .size = sizeof(data(args)), \ - .type = cmd_type, \ - } -@@ -83,7 +83,7 @@ struct test_data { - #define frg_pdu(args...) \ - { \ - .valid = true, \ -- .data = data(args), \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ - .size = sizeof(data(args)), \ - .fragmented = true, \ - } -@@ -119,6 +119,11 @@ struct test_data { - static void test_free(gconstpointer user_data) - { - const struct test_data *data = user_data; -+ struct test_pdu *pdu; -+ int i; -+ -+ for (i = 0; (pdu = &data->pdu_list[i]) && pdu->valid; i++) -+ g_free(pdu->data); - - g_free(data->test_name); - g_free(data->pdu_list); -diff --git a/unit/test-hog.c b/unit/test-hog.c -index 37d3abe3f..e257fbd88 100644 ---- a/unit/test-hog.c -+++ b/unit/test-hog.c -@@ -69,11 +69,11 @@ struct context { - - #define data(args...) ((const unsigned char[]) { args }) - --#define raw_pdu(args...) \ --{ \ -- .valid = true, \ -- .data = data(args), \ -- .size = sizeof(data(args)),\ -+#define raw_pdu(args...) \ -+{ \ -+ .valid = true, \ -+ .data = g_memdup(data(args), sizeof(data(args))), \ -+ .size = sizeof(data(args)), \ - } - - #define false_pdu() \ -diff --git a/unit/test-sdp.c b/unit/test-sdp.c -index 66da038cd..03501d021 100644 ---- a/unit/test-sdp.c -+++ b/unit/test-sdp.c -@@ -60,14 +60,14 @@ struct test_data { - #define raw_pdu(args...) \ - { \ - .valid = true, \ -- .raw_data = raw_data(args), \ -+ .raw_data = g_memdup(raw_data(args), sizeof(raw_data(args))), \ - .raw_size = sizeof(raw_data(args)), \ - } - - #define raw_pdu_cont(cont, args...) \ - { \ - .valid = true, \ -- .raw_data = raw_data(args), \ -+ .raw_data = g_memdup(raw_data(args), sizeof(raw_data(args))), \ - .raw_size = sizeof(raw_data(args)), \ - .cont_len = cont, \ - } -@@ -105,7 +105,7 @@ struct test_data_de { - #define define_test_de_attr(name, input, exp) \ - do { \ - static struct test_data_de data; \ -- data.input_data = input; \ -+ data.input_data = g_memdup(input, sizeof(input)); \ - data.input_size = sizeof(input); \ - data.expected = exp; \ - tester_add("/sdp/DE/ATTR/" name, &data, NULL, \ --- -cgit 1.2-0.3.lf.el7 - diff --git a/bluez-5.50.tar.xz b/bluez-5.50.tar.xz deleted file mode 100644 index 7b70548..0000000 --- a/bluez-5.50.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5ffcaae18bbb6155f1591be8c24898dc12f062075a40b538b745bfd477481911 -size 1755384 diff --git a/bluez-5.51-disable-broken-tests.diff b/bluez-5.51-disable-broken-tests.diff new file mode 100644 index 0000000..b84059d --- /dev/null +++ b/bluez-5.51-disable-broken-tests.diff @@ -0,0 +1,24 @@ +Index: b/Makefile.am +=================================================================== +--- a/Makefile.am ++++ b/Makefile.am +@@ -474,7 +474,8 @@ unit_test_lib_SOURCES = unit/test-lib.c + unit_test_lib_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) + +-unit_tests += unit/test-gatt ++# hangs forever in OBS where AF_ALG is not supported. ++#unit_tests += unit/test-gatt + + unit_test_gatt_SOURCES = unit/test-gatt.c + unit_test_gatt_LDADD = src/libshared-glib.la \ +@@ -504,7 +505,8 @@ unit_test_gattrib_LDADD = lib/libbluetoo + $(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt + + if MIDI +-unit_tests += unit/test-midi ++# fails on i386??? or just random? ++#unit_tests += unit/test-midi + unit_test_midi_CPPFLAGS = $(AM_CPPFLAGS) $(ALSA_CFLAGS) -DMIDI_TEST + unit_test_midi_SOURCES = unit/test-midi.c \ + profiles/midi/libmidi.h \ diff --git a/bluez-5.51.tar.xz b/bluez-5.51.tar.xz new file mode 100644 index 0000000..6dcf402 --- /dev/null +++ b/bluez-5.51.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ebedfb359f62957940822f1d0b39fcee30422380e435608dad06bb3913d5ebba +size 1941904 diff --git a/bluez-cups-libexec.patch b/bluez-cups-libexec.patch index 0b26804..686fe83 100644 --- a/bluez-cups-libexec.patch +++ b/bluez-cups-libexec.patch @@ -1,26 +1,26 @@ -Index: bluez-5.44/Makefile.in +Index: b/Makefile.in =================================================================== ---- bluez-5.44.orig/Makefile.in -+++ bluez-5.44/Makefile.in -@@ -2710,7 +2710,7 @@ unit_tests = $(am__append_48) unit/test- +--- a/Makefile.in ++++ b/Makefile.in +@@ -3439,7 +3439,7 @@ unit_tests = $(am__append_54) unit/test- @DEPRECATED_TRUE@@READLINE_TRUE@attrib_gatttool_LDADD = lib/libbluetooth-internal.la \ - @DEPRECATED_TRUE@@READLINE_TRUE@ src/libshared-glib.la @GLIB_LIBS@ -lreadline + @DEPRECATED_TRUE@@READLINE_TRUE@ src/libshared-glib.la $(GLIB_LIBS) -lreadline -@CUPS_TRUE@cupsdir = $(libdir)/cups/backend -+@CUPS_TRUE@cupsdir = $(libexecdir)/../cups/backend ++@CUPS_TRUE@cupsdir = $(libexecdir)/cups/backend @CUPS_TRUE@profiles_cups_bluetooth_SOURCES = profiles/cups/main.c \ @CUPS_TRUE@ profiles/cups/cups.h \ @CUPS_TRUE@ profiles/cups/sdp.c \ -Index: bluez-5.44/Makefile.tools +Index: b/Makefile.tools =================================================================== ---- bluez-5.44.orig/Makefile.tools -+++ bluez-5.44/Makefile.tools -@@ -388,7 +388,7 @@ endif +--- a/Makefile.tools ++++ b/Makefile.tools +@@ -441,7 +441,7 @@ endif endif if CUPS -cupsdir = $(libdir)/cups/backend -+cupsdir = $(libexecdir)/../cups/backend ++cupsdir = $(libexecdir)/cups/backend cups_PROGRAMS = profiles/cups/bluetooth diff --git a/bluez.changes b/bluez.changes index 34d64aa..2b787b0 100644 --- a/bluez.changes +++ b/bluez.changes @@ -1,3 +1,32 @@ +------------------------------------------------------------------- +Fri Sep 20 19:32:43 UTC 2019 - Stefan Seyfried + +- update to version 5.51: + * Fix issue with first agent not being registered as default. + * Fix issue with loading devices without Service Changed CCC. + * Fix issue with GATT client and extended property reading. + * Fix issue with handling GATT client invalid read behavior. + * Fix issue with handling GATT disconnect handler removal. + * Fix issue with missing GATT/GAP service records for SDP. + * Fix issue with checking SDP continuation state length. + * Fix issue with HID device removal on HoG disconnect. + * Fix issue with AVDTP and session destroy handling. + * Fix issue with AVCTP and output MTU accounting. + * Fix issue with AVRCP and creating media items. + * Add support for GATT database caching feature. + * Add experimental support for Bluetooth Mesh Profile. +- removed obsoleted patches: + * 0001-obexd-use-AM_LDFLAGS-for-linking.patch + * 0001-policy-Add-logic-to-connect-a-Sink.patch + * 0001-tools-Fix-build-after-y2038-changes-in-glibc.patch + * bluez-5.50-a2dp-backports.patch + * bluez-5.50-gcc9.patch + * disable_some_obex_tests.patch +- refreshed bluez-cups-libexec.patch +- rebased bluez-5.45-disable-broken-tests.diff to bluez-5.51- + disable-broken-tests.diff +- add temporary rpmlintrc until security team approves + ------------------------------------------------------------------- Sun Aug 18 18:11:08 UTC 2019 - Antoine Belvire diff --git a/bluez.spec b/bluez.spec index 664b5fc..e53cad7 100644 --- a/bluez.spec +++ b/bluez.spec @@ -18,7 +18,7 @@ Name: bluez -Version: 5.50 +Version: 5.51 Release: 0 Summary: Bluetooth Stack for Linux License: GPL-2.0-or-later @@ -33,21 +33,9 @@ Patch2: bluez-sdp-unix-path.patch # PATCH-FIX-UPSTREAM: find the cups dir in libexec not in libdir Patch3: bluez-cups-libexec.patch # workaround for broken tests (reported upstream but not yet fixed) -Patch4: bluez-5.45-disable-broken-tests.diff -# PATCH-FIX-UPSTREAM: obexd not compiled with -fpie -- seife+obs@b1-systems.com -Patch5: 0001-obexd-use-AM_LDFLAGS-for-linking.patch -# disable tests for bypass boo#1078285 -Patch6: disable_some_obex_tests.patch -# PATCH-FIX-UPSTREAM: improve profile availability on some audio devices -Patch7: 0001-policy-Add-logic-to-connect-a-Sink.patch -# PATCH-FIX-UPSTREAM a2dp fixes for newer codecs -Patch8: bluez-5.50-a2dp-backports.patch -# PATCH-FIX-UPSTREAM tools: Fix build after y2038 changes in glibc -Patch9: 0001-tools-Fix-build-after-y2038-changes-in-glibc.patch +Patch4: bluez-5.51-disable-broken-tests.diff # Move 43xx firmware path for RPi3 bluetooth support bsc#1140688 Patch10: RPi-Move-the-43xx-firmware-into-lib-firmware.patch -# PATCH-FIX-UPSTREAM fix build with gcc 9, picked from upstream and rebased (boo#1121404, bko#202213) -Patch11: bluez-5.50-gcc9.patch # Upstream suggests to use btmon instead of hcidump and does not want those patches # => PATCH-FIX-OPENSUSE for those two :-) # fix some memory leak with malformed packet (reported upstream but not yet fixed) @@ -160,15 +148,7 @@ desktop specific applets like blueman or GNOME or KDE applets). %patch2 -p1 %patch3 -p1 %patch4 -p1 -%patch5 -p1 -%ifarch ppc ppc64 ppc64le -%patch6 -p1 -%endif -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 %patch10 -p1 -%patch11 -p1 %patch101 -p1 %patch102 -p1 mkdir dbus-apis @@ -289,6 +269,7 @@ make check V=0 %{_libdir}/bluetooth/plugins/sixaxis.so %dir %{_libexecdir}/bluetooth %{_libexecdir}/bluetooth/bluetoothd +%{_libexecdir}/bluetooth/bluetooth-meshd %{_libexecdir}/bluetooth/obexd %{_bindir}/bluetoothctl %{_bindir}/btmon @@ -312,12 +293,16 @@ make check V=0 %{_mandir}/man1/rfcomm.1%{ext_man} %{_mandir}/man1/rctest.1%{ext_man} %config %{_sysconfdir}/dbus-1/system.d/bluetooth.conf +%config %{_sysconfdir}/dbus-1/system.d/bluetooth-mesh.conf %dir %{_localstatedir}/lib/bluetooth %dir %{_sysconfdir}/modprobe.d %config(noreplace) %{_sysconfdir}/modprobe.d/50-bluetooth.conf %{_unitdir}/bluetooth.service +%{_unitdir}/bluetooth-mesh.service %{_datadir}/dbus-1/system-services/org.bluez.service %{_datadir}/dbus-1/services/org.bluez.obex.service +%{_datadir}/dbus-1/system-services/org.bluez.mesh.service +%{_datadir}/zsh/site-functions/_bluetoothctl %files devel %defattr(-, root, root) diff --git a/disable_some_obex_tests.patch b/disable_some_obex_tests.patch deleted file mode 100644 index d82d828..0000000 --- a/disable_some_obex_tests.patch +++ /dev/null @@ -1,28 +0,0 @@ -From: Michel Normand -Subject: disable some obex tests -Date: Tue, 30 Jan 2018 17:01:45 +0100 - -disable some obex tests as transient failures -reported by bug -https://bugzilla.suse.com/show_bug.cgi?id=1078285 - -Signed-off-by: Michel Normand ---- - Makefile.am | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -Index: bluez-5.48/Makefile.am -=================================================================== ---- bluez-5.48.orig/Makefile.am -+++ bluez-5.48/Makefile.am -@@ -363,8 +363,8 @@ unit_test_gdbus_client_SOURCES = unit/te - unit_test_gdbus_client_LDADD = gdbus/libgdbus-internal.la \ - src/libshared-glib.la @GLIB_LIBS@ @DBUS_LIBS@ - --unit_tests += unit/test-gobex-header unit/test-gobex-packet unit/test-gobex \ -- unit/test-gobex-transfer unit/test-gobex-apparam -+unit_tests += unit/test-gobex-header unit/test-gobex-packet \ -+ unit/test-gobex-apparam - - unit_test_gobex_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ - unit/test-gobex.c diff --git a/temporary-rpmlintrc b/temporary-rpmlintrc new file mode 100644 index 0000000..a70e508 --- /dev/null +++ b/temporary-rpmlintrc @@ -0,0 +1 @@ +setBadness('suse-dbus-unauthorized-service', 100)