OSDN Git Service

auto import from //branches/cupcake/...@125939
authorThe Android Open Source Project <initial-contribution@android.com>
Sat, 10 Jan 2009 01:51:19 +0000 (17:51 -0800)
committerThe Android Open Source Project <initial-contribution@android.com>
Sat, 10 Jan 2009 01:51:19 +0000 (17:51 -0800)
utils/audio/avdtp.c
utils/audio/liba2dp.c
utils/audio/liba2dp.h
utils/audio/unix.c
utils/tools/Android.mk

index db97ec5..130cd16 100644 (file)
@@ -583,8 +583,9 @@ static gboolean stream_timeout(struct avdtp_stream *stream)
 {
        struct avdtp *session = stream->session;
 
+/* Disabled so we do not disconnect immediately after sending BT_STREAMSTOP_REQ
        avdtp_close(session, stream);
-
+*/
        stream->idle_timer = 0;
 
        return FALSE;
@@ -2758,7 +2759,6 @@ static void avdtp_server_cb(GIOChannel *chan, int err, const bdaddr_t *src,
 
        session->io = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
                                        (GIOFunc) session_cb, session);
-       g_io_channel_unref(chan);
 
        if (service_req_auth(src, dst, ADVANCED_AUDIO_UUID, auth_cb,
                        session) < 0) {
@@ -2766,6 +2766,7 @@ static void avdtp_server_cb(GIOChannel *chan, int err, const bdaddr_t *src,
                goto drop;
        }
 
+       g_io_channel_unref(chan);
        return;
 
 drop:
index 7904948..1eaefa0 100644 (file)
@@ -29,8 +29,6 @@
 #include <stdint.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <time.h>
-#include <sys/time.h>
 #include <signal.h>
 #include <limits.h>
 #include <fcntl.h>
@@ -47,7 +45,7 @@
 #define LOG_TAG "A2DP"
 #include <utils/Log.h>
 
-// #define ENABLE_DEBUG
+/* #define ENABLE_DEBUG */
 
 #define BUFFER_SIZE 2048
 
 
 #define SNDERR LOGE
 
-struct bluetooth_a2dp {
+/* Number of milliseconds worth of audio to buffer in our the data->stream.fd socket */
+#define SOCK_BUFFER_MS         100
+
+struct bluetooth_data {
+       int link_mtu;                                   /* MTU for selected transport channel */
+       struct pollfd stream;                   /* Audio stream filedescriptor */
+       struct pollfd server;                   /* Audio daemon filedescriptor */
+
        sbc_capabilities_t sbc_capabilities;
        sbc_t sbc;                              /* Codec data */
        int sbc_initialized;                    /* Keep track if the encoder is initialized */
+       int     frame_duration;                 /* length of an SBC frame in microseconds */
        int codesize;                           /* SBC codesize */
        int samples;                            /* Number of encoded samples */
        uint8_t buffer[BUFFER_SIZE];            /* Codec transfer buffer */
@@ -83,46 +89,40 @@ struct bluetooth_a2dp {
        int nsamples;                           /* Cumulative number of codec samples */
        uint16_t seq_num;                       /* Cumulative packet sequence */
        int frame_count;                        /* Current frames in buffer*/
-};
 
+       int             started;
+       char    address[20];
+       int     rate;
+       int     channels;
 
-struct bluetooth_data {
-       volatile long hw_ptr;
-       int transport;                                  /* chosen transport SCO or AD2P */
-       int link_mtu;                                   /* MTU for selected transport channel */
-       volatile struct pollfd stream;                  /* Audio stream filedescriptor */
-       struct pollfd server;                           /* Audio daemon filedescriptor */
-       uint8_t buffer[BUFFER_SIZE];            /* Encoded transfer buffer */
-       int count;                                      /* Transfer buffer counter */
-       struct bluetooth_a2dp a2dp;                     /* A2DP data */
+       /* used for pacing our writes to the output socket */
+       struct timeval  last_write;
+       unsigned long   last_duration;
 
-       sig_atomic_t reset;             /* Request XRUN handling */
-       
-       char    address[20];
+       /* true if we already set the buffer size on the data->stream.fd socket */
+       int adjusted_sock_buffer;
 };
 
 
-
 static int audioservice_send(int sk, const bt_audio_msg_header_t *msg);
 static int audioservice_expect(int sk, bt_audio_msg_header_t *outmsg,
                                int expected_type);
+static int bluetooth_a2dp_hw_params(struct bluetooth_data *data);
 
 
 static void bluetooth_exit(struct bluetooth_data *data)
 {
-       struct bluetooth_a2dp *a2dp = &data->a2dp;
-
        if (data->server.fd >= 0)
                bt_audio_service_close(data->server.fd);
 
        if (data->stream.fd >= 0)
                close(data->stream.fd);
 
-       if (a2dp->sbc_initialized)
-               sbc_finish(&a2dp->sbc);
+       if (data->sbc_initialized)
+               sbc_finish(&data->sbc);
 }
 
-static int bluetooth_prepare(struct bluetooth_data *data)
+static int bluetooth_start(struct bluetooth_data *data)
 {
        char c = 'w';
        char buf[BT_AUDIO_IPC_PACKET_SIZE];
@@ -130,12 +130,9 @@ static int bluetooth_prepare(struct bluetooth_data *data)
        bt_audio_rsp_msg_header_t *rsp_hdr = (void*) buf;
        struct bt_streamfd_ind *streamfd_ind = (void*) buf;
        int opt_name, err;
-       struct timeval t = { 100, 0 };
-       int buffer;
-
-       data->reset = 0;
-       data->hw_ptr = 0;
+       int retry = 0;
 
+retry:
        /* send start */
        memset(start_req, 0, BT_AUDIO_IPC_PACKET_SIZE);
        start_req->h.msg_type = BT_STREAMSTART_REQ;
@@ -153,6 +150,14 @@ static int bluetooth_prepare(struct bluetooth_data *data)
                SNDERR("BT_START failed : %s(%d)",
                                        strerror(rsp_hdr->posix_errno),
                                        rsp_hdr->posix_errno);
+               
+               /* if the connection dropped, we may need to reset the configuration */
+               if (!retry) {
+                       retry = 1;
+                       if (bluetooth_a2dp_hw_params(data) == 0)
+                               goto retry;
+               }
+
                return -rsp_hdr->posix_errno;
        }
 
@@ -161,21 +166,54 @@ static int bluetooth_prepare(struct bluetooth_data *data)
        if (err < 0)
                return err;
 
-       if (data->stream.fd >= 0)
+       if (data->stream.fd >= 0) {
                close(data->stream.fd);
+               data->stream.fd = -1;
+               data->adjusted_sock_buffer = 0;
+       }
 
        data->stream.fd = bt_audio_service_get_data_fd(data->server.fd);
        if (data->stream.fd < 0) {
                return -errno;
        }
+       data->stream.events = POLLOUT;
 
-       if (setsockopt(data->stream.fd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t)) < 0)
-               return -errno;
+       return 0;
+}
 
-       /* disable buffering to reduce latency when pausing or changing volume */
-       buffer = 0;
-       if (setsockopt(data->stream.fd, SOL_SOCKET, SO_SNDBUF, &buffer, sizeof(buffer)) < 0)
-               return -errno;
+static int bluetooth_stop(struct bluetooth_data *data)
+{
+       char buf[BT_AUDIO_IPC_PACKET_SIZE];
+       struct bt_streamstop_req *stop_req = (void*) buf;
+       bt_audio_rsp_msg_header_t *rsp_hdr = (void*) buf;
+       int err;
+
+       data->started = 0;
+
+       if (data->stream.fd >= 0) {
+               close(data->stream.fd);
+               data->stream.fd = 0;
+       }
+
+       /* send stop request */
+       memset(stop_req, 0, BT_AUDIO_IPC_PACKET_SIZE);
+       stop_req->h.msg_type = BT_STREAMSTOP_REQ;
+
+       err = audioservice_send(data->server.fd, &stop_req->h);
+       if (err < 0)
+               return err;
+
+       err = audioservice_expect(data->server.fd, &rsp_hdr->msg_h,
+                                       BT_STREAMSTOP_RSP);
+       if (err < 0)
+               return err;
+
+       if (rsp_hdr->posix_errno != 0) {
+               SNDERR("BT_STREAMSTOP failed : %s(%d)",
+                                       strerror(rsp_hdr->posix_errno),
+                                       rsp_hdr->posix_errno);
+               return -rsp_hdr->posix_errno;
+       }
 
        return 0;
 }
@@ -216,13 +254,13 @@ static uint8_t default_bitpool(uint8_t freq, uint8_t mode)
        }
 }
 
-static int bluetooth_a2dp_init(struct bluetooth_data *data, int rate, int channels)
+static int bluetooth_a2dp_init(struct bluetooth_data *data)
 {
-       sbc_capabilities_t *cap = &data->a2dp.sbc_capabilities;
+       sbc_capabilities_t *cap = &data->sbc_capabilities;
        unsigned int max_bitpool, min_bitpool;
        int dir;
 
-       switch (rate) {
+       switch (data->rate) {
        case 48000:
                cap->frequency = BT_SBC_SAMPLING_FREQ_48000;
                break;
@@ -236,11 +274,11 @@ static int bluetooth_a2dp_init(struct bluetooth_data *data, int rate, int channe
                cap->frequency = BT_SBC_SAMPLING_FREQ_16000;
                break;
        default:
-               DBG("Rate %d not supported", rate);
+               DBG("Rate %d not supported", data->rate);
                return -1;
        }
 
-       if (channels == 2) {
+       if (data->channels == 2) {
                if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)
                        cap->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
                else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO)
@@ -292,91 +330,91 @@ static int bluetooth_a2dp_init(struct bluetooth_data *data, int rate, int channe
        cap->min_bitpool = min_bitpool;
        cap->max_bitpool = max_bitpool;
 
-DBG("bluetooth_a2dp_init bottom:\n  channel_mode: %d\n  frequency: %d\n  allocation_method: %d\n  subbands: %d\n  block_length: %d\n  min_bitpool: %d\n  max_bitpool: %d\n  ",
-    cap->channel_mode, cap->frequency, cap->allocation_method, cap->subbands, 
-    cap->block_length, cap->min_bitpool, cap->max_bitpool);
+       DBG("bluetooth_a2dp_init bottom:\n  channel_mode: %d\n  frequency: %d\n  allocation_method: %d\n  subbands: %d\n  block_length: %d\n  min_bitpool: %d\n  max_bitpool: %d\n  ",
+               cap->channel_mode, cap->frequency, cap->allocation_method, cap->subbands, 
+               cap->block_length, cap->min_bitpool, cap->max_bitpool);
 
 
        return 0;
 }
 
-static void bluetooth_a2dp_setup(struct bluetooth_a2dp *a2dp)
+static void bluetooth_a2dp_setup(struct bluetooth_data *data)
 {
-       sbc_capabilities_t active_capabilities = a2dp->sbc_capabilities;
+       sbc_capabilities_t active_capabilities = data->sbc_capabilities;
 
-       if (a2dp->sbc_initialized)
-               sbc_reinit(&a2dp->sbc, 0);
+       if (data->sbc_initialized)
+               sbc_reinit(&data->sbc, 0);
        else
-               sbc_init(&a2dp->sbc, 0);
-       a2dp->sbc_initialized = 1;
+               sbc_init(&data->sbc, 0);
+       data->sbc_initialized = 1;
 
        if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_16000)
-               a2dp->sbc.frequency = SBC_FREQ_16000;
+               data->sbc.frequency = SBC_FREQ_16000;
 
        if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_32000)
-               a2dp->sbc.frequency = SBC_FREQ_32000;
+               data->sbc.frequency = SBC_FREQ_32000;
 
        if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_44100)
-               a2dp->sbc.frequency = SBC_FREQ_44100;
+               data->sbc.frequency = SBC_FREQ_44100;
 
        if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_48000)
