summaryrefslogtreecommitdiffstats
path: root/audio/pcm_bluetooth.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2007-06-07 12:26:17 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2007-06-07 12:26:17 +0000
commit00c71248e732de0230c12df4240087a6b2747179 (patch)
treedc247555a0ff1861509351ed6ebc9c4c184c294e /audio/pcm_bluetooth.c
parent9756e32f5a6172ec455c0ff04250a86852457b5d (diff)
Major cleanup after importing code from plugz
Diffstat (limited to 'audio/pcm_bluetooth.c')
-rw-r--r--audio/pcm_bluetooth.c237
1 files changed, 128 insertions, 109 deletions
diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c
index c8988edc..6ca86cf4 100644
--- a/audio/pcm_bluetooth.c
+++ b/audio/pcm_bluetooth.c
@@ -96,14 +96,17 @@ static int bluetooth_prepare(snd_pcm_ioplug_t *io)
{
struct bluetooth_data *data = io->private_data;
- DBG("Preparing with io->period_size = %lu, io->buffer_size = %lu", io->period_size, io->buffer_size);
+ DBG("Preparing with io->period_size = %lu, io->buffer_size = %lu",
+ io->period_size, io->buffer_size);
if (io->stream == SND_PCM_STREAM_PLAYBACK) {
- /* If not null for playback, xmms doesn't display time correctly */
+ /* If not null for playback, xmms doesn't display time
+ * correctly */
data->hw_ptr = 0;
}
else {
- /* ALSA library is really picky on the fact hw_ptr is not null. If it is, capture won't start */
+ /* ALSA library is really picky on the fact hw_ptr is not null.
+ * If it is, capture won't start */
data->hw_ptr = io->period_size;
}
return 0;
@@ -114,23 +117,28 @@ static int bluetooth_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params
struct bluetooth_data *data = io->private_data;
struct ipc_data_cfg cfg = data->cfg;
uint32_t period_count = io->buffer_size / io->period_size;
+ int opt_name;
+
+ opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
+ SCO_TXBUFS : SCO_RXBUFS;
DBG("fd = %d, period_count = %d", cfg.fd, period_count);
- if(setsockopt(cfg.fd, SOL_SCO,
- io->stream == SND_PCM_STREAM_PLAYBACK ? SCO_TXBUFS : SCO_RXBUFS,
- &period_count,
- sizeof(period_count)) == 0) {
+ if (setsockopt(cfg.fd, SOL_SCO, opt_name, &period_count,
+ sizeof(period_count)) == 0)
return 0;
- } else if(setsockopt(cfg.fd, SOL_SCO,
- io->stream == SND_PCM_STREAM_PLAYBACK ? SO_SNDBUF : SO_RCVBUF,
- &period_count,
- sizeof(period_count)) == 0) {
+
+ opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
+ SO_SNDBUF : SO_RCVBUF;
+
+ if (setsockopt(cfg.fd, SOL_SCO, opt_name, &period_count,
+ sizeof(period_count)) == 0)
return 0;
- } else {
- SNDERR("Unable to set number of SCO buffers : please upgrade your Kernel !");
- return -EINVAL;
- }
+
+ SNDERR("Unable to set number of SCO buffers: please upgrade your"
+ "kernel!");
+
+ return -EINVAL;
}
static snd_pcm_sframes_t bluetooth_read(snd_pcm_ioplug_t *io,
@@ -140,56 +148,50 @@ static snd_pcm_sframes_t bluetooth_read(snd_pcm_ioplug_t *io,
{
struct bluetooth_data *data = io->private_data;
struct ipc_data_cfg cfg = data->cfg;
-
- snd_pcm_sframes_t ret = 0;
+ snd_pcm_uframes_t frames_to_write, ret;
+ unsigned char *buff;
+ int nrecv;
DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu, io->nonblock=%u",
areas->step, areas->first, offset, size, io->nonblock);
- if (data->count == 0) {
- int nrecv;
-
- nrecv = recv(cfg.fd, data->buffer, cfg.pkt_len,
- MSG_WAITALL | (io->nonblock ? MSG_DONTWAIT : 0 ));
-
- if (nrecv == cfg.pkt_len) {
- ret = 0;
- /* Increment hardware transmition pointer */
- data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % io->buffer_size;
- }
- else if (nrecv > 0) {
- ret = -EIO;
- SNDERR(strerror(-ret));
- }
- else if (nrecv == -1 && errno == EAGAIN) {
- ret = -EAGAIN;
- }
- else { /* nrecv < 0 */
- /* EPIPE means device underrun in ALSA world. But we mean we lost contact
- with server, so we have to find another error code */
- ret = (errno == EPIPE ? -EIO : -errno);
- SYSERR("Lost contact with headsetd");
- }
+ if (data->count > 0)
+ goto proceed;
+
+ nrecv = recv(cfg.fd, data->buffer, cfg.pkt_len,
+ MSG_WAITALL | (io->nonblock ? MSG_DONTWAIT : 0));
+
+ if (nrecv < 0) {
+ ret = (errno == EPIPE) ? -EIO : -errno;
+ goto done;
}
- if(ret == 0) { /* Still ok, proceed */
- snd_pcm_uframes_t frames_to_write;
- unsigned char *buff;
-
- buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8;
-
- if((data->count + cfg.sample_size * size) <= cfg.pkt_len)
- frames_to_write = size;
- else
- frames_to_write = (cfg.pkt_len - data->count) / cfg.sample_size;
-
- memcpy(buff, data->buffer + data->count, areas->step / 8 * frames_to_write);
- data->count += (areas->step / 8 * frames_to_write);
- data->count %= cfg.pkt_len;
- /* Return written frames count */
- ret = frames_to_write;
+
+ if (nrecv != cfg.pkt_len) {
+ ret = -EIO;
+ SNDERR(strerror(-ret));
+ goto done;
}
- DBG("returning %d", (int)ret);
+ /* Increment hardware transmition pointer */
+ data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % io->buffer_size;
+
+proceed:
+ buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8;
+
+ if ((data->count + cfg.sample_size * size) <= cfg.pkt_len)
+ frames_to_write = size;
+ else
+ frames_to_write = (cfg.pkt_len - data->count) / cfg.sample_size;
+
+ memcpy(buff, data->buffer + data->count, areas->step / 8 * frames_to_write);
+ data->count += (areas->step / 8 * frames_to_write);
+ data->count %= cfg.pkt_len;
+
+ /* Return written frames count */
+ ret = frames_to_write;
+
+done:
+ DBG("returning %lu", ret);
return ret;
}
@@ -203,9 +205,11 @@ static snd_pcm_sframes_t bluetooth_write(snd_pcm_ioplug_t *io,
snd_pcm_sframes_t ret = 0;
snd_pcm_uframes_t frames_to_read;
unsigned char *buff;
+ int rsend;
- DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu, io->nonblock=%u",
- areas->step, areas->first, offset, size, io->nonblock);
+ DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu,"
+ "io->nonblock=%u", areas->step, areas->first,
+ offset, size, io->nonblock);
if ((data->count + cfg.sample_size * size) <= cfg.pkt_len)
frames_to_read = size;
@@ -216,34 +220,28 @@ static snd_pcm_sframes_t bluetooth_write(snd_pcm_ioplug_t *io,
buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8;
memcpy(data->buffer + data->count, buff, areas->step / 8 * frames_to_read);
- if ((data->count + areas->step / 8 * frames_to_read) == cfg.pkt_len) {
- int rsend;
- /* Actually send packet */
- rsend = send(cfg.fd, data->buffer, cfg.pkt_len, io->nonblock ? MSG_DONTWAIT : 0);
- if (rsend > 0) {
- /* Reset count pointer */
- data->count = 0;
-
- /* Increment hardware transmition pointer */
- data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % io->buffer_size;
-
- ret = frames_to_read;
- }
- else {
- /* EPIPE means device underrun in ALSA world. But we mean we lost contact
- with server, so we have to find another error code */
- ret = (errno == EPIPE ? -EIO : -errno);
- if(errno == EPIPE)
- SYSERR("Lost contact with headsetd");
- }
- }
- else {
+ if ((data->count + areas->step / 8 * frames_to_read) != cfg.pkt_len) {
/* Remember we have some frame in the pipe now */
data->count += areas->step / 8 * frames_to_read;
- /* Ask for more */
ret = frames_to_read;
+ goto done;
}
+ rsend = send(cfg.fd, data->buffer, cfg.pkt_len, io->nonblock ? MSG_DONTWAIT : 0);
+ if (rsend > 0) {
+ /* Reset count pointer */
+ data->count = 0;
+
+ /* Increment hardware transmition pointer */
+ data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % io->buffer_size;
+
+ ret = frames_to_read;
+ } else if (rsend < 0)
+ ret = (errno == EPIPE) ? -EIO : -errno;
+ else
+ ret = -EIO;
+
+done:
DBG("returning %d", (int)ret);
return ret;
}
@@ -320,37 +318,46 @@ static int bluetooth_cfg(struct bluetooth_data *data)
struct ipc_packet *pkt;
DBG("Sending PKT_TYPE_CFG_REQ...");
+
pkt = malloc(len);
+ if (!pkt)
+ return -ENOMEM;
+
memset(pkt, 0, len);
pkt->type = PKT_TYPE_CFG_REQ;
pkt->role = PKT_ROLE_NONE;
pkt->error = PKT_ERROR_NONE;
+
res = send(data->sock, pkt, len, 0);
if (res < 0)
- return errno;
+ return -errno;
+
DBG("OK - %d bytes sent", res);
DBG("Waiting for response...");
memset(pkt, 0, len);
res = recv(data->sock, pkt, len, 0);
-
if (res < 0)
return -errno;
+
DBG("OK - %d bytes received", res);
if (pkt->type != PKT_TYPE_CFG_RSP) {
- SNDERR("Unexpected packet type received: type = %d", pkt->type);
+ SNDERR("Unexpected packet type received: type = %d",
+ pkt->type);
return -EINVAL;
}
if (pkt->error != PKT_ERROR_NONE) {
- SNDERR("Error while configuring device: error = %d", pkt->error);
+ SNDERR("Error while configuring device: error = %d",
+ pkt->error);
return pkt->error;
}
if (pkt->length != sizeof(struct ipc_data_cfg)) {
- SNDERR("Error while configuring device: packet size doesn't match");
+ SNDERR("Error while configuring device: packet size doesn't"
+ "match");
return -EINVAL;
}
@@ -358,16 +365,19 @@ static int bluetooth_cfg(struct bluetooth_data *data)
DBG("Device configuration:");
- DBG("fd=%d, fd_opt=%u, channels=%u, pkt_len=%u, sample_size=%u, rate=%u",
- data->cfg.fd, data->cfg.fd_opt, data->cfg.channels,
- data->cfg.pkt_len, data->cfg.sample_size, data->cfg.rate);
+ DBG("fd=%d, fd_opt=%u, channels=%u, pkt_len=%u, sample_size=%u,"
+ "rate=%u", data->cfg.fd, data->cfg.fd_opt,
+ data->cfg.channels, data->cfg.pkt_len,
+ data->cfg.sample_size, data->cfg.rate);
if (data->cfg.fd == -1) {
- SNDERR("Error while configuring device: could not acquire audio socket");
+ SNDERR("Error while configuring device: could not acquire"
+ "audio socket");
return -EINVAL;
}
free(pkt);
+
return 0;
}
@@ -379,10 +389,15 @@ static int bluetooth_init(struct bluetooth_data *data)
if (!data)
return -EINVAL;
+ memset(data, 0, sizeof(struct bluetooth_data));
+
+ data->sock = -1;
+
id = abs(getpid() * rand());
sk = socket(PF_LOCAL, SOCK_DGRAM, 0);
if (sk < 0) {
+ err = -errno;
SNDERR("Can't open socket");
return -errno;
}
@@ -394,9 +409,10 @@ static int bluetooth_init(struct bluetooth_data *data)
DBG("Binding address: %s", addr.sun_path + 1);
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = -errno;
SNDERR("Can't bind socket");
close(sk);
- return -errno;
+ return err;
}
memset(&addr, 0, sizeof(addr));
@@ -405,19 +421,21 @@ static int bluetooth_init(struct bluetooth_data *data)
DBG("Connecting to address: %s", addr.sun_path + 1);
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = -errno;
SNDERR("Can't connect socket");
close(sk);
- return -errno;
+ return err;
}
data->sock = sk;
- if ((err = bluetooth_cfg(data)) < 0) {
- free(data);
+ err = bluetooth_cfg(data);
+ if (err < 0)
return err;
- }
data->buffer = malloc(data->cfg.pkt_len);
+ if (!data->buffer)
+ return -ENOMEM;
memset(data->buffer, 0, data->cfg.pkt_len);
@@ -426,33 +444,31 @@ static int bluetooth_init(struct bluetooth_data *data)
SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
{
-// snd_config_iterator_t iter, next;
struct bluetooth_data *data;
int err;
- DBG("Bluetooth PCM plugin blablabla (%s)",
+ DBG("Bluetooth PCM plugin (%s)",
stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture");
-// snd_config_for_each(iter, next, conf) {
-// }
-
- DBG("Initing Bluetooth...");
data = malloc(sizeof(struct bluetooth_data));
- memset(data, 0, sizeof(struct bluetooth_data));
+ if (!data) {
+ err = -ENOMEM;
+ goto error;
+ }
+
err = bluetooth_init(data);
if (err < 0)
goto error;
- DBG("Done");
data->io.version = SND_PCM_IOPLUG_VERSION;
data->io.name = "Bluetooth Audio Device";
- data->io.mmap_rw = 0; /* No direct mmap communication */
+ data->io.mmap_rw = 0; /* No direct mmap communication */
data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
&bluetooth_playback_callback : &bluetooth_capture_callback;
data->io.poll_fd = data->cfg.fd;
data->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ?
- POLLOUT : POLLIN;
+ POLLOUT : POLLIN;
data->io.private_data = data;
err = snd_pcm_ioplug_create(&data->io, name, stream, mode);
@@ -470,8 +486,11 @@ SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
return 0;
error:
- close(data->sock);
- free(data);
+ if (data) {
+ if (data->sock >= 0)
+ close(data->sock);
+ free(data);
+ }
return err;
}