summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2007-08-20 09:06:13 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2007-08-20 09:06:13 +0000
commit8905b2bad9aebd0911d452b53b9cbe975ad5bdcc (patch)
treeced4c2609ba511da209c8fdbba04d1560c8cf117
parent3919df0168ddf293912231e5e6477bc6f0c24115 (diff)
Revert accidental commit of pcm_bluetooth.c changes
-rw-r--r--audio/pcm_bluetooth.c411
1 files changed, 147 insertions, 264 deletions
diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c
index a7c90661..c75f8af3 100644
--- a/audio/pcm_bluetooth.c
+++ b/audio/pcm_bluetooth.c
@@ -28,7 +28,6 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
-#include <pthread.h>
#include <netinet/in.h>
@@ -41,7 +40,7 @@
#include "ipc.h"
#include "sbc.h"
-/*#define ENABLE_DEBUG*/
+//#define ENABLE_DEBUG
#define BUFFER_SIZE 2048
@@ -59,9 +58,6 @@
#define SCO_RXBUFS 0x04
#endif
-#define PERIOD_TIME_USECS(data) (1000000.0 * \
- ((data)->io.period_size) / \
- (data)->io.rate)
struct rtp_header {
uint8_t cc:4;
uint8_t x:1;
@@ -97,13 +93,13 @@ struct bluetooth_a2dp {
uint16_t seq_num; /* */
int frame_count; /* */
- pthread_t hw_thread; /* Makes virtual hw pointer move */
- int pipefd[2]; /* Inter thread communication */
+ int bandwithcount;
+ struct timeval bandwithtimestamp;
};
struct bluetooth_data {
snd_pcm_ioplug_t io;
- volatile snd_pcm_sframes_t hw_ptr;
+ snd_pcm_sframes_t hw_ptr;
struct ipc_data_cfg cfg; /* Bluetooth device config */
int stream_fd; /* Audio stream filedescriptor */
int sock; /* Daemon unix socket */
@@ -117,9 +113,9 @@ void memcpy_changeendian(void *dst, const void *src, int size)
int i;
const uint16_t *ptrsrc = src;
uint16_t *ptrdst = dst;
-
- for (i = 0; i < size / 2; i++)
+ for (i = 0; i < size / 2; i++) {
*ptrdst++ = htons(*ptrsrc++);
+ }
}
static int bluetooth_start(snd_pcm_ioplug_t *io)
@@ -136,85 +132,6 @@ static int bluetooth_stop(snd_pcm_ioplug_t *io)
return 0;
}
-static void *a2dp_playback_hw_thread(void *param)
-{
- struct bluetooth_data* data = (struct bluetooth_data *)param;
- unsigned int num_period_elapsed = 0;
- unsigned long long starttime; /* in usecs */
- struct timeval tv;
- int ret;
-
- gettimeofday(&tv, 0);
- starttime = tv.tv_sec * 1000000 + tv.tv_usec;
-
- for(;;) {
- unsigned long long curtime;
- unsigned int ntimes;
-
- gettimeofday(&tv, 0);
-
- /* How much time period_time has elapsed since the thread started ? */
- curtime = tv.tv_sec * 1000000 + tv.tv_usec;
- ntimes = (1.0 * (curtime - starttime)) / PERIOD_TIME_USECS(data);
-
- if (ntimes > num_period_elapsed) {
- char c = 'w';
- data->hw_ptr = (data->hw_ptr +
- (ntimes - num_period_elapsed)
- * data->io.period_size)
- % data->io.buffer_size;
- DBG("pointer = %ld", data->hw_ptr);
- /* Notify user that hardware pointer has moved */
- ret = write(data->a2dp.pipefd[1], &c, 1);
- assert(ret == 1);
- num_period_elapsed = ntimes;
- }
- /* Period time is usually no shorter that 1 ms,
- no need to sleep for a shorter amount of time */
- usleep(1000);
- /* Offer opportunity to be canceled by main thread */
- pthread_testcancel();
- }
-}
-static int bluetooth_a2dp_playback_start(snd_pcm_ioplug_t *io)
-{
- struct bluetooth_data *data = io->private_data;
- struct bluetooth_a2dp *a2dp_data = &data->a2dp;
- int ret = 0;
-
- DBG("%p", io);
-
- assert(a2dp_data->hw_thread == 0);
- ret = -pthread_create(&a2dp_data->hw_thread, 0, a2dp_playback_hw_thread, data);
-
- DBG(" - return %d", ret);
-
- return ret;
-}
-
-static int bluetooth_a2dp_playback_stop(snd_pcm_ioplug_t *io)
-{
- struct bluetooth_data *data = io->private_data;
- struct bluetooth_a2dp *a2dp_data = &data->a2dp;
- int ret = 0;
-
- DBG("%p", io);
-
- /* Beware - We can be called more than once */
- if (a2dp_data->hw_thread != 0) {
- ret = -pthread_cancel(a2dp_data->hw_thread);
- if (ret != 0)
- goto done;
-
- ret = -pthread_join(a2dp_data->hw_thread, 0);
- }
-
-done:
- a2dp_data->hw_thread = 0;
- DBG(" - return %d", ret);
- return ret;
-}
-
static snd_pcm_sframes_t bluetooth_pointer(snd_pcm_ioplug_t *io)
{
struct bluetooth_data *data = io->private_data;
@@ -237,12 +154,6 @@ static void bluetooth_exit(struct bluetooth_data *data)
if (data->cfg.codec == CFG_CODEC_SBC)
sbc_finish(&data->a2dp.sbc);
- if(data->a2dp.pipefd[0] > 0)
- close(data->a2dp.pipefd[0]);
-
- if(data->a2dp.pipefd[1] > 0)
- close(data->a2dp.pipefd[1]);
-
free(data);
}
@@ -260,7 +171,6 @@ static int bluetooth_close(snd_pcm_ioplug_t *io)
static int bluetooth_prepare(snd_pcm_ioplug_t *io)
{
struct bluetooth_data *data = io->private_data;
- char c = 'w';
DBG("Preparing with io->period_size = %lu, io->buffer_size = %lu",
io->period_size, io->buffer_size);
@@ -274,8 +184,7 @@ static int bluetooth_prepare(snd_pcm_ioplug_t *io)
* If it is, capture won't start */
data->hw_ptr = io->period_size;
- /* a2dp : wake up any client polling at us */
- return write(data->a2dp.pipefd[1], &c, 1);
+ return 0;
}
static int bluetooth_hsp_hw_params(snd_pcm_ioplug_t *io,
@@ -325,80 +234,11 @@ static int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io,
return 0;
err = errno;
-
SNDERR("%s (%d)", strerror(err), err);
return -err;
}
-static int bluetooth_poll_descriptors(snd_pcm_ioplug_t *io,
- struct pollfd *pfd,
- unsigned int space)
-{
- assert(io);
- assert(space >= 1);
-
- pfd[0].fd = ((struct bluetooth_data *)io->private_data)->stream_fd;
- pfd[0].events = POLLIN;
- pfd[0].revents = 0;
-
- return 1;
-}
-
-static int bluetooth_poll_revents(snd_pcm_ioplug_t *io ATTRIBUTE_UNUSED,
- struct pollfd *pfds, unsigned int nfds,
- unsigned short *revents)
-{
- assert(pfds && nfds == 1 && revents);
-
- *revents = pfds[0].revents;
-
- return 0;
-}
-
-static int bluetooth_a2dp_playback_poll_descriptors(snd_pcm_ioplug_t *io,
- struct pollfd *pfd,
- unsigned int space)
-{
- struct bluetooth_data *data = io->private_data;
-
- DBG("");
-
- assert(io);
- assert(space >= 1);
- assert(data->a2dp.pipefd[0] != 0);
-
- pfd[0].fd = data->a2dp.pipefd[0];
- pfd[0].events = POLLIN;
- pfd[0].revents = 0;
-
- return 1;
-}
-
-static int bluetooth_a2dp_playback_poll_revents(snd_pcm_ioplug_t *io,
- struct pollfd *pfds,
- unsigned int nfds,
- unsigned short *revents)
-{
- static char buf[1];
- int ret = 0;
-
- DBG("");
-
- assert(pfds);
- assert(nfds == 1);
- assert(revents);
- assert(pfds[0].fd != 0);
-
- if (io->state != SND_PCM_STATE_PREPARED)
- ret = read(pfds[0].fd, buf, 1);
-
- *revents = (pfds[0].revents & ~POLLIN) | POLLOUT;
-
- return 0;
-}
-
-
static snd_pcm_sframes_t bluetooth_hsp_read(snd_pcm_ioplug_t *io,
const snd_pcm_channel_area_t *areas,
snd_pcm_uframes_t offset,
@@ -524,14 +364,19 @@ static snd_pcm_sframes_t bluetooth_a2dp_read(snd_pcm_ioplug_t *io,
return ret;
}
-static int avdtp_write(struct bluetooth_data *data)
+static int avdtp_write(struct bluetooth_data *data, unsigned int nonblock)
{
- int ret = 0;
+ int count = 0, written = 0, ret = 0;
struct rtp_header *header;
struct rtp_payload *payload;
struct bluetooth_a2dp *a2dp = &data->a2dp;
+#ifdef ENABLE_DEBUG
+ static struct timeval send_date = { 0, 0 };
+ static struct timeval prev_date = { 0, 0 };
+ struct timeval send_delay = { 0, 0 };
+ struct timeval sendz_delay = { 0, 0 };
+#endif
- DBG("");
header = (void *) a2dp->buffer;
payload = (void *) (a2dp->buffer + sizeof(*header));
@@ -544,24 +389,98 @@ static int avdtp_write(struct bluetooth_data *data)
header->timestamp = htonl(a2dp->nsamples);
header->ssrc = htonl(1);
- ret = send(data->stream_fd, a2dp->buffer, a2dp->count,
- MSG_DONTWAIT);
- if(ret == -1)
- ret = -errno;
+ while (count++ < 10) {
+#ifdef ENABLE_DEBUG
+ gettimeofday(&send_date, NULL);
+#endif
+ ret = send(data->stream_fd, a2dp->buffer, a2dp->count,
+ nonblock ? MSG_DONTWAIT : 0);
+ if (ret < 0) {
+ ret = -errno;
+ if (errno == EAGAIN)
+ goto retry;
+ fprintf(stderr, "send: %s (%d)\n", strerror(errno),
+ errno);
+ goto done;
+ }
+
+ written += ret;
+
+#ifdef ENABLE_DEBUG
+ if ((written >= 0 || errno == EAGAIN) && prev_date.tv_sec != 0) {
+ long delay, real, theo, delta;
+
+ delay = (long) (send_delay.tv_sec * 1000 +
+ send_delay.tv_usec / 1000),
+ real = (long) (sendz_delay.tv_sec * 1000 +
+ sendz_delay.tv_usec / 1000);
+ theo = (long) (((float) a2dp->nsamples) /
+ data->cfg.rate * 1000.0);
+ delta = (long) (sendz_delay.tv_sec * 1000 +
+ sendz_delay.tv_usec / 1000) -
+ (long) (((float) a2dp->nsamples) /
+ data->cfg.rate * 1000.0);
+
+ timersub(&send_date, &prev_date, &send_delay);
+ timersub(&send_date, &a2dp->ntimestamp, &sendz_delay);
+
+ printf("send %d (cumul=%d) samples (delay=%ld ms,"
+ " real=%ld ms, theo=%ld ms,"
+ " delta=%ld ms).\n", a2dp->samples,
+ a2dp->nsamples, delay, real, theo,
+ delta);
+ }
+#endif
+ if (written == a2dp->count)
+ break;
+
+ a2dp->count -= written;
- /* Kernel side l2cap socket layer makes sure either everything
- is buffered for sending, or nothing is buffered.
- This assertion is to remind people of this fact (and be noticed
- the day that changes)
- */
- assert(ret < 0 || ret == a2dp->count);
+retry:
+ DBG("send (retry).");
+ usleep(150000);
+ }
+
+#ifdef ENABLE_DEBUG
+ prev_date = send_date;
+#endif
+
+ if (written != a2dp->count)
+ printf("Wrote %d not %d bytes\n", written, a2dp->count);
+
+#ifdef ENABLE_DEBUG
+ else {
+ /* Measure bandwith usage */
+ struct timeval now = { 0, 0 };
+ struct timeval interval = { 0, 0 };
+
+ if(a2dp->bandwithtimestamp.tv_sec == 0)
+ gettimeofday(&a2dp->bandwithtimestamp, NULL);
+
+ /* See if we must wait again */
+ gettimeofday(&now, NULL);
+ timersub(&now, &a2dp->bandwithtimestamp, &interval);
+ if(interval.tv_sec > 0)
+ printf("Bandwith: %d (%d kbps)\n", a2dp->bandwithcount,
+ a2dp->bandwithcount / 128);
+ a2dp->bandwithtimestamp = now;
+ a2dp->bandwithcount = 0;
+ }
+
+ a2dp->bandwithcount += written;
+#endif
+
+done:
/* Reset buffer of data to send */
a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
a2dp->frame_count = 0;
a2dp->samples = 0;
a2dp->seq_num++;
+ if (written > 0)
+ return written;
+
return ret;
}
@@ -578,35 +497,9 @@ static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,
uint8_t *buff;
static int codesize = 0;
- DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu"
- , areas->step, areas->first, offset, size);
- DBG("hw_ptr = %lu, appl_ptr = %lu"
- , io->hw_ptr, io->appl_ptr);
-
- if(io->hw_ptr > io->appl_ptr) {
- ret = bluetooth_a2dp_playback_stop(io);
- if(ret == 0)
- ret = -EPIPE;
- goto done;
- }
-
- /* Check if we should autostart */
- if(io->state == SND_PCM_STATE_PREPARED) {
- snd_pcm_sw_params_t *swparams;
- snd_pcm_uframes_t threshold;
-
- snd_pcm_sw_params_malloc(&swparams);
- if(!snd_pcm_sw_params_current(io->pcm, swparams)
- && !snd_pcm_sw_params_get_start_threshold(swparams,
- &threshold) ) {
- if(io->appl_ptr >= threshold) {
- ret = snd_pcm_start(io->pcm);
- if(ret != 0)
- goto done;
- }
- }
- snd_pcm_sw_params_free(swparams);
- }
+ DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu,"
+ "io->nonblock=%u", areas->step, areas->first,
+ offset, size, io->nonblock);
if (codesize == 0) {
/* How much data can be encoded by sbc at a time? */
@@ -655,7 +548,7 @@ static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,
DBG("encoded = %d a2dp.sbc.len= %d", encoded, a2dp->sbc.len);
if (a2dp->count + a2dp->sbc.len >= data->cfg.pkt_len) {
- ret = avdtp_write(data);
+ ret = avdtp_write(data, io->nonblock);
if (ret < 0) {
if (-ret == EPIPE)
ret = -EIO;
@@ -668,60 +561,55 @@ static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,
a2dp->frame_count++;
a2dp->samples += encoded / frame_size;
a2dp->nsamples += encoded / frame_size;
+ /* Increment hardware transmition pointer */
+ data->hw_ptr = (data->hw_ptr + encoded / frame_size)
+ % io->buffer_size;
ret = frames_to_read;
done:
- DBG("returning %ld", ret);
+ DBG("returning %lu", ret);
return ret;
}
static snd_pcm_ioplug_callback_t bluetooth_hsp_playback = {
- .start = bluetooth_start,
- .stop = bluetooth_stop,
- .pointer = bluetooth_pointer,
- .close = bluetooth_close,
- .hw_params = bluetooth_hsp_hw_params,
- .prepare = bluetooth_prepare,
- .transfer = bluetooth_hsp_write,
- .poll_descriptors = bluetooth_poll_descriptors,
- .poll_revents = bluetooth_poll_revents,
+ .start = bluetooth_start,
+ .stop = bluetooth_stop,
+ .pointer = bluetooth_pointer,
+ .close = bluetooth_close,
+ .hw_params = bluetooth_hsp_hw_params,
+ .prepare = bluetooth_prepare,
+ .transfer = bluetooth_hsp_write,
};
static snd_pcm_ioplug_callback_t bluetooth_hsp_capture = {
- .start = bluetooth_start,
- .stop = bluetooth_stop,
- .pointer = bluetooth_pointer,
- .close = bluetooth_close,
- .hw_params = bluetooth_hsp_hw_params,
- .prepare = bluetooth_prepare,
- .transfer = bluetooth_hsp_read,
- .poll_descriptors = bluetooth_poll_descriptors,
- .poll_revents = bluetooth_poll_revents,
+ .start = bluetooth_start,
+ .stop = bluetooth_stop,
+ .pointer = bluetooth_pointer,
+ .close = bluetooth_close,
+ .hw_params = bluetooth_hsp_hw_params,
+ .prepare = bluetooth_prepare,
+ .transfer = bluetooth_hsp_read,
};
static snd_pcm_ioplug_callback_t bluetooth_a2dp_playback = {
- .start = bluetooth_a2dp_playback_start,
- .stop = bluetooth_a2dp_playback_stop,
- .pointer = bluetooth_pointer,
- .close = bluetooth_close,
- .hw_params = bluetooth_a2dp_hw_params,
- .prepare = bluetooth_prepare,
- .transfer = bluetooth_a2dp_write,
- .poll_descriptors = bluetooth_a2dp_playback_poll_descriptors,
- .poll_revents = bluetooth_a2dp_playback_poll_revents,
+ .start = bluetooth_start,
+ .stop = bluetooth_stop,
+ .pointer = bluetooth_pointer,
+ .close = bluetooth_close,
+ .hw_params = bluetooth_a2dp_hw_params,
+ .prepare = bluetooth_prepare,
+ .transfer = bluetooth_a2dp_write,
};
static snd_pcm_ioplug_callback_t bluetooth_a2dp_capture = {
- .start = bluetooth_start,
- .stop = bluetooth_stop,
- .pointer = bluetooth_pointer,
- .close = bluetooth_close,
- .hw_params = bluetooth_a2dp_hw_params,
- .prepare = bluetooth_prepare,
- .transfer = bluetooth_a2dp_read,
- .poll_descriptors = bluetooth_poll_descriptors,
- .poll_revents = bluetooth_poll_revents,
+ .start = bluetooth_start,
+ .stop = bluetooth_stop,
+ .pointer = bluetooth_pointer,
+ .close = bluetooth_close,
+ .hw_params = bluetooth_a2dp_hw_params,
+ .prepare = bluetooth_prepare,
+ .transfer = bluetooth_a2dp_read,
};
#define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0]))
@@ -773,7 +661,7 @@ static int bluetooth_hw_constraint(snd_pcm_ioplug_t *io)
return err;
err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS,
- 2, 50);
+ 2, 200);
if (err < 0)
return err;
@@ -790,13 +678,13 @@ static int bluetooth_recvmsg_fd(struct bluetooth_data *data)
.iov_len = sizeof(pkt)
};
struct msghdr msgh = {
- .msg_name = 0,
- .msg_namelen = 0,
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_control = &cmsg_b,
- .msg_controllen = CMSG_LEN(sizeof(int)),
- .msg_flags = 0
+ .msg_name = 0,
+ .msg_namelen = 0,
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = &cmsg_b,
+ .msg_controllen = CMSG_LEN(sizeof(int)),
+ .msg_flags = 0
};
ret = recvmsg(data->sock, &msgh, 0);
@@ -850,14 +738,6 @@ static int bluetooth_a2dp_init(struct bluetooth_data *data,
a2dp->sbc.blocks = sbc->blocks;
a2dp->sbc.bitpool = sbc->bitpool;
-
- if(pipe(a2dp->pipefd) != 0)
- return -errno;
- if(fcntl(a2dp->pipefd[0], F_SETFL, O_NONBLOCK) != 0)
- return -errno;
- if(fcntl(a2dp->pipefd[1], F_SETFL, O_NONBLOCK) != 0)
- return -errno;
-
return 0;
}
@@ -1008,7 +888,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
DBG("Bluetooth PCM plugin (%s)",
stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture");
- data = calloc(1, sizeof(struct bluetooth_data));
+ data = malloc(sizeof(struct bluetooth_data));
if (!data) {
err = -ENOMEM;
goto error;
@@ -1021,6 +901,9 @@ SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
data->io.version = SND_PCM_IOPLUG_VERSION;
data->io.name = "Bluetooth Audio Device";
data->io.mmap_rw = 0; /* No direct mmap communication */
+ data->io.poll_fd = data->stream_fd;
+ data->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ?
+ POLLOUT : POLLIN;
data->io.private_data = data;
if (data->cfg.codec == CFG_CODEC_SBC)