-               a2dp->sbc.frequency = SBC_FREQ_48000;
+               data->sbc.frequency = SBC_FREQ_48000;
 
        if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
-               a2dp->sbc.mode = SBC_MODE_MONO;
+               data->sbc.mode = SBC_MODE_MONO;
 
        if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL)
-               a2dp->sbc.mode = SBC_MODE_DUAL_CHANNEL;
+               data->sbc.mode = SBC_MODE_DUAL_CHANNEL;
 
        if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_STEREO)
-               a2dp->sbc.mode = SBC_MODE_STEREO;
+               data->sbc.mode = SBC_MODE_STEREO;
 
        if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)
-               a2dp->sbc.mode = SBC_MODE_JOINT_STEREO;
+               data->sbc.mode = SBC_MODE_JOINT_STEREO;
 
-       a2dp->sbc.allocation = active_capabilities.allocation_method
+       data->sbc.allocation = active_capabilities.allocation_method
                                == BT_A2DP_ALLOCATION_SNR ? SBC_AM_SNR
                                : SBC_AM_LOUDNESS;
 
        switch (active_capabilities.subbands) {
        case BT_A2DP_SUBBANDS_4:
-               a2dp->sbc.subbands = SBC_SB_4;
+               data->sbc.subbands = SBC_SB_4;
                break;
        case BT_A2DP_SUBBANDS_8:
-               a2dp->sbc.subbands = SBC_SB_8;
+               data->sbc.subbands = SBC_SB_8;
                break;
        }
 
        switch (active_capabilities.block_length) {
        case BT_A2DP_BLOCK_LENGTH_4:
-               a2dp->sbc.blocks = SBC_BLK_4;
+               data->sbc.blocks = SBC_BLK_4;
                break;
        case BT_A2DP_BLOCK_LENGTH_8:
-               a2dp->sbc.blocks = SBC_BLK_8;
+               data->sbc.blocks = SBC_BLK_8;
                break;
        case BT_A2DP_BLOCK_LENGTH_12:
-               a2dp->sbc.blocks = SBC_BLK_12;
+               data->sbc.blocks = SBC_BLK_12;
                break;
        case BT_A2DP_BLOCK_LENGTH_16:
-               a2dp->sbc.blocks = SBC_BLK_16;
+               data->sbc.blocks = SBC_BLK_16;
                break;
        }
 
