Skip to content

Commit

Permalink
Improve SCO socket transfer size selection and timing
Browse files Browse the repository at this point in the history
Linux btusb module does not report the required message size
for SCO sockets, rather the "MTU" it reports is actually the
controller SCO buffer size. However, we can obtain the correct
size by reading the first incoming message. SCO packet transfers
begin, in both directions, as soon as the transport is acquired,
so we are guaranteed to have incoming packets even if the remote
microphone is not enabled (provided the adapter is routing
incoming SCO through the HCI).

This commit adjusts the outgoing message size, if necessary, after
the first incoming message has been received.

For mSBC streams the timing logic is also modified so that no USB
slots are missed if the client runs too slowly.
  • Loading branch information
borine committed Aug 30, 2023
1 parent ed24c9c commit b2fc3e7
Show file tree
Hide file tree
Showing 9 changed files with 453 additions and 94 deletions.
2 changes: 2 additions & 0 deletions .github/spellcheck-wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ UI
UUID
UUIDs
VBR
WBS
XQ

# Proper Names
Expand Down Expand Up @@ -84,6 +85,7 @@ endianness
enum
getter
init
isochronous
middleware
mutex
natively
Expand Down
2 changes: 1 addition & 1 deletion src/ba-transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ static int transport_acquire_bt_sco(struct ba_transport *t) {

debug("New SCO link: %s: %d", batostr_(&d->addr), fd);

t->mtu_read = t->mtu_write = hci_sco_get_mtu(fd, d->a);
t->mtu_read = t->mtu_write = hci_sco_get_mtu(fd);
t->bt_fd = fd;

return fd;
Expand Down
3 changes: 3 additions & 0 deletions src/ba-transport.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#endif

#include <pthread.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
Expand Down Expand Up @@ -256,6 +257,8 @@ struct ba_transport {
/* time-stamp when the SCO link has been closed */
struct timespec closed_at;

/* The SCO socket message size may differ from the reported MTU */
atomic_uint transfer_bytes;
} sco;

};
Expand Down
42 changes: 17 additions & 25 deletions src/hci.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@
#include <bluetooth/hci_lib.h>
#include <bluetooth/sco.h>

#include "ba-adapter.h"
#include "bluealsa-config.h"
#include "shared/bluetooth.h"
#include "shared/log.h"

/**
Expand Down Expand Up @@ -112,45 +109,40 @@ int hci_sco_connect(int sco_fd, const bdaddr_t *ba, uint16_t voice) {
/**
* Get read/write MTU for given SCO socket.
*
* Note that the SCO socket "MTU" reported by the Linux kernel is actually
* the response of the HCI HCI_Read_Buffer_Size command. The actual transfer
* size is determined by the underlying bus type, and this is not reported by
* the socket options. We use the socket option MTU as an upper bound for
* choosing the initial buffer size, but this is later optimized when we know
* the actual transfer size by reading the first incoming message.
*
* @param sco_fd File descriptor of opened SCO socket.
* @param a The adapter associated with sco_fd.
* @return On success this function returns MTU value. Otherwise, 0 is returned and
* errno is set to indicate the error. */
unsigned int hci_sco_get_mtu(int sco_fd, struct ba_adapter *a) {
unsigned int hci_sco_get_mtu(int sco_fd) {

int so_error;
struct sco_options options = { 0 };
struct bt_voice voice = { 0 };
socklen_t len;

struct pollfd pfd = { sco_fd, POLLOUT, 0 };
if (poll(&pfd, 1, -1) == -1)
warn("Couldn't wait for SCO connection: %s", strerror(errno));

len = sizeof(so_error);
if (getsockopt(sco_fd, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1)
warn("Couldn't get SCO socket error: %s", strerror(errno));
if (so_error != 0) {
error("SCO socket connect error: %s", strerror(so_error));
return 0;
}

len = sizeof(options);
if (getsockopt(sco_fd, SOL_SCO, SCO_OPTIONS, &options, &len) == -1)
warn("Couldn't get SCO socket options: %s", strerror(errno));

len = sizeof(voice);
if (getsockopt(sco_fd, SOL_BLUETOOTH, BT_VOICE, &voice, &len) == -1)
warn("Couldn't get SCO voice options: %s", strerror(errno));

debug("SCO link socket MTU: %d: %u", sco_fd, options.mtu);

/* XXX: It seems, that the MTU value returned by kernel btusb driver
* is incorrect. */
if ((a->hci.type & 0x0F) == HCI_USB) {
options.mtu = 48;
if (voice.setting == BT_VOICE_TRANSPARENT) {
if (a->chip.manufacturer == 0)
hci_get_version(a->hci.dev_id, &a->chip);
if (!config.disable_realtek_usb_fix && a->chip.manufacturer == BT_COMPID_REALTEK)
options.mtu = 72;
else
options.mtu = 24;
}
debug("USB adjusted SCO MTU: %d: %u", sco_fd, options.mtu);
}

return options.mtu;
}

Expand Down
4 changes: 1 addition & 3 deletions src/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
#include <bluetooth/hci.h> /* IWYU pragma: keep */
#include <bluetooth/hci_lib.h>

#include "ba-adapter.h"

int hci_get_version(int dev_id, struct hci_version *ver);

/**
Expand All @@ -39,7 +37,7 @@ int hci_get_version(int dev_id, struct hci_version *ver);
int hci_sco_open(int dev_id);
int hci_sco_connect(int sco_fd, const bdaddr_t *ba, uint16_t voice);

unsigned int hci_sco_get_mtu(int sco_fd, struct ba_adapter *a);
unsigned int hci_sco_get_mtu(int sco_fd);

#define BT_BCM_PARAM_ROUTING_PCM 0x0
#define BT_BCM_PARAM_ROUTING_TRANSPORT 0x1
Expand Down
3 changes: 3 additions & 0 deletions src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,9 @@ ssize_t io_poll_and_read_bt(
return -1;
}

if (poll_rv == 0)
return errno = ETIME, -1;

if (fds[0].revents & POLLIN) {
/* dispatch incoming event */
io_poll_signal_filter *filter = io->signal.filter != NULL ?
Expand Down
6 changes: 4 additions & 2 deletions src/ofono.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <unistd.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h> /* IWYU pragma: keep */
#include <bluetooth/hci_lib.h>

#include <gio/gio.h>
Expand Down Expand Up @@ -129,7 +130,7 @@ static int ofono_acquire_bt_sco(struct ba_transport *t) {
#endif

t->bt_fd = fd;
t->mtu_read = t->mtu_write = hci_sco_get_mtu(fd, t->d->a);
t->mtu_read = t->mtu_write = hci_sco_get_mtu(fd);
ba_transport_set_codec(t, codec);

debug("New oFono SCO link (codec: %#x): %d", codec, fd);
Expand Down Expand Up @@ -826,7 +827,8 @@ static void ofono_agent_new_connection(GDBusMethodInvocation *inv, void *userdat
debug("New oFono SCO link (codec: %#x): %d", codec, fd);

t->bt_fd = fd;
t->mtu_read = t->mtu_write = hci_sco_get_mtu(fd, t->d->a);
t->mtu_read = t->mtu_write = hci_sco_get_mtu(fd);

ba_transport_set_codec(t, codec);

pthread_mutex_unlock(&t->bt_fd_mtx);
Expand Down
Loading

0 comments on commit b2fc3e7

Please sign in to comment.