From 7a84a24652e4bace694a9daf7ce66a70d0ef0cea Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sun, 12 Feb 2017 23:42:00 +0100 Subject: [PATCH] bluetooth: backend-native: add battery level reporting Devices for Apple's iOS uses a few extra HFP AT commands to inform the iPhone about the headphone's battery status. Apple documented the AT commands in the following document: https://developer.apple.com/hardwaredrivers/BluetoothDesignGuidelines.pdf The patch has been tested with a Bose QC35, which results in the following communication: D: [pulseaudio] backend-native.c: RFCOMM << AT+VGS=14 D: [pulseaudio] backend-native.c: RFCOMM >> OK D: [pulseaudio] backend-native.c: RFCOMM << AT+XAPL=009E-400C-0129,3 D: [pulseaudio] backend-native.c: RFCOMM >> +XAPL=iPhone,2 D: [pulseaudio] backend-native.c: RFCOMM >> OK D: [pulseaudio] backend-native.c: RFCOMM << AT+XEVENT=Bose SoundLink,158 D: [pulseaudio] backend-native.c: RFCOMM >> OK D: [pulseaudio] backend-native.c: RFCOMM << AT+IPHONEACCEV=2,1,4,2,0 N: [pulseaudio] backend-native.c: Battery Level: 50% N: [pulseaudio] backend-native.c: Dock Status: undocked D: [pulseaudio] backend-native.c: RFCOMM >> OK [Marijn: Adapt for recent HSP/HFP code changes] Co-authored-by: Marijn Suijten Part-of: --- src/modules/bluetooth/backend-native.c | 29 +++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index 79ab4db72..b39fcd9f9 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -693,7 +693,9 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i char buf[512]; ssize_t len; int gain, dummy; - bool do_reply = false; + bool do_reply = false; + int vendor, product, version, features; + int num; len = pa_read(fd, buf, 511, NULL); if (len < 0) { @@ -734,6 +736,31 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i do_reply = true; } else if (sscanf(buf, "AT+CKPD=%d", &dummy) == 1) { do_reply = true; + } else if (sscanf(buf, "AT+XAPL=%04x-%04x-%04x,%d", &vendor, &product, &version, &features) == 4) { + if (features & 0x2) + /* claim, that we support battery status reports */ + rfcomm_write_response(fd, "+XAPL=iPhone,2"); + do_reply = true; + } else if (sscanf(buf, "AT+IPHONEACCEV=%d", &num) == 1) { + char *substr = strchr(buf, ','); + bool isval = false; + int key, val; + + for (; substr; substr = strchr(substr, ',')) { + substr++; + if (!isval) { + key = atoi(substr); + } else { + val = atoi(substr); + if (key == 1) { + pa_log_notice("Battery Level: %d0%%", val + 1); + } else if (key == 2) { + pa_log_notice("Dock Status: %s", val ? "docked" : "undocked"); + } + } + isval = !isval; + } + do_reply = true; } else if (t->config) { /* t->config is only non-null for hfp profile */ do_reply = hfp_rfcomm_handle(fd, t, buf); } else {