mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
bluez5: replace sco-sink with media-sink
Change media-sink to use sco-io for HFP codecs. Move SCO fragmentation to sco-io side. Replace sco-sink with media-sink. sco-sink is mostly copypaste from media-sink, and only differed in the fragmentation detail, which can as well be handled on sco-io side.
This commit is contained in:
parent
f9b0bf3f95
commit
5b4e9dc33e
5 changed files with 141 additions and 1731 deletions
|
|
@ -56,7 +56,10 @@ struct spa_bt_sco_io {
|
|||
bool started;
|
||||
|
||||
uint8_t read_buffer[MAX_MTU];
|
||||
uint32_t read_size;
|
||||
size_t read_size;
|
||||
|
||||
uint8_t write_buffer[MAX_MTU];
|
||||
size_t write_size;
|
||||
|
||||
int fd;
|
||||
uint16_t read_mtu;
|
||||
|
|
@ -71,28 +74,9 @@ struct spa_bt_sco_io {
|
|||
|
||||
int (*source_cb)(void *userdata, uint8_t *data, int size, uint64_t rx_time);
|
||||
void *source_userdata;
|
||||
|
||||
int (*sink_cb)(void *userdata);
|
||||
void *sink_userdata;
|
||||
};
|
||||
|
||||
|
||||
static void update_source(struct spa_bt_sco_io *io)
|
||||
{
|
||||
int enabled;
|
||||
int changed = 0;
|
||||
|
||||
enabled = io->sink_cb != NULL;
|
||||
if (SPA_FLAG_IS_SET(io->source.mask, SPA_IO_OUT) != enabled) {
|
||||
SPA_FLAG_UPDATE(io->source.mask, SPA_IO_OUT, enabled);
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
spa_loop_update_source(io->data_loop, &io->source);
|
||||
}
|
||||
}
|
||||
|
||||
static void sco_io_on_ready(struct spa_source *source)
|
||||
{
|
||||
struct spa_bt_sco_io *io = source->data;
|
||||
|
|
@ -116,9 +100,13 @@ static void sco_io_on_ready(struct spa_source *source)
|
|||
goto stop;
|
||||
}
|
||||
|
||||
if (res != (int)io->read_size)
|
||||
if (res != (int)io->read_size) {
|
||||
spa_log_trace(io->log, "%p: packet size:%d", io, res);
|
||||
|
||||
/* drop buffer when packet size changes */
|
||||
io->write_size = 0;
|
||||
}
|
||||
|
||||
io->read_size = res;
|
||||
|
||||
if (io->source_cb) {
|
||||
|
|
@ -131,23 +119,9 @@ static void sco_io_on_ready(struct spa_source *source)
|
|||
}
|
||||
|
||||
read_done:
|
||||
if (SPA_FLAG_IS_SET(source->rmask, SPA_IO_OUT)) {
|
||||
if (io->sink_cb) {
|
||||
int res;
|
||||
res = io->sink_cb(io->sink_userdata);
|
||||
if (res) {
|
||||
io->sink_cb = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SPA_FLAG_IS_SET(source->rmask, SPA_IO_ERR) || SPA_FLAG_IS_SET(source->rmask, SPA_IO_HUP)) {
|
||||
goto stop;
|
||||
}
|
||||
|
||||
/* Poll socket in/out only if necessary */
|
||||
update_source(io);
|
||||
|
||||
return;
|
||||
|
||||
stop:
|
||||
|
|
@ -157,47 +131,80 @@ stop:
|
|||
}
|
||||
}
|
||||
|
||||
static int write_packets(struct spa_bt_sco_io *io, const uint8_t **buf, size_t *size, size_t packet_size)
|
||||
{
|
||||
while (*size >= packet_size) {
|
||||
ssize_t written;
|
||||
|
||||
written = send(io->fd, *buf, packet_size, MSG_DONTWAIT | MSG_NOSIGNAL);
|
||||
if (written < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
*buf += written;
|
||||
*size -= written;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write data to socket in correctly sized blocks.
|
||||
* Returns the number of bytes written, 0 when data cannot be written now or
|
||||
* there is too little of it to write, and <0 on write error.
|
||||
* Returns the number of bytes written or buffered, and <0 on write error.
|
||||
*/
|
||||
int spa_bt_sco_io_write(struct spa_bt_sco_io *io, uint8_t *buf, int size)
|
||||
int spa_bt_sco_io_write(struct spa_bt_sco_io *io, const uint8_t *buf, size_t size)
|
||||
{
|
||||
uint16_t packet_size;
|
||||
uint8_t *buf_start = buf;
|
||||
const size_t orig_size = size;
|
||||
const uint8_t *pos;
|
||||
size_t packet_size;
|
||||
int res;
|
||||
|
||||
if (io->read_size == 0) {
|
||||
/* The proper write packet size is not known yet */
|
||||
return 0;
|
||||
}
|
||||
|
||||
packet_size = SPA_MIN(io->write_mtu, io->read_size);
|
||||
packet_size = SPA_MIN(SPA_MIN(io->write_mtu, io->read_size), sizeof(io->write_buffer));
|
||||
|
||||
if (size < packet_size) {
|
||||
return 0;
|
||||
if (io->write_size >= packet_size) {
|
||||
/* packet size changed, drop data */
|
||||
io->write_size = 0;
|
||||
} else if (io->write_size) {
|
||||
/* write fragment */
|
||||
size_t need = SPA_MIN(packet_size - io->write_size, size);
|
||||
|
||||
memcpy(io->write_buffer + io->write_size, buf, need);
|
||||
buf += need;
|
||||
size -= need;
|
||||
io->write_size += need;
|
||||
|
||||
if (io->write_size < packet_size)
|
||||
return orig_size;
|
||||
|
||||
pos = io->write_buffer;
|
||||
if ((res = write_packets(io, &pos, &io->write_size, packet_size)) < 0)
|
||||
goto fail;
|
||||
if (io->write_size)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
do {
|
||||
int written;
|
||||
/* write */
|
||||
if ((res = write_packets(io, &buf, &size, packet_size)) < 0)
|
||||
goto fail;
|
||||
|
||||
written = send(io->fd, buf, packet_size, MSG_DONTWAIT | MSG_NOSIGNAL);
|
||||
if (written < 0) {
|
||||
if (errno == EINTR) {
|
||||
/* retry if interrupted */
|
||||
continue;
|
||||
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
/* Don't continue writing */
|
||||
break;
|
||||
}
|
||||
return -errno;
|
||||
}
|
||||
spa_assert(size < packet_size);
|
||||
|
||||
buf += written;
|
||||
size -= written;
|
||||
} while (size >= packet_size);
|
||||
/* store fragment */
|
||||
io->write_size = size;
|
||||
if (size)
|
||||
memcpy(io->write_buffer, buf, size);
|
||||
|
||||
return buf - buf_start;
|
||||
return orig_size;
|
||||
|
||||
fail:
|
||||
io->write_size = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -236,7 +243,7 @@ struct spa_bt_sco_io *spa_bt_sco_io_create(struct spa_bt_transport *transport, s
|
|||
}
|
||||
}
|
||||
|
||||
spa_log_debug(io->log, "%p: initial packet size:%d", io, io->read_size);
|
||||
spa_log_debug(io->log, "%p: initial packet size:%d", io, (int)io->read_size);
|
||||
|
||||
spa_bt_recvmsg_init(&io->recv, io->fd, io->data_system, io->log);
|
||||
|
||||
|
|
@ -244,7 +251,7 @@ struct spa_bt_sco_io *spa_bt_sco_io_create(struct spa_bt_transport *transport, s
|
|||
io->source.data = io;
|
||||
io->source.fd = io->fd;
|
||||
io->source.func = sco_io_on_ready;
|
||||
io->source.mask = SPA_IO_IN | SPA_IO_OUT | SPA_IO_ERR | SPA_IO_HUP;
|
||||
io->source.mask = SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP;
|
||||
io->source.rmask = 0;
|
||||
spa_loop_add_source(io->data_loop, &io->source);
|
||||
|
||||
|
|
@ -285,22 +292,4 @@ void spa_bt_sco_io_set_source_cb(struct spa_bt_sco_io *io, int (*source_cb)(void
|
|||
{
|
||||
io->source_cb = source_cb;
|
||||
io->source_userdata = userdata;
|
||||
|
||||
if (io->started) {
|
||||
update_source(io);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set sink callback.
|
||||
* This function should only be called from the data thread.
|
||||
* Callback is called (in data loop) when socket can be written to.
|
||||
*/
|
||||
void spa_bt_sco_io_set_sink_cb(struct spa_bt_sco_io *io, int (*sink_cb)(void *), void *userdata)
|
||||
{
|
||||
io->sink_cb = sink_cb;
|
||||
io->sink_userdata = userdata;
|
||||
|
||||
if (io->started) {
|
||||
update_source(io);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue