[PATCH] Fix: Distorted audio during Bluetooth SCO HFP/HSP playback

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Issue: When HFP/HSP profile is used with certain BT chipsets, the
audio sounds heavily distorted, with very slow playback full of noise.
During recording, the samples are dropped and it distorts the recorded
audio samples.

The root cause of both the issues are related to the fixed MTU sizes
in the PA stack, which is 48 bytes. Here, the BT chipset CC256x had
180 bytes MTU and it was being under-utilized and the rate at which
the samples were being accepted where not matching the expected rate,
and hence the distortion.

Solution: The appropriate solution to this problem is by reading the
MTU size of the SCO socket using getsockopts dynamically.

BugLink: http://bit.ly/2gDpGPv
BugLink: http://bit.ly/2hQsARK
---
 src/modules/bluetooth/backend-native.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c
index cf88126..4974c3f 100644
--- a/src/modules/bluetooth/backend-native.c
+++ b/src/modules/bluetooth/backend-native.c
@@ -103,6 +103,8 @@ static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_backend *backend, D
 static int bluez5_sco_acquire_cb(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) {
     pa_bluetooth_device *d = t->device;
     struct sockaddr_sco addr;
+    struct sco_options sco_opt;
+    socklen_t len;
     int err, i;
     int sock;
     bdaddr_t src;
@@ -124,34 +126,40 @@ static int bluez5_sco_acquire_cb(pa_bluetooth_transport *t, bool optional, size_
         return -1;
     }
 
-    memset(&addr, 0, sizeof(addr));
+    len = sizeof(addr);
+    memset(&addr, 0, len);
     addr.sco_family = AF_BLUETOOTH;
     bacpy(&addr.sco_bdaddr, &src);
 
-    if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+    if (bind(sock, (struct sockaddr *) &addr, len) < 0) {
         pa_log_error("bind(): %s", pa_cstrerror(errno));
         goto fail_close;
     }
 
-    memset(&addr, 0, sizeof(addr));
+    memset(&addr, 0, len);
     addr.sco_family = AF_BLUETOOTH;
     bacpy(&addr.sco_bdaddr, &dst);
 
     pa_log_info("doing connect");
-    err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+    err = connect(sock, (struct sockaddr *) &addr, len);
     if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
         pa_log_error("connect(): %s", pa_cstrerror(errno));
         goto fail_close;
     }
 
-    /* The "48" below is hardcoded until we get meaningful MTU values exposed
-     * by the kernel */
+    len = sizeof(sco_opt);
+    memset(&sco_opt, 0, len);
 
-    if (imtu)
-        *imtu = 48;
+    if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
+        pa_log_warn("getsockopt(SCO_OPTIONS) failed, loading defaults");
 
-    if (omtu)
-        *omtu = 48;
+        /* Setting defaults in case of error */
+        if (imtu) *imtu = 48;
+        if (omtu) *omtu = 48;
+    } else {
+        if (imtu) *imtu = sco_opt.mtu;
+        if (omtu) *omtu = sco_opt.mtu;
+    }
 
     return sock;
 
-- 
1.9.1



[Index of Archives]     [Linux Audio Users]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux