summaryrefslogtreecommitdiffstats
path: root/alsa/pcm_a2dp.c
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2005-04-23 18:44:39 +0000
committerMarcel Holtmann <marcel@holtmann.org>2005-04-23 18:44:39 +0000
commita6c9d1b70a9b29e371cb890d417d41b58ba8a901 (patch)
treef68d0edd7c72d2c14e6165ffc11d0b4d4c69def9 /alsa/pcm_a2dp.c
parentcb079810a52ebbc4ec46c33b2a0f31a6b9c8c778 (diff)
Implement connection caching
Diffstat (limited to 'alsa/pcm_a2dp.c')
-rw-r--r--alsa/pcm_a2dp.c133
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;
}