diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2005-04-23 18:44:39 +0000 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2005-04-23 18:44:39 +0000 |
commit | a6c9d1b70a9b29e371cb890d417d41b58ba8a901 (patch) | |
tree | f68d0edd7c72d2c14e6165ffc11d0b4d4c69def9 | |
parent | cb079810a52ebbc4ec46c33b2a0f31a6b9c8c778 (diff) |
Implement connection caching
-rw-r--r-- | alsa/pcm_a2dp.c | 133 |
1 files changed, 109 insertions, 24 deletions
diff --git a/alsa/pcm_a2dp.c b/alsa/pcm_a2dp.c index 90ee7107..be89e677 100644 --- a/alsa/pcm_a2dp.c +++ b/alsa/pcm_a2dp.c @@ -28,6 +28,7 @@ #include <stdio.h> #include <errno.h> #include <malloc.h> +#include <signal.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -44,6 +45,7 @@ typedef struct snd_pcm_a2dp { snd_pcm_ioplug_t io; + int refcnt; bdaddr_t src; bdaddr_t dst; int sk; @@ -54,6 +56,31 @@ typedef struct snd_pcm_a2dp { unsigned int frame_bytes; } snd_pcm_a2dp_t; +#define MAX_CONNECTIONS 10 + +static snd_pcm_a2dp_t *connections[MAX_CONNECTIONS]; + +static void sig_alarm(int sig) +{ + int i; + + for (i = 0; i < MAX_CONNECTIONS; i++) { + snd_pcm_a2dp_t *a2dp = connections[i]; + + if (!a2dp || a2dp->refcnt > 0) + continue; + + connections[i] = NULL; + + if (a2dp->sk >= 0) + close(a2dp->sk); + + sbc_finish(&a2dp->sbc); + + free(a2dp); + } +} + static int a2dp_start(snd_pcm_ioplug_t *io) { snd_pcm_a2dp_t *a2dp = io->private_data; @@ -120,15 +147,11 @@ static int a2dp_close(snd_pcm_ioplug_t *io) a2dp->len = 0; - if (a2dp->sk >= 0) { - shutdown(a2dp->sk, SHUT_RDWR); - sleep(1); - close(a2dp->sk); - } + a2dp->refcnt--; - sbc_finish(&a2dp->sbc); + if (!a2dp->refcnt) + alarm(2); - free(a2dp); return 0; } @@ -158,6 +181,10 @@ static int a2dp_prepare(snd_pcm_ioplug_t *io) DBG("a2dp %p", a2dp); + a2dp->len = 0; + + a2dp->num = 0; + a2dp->sbc.rate = io->rate; a2dp->sbc.channels = io->channels; @@ -175,6 +202,14 @@ static int a2dp_drain(snd_pcm_ioplug_t *io) return 0; } +static int a2dp_poll(snd_pcm_ioplug_t *io, struct pollfd *ufds, + unsigned int nfds, unsigned short *revents) +{ + *revents = ufds[0].revents; + + return 0; +} + static snd_pcm_ioplug_callback_t a2dp_callback = { .start = a2dp_start, .stop = a2dp_stop, @@ -184,11 +219,13 @@ static snd_pcm_ioplug_callback_t a2dp_callback = { .hw_params = a2dp_params, .prepare = a2dp_prepare, .drain = a2dp_drain, + .poll_revents = a2dp_poll, }; static int a2dp_connect(snd_pcm_a2dp_t *a2dp) { struct sockaddr_rc addr; + socklen_t len; int sk; DBG("a2dp %p", a2dp); @@ -216,7 +253,18 @@ static int a2dp_connect(snd_pcm_a2dp_t *a2dp) return -errno; } + memset(&addr, 0, sizeof(addr)); + len = sizeof(addr); + + if (getsockname(sk, (struct sockaddr *) &addr, &len) < 0) { + close(sk); + return -errno; + } + + bacpy(&a2dp->src, &addr.rc_bdaddr); + a2dp->sk = sk; + return 0; } @@ -271,10 +319,10 @@ static int a2dp_constraint(snd_pcm_a2dp_t *a2dp) SND_PCM_PLUGIN_DEFINE_FUNC(a2dp) { - snd_pcm_a2dp_t *a2dp; + snd_pcm_a2dp_t *a2dp = NULL; snd_config_iterator_t i, next; bdaddr_t src, dst; - int err; + int err, n, pos = -1; DBG("name %s mode %d", name, mode); @@ -300,7 +348,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(a2dp) continue; } - if (strcmp(id, "src") == 0) { + if (!strcmp(id, "local") || !strcmp(id, "src")) { if (snd_config_get_string(n, &addr) < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; @@ -313,26 +361,59 @@ SND_PCM_PLUGIN_DEFINE_FUNC(a2dp) return -EINVAL; } - a2dp = malloc(sizeof(*a2dp)); - if (!a2dp) { - SNDERR("Cannot allocate"); - return -ENOMEM; + for (n = 0; n < MAX_CONNECTIONS; n++) { + if (connections[n]) { + if (!bacmp(&connections[n]->dst, &dst) && + (!bacmp(&connections[n]->src, &src) || + !bacmp(&src, BDADDR_ANY))) { + a2dp = connections[n]; + a2dp->refcnt++; + break; + } + } else if (pos < 0) + pos = n; } - memset(a2dp, 0, sizeof(*a2dp)); + if (!a2dp) { + struct sigaction sa; - bacpy(&a2dp->src, &src); - bacpy(&a2dp->dst, &dst); + if (pos < 0) { + SNDERR("Too many connections"); + return -ENOMEM; + } - err = a2dp_connect(a2dp); - if (err < 0) { - SNDERR("Cannot connect"); - goto error; + a2dp = malloc(sizeof(*a2dp)); + if (!a2dp) { + SNDERR("Cannot allocate"); + return -ENOMEM; + } + + memset(a2dp, 0, sizeof(*a2dp)); + + a2dp->refcnt = 1; + + bacpy(&a2dp->src, &src); + bacpy(&a2dp->dst, &dst); + + err = a2dp_connect(a2dp); + if (err < 0) { + SNDERR("Cannot connect"); + goto error; + } + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = sig_alarm; + sigaction(SIGALRM, &sa, NULL); + + alarm(0); + + connections[pos] = a2dp; } a2dp->io.name = "Bluetooth Advanced Audio Distribution"; a2dp->io.poll_fd = a2dp->sk; - a2dp->io.poll_events = POLLOUT | POLLHUP; + a2dp->io.poll_events = POLLOUT; a2dp->io.mmap_rw = 0; a2dp->io.callback = &a2dp_callback; a2dp->io.private_data = a2dp; @@ -344,14 +425,18 @@ SND_PCM_PLUGIN_DEFINE_FUNC(a2dp) err = a2dp_constraint(a2dp); if (err < 0) { snd_pcm_ioplug_delete(&a2dp->io); - return err; + goto error; } *pcmp = a2dp->io.pcm; return 0; error: - free(a2dp); + a2dp->refcnt--; + + if (!a2dp->refcnt) + alarm(2); + return err; } |