Skip to content

Commit

Permalink
Drain optimization - use timeout only when needed
Browse files Browse the repository at this point in the history
This commit also fixes a bug introduced in the 99d9d72. Since then it
was impossible to exit (cleanly and without breaking bluealsa server)
SCO thread with a player which uses snd_pcm_drain() call.
  • Loading branch information
arkq committed Feb 16, 2018
1 parent 8b3335c commit 3e600b8
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 12 deletions.
45 changes: 33 additions & 12 deletions src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ void *io_thread_a2dp_source_sbc(void *arg) {
int16_t *in_buffer_tail = in_buffer;
size_t in_samples = in_buffer_size / sizeof(int16_t);

int poll_timeout = -1;
struct asrsync asrs = { .frames = 0 };
struct pollfd pfds[] = {
{ t->event_fd, POLLIN, 0 },
Expand All @@ -371,10 +372,10 @@ void *io_thread_a2dp_source_sbc(void *arg) {
/* add PCM socket to the poll if transport is active */
pfds[1].fd = t->state == TRANSPORT_ACTIVE ? t->a2dp.pcm.fd : -1;

switch (poll(pfds, sizeof(pfds) / sizeof(*pfds), 100)) {
switch (poll(pfds, sizeof(pfds) / sizeof(*pfds), poll_timeout)) {
case 0:
if (t->a2dp.pcm.sync)
pthread_cond_signal(&t->a2dp.pcm.drained);
pthread_cond_signal(&t->a2dp.pcm.drained);
poll_timeout = -1;
continue;
case -1:
error("Transport poll error: %s", strerror(errno));
Expand All @@ -386,6 +387,8 @@ void *io_thread_a2dp_source_sbc(void *arg) {
eventfd_t event;
eventfd_read(pfds[0].fd, &event);
asrs.frames = 0;
if (t->a2dp.pcm.sync)
poll_timeout = 100;
continue;
}

Expand Down Expand Up @@ -795,6 +798,7 @@ void *io_thread_a2dp_source_aac(void *arg) {
size_t in_samples = in_buffer_size / in_buffer_element_size;
in_buffer_tail = in_buffer;

int poll_timeout = -1;
struct asrsync asrs = { .frames = 0 };
struct pollfd pfds[] = {
{ t->event_fd, POLLIN, 0 },
Expand All @@ -811,10 +815,10 @@ void *io_thread_a2dp_source_aac(void *arg) {
/* add PCM socket to the poll if transport is active */
pfds[1].fd = t->state == TRANSPORT_ACTIVE ? t->a2dp.pcm.fd : -1;

switch (poll(pfds, sizeof(pfds) / sizeof(*pfds), 100)) {
switch (poll(pfds, sizeof(pfds) / sizeof(*pfds), poll_timeout)) {
case 0:
if (t->a2dp.pcm.sync)
pthread_cond_signal(&t->a2dp.pcm.drained);
pthread_cond_signal(&t->a2dp.pcm.drained);
poll_timeout = -1;
continue;
case -1:
error("Transport poll error: %s", strerror(errno));
Expand All @@ -826,6 +830,8 @@ void *io_thread_a2dp_source_aac(void *arg) {
eventfd_t event;
eventfd_read(pfds[0].fd, &event);
asrs.frames = 0;
if (t->a2dp.pcm.sync)
poll_timeout = 100;
continue;
}

Expand Down Expand Up @@ -978,6 +984,7 @@ void *io_thread_a2dp_source_aptx(void *arg) {
int16_t *in_buffer_tail = in_buffer;
size_t in_samples = in_buffer_size / sizeof(int16_t);

int poll_timeout = -1;
struct asrsync asrs = { .frames = 0 };
struct pollfd pfds[] = {
{ t->event_fd, POLLIN, 0 },
Expand All @@ -994,10 +1001,10 @@ void *io_thread_a2dp_source_aptx(void *arg) {
/* add PCM socket to the poll if transport is active */
pfds[1].fd = t->state == TRANSPORT_ACTIVE ? t->a2dp.pcm.fd : -1;

switch (poll(pfds, sizeof(pfds) / sizeof(*pfds), 100)) {
switch (poll(pfds, sizeof(pfds) / sizeof(*pfds), poll_timeout)) {
case 0:
if (t->a2dp.pcm.sync)
pthread_cond_signal(&t->a2dp.pcm.drained);
pthread_cond_signal(&t->a2dp.pcm.drained);
poll_timeout = -1;
continue;
case -1:
error("Transport poll error: %s", strerror(errno));
Expand All @@ -1009,6 +1016,8 @@ void *io_thread_a2dp_source_aptx(void *arg) {
eventfd_t event;
eventfd_read(pfds[0].fd, &event);
asrs.frames = 0;
if (t->a2dp.pcm.sync)
poll_timeout = 100;
continue;
}

Expand Down Expand Up @@ -1126,6 +1135,7 @@ void *io_thread_sco(void *arg) {
goto fail;
}

int poll_timeout = -1;
struct asrsync asrs = { .frames = 0 };
struct pollfd pfds[] = {
{ t->event_fd, POLLIN, 0 },
Expand Down Expand Up @@ -1162,10 +1172,10 @@ void *io_thread_sco(void *arg) {
if (t->sco.mic_pcm.fd == -1)
pfds[1].fd = -1;

switch (poll(pfds, sizeof(pfds) / sizeof(*pfds), 100)) {
switch (poll(pfds, sizeof(pfds) / sizeof(*pfds), poll_timeout)) {
case 0:
if (t->sco.spk_pcm.sync)
pthread_cond_signal(&t->sco.spk_pcm.drained);
pthread_cond_signal(&t->sco.spk_pcm.drained);
poll_timeout = -1;
continue;
case -1:
error("Transport poll error: %s", strerror(errno));
Expand All @@ -1180,6 +1190,15 @@ void *io_thread_sco(void *arg) {
eventfd_t event;
eventfd_read(pfds[0].fd, &event);

/* FIXME: Drain functionality for speaker.
* XXX: Right now it is not possible to drain speaker PCM (in a clean
* fashion), because poll() will not timeout if we've got incoming
* data from the microphone (BT SCO socket). In order not to hang
* forever in the transport_drain_pcm() function, we will signal
* PCM drain right now. */
if (t->sco.spk_pcm.sync)
pthread_cond_signal(&t->sco.spk_pcm.drained);

const enum hfp_ind *inds = t->sco.rfcomm->rfcomm.hfp_inds;
bool release = false;

Expand Down Expand Up @@ -1321,6 +1340,8 @@ void *io_thread_sco(void *arg) {
}
else if (pfds[3].revents & (POLLERR | POLLHUP)) {
debug("PCM poll error status: %#x", pfds[3].revents);
close(t->sco.spk_pcm.fd);
t->sco.spk_pcm.fd = -1;
}

if (pfds[4].revents & POLLOUT) {
Expand Down
1 change: 1 addition & 0 deletions src/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,7 @@ int transport_drain_pcm(struct ba_transport *t) {
pthread_mutex_lock(&pcm->drained_mn);

pcm->sync = true;
eventfd_write(t->event_fd, 1);
pthread_cond_wait(&pcm->drained, &pcm->drained_mn);
pcm->sync = false;

Expand Down

0 comments on commit 3e600b8

Please sign in to comment.