-       a2dp->sbc.bitpool = active_capabilities.max_bitpool;
-       a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
-       a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
+       data->sbc.bitpool = active_capabilities.max_bitpool;
+       data->codesize = sbc_get_codesize(&data->sbc);
+       data->frame_duration = sbc_get_frame_duration(&data->sbc);
+       data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
 }
 
-static int bluetooth_a2dp_hw_params(struct bluetooth_data *data, int rate, int channels)
+static int bluetooth_a2dp_hw_params(struct bluetooth_data *data)
 {
-       struct bluetooth_a2dp *a2dp = &data->a2dp;
        char buf[BT_AUDIO_IPC_PACKET_SIZE];
        bt_audio_rsp_msg_header_t *rsp_hdr = (void*) buf;
        struct bt_setconfiguration_req *setconf_req = (void*) buf;
        struct bt_setconfiguration_rsp *setconf_rsp = (void*) buf;
        int err;
 
-       err = bluetooth_a2dp_init(data, rate, channels);
+       err = bluetooth_a2dp_init(data);
        if (err < 0)
                return err;
 
@@ -384,7 +422,7 @@ static int bluetooth_a2dp_hw_params(struct bluetooth_data *data, int rate, int c
        setconf_req->h.msg_type = BT_SETCONFIGURATION_REQ;
        strncpy(setconf_req->device, data->address, 18);
        setconf_req->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
-       setconf_req->sbc_capabilities = a2dp->sbc_capabilities;
+       setconf_req->sbc_capabilities = data->sbc_capabilities;
        setconf_req->access_mode = BT_CAPABILITIES_ACCESS_MODE_WRITE;
 
        err = audioservice_send(data->server.fd, &setconf_req->h);
@@ -403,128 +441,86 @@ static int bluetooth_a2dp_hw_params(struct bluetooth_data *data, int rate, int c
                return -rsp_hdr->posix_errno;
        }
 
-       data->transport = setconf_rsp->transport;
        data->link_mtu = setconf_rsp->link_mtu;
 
        /* Setup SBC encoder now we agree on parameters */
-       bluetooth_a2dp_setup(a2dp);
+       bluetooth_a2dp_setup(data);
 
        DBG("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
-               a2dp->sbc.allocation, a2dp->sbc.subbands, a2dp->sbc.blocks,
-               a2dp->sbc.bitpool);
+               data->sbc.allocation, data->sbc.subbands, data->sbc.blocks,
+               data->sbc.bitpool);
 
        return 0;
 }
 
