From 234ae94fa065ce6da7ec7b99b882c94877e6bd65 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Fri, 20 Sep 2019 15:25:44 +0100 Subject: [PATCH] 5.51 --- ...emove-deprecated-at_console-statemen.patch | 43 - ...d-Always-define-confdir-and-statedir.patch | 22 +- 0001-build-Enable-BIND_NOW.patch | 31 - 0001-policy-Add-logic-to-connect-a-Sink.patch | 72 - ...x-build-after-y2038-changes-in-glibc.patch | 63 - ...ivateTmp-and-NoNewPrivileges-options.patch | 6 +- ...systemd-Add-more-filesystem-lockdown.patch | 20 +- ...ools-csr_usb-Fix-compilation-failure.patch | 41 - 0004-systemd-More-lockdown.patch | 6 +- bluez-5.50-a2dp-backports.patch | 4714 ----------------- bluez-5.50-autopair-backports.patch | 81 - bluez-5.50-discoverability-backports.patch | 1243 ----- bluez-5.50-sixaxis-fixes.patch | 60 - bluez.spec | 65 +- sources | 2 +- 15 files changed, 61 insertions(+), 6408 deletions(-) delete mode 100644 0001-bluetooth.conf-remove-deprecated-at_console-statemen.patch delete mode 100644 0001-build-Enable-BIND_NOW.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 0003-tools-csr_usb-Fix-compilation-failure.patch delete mode 100644 bluez-5.50-a2dp-backports.patch delete mode 100644 bluez-5.50-autopair-backports.patch delete mode 100644 bluez-5.50-discoverability-backports.patch delete mode 100644 bluez-5.50-sixaxis-fixes.patch diff --git a/0001-bluetooth.conf-remove-deprecated-at_console-statemen.patch b/0001-bluetooth.conf-remove-deprecated-at_console-statemen.patch deleted file mode 100644 index e73b931..0000000 --- a/0001-bluetooth.conf-remove-deprecated-at_console-statemen.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 74174217fc3f15255be875659d1e1d9403646bba Mon Sep 17 00:00:00 2001 -From: Tom Gundersen -Date: Tue, 6 Nov 2018 12:07:17 +0100 -Subject: [PATCH] bluetooth.conf: remove deprecated at_console statement - -As described in [0], this likely did not have the intended effect, so -simply remove it. The change in behavior is that up until this patch -it would be possible for root, lp, and any non-system user to potentially -gain access to bluez' dbus interface. Now this is extended to also allow -any system user. - -[0]: ---- - src/bluetooth.conf | 12 +----------- - 1 file changed, 1 insertion(+), 11 deletions(-) - -diff --git a/src/bluetooth.conf b/src/bluetooth.conf -index 0c0b221bb..05f407d1a 100644 ---- a/src/bluetooth.conf -+++ b/src/bluetooth.conf -@@ -21,18 +21,8 @@ - - - -- -- -- -- -- -- -- -- -- - -- -+ - - - --- -2.21.0 - diff --git a/0001-build-Always-define-confdir-and-statedir.patch b/0001-build-Always-define-confdir-and-statedir.patch index 6e0c8ca..2af8f18 100644 --- a/0001-build-Always-define-confdir-and-statedir.patch +++ b/0001-build-Always-define-confdir-and-statedir.patch @@ -1,35 +1,35 @@ -From 69d2e7bebb79f500179298c6c51fafbc217df6c8 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Wed, 20 Sep 2017 12:49:10 +0200 +From d0c73c6ce1ab9dc21f6a94be70475c90068e4acc Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Fri, 20 Sep 2019 14:53:03 +0100 Subject: [PATCH 1/4] build: Always define confdir and statedir As we will need those paths to lock down on them. --- - Makefile.am | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) + Makefile.am | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am -index 555f301ca..1c38d94e5 100644 +index 404e6a460..033faf3bf 100644 --- a/Makefile.am +++ b/Makefile.am -@@ -30,14 +30,14 @@ include_HEADERS = - AM_CFLAGS = $(WARNING_CFLAGS) $(MISC_CFLAGS) +@@ -31,14 +31,15 @@ pkginclude_HEADERS = + AM_CFLAGS = $(WARNING_CFLAGS) $(MISC_CFLAGS) $(UDEV_CFLAGS) $(ell_cflags) AM_LDFLAGS = $(MISC_LDFLAGS) +confdir = $(sysconfdir)/bluetooth +statedir = $(localstatedir)/lib/bluetooth + if DATAFILES - dbusdir = @DBUS_CONFDIR@/dbus-1/system.d + dbusdir = $(DBUS_CONFDIR)/dbus-1/system.d dbus_DATA = src/bluetooth.conf -confdir = $(sysconfdir)/bluetooth conf_DATA = -- + -statedir = $(localstatedir)/lib/bluetooth state_DATA = endif -- -2.14.1 +2.21.0 diff --git a/0001-build-Enable-BIND_NOW.patch b/0001-build-Enable-BIND_NOW.patch deleted file mode 100644 index b7c7e57..0000000 --- a/0001-build-Enable-BIND_NOW.patch +++ /dev/null @@ -1,31 +0,0 @@ -From e45c8fdcb3d7cdb654f6819c02d1bbb5b40b6116 Mon Sep 17 00:00:00 2001 -From: Florian Weimer -Date: Thu, 7 Nov 2013 09:23:35 +0100 -Subject: [PATCH 1/4] build: Enable BIND_NOW - -Partial RELRO means that the object is GNU_RELRO but not BIND_NOW. This -reduces the effectiveness of RELRO. bluez triggers this because it -enables PIE during the build, and rpmdiff takes this as an indicator -that the best possible hardening is desired. - -https://bugzilla.redhat.com/show_bug.cgi?id=983161 ---- - acinclude.m4 | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/acinclude.m4 b/acinclude.m4 -index bc39c6d73..efce2f3cb 100644 ---- a/acinclude.m4 -+++ b/acinclude.m4 -@@ -50,7 +50,7 @@ AC_DEFUN([MISC_FLAGS], [ - if (test "${enableval}" = "yes" && - test "${ac_cv_prog_cc_pie}" = "yes"); then - misc_cflags="$misc_cflags -fPIC" -- misc_ldflags="$misc_ldflags -pie" -+ misc_ldflags="$misc_ldflags -pie -Wl,-z,now" - fi - ]) - if (test "$enable_coverage" = "yes"); then --- -2.14.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 3a3d9a0..0000000 --- a/0001-policy-Add-logic-to-connect-a-Sink.patch +++ /dev/null @@ -1,72 +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 - -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. ---- - plugins/policy.c | 39 +++++++++++++++++++++++++++++++++++++++ - 1 file changed, 39 insertions(+) - -diff --git a/plugins/policy.c b/plugins/policy.c -index 1f5a506a2..de51e58b9 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.17.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 8e1009e..0000000 --- a/0001-tools-Fix-build-after-y2038-changes-in-glibc.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 3a8cc80e916bd9b88a33cd08ccbd99e43113d530 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Fri, 7 Jun 2019 09:25:12 +0200 -Subject: [PATCH] tools: Fix build after y2038 changes in glibc - -The 32-bit SIOCGSTAMP has been deprecated. Use the deprecated name -to fix the build. ---- - 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/0002-systemd-Add-PrivateTmp-and-NoNewPrivileges-options.patch b/0002-systemd-Add-PrivateTmp-and-NoNewPrivileges-options.patch index cd9f69e..b90a692 100644 --- a/0002-systemd-Add-PrivateTmp-and-NoNewPrivileges-options.patch +++ b/0002-systemd-Add-PrivateTmp-and-NoNewPrivileges-options.patch @@ -1,4 +1,4 @@ -From 4570164f0c90603bd07eb9e7c07e17bbafb5b5da Mon Sep 17 00:00:00 2001 +From 4e027d3c019846e216c6f76496d71c89f063ed59 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Wed, 13 Sep 2017 15:23:09 +0200 Subject: [PATCH 2/4] systemd: Add PrivateTmp and NoNewPrivileges options @@ -15,7 +15,7 @@ possible privilege escalations. 1 file changed, 6 insertions(+) diff --git a/src/bluetooth.service.in b/src/bluetooth.service.in -index f799f65f0..a6f3030f9 100644 +index f9faaa452..7c2f60bb4 100644 --- a/src/bluetooth.service.in +++ b/src/bluetooth.service.in @@ -12,8 +12,14 @@ NotifyAccess=main @@ -34,5 +34,5 @@ index f799f65f0..a6f3030f9 100644 [Install] WantedBy=bluetooth.target -- -2.14.1 +2.21.0 diff --git a/0003-systemd-Add-more-filesystem-lockdown.patch b/0003-systemd-Add-more-filesystem-lockdown.patch index 6d14e2e..33b3928 100644 --- a/0003-systemd-Add-more-filesystem-lockdown.patch +++ b/0003-systemd-Add-more-filesystem-lockdown.patch @@ -1,6 +1,6 @@ -From 73a9c0902e7c97adf96e735407a75033152c04a9 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Wed, 13 Sep 2017 15:37:11 +0200 +From 5a65aa9b9d4035f94cee1016a256cec017a42aad Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Fri, 20 Sep 2019 14:55:28 +0100 Subject: [PATCH 3/4] systemd: Add more filesystem lockdown We can only access the configuration file as read-only and read-write @@ -11,20 +11,20 @@ to the Bluetooth cache directory and sub-directories. 2 files changed, 6 insertions(+) diff --git a/Makefile.am b/Makefile.am -index 1c38d94e5..13ccf9079 100644 +index 033faf3bf..f6347a14b 100644 --- a/Makefile.am +++ b/Makefile.am -@@ -478,6 +478,8 @@ MAINTAINERCLEANFILES = Makefile.in \ +@@ -563,6 +563,8 @@ MAINTAINERCLEANFILES = Makefile.in \ SED_PROCESS = $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(SED) -e 's,@libexecdir\@,$(libexecdir),g' \ -+ -e 's,@statedir\@,$(statedir),g' \ -+ -e 's,@confdir\@,$(confdir),g' \ + $(SED) -e 's,@pkglibexecdir\@,$(pkglibexecdir),g' \ ++ -e 's,@statedir\@,$(statedir),g' \ ++ -e 's,@confdir\@,$(confdir),g' \ < $< > $@ %.service: %.service.in Makefile diff --git a/src/bluetooth.service.in b/src/bluetooth.service.in -index a6f3030f9..7e55b5043 100644 +index 7c2f60bb4..4daedef2a 100644 --- a/src/bluetooth.service.in +++ b/src/bluetooth.service.in @@ -17,6 +17,10 @@ LimitNPROC=1 @@ -39,5 +39,5 @@ index a6f3030f9..7e55b5043 100644 # Privilege escalation NoNewPrivileges=true -- -2.14.1 +2.21.0 diff --git a/0003-tools-csr_usb-Fix-compilation-failure.patch b/0003-tools-csr_usb-Fix-compilation-failure.patch deleted file mode 100644 index 1113fe7..0000000 --- a/0003-tools-csr_usb-Fix-compilation-failure.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 07a12a6685ea57be18f39e349dbc42e4af3744ed Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Tue, 5 Sep 2017 10:32:15 +0200 -Subject: [PATCH 3/4] tools/csr_usb: Fix compilation failure - -GCC's "format-nonliteral" security check is enabled as an error in -recent versions of Fedora. Given the reduced scope of use, mark the -error as ignorable through pragma. - -tools/csr_usb.c: In function 'read_value': -tools/csr_usb.c:82:2: error: format not a string literal, argument types not checked [-Werror=format-nonliteral] - n = fscanf(file, format, &value); - ^ ---- - tools/csr_usb.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/tools/csr_usb.c b/tools/csr_usb.c -index a1d7324f7..33e9968a2 100644 ---- a/tools/csr_usb.c -+++ b/tools/csr_usb.c -@@ -67,6 +67,8 @@ struct usbfs_bulktransfer { - #define USBFS_IOCTL_CLAIMINTF _IOR('U', 15, unsigned int) - #define USBFS_IOCTL_RELEASEINTF _IOR('U', 16, unsigned int) - -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wformat-nonliteral" - static int read_value(const char *name, const char *attr, const char *format) - { - char path[PATH_MAX]; -@@ -88,6 +90,7 @@ static int read_value(const char *name, const char *attr, const char *format) - fclose(file); - return value; - } -+#pragma GCC diagnostic pop - - static char *check_device(const char *name) - { --- -2.14.1 - diff --git a/0004-systemd-More-lockdown.patch b/0004-systemd-More-lockdown.patch index 3ad3e14..f4afda0 100644 --- a/0004-systemd-More-lockdown.patch +++ b/0004-systemd-More-lockdown.patch @@ -1,4 +1,4 @@ -From 171d812218883281fed57b57fafd5c18eac441ac Mon Sep 17 00:00:00 2001 +From b3ba84d0327cdda5621f3b4bde7d4cfa496d7c4a Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Wed, 13 Sep 2017 15:38:26 +0200 Subject: [PATCH 4/4] systemd: More lockdown @@ -10,7 +10,7 @@ access, so block those. 1 file changed, 6 insertions(+) diff --git a/src/bluetooth.service.in b/src/bluetooth.service.in -index 7e55b5043..e8267b338 100644 +index 4daedef2a..f18801866 100644 --- a/src/bluetooth.service.in +++ b/src/bluetooth.service.in @@ -22,9 +22,15 @@ ProtectControlGroups=true @@ -30,5 +30,5 @@ index 7e55b5043..e8267b338 100644 WantedBy=bluetooth.target Alias=dbus-org.bluez.service -- -2.14.1 +2.21.0 diff --git a/bluez-5.50-a2dp-backports.patch b/bluez-5.50-a2dp-backports.patch deleted file mode 100644 index d8fbb4d..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-autopair-backports.patch b/bluez-5.50-autopair-backports.patch deleted file mode 100644 index 8981042..0000000 --- a/bluez-5.50-autopair-backports.patch +++ /dev/null @@ -1,81 +0,0 @@ -From b83e617e98ddfce94f3209399c290c8a764ffe3e Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Mon, 27 Nov 2017 16:26:50 +0100 -Subject: [PATCH 1/2] autopair: Add more common PIN codes for audio devices - -PIN codes "1111", and "1234" are fairly common PIN codes used for audio -devices such as speakers and headsets. This replaces similar quirks -already present in gnome-bluetooth's PIN database. ---- - plugins/autopair.c | 18 ++++++++++++++---- - 1 file changed, 14 insertions(+), 4 deletions(-) - -diff --git a/plugins/autopair.c b/plugins/autopair.c -index 6980b0a64..70e19930e 100644 ---- a/plugins/autopair.c -+++ b/plugins/autopair.c -@@ -92,10 +92,20 @@ static ssize_t autopair_pincb(struct btd_adapter *adapter, - case 0x06: /* Headphones */ - case 0x07: /* Portable Audio */ - case 0x0a: /* HiFi Audio Device */ -- if (attempt > 1) -- return 0; -- memcpy(pinbuf, "0000", 4); -- return 4; -+ { -+ const char *pincodes[] = { -+ "0000", -+ "1234", -+ "1111" -+ }; -+ const char *pincode; -+ -+ if (attempt > G_N_ELEMENTS(pincodes)) -+ return 0; -+ pincode = pincodes[attempt - 1]; -+ memcpy(pinbuf, pincode, strlen(pincode)); -+ return strlen(pincode); -+ } - } - break; - --- -2.21.0 - - -From 62d8a8237e3cb5bea5333d485416cc8d8b92556c Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Mon, 27 Nov 2017 16:26:51 +0100 -Subject: [PATCH 2/2] autopair: Add pin codes to try for gaming input devices - -As well as remote controls. ---- - plugins/autopair.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/plugins/autopair.c b/plugins/autopair.c -index 70e19930e..043bd9b9d 100644 ---- a/plugins/autopair.c -+++ b/plugins/autopair.c -@@ -111,6 +111,18 @@ static ssize_t autopair_pincb(struct btd_adapter *adapter, - - case 0x05: /* Peripheral */ - switch ((class & 0xc0) >> 6) { -+ case 0x00: -+ switch ((class & 0x1e) >> 2) { -+ case 0x01: /* Joystick */ -+ case 0x02: /* Gamepad */ -+ case 0x03: /* Remote Control */ -+ if (attempt > 1) -+ return 0; -+ memcpy(pinbuf, "0000", 4); -+ return 4; -+ } -+ -+ break; - case 0x01: /* Keyboard */ - case 0x03: /* Combo keyboard/pointing device */ - /* For keyboards rejecting the first random code --- -2.21.0 - diff --git a/bluez-5.50-discoverability-backports.patch b/bluez-5.50-discoverability-backports.patch deleted file mode 100644 index 67d7d28..0000000 --- a/bluez-5.50-discoverability-backports.patch +++ /dev/null @@ -1,1243 +0,0 @@ -From c43718e84e290eaf8846baae0c1f6f1a4d464b78 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Tue, 24 Jul 2018 16:03:07 +0300 -Subject: [PATCH 01/15] client: Add discoverable-timeout command - -This adds discoverable-timeout command which can be used to get/set -DiscoverableTimeout property: - -[bluetooth]# discoverable-timeout 180 -Changing discoverable-timeout 180 succeeded ---- - client/main.c | 43 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 43 insertions(+) - -diff --git a/client/main.c b/client/main.c -index 87323d8f7..59820c6d9 100644 ---- a/client/main.c -+++ b/client/main.c -@@ -1061,6 +1061,47 @@ static void cmd_discoverable(int argc, char *argv[]) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - -+static void cmd_discoverable_timeout(int argc, char *argv[]) -+{ -+ uint32_t value; -+ char *endptr = NULL; -+ char *str; -+ -+ if (argc < 2) { -+ DBusMessageIter iter; -+ -+ if (!g_dbus_proxy_get_property(default_ctrl->proxy, -+ "DiscoverableTimeout", &iter)) { -+ bt_shell_printf("Unable to get DiscoverableTimeout\n"); -+ return bt_shell_noninteractive_quit(EXIT_FAILURE); -+ } -+ -+ dbus_message_iter_get_basic(&iter, &value); -+ -+ bt_shell_printf("DiscoverableTimeout: %d seconds\n", value); -+ -+ return; -+ } -+ -+ value = strtol(argv[1], &endptr, 0); -+ if (!endptr || *endptr != '\0' || value > UINT32_MAX) { -+ bt_shell_printf("Invalid argument\n"); -+ return bt_shell_noninteractive_quit(EXIT_FAILURE); -+ } -+ -+ str = g_strdup_printf("discoverable-timeout %d", value); -+ -+ if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, -+ "DiscoverableTimeout", -+ DBUS_TYPE_UINT32, &value, -+ generic_callback, str, g_free)) -+ return; -+ -+ g_free(str); -+ -+ return bt_shell_noninteractive_quit(EXIT_FAILURE); -+} -+ - static void cmd_agent(int argc, char *argv[]) - { - dbus_bool_t enable; -@@ -2549,6 +2590,8 @@ static const struct bt_shell_menu main_menu = { - { "discoverable", "", cmd_discoverable, - "Set controller discoverable mode", - NULL }, -+ { "discoverable-timeout", "[value]", cmd_discoverable_timeout, -+ "Set discoverable timeout", NULL }, - { "agent", "", cmd_agent, - "Enable/disable agent with given capability", - capability_generator}, --- -2.21.0 - - -From 8d6f314f517b88fa286c888281a3d70797c94135 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Wed, 25 Jul 2018 10:22:45 +0300 -Subject: [PATCH 02/15] client: Make show command print DiscoverableTimeout - -Controller XX:XX:XX:XX:XX:XX (public) - Name: Vudentz's T460s - Alias: Intel-1 - Class: 0x004c010c - Powered: yes - Discoverable: no - DiscoverableTimeout: 0x00000000 - Pairable: yes - UUID: Headset AG (00001112-0000-1000-8000-00805f9b34fb) - UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb) - UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb) - UUID: SIM Access (0000112d-0000-1000-8000-00805f9b34fb) - UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb) - UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb) - UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb) - UUID: Audio Source (0000110a-0000-1000-8000-00805f9b34fb) - UUID: Audio Sink (0000110b-0000-1000-8000-00805f9b34fb) - UUID: Headset (00001108-0000-1000-8000-00805f9b34fb) - Modalias: usb:v1D6Bp0246d0532 - Discovering: no ---- - client/main.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/client/main.c b/client/main.c -index 59820c6d9..6f472d050 100644 ---- a/client/main.c -+++ b/client/main.c -@@ -877,6 +877,7 @@ static void cmd_show(int argc, char *argv[]) - print_property(proxy, "Class"); - print_property(proxy, "Powered"); - print_property(proxy, "Discoverable"); -+ print_property(proxy, "DiscoverableTimeout"); - print_property(proxy, "Pairable"); - print_uuids(proxy); - print_property(proxy, "Modalias"); --- -2.21.0 - - -From 4dfe6d7691395dda5c711c290ec2087b3d4b79ee Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Wed, 25 Jul 2018 11:27:37 +0300 -Subject: [PATCH 03/15] adapter: Track pending settings - -This tracks settings being changed and in case the settings is already -pending considered it to be done. ---- - src/adapter.c | 30 ++++++++++++++++++++++++++++-- - 1 file changed, 28 insertions(+), 2 deletions(-) - -diff --git a/src/adapter.c b/src/adapter.c -index af340fd6e..20c20f9e9 100644 ---- a/src/adapter.c -+++ b/src/adapter.c -@@ -196,6 +196,7 @@ struct btd_adapter { - char *name; /* controller device name */ - char *short_name; /* controller short name */ - uint32_t supported_settings; /* controller supported settings */ -+ uint32_t pending_settings; /* pending controller settings */ - uint32_t current_settings; /* current controller settings */ - - char *path; /* adapter object path */ -@@ -509,8 +510,10 @@ static void settings_changed(struct btd_adapter *adapter, uint32_t settings) - changed_mask = adapter->current_settings ^ settings; - - adapter->current_settings = settings; -+ adapter->pending_settings &= ~changed_mask; - - DBG("Changed settings: 0x%08x", changed_mask); -+ DBG("Pending settings: 0x%08x", adapter->pending_settings); - - if (changed_mask & MGMT_SETTING_POWERED) { - g_dbus_emit_property_changed(dbus_conn, adapter->path, -@@ -596,10 +599,31 @@ static bool set_mode(struct btd_adapter *adapter, uint16_t opcode, - uint8_t mode) - { - struct mgmt_mode cp; -+ uint32_t setting = 0; - - memset(&cp, 0, sizeof(cp)); - cp.val = mode; - -+ switch (mode) { -+ case MGMT_OP_SET_POWERED: -+ setting = MGMT_SETTING_POWERED; -+ break; -+ case MGMT_OP_SET_CONNECTABLE: -+ setting = MGMT_SETTING_CONNECTABLE; -+ break; -+ case MGMT_OP_SET_FAST_CONNECTABLE: -+ setting = MGMT_SETTING_FAST_CONNECTABLE; -+ break; -+ case MGMT_OP_SET_DISCOVERABLE: -+ setting = MGMT_SETTING_DISCOVERABLE; -+ break; -+ case MGMT_OP_SET_BONDABLE: -+ setting = MGMT_SETTING_DISCOVERABLE; -+ break; -+ } -+ -+ adapter->pending_settings |= setting; -+ - DBG("sending set mode command for index %u", adapter->dev_id); - - if (mgmt_send(adapter->mgmt, opcode, -@@ -2739,13 +2763,15 @@ static void property_set_mode(struct btd_adapter *adapter, uint32_t setting, - else - current_enable = FALSE; - -- if (enable == current_enable) { -+ if (enable == current_enable || adapter->pending_settings & setting) { - g_dbus_pending_property_success(id); - return; - } - - mode = (enable == TRUE) ? 0x01 : 0x00; - -+ adapter->pending_settings |= setting; -+ - switch (setting) { - case MGMT_SETTING_POWERED: - opcode = MGMT_OP_SET_POWERED; -@@ -2798,7 +2824,7 @@ static void property_set_mode(struct btd_adapter *adapter, uint32_t setting, - data->id = id; - - if (mgmt_send(adapter->mgmt, opcode, adapter->dev_id, len, param, -- property_set_mode_complete, data, g_free) > 0) -+ property_set_mode_complete, data, g_free) > 0) - return; - - g_free(data); --- -2.21.0 - - -From 307f81edd84cb104989154ec0d8f1c9ece3e048a Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Wed, 25 Jul 2018 11:39:55 +0300 -Subject: [PATCH 04/15] adapter: Check pending when setting DiscoverableTimeout - -This makes DiscoverableTimeout check if discoverable is already pending -and don't attempt to set it once again which may cause discoverable to -be re-enabled when in fact the application just want to set the timeout -alone. ---- - src/adapter.c | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/src/adapter.c b/src/adapter.c -index 20c20f9e9..f92c897c7 100644 ---- a/src/adapter.c -+++ b/src/adapter.c -@@ -2901,6 +2901,7 @@ static void property_set_discoverable_timeout( - GDBusPendingPropertySet id, void *user_data) - { - struct btd_adapter *adapter = user_data; -+ bool enabled; - dbus_uint32_t value; - - dbus_message_iter_get_basic(iter, &value); -@@ -2914,8 +2915,19 @@ static void property_set_discoverable_timeout( - g_dbus_emit_property_changed(dbus_conn, adapter->path, - ADAPTER_INTERFACE, "DiscoverableTimeout"); - -+ if (adapter->pending_settings & MGMT_SETTING_DISCOVERABLE) { -+ if (adapter->current_settings & MGMT_SETTING_DISCOVERABLE) -+ enabled = false; -+ else -+ enabled = true; -+ } else { -+ if (adapter->current_settings & MGMT_SETTING_DISCOVERABLE) -+ enabled = true; -+ else -+ enabled = false; -+ } - -- if (adapter->current_settings & MGMT_SETTING_DISCOVERABLE) -+ if (enabled) - set_discoverable(adapter, 0x01, adapter->discoverable_timeout); - } - --- -2.21.0 - - -From 17070fc01c9734fd4c63704fbf08f81aac49d1b6 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Fri, 27 Jul 2018 11:14:04 +0300 -Subject: [PATCH 05/15] core: Add AlwaysPairable to main.conf - -This adds a new option called AlwaysPairable to main.conf, it can be -used to enable Adapter.Pairable even in case there is no Agent -available. - -Since that could be consider a security problem to allow pairing -without user's consent the option defaults to false. ---- - src/adapter.c | 16 +++++++++++++++- - src/agent.h | 7 +++++++ - src/device.c | 2 -- - src/hcid.h | 1 + - src/main.c | 11 +++++++++++ - src/main.conf | 5 +++++ - 6 files changed, 39 insertions(+), 3 deletions(-) - -diff --git a/src/adapter.c b/src/adapter.c -index f92c897c7..f730c1639 100644 ---- a/src/adapter.c -+++ b/src/adapter.c -@@ -7792,6 +7792,19 @@ int adapter_set_io_capability(struct btd_adapter *adapter, uint8_t io_cap) - { - struct mgmt_cp_set_io_capability cp; - -+ if (!main_opts.pairable) { -+ if (io_cap == IO_CAPABILITY_INVALID) { -+ if (adapter->current_settings & MGMT_SETTING_BONDABLE) -+ set_mode(adapter, MGMT_OP_SET_BONDABLE, 0x00); -+ -+ return 0; -+ } -+ -+ if (!(adapter->current_settings & MGMT_SETTING_BONDABLE)) -+ set_mode(adapter, MGMT_OP_SET_BONDABLE, 0x01); -+ } else if (io_cap == IO_CAPABILITY_INVALID) -+ io_cap = IO_CAPABILITY_NOINPUTNOOUTPUT; -+ - memset(&cp, 0, sizeof(cp)); - cp.io_capability = io_cap; - -@@ -8720,7 +8733,8 @@ static void read_info_complete(uint8_t status, uint16_t length, - - set_name(adapter, btd_adapter_get_name(adapter)); - -- if (!(adapter->current_settings & MGMT_SETTING_BONDABLE)) -+ if (main_opts.pairable && -+ !(adapter->current_settings & MGMT_SETTING_BONDABLE)) - set_mode(adapter, MGMT_OP_SET_BONDABLE, 0x01); - - if (!kernel_conn_control) -diff --git a/src/agent.h b/src/agent.h -index 1e4692036..f14d14325 100644 ---- a/src/agent.h -+++ b/src/agent.h -@@ -22,6 +22,13 @@ - * - */ - -+#define IO_CAPABILITY_DISPLAYONLY 0x00 -+#define IO_CAPABILITY_DISPLAYYESNO 0x01 -+#define IO_CAPABILITY_KEYBOARDONLY 0x02 -+#define IO_CAPABILITY_NOINPUTNOOUTPUT 0x03 -+#define IO_CAPABILITY_KEYBOARDDISPLAY 0x04 -+#define IO_CAPABILITY_INVALID 0xFF -+ - struct agent; - - typedef void (*agent_cb) (struct agent *agent, DBusError *err, -diff --git a/src/device.c b/src/device.c -index 4f1af7012..0d7907a69 100644 ---- a/src/device.c -+++ b/src/device.c -@@ -75,8 +75,6 @@ - #include "attrib-server.h" - #include "eir.h" - --#define IO_CAPABILITY_NOINPUTNOOUTPUT 0x03 -- - #define DISCONNECT_TIMER 2 - #define DISCOVERY_TIMER 1 - #define INVALID_FLAGS 0xff -diff --git a/src/hcid.h b/src/hcid.h -index 2c2b89d9c..ba250578a 100644 ---- a/src/hcid.h -+++ b/src/hcid.h -@@ -38,6 +38,7 @@ typedef enum { - struct main_opts { - char *name; - uint32_t class; -+ gboolean pairable; - uint32_t pairto; - uint32_t discovto; - uint8_t privacy; -diff --git a/src/main.c b/src/main.c -index 7e6af42cd..156406343 100644 ---- a/src/main.c -+++ b/src/main.c -@@ -81,6 +81,7 @@ static const char *supported_options[] = { - "Name", - "Class", - "DiscoverableTimeout", -+ "AlwaysPairable" - "PairableTimeout", - "DeviceID", - "ReverseServiceDiscovery", -@@ -287,6 +288,16 @@ static void parse_config(GKeyFile *config) - main_opts.discovto = val; - } - -+ boolean = g_key_file_get_boolean(config, "General", -+ "AlwaysPairable", &err); -+ if (err) { -+ DBG("%s", err->message); -+ g_clear_error(&err); -+ } else { -+ DBG("pairable=%s", boolean ? "true" : "false"); -+ main_opts.pairable = boolean; -+ } -+ - val = g_key_file_get_integer(config, "General", - "PairableTimeout", &err); - if (err) { -diff --git a/src/main.conf b/src/main.conf -index cbae32ec5..0d480d183 100644 ---- a/src/main.conf -+++ b/src/main.conf -@@ -13,6 +13,11 @@ - # 0 = disable timer, i.e. stay discoverable forever - #DiscoverableTimeout = 0 - -+# Always allow pairing even if there are no agent registered -+# Possible values: true, false -+# Default: false -+#AlwaysPairable = false -+ - # How long to stay in pairable mode before going back to non-discoverable - # The value is in seconds. Default is 0. - # 0 = disable timer, i.e. stay pairable forever --- -2.21.0 - - -From 27a5db2185864d7d4a8b51199c86b5c69ecc6fa3 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Fri, 27 Jul 2018 11:01:04 +0300 -Subject: [PATCH 06/15] agent: Make the first agent to register the default - -This simplifies the handling of default agent and enforce the IO -capabilities to be set whenever there is an agent available in the -system. ---- - src/agent.c | 14 ++++++-------- - 1 file changed, 6 insertions(+), 8 deletions(-) - -diff --git a/src/agent.c b/src/agent.c -index ff44d5755..183e2f190 100644 ---- a/src/agent.c -+++ b/src/agent.c -@@ -50,13 +50,6 @@ - #include "agent.h" - #include "shared/queue.h" - --#define IO_CAPABILITY_DISPLAYONLY 0x00 --#define IO_CAPABILITY_DISPLAYYESNO 0x01 --#define IO_CAPABILITY_KEYBOARDONLY 0x02 --#define IO_CAPABILITY_NOINPUTNOOUTPUT 0x03 --#define IO_CAPABILITY_KEYBOARDDISPLAY 0x04 --#define IO_CAPABILITY_INVALID 0xFF -- - #define REQUEST_TIMEOUT (60 * 1000) /* 60 seconds */ - #define AGENT_INTERFACE "org.bluez.Agent1" - -@@ -150,7 +143,7 @@ static void set_io_cap(struct btd_adapter *adapter, gpointer user_data) - if (agent) - io_cap = agent->capability; - else -- io_cap = IO_CAPABILITY_NOINPUTNOOUTPUT; -+ io_cap = IO_CAPABILITY_INVALID; - - adapter_set_io_capability(adapter, io_cap); - } -@@ -294,6 +287,11 @@ static struct agent *agent_create( const char *name, const char *path, - name, agent_disconnect, - agent, NULL); - -+ if (queue_isempty(default_agents)) -+ add_default_agent(agent); -+ else -+ queue_push_tail(default_agents, agent); -+ - return agent_ref(agent); - } - --- -2.21.0 - - -From dc29a486f90e437de541f0e5644465a8f91121aa Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Thu, 26 Jul 2018 15:15:12 +0300 -Subject: [PATCH 07/15] doc/adapter-api: Add Discoverable option to - SetDiscoveryFilter - -This enables the client to set its discoverable setting while -discovering which is very typical situation as usually the setings -application would allow incoming pairing request while scanning, so -this would reduce the number of calls setting Discoverable and -DiscoverableTimeout and restoring after done with discovery. ---- - doc/adapter-api.txt | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt -index d14d0ca50..4791af2c7 100644 ---- a/doc/adapter-api.txt -+++ b/doc/adapter-api.txt -@@ -113,6 +113,12 @@ Methods void StartDiscovery() - generated for either ManufacturerData and - ServiceData everytime they are discovered. - -+ bool Discoverable (Default: false) -+ -+ Make adapter discoverable while discovering, -+ if the adapter is already discoverable this -+ setting this filter won't do anything. -+ - When discovery filter is set, Device objects will be - created as new devices with matching criteria are - discovered regardless of they are connectable or --- -2.21.0 - - -From febbee4d7eee29a8e69039ec2aa82b7ea68163d1 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Thu, 26 Jul 2018 15:23:05 +0300 -Subject: [PATCH 08/15] adapter: Discovery filter discoverable - -This implements the discovery filter discoverable and tracks which -clients had enabled it and restores the settings when the last client -enabling it exits. ---- - src/adapter.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 54 insertions(+), 2 deletions(-) - -diff --git a/src/adapter.c b/src/adapter.c -index f730c1639..ecd2c40ae 100644 ---- a/src/adapter.c -+++ b/src/adapter.c -@@ -157,6 +157,7 @@ struct discovery_filter { - int16_t rssi; - GSList *uuids; - bool duplicate; -+ bool discoverable; - }; - - struct watch_client { -@@ -219,6 +220,7 @@ struct btd_adapter { - uint8_t discovery_type; /* current active discovery type */ - uint8_t discovery_enable; /* discovery enabled/disabled */ - bool discovery_suspended; /* discovery has been suspended */ -+ bool discovery_discoverable; /* discoverable while discovering */ - GSList *discovery_list; /* list of discovery clients */ - GSList *set_filter_list; /* list of clients that specified - * filter, but don't scan yet -@@ -1842,6 +1844,20 @@ static void discovery_free(void *user_data) - g_free(client); - } - -+static bool set_discovery_discoverable(struct btd_adapter *adapter, bool enable) -+{ -+ if (adapter->discovery_discoverable == enable) -+ return true; -+ -+ /* Reset discoverable filter if already set */ -+ if (enable && (adapter->current_settings & MGMT_OP_SET_DISCOVERABLE)) -+ return true; -+ -+ adapter->discovery_discoverable = enable; -+ -+ return set_discoverable(adapter, enable, 0); -+} -+ - static void discovery_remove(struct watch_client *client) - { - struct btd_adapter *adapter = client->adapter; -@@ -2090,6 +2106,8 @@ static bool filters_equal(struct mgmt_cp_start_service_discovery *a, - static int update_discovery_filter(struct btd_adapter *adapter) - { - struct mgmt_cp_start_service_discovery *sd_cp; -+ GSList *l; -+ - - DBG(""); - -@@ -2099,6 +2117,18 @@ static int update_discovery_filter(struct btd_adapter *adapter) - return -ENOMEM; - } - -+ for (l = adapter->discovery_list; l; l = g_slist_next(l)) { -+ struct watch_client *client = l->data; -+ -+ if (!client->discovery_filter) -+ continue; -+ -+ if (client->discovery_filter->discoverable) -+ break; -+ } -+ -+ set_discovery_discoverable(adapter, l ? true : false); -+ - /* - * If filters are equal, then don't update scan, except for when - * starting discovery. -@@ -2130,6 +2160,9 @@ static int discovery_stop(struct watch_client *client) - return 0; - } - -+ if (adapter->discovery_discoverable) -+ set_discovery_discoverable(adapter, false); -+ - /* - * In the idle phase of a discovery, there is no need to stop it - * and so it is enough to send out the signal and just return. -@@ -2224,6 +2257,7 @@ static DBusMessage *start_discovery(DBusConnection *conn, - adapter->set_filter_list, client); - adapter->discovery_list = g_slist_prepend( - adapter->discovery_list, client); -+ - goto done; - } - -@@ -2348,6 +2382,17 @@ static bool parse_duplicate_data(DBusMessageIter *value, - return true; - } - -+static bool parse_discoverable(DBusMessageIter *value, -+ struct discovery_filter *filter) -+{ -+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) -+ return false; -+ -+ dbus_message_iter_get_basic(value, &filter->discoverable); -+ -+ return true; -+} -+ - struct filter_parser { - const char *name; - bool (*func)(DBusMessageIter *iter, struct discovery_filter *filter); -@@ -2357,6 +2402,7 @@ struct filter_parser { - { "Pathloss", parse_pathloss }, - { "Transport", parse_transport }, - { "DuplicateData", parse_duplicate_data }, -+ { "Discoverable", parse_discoverable }, - { } - }; - -@@ -2396,6 +2442,7 @@ static bool parse_discovery_filter_dict(struct btd_adapter *adapter, - (*filter)->rssi = DISTANCE_VAL_INVALID; - (*filter)->type = get_scan_type(adapter); - (*filter)->duplicate = false; -+ (*filter)->discoverable = false; - - dbus_message_iter_init(msg, &iter); - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || -@@ -2441,8 +2488,10 @@ static bool parse_discovery_filter_dict(struct btd_adapter *adapter, - goto invalid_args; - - DBG("filtered discovery params: transport: %d rssi: %d pathloss: %d " -- " duplicate data: %s ", (*filter)->type, (*filter)->rssi, -- (*filter)->pathloss, (*filter)->duplicate ? "true" : "false"); -+ " duplicate data: %s discoverable %s", (*filter)->type, -+ (*filter)->rssi, (*filter)->pathloss, -+ (*filter)->duplicate ? "true" : "false", -+ (*filter)->discoverable ? "true" : "false"); - - return true; - -@@ -2880,6 +2929,9 @@ static void property_set_discoverable(const GDBusPropertyTable *property, - return; - } - -+ /* Reset discovery_discoverable as Discoverable takes precedence */ -+ adapter->discovery_discoverable = false; -+ - property_set_mode(adapter, MGMT_SETTING_DISCOVERABLE, iter, id); - } - --- -2.21.0 - - -From c3ac3db663fe09c6c6b12a0738001e53d6971e29 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Thu, 26 Jul 2018 15:26:30 +0300 -Subject: [PATCH 09/15] client: Add scan.discoverable command - -This adds discoverable command to scan menu which can be used to set -if adapter should become discoverable while scanning: - -[bluetooth]# scan.discoverable on -[bluetooth]# scan on -SetDiscoveryFilter success -[CHG] Controller XX:XX:XX:XX:XX:XX Discoverable: yes -Discovery started -[CHG] Controller XX:XX:XX:XX:XX:XX Discovering: yes -[bluetooth]# scan off -Discovery stopped -[CHG] Controller XX:XX:XX:XX:XX:XX Discoverable: no ---- - client/main.c | 29 +++++++++++++++++++++++++++++ - 1 file changed, 29 insertions(+) - -diff --git a/client/main.c b/client/main.c -index 6f472d050..6e6f6d2fb 100644 ---- a/client/main.c -+++ b/client/main.c -@@ -1166,6 +1166,7 @@ static struct set_discovery_filter_args { - char **uuids; - size_t uuids_len; - dbus_bool_t duplicate; -+ dbus_bool_t discoverable; - bool set; - } filter = { - .rssi = DISTANCE_VAL_INVALID, -@@ -1205,6 +1206,11 @@ static void set_discovery_filter_setup(DBusMessageIter *iter, void *user_data) - DBUS_TYPE_BOOLEAN, - &args->duplicate); - -+ if (args->discoverable) -+ g_dbus_dict_append_entry(&dict, "Discoverable", -+ DBUS_TYPE_BOOLEAN, -+ &args->discoverable); -+ - dbus_message_iter_close_container(iter, &dict); - } - -@@ -1362,6 +1368,26 @@ static void cmd_scan_filter_duplicate_data(int argc, char *argv[]) - filter.set = false; - } - -+static void cmd_scan_filter_discoverable(int argc, char *argv[]) -+{ -+ if (argc < 2 || !strlen(argv[1])) { -+ bt_shell_printf("Discoverable: %s\n", -+ filter.discoverable ? "on" : "off"); -+ return bt_shell_noninteractive_quit(EXIT_SUCCESS); -+ } -+ -+ if (!strcmp(argv[1], "on")) -+ filter.discoverable = true; -+ else if (!strcmp(argv[1], "off")) -+ filter.discoverable = false; -+ else { -+ bt_shell_printf("Invalid option: %s\n", argv[1]); -+ return bt_shell_noninteractive_quit(EXIT_FAILURE); -+ } -+ -+ filter.set = false; -+} -+ - static void filter_clear_uuids(void) - { - g_strfreev(filter.uuids); -@@ -2510,6 +2536,9 @@ static const struct bt_shell_menu scan_menu = { - { "duplicate-data", "[on/off]", cmd_scan_filter_duplicate_data, - "Set/Get duplicate data filter", - NULL }, -+ { "discoverable", "[on/off]", cmd_scan_filter_discoverable, -+ "Set/Get discoverable filter", -+ NULL }, - { "clear", "[uuids/rssi/pathloss/transport/duplicate-data]", - cmd_scan_filter_clear, - "Clears discovery filter.", --- -2.21.0 - - -From a8f14e570ab1b39c360ff194d0df54f7190704cf Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Thu, 26 Jul 2018 15:40:55 +0300 -Subject: [PATCH 10/15] client: Add scan.clear discoverable - -This implements scan.clear for discoverable filter. ---- - client/main.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/client/main.c b/client/main.c -index 6e6f6d2fb..1a66a3ab4 100644 ---- a/client/main.c -+++ b/client/main.c -@@ -1416,6 +1416,11 @@ static void filter_clear_duplicate(void) - filter.duplicate = false; - } - -+static void filter_clear_discoverable(void) -+{ -+ filter.discoverable = false; -+} -+ - struct clear_entry { - const char *name; - void (*clear) (void); -@@ -1427,6 +1432,7 @@ static const struct clear_entry filter_clear[] = { - { "pathloss", filter_clear_pathloss }, - { "transport", filter_clear_transport }, - { "duplicate-data", filter_clear_duplicate }, -+ { "discoverable", filter_clear_discoverable }, - {} - }; - -@@ -2539,7 +2545,8 @@ static const struct bt_shell_menu scan_menu = { - { "discoverable", "[on/off]", cmd_scan_filter_discoverable, - "Set/Get discoverable filter", - NULL }, -- { "clear", "[uuids/rssi/pathloss/transport/duplicate-data]", -+ { "clear", -+ "[uuids/rssi/pathloss/transport/duplicate-data/discoverable]", - cmd_scan_filter_clear, - "Clears discovery filter.", - filter_clear_generator }, --- -2.21.0 - - -From 1ab3a106737f6b71dd6ebb5f180a25491212a5b7 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Thu, 26 Jul 2018 17:13:12 +0300 -Subject: [PATCH 11/15] adapter: Fix not keeping discovery filters - -If the discovery has been stopped and the client has set filters those -should be put back into filter list since the client may still be -interested in using them the next time it start a scanning. ---- - src/adapter.c | 25 ++++++++++++++++--------- - 1 file changed, 16 insertions(+), 9 deletions(-) - -diff --git a/src/adapter.c b/src/adapter.c -index ecd2c40ae..c24432125 100644 ---- a/src/adapter.c -+++ b/src/adapter.c -@@ -1858,7 +1858,7 @@ static bool set_discovery_discoverable(struct btd_adapter *adapter, bool enable) - return set_discoverable(adapter, enable, 0); - } - --static void discovery_remove(struct watch_client *client) -+static void discovery_remove(struct watch_client *client, bool exit) - { - struct btd_adapter *adapter = client->adapter; - -@@ -1870,7 +1870,11 @@ static void discovery_remove(struct watch_client *client) - adapter->discovery_list = g_slist_remove(adapter->discovery_list, - client); - -- discovery_free(client); -+ if (!exit && client->discovery_filter) -+ adapter->set_filter_list = g_slist_prepend( -+ adapter->set_filter_list, client); -+ else -+ discovery_free(client); - - /* - * If there are other client discoveries in progress, then leave -@@ -1899,8 +1903,11 @@ static void stop_discovery_complete(uint8_t status, uint16_t length, - goto done; - } - -- if (client->msg) -+ if (client->msg) { - g_dbus_send_reply(dbus_conn, client->msg, DBUS_TYPE_INVALID); -+ dbus_message_unref(client->msg); -+ client->msg = NULL; -+ } - - adapter->discovery_type = 0x00; - adapter->discovery_enable = 0x00; -@@ -1913,7 +1920,7 @@ static void stop_discovery_complete(uint8_t status, uint16_t length, - trigger_passive_scanning(adapter); - - done: -- discovery_remove(client); -+ discovery_remove(client, false); - } - - static int compare_sender(gconstpointer a, gconstpointer b) -@@ -2148,14 +2155,14 @@ static int update_discovery_filter(struct btd_adapter *adapter) - return -EINPROGRESS; - } - --static int discovery_stop(struct watch_client *client) -+static int discovery_stop(struct watch_client *client, bool exit) - { - struct btd_adapter *adapter = client->adapter; - struct mgmt_cp_stop_discovery cp; - - /* Check if there are more client discovering */ - if (g_slist_next(adapter->discovery_list)) { -- discovery_remove(client); -+ discovery_remove(client, exit); - update_discovery_filter(adapter); - return 0; - } -@@ -2168,7 +2175,7 @@ static int discovery_stop(struct watch_client *client) - * and so it is enough to send out the signal and just return. - */ - if (adapter->discovery_enable == 0x00) { -- discovery_remove(client); -+ discovery_remove(client, exit); - adapter->discovering = false; - g_dbus_emit_property_changed(dbus_conn, adapter->path, - ADAPTER_INTERFACE, "Discovering"); -@@ -2193,7 +2200,7 @@ static void discovery_disconnect(DBusConnection *conn, void *user_data) - - DBG("owner %s", client->owner); - -- discovery_stop(client); -+ discovery_stop(client, true); - } - - /* -@@ -2583,7 +2590,7 @@ static DBusMessage *stop_discovery(DBusConnection *conn, - if (client->msg) - return btd_error_busy(msg); - -- err = discovery_stop(client); -+ err = discovery_stop(client, false); - switch (err) { - case 0: - return dbus_message_new_method_return(msg); --- -2.21.0 - - -From 38706123e9bf05169793589e7f452f3600ce4980 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Mon, 30 Jul 2018 14:11:38 +0300 -Subject: [PATCH 12/15] client: Commit changes to scan filter if active - -This detects if the command scan has been triggered and if so commit -changes to filter immediately so they take effect in the current -session. ---- - client/main.c | 55 +++++++++++++++++++++++++++++++++++---------------- - 1 file changed, 38 insertions(+), 17 deletions(-) - -diff --git a/client/main.c b/client/main.c -index 1a66a3ab4..4d848176c 100644 ---- a/client/main.c -+++ b/client/main.c -@@ -1139,6 +1139,24 @@ static void cmd_default_agent(int argc, char *argv[]) - agent_default(dbus_conn, agent_manager); - } - -+#define DISTANCE_VAL_INVALID 0x7FFF -+ -+static struct set_discovery_filter_args { -+ char *transport; -+ dbus_uint16_t rssi; -+ dbus_int16_t pathloss; -+ char **uuids; -+ size_t uuids_len; -+ dbus_bool_t duplicate; -+ dbus_bool_t discoverable; -+ bool set; -+ bool active; -+} filter = { -+ .rssi = DISTANCE_VAL_INVALID, -+ .pathloss = DISTANCE_VAL_INVALID, -+ .set = true, -+}; -+ - static void start_discovery_reply(DBusMessage *message, void *user_data) - { - dbus_bool_t enable = GPOINTER_TO_UINT(user_data); -@@ -1154,26 +1172,11 @@ static void start_discovery_reply(DBusMessage *message, void *user_data) - } - - bt_shell_printf("Discovery %s\n", enable ? "started" : "stopped"); -+ -+ filter.active = enable; - /* Leave the discovery running even on noninteractive mode */ - } - --#define DISTANCE_VAL_INVALID 0x7FFF -- --static struct set_discovery_filter_args { -- char *transport; -- dbus_uint16_t rssi; -- dbus_int16_t pathloss; -- char **uuids; -- size_t uuids_len; -- dbus_bool_t duplicate; -- dbus_bool_t discoverable; -- bool set; --} filter = { -- .rssi = DISTANCE_VAL_INVALID, -- .pathloss = DISTANCE_VAL_INVALID, -- .set = true, --}; -- - static void set_discovery_filter_setup(DBusMessageIter *iter, void *user_data) - { - struct set_discovery_filter_args *args = user_data; -@@ -1302,6 +1305,9 @@ static void cmd_scan_filter_uuids(int argc, char *argv[]) - - commit: - filter.set = false; -+ -+ if (filter.active) -+ set_discovery_filter(); - } - - static void cmd_scan_filter_rssi(int argc, char *argv[]) -@@ -1316,6 +1322,9 @@ static void cmd_scan_filter_rssi(int argc, char *argv[]) - filter.rssi = atoi(argv[1]); - - filter.set = false; -+ -+ if (filter.active) -+ set_discovery_filter(); - } - - static void cmd_scan_filter_pathloss(int argc, char *argv[]) -@@ -1331,6 +1340,9 @@ static void cmd_scan_filter_pathloss(int argc, char *argv[]) - filter.pathloss = atoi(argv[1]); - - filter.set = false; -+ -+ if (filter.active) -+ set_discovery_filter(); - } - - static void cmd_scan_filter_transport(int argc, char *argv[]) -@@ -1346,6 +1358,9 @@ static void cmd_scan_filter_transport(int argc, char *argv[]) - filter.transport = g_strdup(argv[1]); - - filter.set = false; -+ -+ if (filter.active) -+ set_discovery_filter(); - } - - static void cmd_scan_filter_duplicate_data(int argc, char *argv[]) -@@ -1366,6 +1381,9 @@ static void cmd_scan_filter_duplicate_data(int argc, char *argv[]) - } - - filter.set = false; -+ -+ if (filter.active) -+ set_discovery_filter(); - } - - static void cmd_scan_filter_discoverable(int argc, char *argv[]) -@@ -1386,6 +1404,9 @@ static void cmd_scan_filter_discoverable(int argc, char *argv[]) - } - - filter.set = false; -+ -+ if (filter.active) -+ set_discovery_filter(); - } - - static void filter_clear_uuids(void) --- -2.21.0 - - -From 43e27149272b09159a9d15af74099fe901b24d66 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Wed, 1 Aug 2018 14:21:55 +0300 -Subject: [PATCH 13/15] client: Fix not resetting filters on scan.clear - -If call to SetDiscoveryFilter comes with any value set the daemon will -not attempt to clear the filters, instead the client is suppose to send -an empty dict. ---- - client/main.c | 39 ++++++++++++++++++++++++++++----------- - 1 file changed, 28 insertions(+), 11 deletions(-) - -diff --git a/client/main.c b/client/main.c -index 4d848176c..196b31a4d 100644 ---- a/client/main.c -+++ b/client/main.c -@@ -1177,6 +1177,19 @@ static void start_discovery_reply(DBusMessage *message, void *user_data) - /* Leave the discovery running even on noninteractive mode */ - } - -+static void clear_discovery_filter(DBusMessageIter *iter, void *user_data) -+{ -+ DBusMessageIter dict; -+ -+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, -+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING -+ DBUS_TYPE_STRING_AS_STRING -+ DBUS_TYPE_VARIANT_AS_STRING -+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); -+ -+ dbus_message_iter_close_container(iter, &dict); -+} -+ - static void set_discovery_filter_setup(DBusMessageIter *iter, void *user_data) - { - struct set_discovery_filter_args *args = user_data; -@@ -1236,14 +1249,18 @@ static void set_discovery_filter_reply(DBusMessage *message, void *user_data) - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - } - --static void set_discovery_filter(void) -+static void set_discovery_filter(bool cleared) - { -+ GDBusSetupFunction func; -+ - if (check_default_ctrl() == FALSE || filter.set) - return; - -+ func = cleared ? clear_discovery_filter : set_discovery_filter_setup; -+ - if (g_dbus_proxy_method_call(default_ctrl->proxy, "SetDiscoveryFilter", -- set_discovery_filter_setup, set_discovery_filter_reply, -- &filter, NULL) == FALSE) { -+ func, set_discovery_filter_reply, -+ &filter, NULL) == FALSE) { - bt_shell_printf("Failed to set discovery filter\n"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -@@ -1263,7 +1280,7 @@ static void cmd_scan(int argc, char *argv[]) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - if (enable == TRUE) { -- set_discovery_filter(); -+ set_discovery_filter(false); - method = "StartDiscovery"; - } else - method = "StopDiscovery"; -@@ -1307,7 +1324,7 @@ commit: - filter.set = false; - - if (filter.active) -- set_discovery_filter(); -+ set_discovery_filter(false); - } - - static void cmd_scan_filter_rssi(int argc, char *argv[]) -@@ -1324,7 +1341,7 @@ static void cmd_scan_filter_rssi(int argc, char *argv[]) - filter.set = false; - - if (filter.active) -- set_discovery_filter(); -+ set_discovery_filter(false); - } - - static void cmd_scan_filter_pathloss(int argc, char *argv[]) -@@ -1342,7 +1359,7 @@ static void cmd_scan_filter_pathloss(int argc, char *argv[]) - filter.set = false; - - if (filter.active) -- set_discovery_filter(); -+ set_discovery_filter(false); - } - - static void cmd_scan_filter_transport(int argc, char *argv[]) -@@ -1360,7 +1377,7 @@ static void cmd_scan_filter_transport(int argc, char *argv[]) - filter.set = false; - - if (filter.active) -- set_discovery_filter(); -+ set_discovery_filter(false); - } - - static void cmd_scan_filter_duplicate_data(int argc, char *argv[]) -@@ -1383,7 +1400,7 @@ static void cmd_scan_filter_duplicate_data(int argc, char *argv[]) - filter.set = false; - - if (filter.active) -- set_discovery_filter(); -+ set_discovery_filter(false); - } - - static void cmd_scan_filter_discoverable(int argc, char *argv[]) -@@ -1406,7 +1423,7 @@ static void cmd_scan_filter_discoverable(int argc, char *argv[]) - filter.set = false; - - if (filter.active) -- set_discovery_filter(); -+ set_discovery_filter(false); - } - - static void filter_clear_uuids(void) -@@ -1518,7 +1535,7 @@ static void cmd_scan_filter_clear(int argc, char *argv[]) - if (check_default_ctrl() == FALSE) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - -- set_discovery_filter(); -+ set_discovery_filter(all); - } - - static struct GDBusProxy *find_device(int argc, char *argv[]) --- -2.21.0 - - -From b47955a4003910c9eacac3d6e96bfb4f545e33e0 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Wed, 1 Aug 2018 16:08:36 +0300 -Subject: [PATCH 14/15] doc/adapter-api: Fix working of Discoverable filter - ---- - doc/adapter-api.txt | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt -index 4791af2c7..2afd61bc3 100644 ---- a/doc/adapter-api.txt -+++ b/doc/adapter-api.txt -@@ -116,8 +116,8 @@ Methods void StartDiscovery() - bool Discoverable (Default: false) - - Make adapter discoverable while discovering, -- if the adapter is already discoverable this -- setting this filter won't do anything. -+ if the adapter is already discoverable setting -+ this filter won't do anything. - - When discovery filter is set, Device objects will be - created as new devices with matching criteria are --- -2.21.0 - - -From 608b35d6354d22092af7f6907ce7a974f9cfb3d2 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz -Date: Fri, 28 Sep 2018 16:08:32 +0300 -Subject: [PATCH 15/15] sdp: Fix buffer overflow -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -sdp_append_buf shall check if there is enough space to store the data -before copying it. - -An independent security researcher, Julian Rauchberger, has reported -this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure -program. ---- - lib/sdp.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/lib/sdp.c b/lib/sdp.c -index eb408a948..84311eda1 100644 ---- a/lib/sdp.c -+++ b/lib/sdp.c -@@ -2834,6 +2834,12 @@ void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len) - SDPDBG("Append src size: %d", len); - SDPDBG("Append dst size: %d", dst->data_size); - SDPDBG("Dst buffer size: %d", dst->buf_size); -+ -+ if (dst->data_size + len > dst->buf_size) { -+ SDPERR("Cannot append"); -+ return; -+ } -+ - if (dst->data_size == 0 && dtd == 0) { - /* create initial sequence */ - *p = SDP_SEQ8; --- -2.21.0 - diff --git a/bluez-5.50-sixaxis-fixes.patch b/bluez-5.50-sixaxis-fixes.patch deleted file mode 100644 index 403100d..0000000 --- a/bluez-5.50-sixaxis-fixes.patch +++ /dev/null @@ -1,60 +0,0 @@ -From f12e00b5127589589d476817cb528d442c30b2c7 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Thu, 6 Jun 2019 18:42:42 +0200 -Subject: [PATCH 1/2] sixaxis: Fix another problem with already setup devices - -If the device went through any kind of pairing once, it might have been -set as trusted. Make sure to set the device as untrusted before starting -the cable pairing authorization so that we don't exit early from -process_auth_queue() (which considers trusted devices to be paired). ---- - plugins/sixaxis.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c -index fed68d2d8..12638829b 100644 ---- a/plugins/sixaxis.c -+++ b/plugins/sixaxis.c -@@ -365,6 +365,7 @@ static bool setup_device(int fd, const char *sysfs_path, - - btd_device_device_set_name(device, cp->name); - btd_device_set_pnpid(device, cp->source, cp->vid, cp->pid, cp->version); -+ btd_device_set_trusted(device, false); - btd_device_set_temporary(device, true); - - closure = g_new0(struct authentication_closure, 1); --- -2.21.0 - - -From 32f6e03823970796b7e08718fe28c76c96de32ac Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Thu, 6 Jun 2019 18:46:23 +0200 -Subject: [PATCH 2/2] sixaxis: Throw an error when cable setup fails - -If btd_request_authorization_cable_configured() fails, throw an error -and free resources. ---- - plugins/sixaxis.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c -index 12638829b..939fed759 100644 ---- a/plugins/sixaxis.c -+++ b/plugins/sixaxis.c -@@ -384,6 +384,12 @@ static bool setup_device(int fd, const char *sysfs_path, - adapter_bdaddr, &device_bdaddr, - HID_UUID, agent_auth_cb, closure); - -+ if (closure->auth_id == 0) { -+ error("sixaxis: could not request cable authorization"); -+ auth_closure_destroy(closure, true); -+ return false; -+ } -+ - g_hash_table_insert(pending_auths, closure->sysfs_path, closure); - - return true; --- -2.21.0 - diff --git a/bluez.spec b/bluez.spec index d599d87..f76de96 100644 --- a/bluez.spec +++ b/bluez.spec @@ -1,7 +1,7 @@ Name: bluez +Version: 5.51 +Release: 1%{?dist} Summary: Bluetooth utilities -Version: 5.50 -Release: 9%{?dist} License: GPLv2+ URL: http://www.bluez.org/ @@ -14,35 +14,14 @@ Source2: 69-btattach-bcm.rules Source3: btattach-bcm@.service Source4: btattach-bcm-service.sh -# https://github.com/hadess/bluez/commits/build-fixes-5.46 -Patch1: 0001-build-Enable-BIND_NOW.patch -Patch2: 0003-tools-csr_usb-Fix-compilation-failure.patch - # https://github.com/hadess/bluez/commits/obex-5.46 -Patch3: 0001-obex-Use-GLib-helper-function-to-manipulate-paths.patch +Patch1: 0001-obex-Use-GLib-helper-function-to-manipulate-paths.patch # https://github.com/hadess/bluez/commits/systemd-hardening -Patch20: 0001-build-Always-define-confdir-and-statedir.patch -Patch21: 0002-systemd-Add-PrivateTmp-and-NoNewPrivileges-options.patch -Patch22: 0003-systemd-Add-more-filesystem-lockdown.patch -Patch23: 0004-systemd-More-lockdown.patch - -# Fix A2DP disconnection with some headsets -Patch30: 0001-policy-Add-logic-to-connect-a-Sink.patch - -# Backports: -# https://bugzilla.redhat.com/show_bug.cgi?id=1711594 -Patch40: 0001-bluetooth.conf-remove-deprecated-at_console-statemen.patch -# autopair enhancements -Patch41: bluez-5.50-autopair-backports.patch -# Discoverable filters support, as used in gnome-bluetooth -Patch42: bluez-5.50-discoverability-backports.patch -# a2dp fixes for newer codecs -Patch43: bluez-5.50-a2dp-backports.patch -# sixaxis pairing fixes -Patch44: bluez-5.50-sixaxis-fixes.patch -# y2038 build fix -Patch45: 0001-tools-Fix-build-after-y2038-changes-in-glibc.patch +Patch10: 0001-build-Always-define-confdir-and-statedir.patch +Patch11: 0002-systemd-Add-PrivateTmp-and-NoNewPrivileges-options.patch +Patch12: 0003-systemd-Add-more-filesystem-lockdown.patch +Patch13: 0004-systemd-More-lockdown.patch BuildRequires: git-core BuildRequires: dbus-devel >= 1.6 @@ -103,6 +82,10 @@ Requires: cups Summary: Put HID proxying bluetooth HCI's into HCI mode Requires: bluez%{?_isa} = %{version}-%{release} +%package mesh +Summary: Bluetooth mesh +Requires: bluez-libs%{?_isa} = %{version}-%{release} + %package obexd Summary: Object Exchange daemon for sharing content Requires: bluez%{?_isa} = %{version}-%{release} @@ -137,6 +120,9 @@ them again. Since you cannot use your bluetooth keyboard and mouse until they are paired, this will require the use of a regular (wired) USB keyboard and mouse. +%description mesh +Services for bluetooth mesh + %description obexd Object Exchange daemon for sharing files, contacts etc over bluetooth @@ -151,10 +137,10 @@ autoreconf -f -i --with-systemdsystemunitdir=%{_unitdir} \ --with-systemduserunitdir=%{_userunitdir} -make %{?_smp_mflags} V=1 +%{make_build} %install -make install DESTDIR=$RPM_BUILD_ROOT +%{make_install} # "make install" fails to install gatttool, necessary for Bluetooth Low Energy # Red Hat Bugzilla bug #1141909 @@ -207,6 +193,12 @@ install -D -p -m0755 %{SOURCE4} ${RPM_BUILD_ROOT}/%{_libexecdir}/bluetooth/ %post hid2hci /sbin/udevadm trigger --subsystem-match=usb +%post mesh +%systemd_user_post bluetooth-mesh.service + +%preun mesh +%systemd_user_preun bluetooth-mesh.service + %post obexd %systemd_user_post obex.service @@ -214,7 +206,6 @@ install -D -p -m0755 %{SOURCE4} ${RPM_BUILD_ROOT}/%{_libexecdir}/bluetooth/ %systemd_user_preun obex.service %files -%{!?_licensedir:%global license %%doc} %license COPYING %doc AUTHORS ChangeLog %config %{_sysconfdir}/dbus-1/system.d/bluetooth.conf @@ -234,7 +225,6 @@ install -D -p -m0755 %{SOURCE4} ${RPM_BUILD_ROOT}/%{_libexecdir}/bluetooth/ %{_bindir}/hcidump %{_bindir}/l2test %{_bindir}/hex2hcd -%{_bindir}/meshctl %{_bindir}/mpris-proxy %{_bindir}/gatttool %{_bindir}/rctest @@ -259,6 +249,7 @@ install -D -p -m0755 %{SOURCE4} ${RPM_BUILD_ROOT}/%{_libexecdir}/bluetooth/ %{_unitdir}/bluetooth.service %{_unitdir}/btattach-bcm@.service %{_udevrulesdir}/69-btattach-bcm.rules +%{_datadir}/zsh/site-functions/_bluetoothctl %files libs %{!?_licensedir:%global license %%doc} @@ -279,12 +270,22 @@ install -D -p -m0755 %{SOURCE4} ${RPM_BUILD_ROOT}/%{_libexecdir}/bluetooth/ %{_mandir}/man1/hid2hci.1* %{_udevrulesdir}/97-hid2hci.rules +%files mesh +%config %{_sysconfdir}/dbus-1/system.d/bluetooth-mesh.conf +%{_bindir}/meshctl +%{_datadir}/dbus-1/system-services/org.bluez.mesh.service +%{_libexecdir}/bluetooth/bluetooth-meshd +%{_unitdir}/bluetooth-mesh.service + %files obexd %{_libexecdir}/bluetooth/obexd %{_datadir}/dbus-1/services/org.bluez.obex.service %{_userunitdir}/obex.service %changelog +* Fri Sep 20 2019 Peter Robinson 5.51-1 ++ bluez 5.51 + * Wed Jul 24 2019 Fedora Release Engineering - 5.50-9 - Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild diff --git a/sources b/sources index af3d179..b83e2f7 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (bluez-5.50.tar.xz) = 64a680e4b3c270bc2439610c91ad2aef36131d84401e4bbdf6c2b7ec8708a19dfc942b31b9189c38a97ca072c761c669ae1aace5f4ff5d06de3ccbf33184be45 +SHA512 (bluez-5.51.tar.xz) = 8b14eea98f541b981162abce728e0f917654ad3c990721ec398fe41bdd68069fe55ff64b61bc3c3b9f813facf42c995b07619f6d5d153965de27154b1a7b578f