From 52beab988fbbff4bb43b78c642f7e5f45eef73d5 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Fri, 9 Jan 2009 17:51:19 -0800 Subject: [PATCH] auto import from //branches/cupcake/...@125939 --- utils/audio/avdtp.c | 5 +- utils/audio/liba2dp.c | 444 ++++++++++++++++++++++++++++--------------------- utils/audio/liba2dp.h | 25 +++ utils/audio/unix.c | 5 +- utils/tools/Android.mk | 24 +++ 5 files changed, 309 insertions(+), 194 deletions(-) diff --git a/utils/audio/avdtp.c b/utils/audio/avdtp.c index db97ec5df..130cd1610 100644 --- a/utils/audio/avdtp.c +++ b/utils/audio/avdtp.c @@ -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: diff --git a/utils/audio/liba2dp.c b/utils/audio/liba2dp.c index 79049488d..1eaefa029 100644 --- a/utils/audio/liba2dp.c +++ b/utils/audio/liba2dp.c @@ -29,8 +29,6 @@ #include #include #include -#include -#include #include #include #include @@ -47,7 +45,7 @@ #define LOG_TAG "A2DP" #include -// #define ENABLE_DEBUG +/* #define ENABLE_DEBUG */ #define BUFFER_SIZE 2048 @@ -71,10 +69,18 @@ #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); } diff --git a/utils/audio/liba2dp.h b/utils/audio/liba2dp.h index 051551713..c135090f7 100644 --- a/utils/audio/liba2dp.h +++ b/utils/audio/liba2dp.h @@ -1,3 +1,27 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2006-2007 Nokia Corporation + * Copyright (C) 2004-2008 Marcel Holtmann + * + * + * 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 diff --git a/utils/audio/unix.c b/utils/audio/unix.c index 93f5788b5..c3fd36830 100644 --- a/utils/audio/unix.c +++ b/utils/audio/unix.c @@ -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, diff --git a/utils/tools/Android.mk b/utils/tools/Android.mk index 5e70ddecf..d0638dc6a 100644 --- a/utils/tools/Android.mk +++ b/utils/tools/Android.mk @@ -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 # -- 2.11.0