-
-
-static int avdtp_write(struct bluetooth_data *data)
+static int avdtp_write(struct bluetooth_data *data, unsigned long duration)
 {
        int ret = 0;
        struct rtp_header *header;
        struct rtp_payload *payload;
-       struct bluetooth_a2dp *a2dp = &data->a2dp;
+       unsigned long delta;
+       struct timeval now;
+       int microseconds, bytes;
 
-       header = (void *) a2dp->buffer;
-       payload = (void *) (a2dp->buffer + sizeof(*header));
+       header = (struct rtp_header *)data->buffer;
+       payload = (struct rtp_payload *)(data->buffer + sizeof(*header));
 
-       memset(a2dp->buffer, 0, sizeof(*header) + sizeof(*payload));
+       memset(data->buffer, 0, sizeof(*header) + sizeof(*payload));
 
-       payload->frame_count = a2dp->frame_count;
+       payload->frame_count = data->frame_count;
        header->v = 2;
        header->pt = 1;
-       header->sequence_number = htons(a2dp->seq_num);
-       header->timestamp = htonl(a2dp->nsamples);
+       header->sequence_number = htons(data->seq_num);
+       header->timestamp = htonl(data->nsamples);
        header->ssrc = htonl(1);
 
-retry:
-    ret = send(data->stream.fd, a2dp->buffer, a2dp->count, MSG_DONTWAIT);
-       if (ret < 0) {
-               DBG("send returned %d errno %s.", ret, strerror(errno));
-               ret = -errno;
-               if (ret == -EAGAIN) {
-                       struct timespec tv;
-                       DBG("retry");
-                       tv.tv_sec = 0;
-                       tv.tv_nsec = 100 * 1000;
-                       nanosleep(&tv, NULL);
-                       goto retry;
+       data->stream.revents = 0;
+       ret = poll(&data->stream, 1, -1);
+       if (ret == 1 && data->stream.revents == POLLOUT) {
+               gettimeofday(&now, NULL);
+               if (data->last_write.tv_sec || data->last_write.tv_usec) {
+                       if (now.tv_usec > data->last_write.tv_usec)
+                               delta = now.tv_usec - data->last_write.tv_usec;
+                       else
+                               delta = (1000000 - data->last_write.tv_usec) + now.tv_usec;
+
+                       if (duration > delta) {
+                               DBG("duration: %ld delta: %ld, delay %ld us", duration, delta, duration - delta);
+                               usleep(duration - delta);
+                       }
                }
-       }
-
-       /* 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++;
-
-       return ret;
-}
-
-static long bluetooth_a2dp_write(struct bluetooth_data *data,
-                const char* buffer,
-                               long size)
-{
-       struct bluetooth_a2dp *a2dp = &data->a2dp;
-       long ret = 0;
-       long frames_to_read, frames_left = size;
-       int encoded, written;
-       const char *buff;
-
-       while (frames_left > 0) {
-
-               if ((data->count + frames_left) <= a2dp->codesize)
-                       frames_to_read = frames_left;
-               else
-                       frames_to_read = a2dp->codesize - data->count;
-        buff = buffer + ret;
-               memcpy(data->buffer + data->count, buff, frames_to_read);
-               /* Remember we have some frames in the pipe now */
-               data->count += frames_to_read;
-               if (data->count != a2dp->codesize) {
-                       ret = frames_to_read;
-                       goto done;
-               }
-
-               /* Enough data to encode (sbc wants 1k blocks) */
-               encoded = sbc_encode(&(a2dp->sbc), data->buffer, a2dp->codesize,
-                                       a2dp->buffer + a2dp->count,
-                                       sizeof(a2dp->buffer) - a2dp->count,
-                                       &written);
-               if (encoded <= 0) {
-                       DBG("Encoding error %d", encoded);
-                       goto done;
-               }
-
-               data->count -= encoded;
-               a2dp->count += written;
-               a2dp->frame_count++;
-               a2dp->samples += encoded;
-               a2dp->nsamples += encoded;
-
-               /* No space left for another frame then send */
-               if (a2dp->count + written >= data->link_mtu) {
-                       DBG("sending packet %d, count %d, link_mtu %u",
-                                       a2dp->seq_num, a2dp->count,
-                                       data->link_mtu);
-                       avdtp_write(data);
+               data->last_write = now;
+       
+               ret = send(data->stream.fd, data->buffer, data->count, 0);
+               if (ret < 0) {
+                       DBG("send returned %d errno %s.", ret, strerror(errno));
+                       ret = -errno;
                }
+       } else {
+               ret = -errno;
+       }
 
-               ret += frames_to_read;
-               frames_left -= frames_to_read;
+       if (!data->adjusted_sock_buffer) {
+               /* microseconds: number of microseconds of audio for this write */
+               microseconds = data->frame_duration * data->frame_count;
+               /* ret: number of bytes written */
+               /* bytes: number of bytes corresponding to SOCK_BUFFER_MS milliseconds of audio playback */
+               bytes = (ret * 1000 * SOCK_BUFFER_MS) / microseconds;
+               
+               DBG("microseconds: %d, ret: %d, bytes: %d\n", microseconds, ret, bytes);
+               setsockopt(data->stream.fd, SOL_SOCKET, SO_SNDBUF, &bytes, sizeof(bytes));
+               data->adjusted_sock_buffer = 1;
        }
 
-       /* note: some ALSA apps will get confused otherwise */
-       if (ret > size)
-               ret = size;
+       /* Reset buffer of data to send */
+       data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
+       data->frame_count = 0;
+       data->samples = 0;
+       data->seq_num++;
 
-done:
-       DBG("returning %ld", ret);
        return ret;
 }
 
-
 static int audioservice_send(int sk, const bt_audio_msg_header_t *msg)
 {
        int err;
@@ -595,9 +591,11 @@ static int bluetooth_init(struct bluetooth_data *data)
 
        data->server.fd = -1;
        data->stream.fd = -1;
+       data->adjusted_sock_buffer = 0;
 
        sk = bt_audio_service_open();
        if (sk <= 0) {
+               SNDERR("bt_audio_service_open failed\n");
                err = -errno;
                goto failed;
        }
@@ -613,30 +611,33 @@ static int bluetooth_init(struct bluetooth_data *data)
        getcaps_req->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
 
        err = audioservice_send(data->server.fd, &getcaps_req->h);
-       if (err < 0)
+       if (err < 0) {
+               SNDERR("audioservice_send failed for BT_GETCAPABILITIES_REQ\n");
                goto failed;
+       }
 
        err = audioservice_expect(data->server.fd, &rsp_hdr->msg_h, BT_GETCAPABILITIES_RSP);
-       if (err < 0)
+       if (err < 0) {
+               SNDERR("audioservice_expect failed for BT_GETCAPABILITIES_RSP\n");
                goto failed;
-
+       }
        if (rsp_hdr->posix_errno != 0) {
                SNDERR("BT_GETCAPABILITIES failed : %s(%d)",
                                        strerror(rsp_hdr->posix_errno),
                                        rsp_hdr->posix_errno);
-               return -rsp_hdr->posix_errno;
+               err = -rsp_hdr->posix_errno;
+               goto failed;
        }
 
-       data->transport = getcaps_rsp->transport;
-
-       if (getcaps_rsp->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
-               data->a2dp.sbc_capabilities = getcaps_rsp->sbc_capabilities;
-       }
+       if (getcaps_rsp->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
+               data->sbc_capabilities = getcaps_rsp->sbc_capabilities;
 
        return 0;
 
 failed:
+       SNDERR("bluetooth_init failed, err: %d\n", err);
        bt_audio_service_close(sk);
+       data->server.fd = -1;
        return err;
 }
 
@@ -644,30 +645,28 @@ int a2dp_init(const char* address, int rate, int channels, a2dpData* dataPtr)
 {
        int err;
 
-    *dataPtr = NULL;
-    struct bluetooth_data* data = malloc(sizeof(struct bluetooth_data));
-    if (!data)
-        return -1;
+       DBG("a2dp_init");
+       *dataPtr = NULL;
+       struct bluetooth_data* data = malloc(sizeof(struct bluetooth_data));
+       if (!data)
+               return -1;
 
        strncpy(data->address, address, 18);
 
        err = bluetooth_init(data);
        if (err < 0)
                goto error;
-               
-    err = bluetooth_a2dp_hw_params(data, rate, channels);
-       if (err < 0) {
-           printf("bluetooth_a2dp_hw_params failed");
-               goto error;
-       }
-    
-       err = bluetooth_prepare(data);
+
+       data->rate = rate;
+       data->channels = channels;
+
+       err = bluetooth_a2dp_hw_params(data);
        if (err < 0) {
-           printf("bluetooth_prepare failed");
+               SNDERR("bluetooth_a2dp_hw_params failed");
                goto error;
        }
 
-    *dataPtr = data;
+       *dataPtr = data;
        return 0;
    
 error:
@@ -679,13 +678,78 @@ error:
 
 int a2dp_write(a2dpData d, const void* buffer, int count)
 {
-    struct bluetooth_data* data = (struct bluetooth_data*)d;
-    return bluetooth_a2dp_write(data, buffer, count); 
+       struct bluetooth_data* data = (struct bluetooth_data*)d;
+       const uint8_t* src = buffer;
+       int codesize = data->codesize;
+       long ret = 0;
+       long frames_left = count;
+       int encoded, written;
+       const char *buff;
+       unsigned long duration = 0;
+       
+       if (!data->started) {
+               ret = bluetooth_start(data);
+               if (ret < 0) {
+                       SNDERR("bluetooth_start failed");
+                       return ret;
+               }
+               data->started = 1;
+       }
+
+       while (frames_left >= codesize) {
+               /* Enough data to encode (sbc wants 1k blocks) */
+               encoded = sbc_encode(&(data->sbc), src, codesize,
+                                       data->buffer + data->count,
+                                       sizeof(data->buffer) - data->count,
+                                       &written);
+               if (encoded <= 0) {
+                       DBG("Encoding error %d", encoded);
+                       goto done;
+               }
+               DBG("sbc_encode returned %d, codesize: %d, written: %d\n", encoded, codesize, written);
+
+               src += encoded;
+               data->count += written;
+               data->frame_count++;
+               data->samples += encoded;
+               data->nsamples += encoded;
+               duration += data->frame_duration;
+
+               /* No space left for another frame then send */
+               if (data->count + written >= data->link_mtu) {
+                       DBG("sending packet %d, count %d, link_mtu %u",
+                                       data->seq_num, data->count,
+                                       data->link_mtu);
+                       avdtp_write(data, data->last_duration);
+                       data->last_duration = duration;
+                       duration = 0;           
+               }
+
+               ret += encoded;
+               frames_left -= encoded;
+       }
+
+       if (frames_left > 0)
+               SNDERR("%ld bytes left at end of a2dp_write\n", frames_left);
+
+done:
+       DBG("returning %ld", ret);
+       return ret;
+}
+
+int a2dp_stop(a2dpData d)
+{
+       struct bluetooth_data* data = (struct bluetooth_data*)d;
+       DBG("a2dp_stop\n");
+       if (!data)
+               return 0;
+       
+       return bluetooth_stop(data);
 }
 
 void a2dp_cleanup(a2dpData d)
 {
-    struct bluetooth_data* data = (struct bluetooth_data*)d;
+       struct bluetooth_data* data = (struct bluetooth_data*)d;
        bluetooth_exit(data);
        free(data);
 }
index 0515517..c135090 100644 (file)
@@ -1,3 +1,27 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2007  Nokia Corporation
+ *  Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -6,6 +30,7 @@ typedef void* a2dpData;
 
 int a2dp_init(const char* address, int rate, int channels, a2dpData* dataPtr);
 int a2dp_write(a2dpData data, const void* buffer, int count);
+int a2dp_stop(a2dpData data);
 void a2dp_cleanup(a2dpData data);
 
 #ifdef __cplusplus
index 93f5788..c3fd368 100644 (file)
@@ -824,6 +824,7 @@ static int handle_a2dp_transport(struct unix_client *client,
        if (client->caps) {
                g_slist_foreach(client->caps, (GFunc) g_free, NULL);
                g_slist_free(client->caps);
+               client->caps = NULL;
        }
 
        media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
@@ -954,7 +955,7 @@ static void handle_streamstart_req(struct unix_client *client,
        return;
 
 failed:
-       unix_ipc_error(client, BT_STREAMSTART_REQ, EIO);
+       unix_ipc_error(client, BT_STREAMSTART_RSP, EIO);
 }
 
 static void handle_streamstop_req(struct unix_client *client,
@@ -968,7 +969,7 @@ static void handle_streamstop_req(struct unix_client *client,
        return;
 
 failed:
-       unix_ipc_error(client, BT_STREAMSTOP_REQ, EIO);
+       unix_ipc_error(client, BT_STREAMSTOP_RSP, EIO);
 }
 
 static void handle_control_req(struct unix_client *client,
index 5e70dde..d0638dc 100644 (file)
@@ -1,6 +1,30 @@
 LOCAL_PATH:= $(call my-dir)
 
 #
+# avinfo
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+       avinfo.c
+
+LOCAL_C_INCLUDES:= \
+       $(call include-path-for, bluez-libs)
+
+LOCAL_CFLAGS:= \
+       -DVERSION=\"3.36\"
+
+LOCAL_SHARED_LIBRARIES := \
+       libbluetooth
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE:=avinfo
+
+include $(BUILD_EXECUTABLE)
+
+#
 # sdptool
 #