From 3e8a242fcbeebea2857fa964ca48624d8433333e Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Fri, 23 May 2014 12:42:24 -0700 Subject: [PATCH] More work on A2DP Sink: Output audio data through A2DP audio HAL rather than playing directly to native AudioTrack API. Add separate HAL interface for A2DP sink Change-Id: I6c6cb6088c350e104b4a7354f328b29c7178e295 --- audio_a2dp_hw/audio_a2dp_hw.c | 492 ++++++++++++++++++++++++++++-------------- audio_a2dp_hw/audio_a2dp_hw.h | 3 +- btif/include/bluetoothTrack.h | 32 --- btif/include/btif_av.h | 4 +- btif/include/btif_media.h | 12 +- btif/src/bluetooth.c | 8 +- btif/src/bluetoothTrack.cpp | 122 ----------- btif/src/btif_av.c | 420 +++++++++++++++++------------------- btif/src/btif_core.c | 2 - btif/src/btif_media_task.c | 114 +++++----- main/Android.mk | 4 +- 11 files changed, 602 insertions(+), 611 deletions(-) delete mode 100644 btif/include/bluetoothTrack.h delete mode 100644 btif/src/bluetoothTrack.cpp diff --git a/audio_a2dp_hw/audio_a2dp_hw.c b/audio_a2dp_hw/audio_a2dp_hw.c index e53ad5d71..60feabac2 100644 --- a/audio_a2dp_hw/audio_a2dp_hw.c +++ b/audio_a2dp_hw/audio_a2dp_hw.c @@ -79,10 +79,12 @@ typedef enum { AUDIO_A2DP_STATE_STANDBY /* allows write to autoresume */ } a2dp_state_t; +struct a2dp_stream_in; struct a2dp_stream_out; struct a2dp_audio_device { struct audio_hw_device device; + struct a2dp_stream_in *input; struct a2dp_stream_out *output; }; @@ -94,18 +96,23 @@ struct a2dp_config { /* move ctrl_fd outside output stream and keep open until HAL unloaded ? */ -struct a2dp_stream_out { - struct audio_stream_out stream; +struct a2dp_stream_common { pthread_mutex_t lock; int ctrl_fd; int audio_fd; size_t buffer_sz; - a2dp_state_t state; struct a2dp_config cfg; + a2dp_state_t state; +}; + +struct a2dp_stream_out { + struct audio_stream_out stream; + struct a2dp_stream_common common; }; struct a2dp_stream_in { - struct audio_stream_in stream; + struct audio_stream_in stream; + struct a2dp_stream_common common; }; /***************************************************************************** @@ -189,14 +196,14 @@ static int calc_audiotime(struct a2dp_config cfg, int bytes) ** *****************************************************************************/ -static int skt_connect(struct a2dp_stream_out *out, char *path) +static int skt_connect(char *path, size_t buffer_sz) { int ret; int skt_fd; struct sockaddr_un remote; int len; - INFO("connect to %s (sz %zu)", path, out->buffer_sz); + INFO("connect to %s (sz %zu)", path, buffer_sz); skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0); @@ -208,7 +215,7 @@ static int skt_connect(struct a2dp_stream_out *out, char *path) return -1; } - len = out->buffer_sz; + len = buffer_sz; ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, (int)sizeof(len)); /* only issue warning if failed */ @@ -220,6 +227,38 @@ static int skt_connect(struct a2dp_stream_out *out, char *path) return skt_fd; } +static int skt_read(int fd, void *p, size_t len, int us_timeout) +{ + int read; + struct pollfd pfd; + struct timespec ts; + + FNLOG(); + + pfd.fd = fd; + pfd.events = POLLIN; + + ts.tv_sec = us_timeout / 1000000; + ts.tv_nsec = (us_timeout % 1000000) * 1000; + + ts_log("skt_read ppoll", len, NULL); + + /* read time out */ + if (ppoll(&pfd, 1, &ts, NULL) == 0) { + return 0; + } + + ts_log("skt_read recv", len, NULL); + + if ((read = recv(fd, p, len, MSG_NOSIGNAL)) == -1) + { + ERROR("write failed with errno=%d\n", errno); + return -1; + } + + return read; +} + static int skt_write(int fd, const void *p, size_t len) { int sent; @@ -267,44 +306,53 @@ static int skt_disconnect(int fd) ** *****************************************************************************/ -static int a2dp_command(struct a2dp_stream_out *out, char cmd) +static int a2dp_ctrl_receive(struct a2dp_stream_common *common, void* buffer, int length) { - char ack; - - DEBUG("A2DP COMMAND %s", dump_a2dp_ctrl_event(cmd)); - - /* send command */ - if (send(out->ctrl_fd, &cmd, 1, MSG_NOSIGNAL) == -1) - { - ERROR("cmd failed (%s)", strerror(errno)); - skt_disconnect(out->ctrl_fd); - out->ctrl_fd = AUDIO_SKT_DISCONNECTED; - return -1; - } - - /* wait for ack byte */ - if (recv(out->ctrl_fd, &ack, 1, MSG_NOSIGNAL) < 0) + int ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL); + if (ret < 0) { ERROR("ack failed (%s)", strerror(errno)); if (errno == EINTR) { /* retry again */ - if (recv(out->ctrl_fd, &ack, 1, MSG_NOSIGNAL) < 0) + ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL); + if (ret < 0) { ERROR("ack failed (%s)", strerror(errno)); - skt_disconnect(out->ctrl_fd); - out->ctrl_fd = AUDIO_SKT_DISCONNECTED; + skt_disconnect(common->ctrl_fd); + common->ctrl_fd = AUDIO_SKT_DISCONNECTED; return -1; } } else { - skt_disconnect(out->ctrl_fd); - out->ctrl_fd = AUDIO_SKT_DISCONNECTED; + skt_disconnect(common->ctrl_fd); + common->ctrl_fd = AUDIO_SKT_DISCONNECTED; return -1; } } + return ret; +} + +static int a2dp_command(struct a2dp_stream_common *common, char cmd) +{ + char ack; + + DEBUG("A2DP COMMAND %s", dump_a2dp_ctrl_event(cmd)); + + /* send command */ + if (send(common->ctrl_fd, &cmd, 1, MSG_NOSIGNAL) == -1) + { + ERROR("cmd failed (%s)", strerror(errno)); + skt_disconnect(common->ctrl_fd); + common->ctrl_fd = AUDIO_SKT_DISCONNECTED; + return -1; + } + + /* wait for ack byte */ + if (a2dp_ctrl_receive(common, &ack, 1) < 0) + return -1; DEBUG("A2DP COMMAND %s DONE STATUS %d", dump_a2dp_ctrl_event(cmd), ack); @@ -314,13 +362,74 @@ static int a2dp_command(struct a2dp_stream_out *out, char cmd) return 0; } +static int check_a2dp_ready(struct a2dp_stream_common *common) +{ + if (a2dp_command(common, A2DP_CTRL_CMD_CHECK_READY) < 0) + { + ERROR("check a2dp ready failed"); + return -1; + } + return 0; +} + +static int a2dp_read_audio_config(struct a2dp_stream_common *common) +{ + char cmd = A2DP_CTRL_GET_AUDIO_CONFIG; + uint32_t sample_rate; + uint8_t channel_count; + + if (a2dp_command(common, A2DP_CTRL_GET_AUDIO_CONFIG) < 0) + { + ERROR("check a2dp ready failed"); + return -1; + } + + if (a2dp_ctrl_receive(common, &sample_rate, 4) < 0) + return -1; + if (a2dp_ctrl_receive(common, &channel_count, 1) < 0) + return -1; + + common->cfg.channel_flags = (channel_count == 1 ? AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO); + common->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT; + common->cfg.rate = sample_rate; + + INFO("got config %d %d", common->cfg.format, common->cfg.rate); + + return 0; +} + +static void a2dp_open_ctrl_path(struct a2dp_stream_common *common) +{ + int i; + + /* retry logic to catch any timing variations on control channel */ + for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++) + { + /* connect control channel if not already connected */ + if ((common->ctrl_fd = skt_connect(A2DP_CTRL_PATH, common->buffer_sz)) > 0) + { + /* success, now check if stack is ready */ + if (check_a2dp_ready(common) == 0) + break; + + ERROR("error : a2dp not ready, wait 250 ms and retry"); + usleep(250000); + skt_disconnect(common->ctrl_fd); + common->ctrl_fd = AUDIO_SKT_DISCONNECTED; + } + + /* ctrl channel not ready, wait a bit */ + usleep(250000); + } +} + /***************************************************************************** ** ** AUDIO DATA PATH ** *****************************************************************************/ -static void a2dp_stream_out_init(struct a2dp_stream_out *out) +static void a2dp_stream_common_init(struct a2dp_stream_common *common) { pthread_mutexattr_t lock_attr; @@ -328,124 +437,109 @@ static void a2dp_stream_out_init(struct a2dp_stream_out *out) pthread_mutexattr_init(&lock_attr); pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&out->lock, &lock_attr); + pthread_mutex_init(&common->lock, &lock_attr); - out->ctrl_fd = AUDIO_SKT_DISCONNECTED; - out->audio_fd = AUDIO_SKT_DISCONNECTED; - out->state = AUDIO_A2DP_STATE_STOPPED; - - out->cfg.channel_flags = AUDIO_STREAM_DEFAULT_CHANNEL_FLAG; - out->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT; - out->cfg.rate = AUDIO_STREAM_DEFAULT_RATE; + common->ctrl_fd = AUDIO_SKT_DISCONNECTED; + common->audio_fd = AUDIO_SKT_DISCONNECTED; + common->state = AUDIO_A2DP_STATE_STOPPED; /* manages max capacity of socket pipe */ - out->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ; + common->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ; } -static int start_audio_datapath(struct a2dp_stream_out *out) +static int start_audio_datapath(struct a2dp_stream_common *common) { - int oldstate = out->state; + int oldstate = common->state; - INFO("state %d", out->state); + INFO("state %d", common->state); - if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) + if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) { + INFO("AUDIO_SKT_DISCONNECTED"); return -1; + } - out->state = AUDIO_A2DP_STATE_STARTING; + common->state = AUDIO_A2DP_STATE_STARTING; - if (a2dp_command(out, A2DP_CTRL_CMD_START) < 0) + if (a2dp_command(common, A2DP_CTRL_CMD_START) < 0) { ERROR("audiopath start failed"); - out->state = oldstate; + common->state = oldstate; return -1; } /* connect socket if not yet connected */ - if (out->audio_fd == AUDIO_SKT_DISCONNECTED) + if (common->audio_fd == AUDIO_SKT_DISCONNECTED) { - out->audio_fd = skt_connect(out, A2DP_DATA_PATH); - - if (out->audio_fd < 0) + common->audio_fd = skt_connect(A2DP_DATA_PATH, common->buffer_sz); + if (common->audio_fd < 0) { - out->state = oldstate; + common->state = oldstate; return -1; } - out->state = AUDIO_A2DP_STATE_STARTED; + common->state = AUDIO_A2DP_STATE_STARTED; } return 0; } -static int stop_audio_datapath(struct a2dp_stream_out *out) +static int stop_audio_datapath(struct a2dp_stream_common *common) { - int oldstate = out->state; + int oldstate = common->state; - INFO("state %d", out->state); + INFO("state %d", common->state); - if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) + if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) return -1; /* prevent any stray output writes from autostarting the stream while stopping audiopath */ - out->state = AUDIO_A2DP_STATE_STOPPING; + common->state = AUDIO_A2DP_STATE_STOPPING; - if (a2dp_command(out, A2DP_CTRL_CMD_STOP) < 0) + if (a2dp_command(common, A2DP_CTRL_CMD_STOP) < 0) { ERROR("audiopath stop failed"); - out->state = oldstate; + common->state = oldstate; return -1; } - out->state = AUDIO_A2DP_STATE_STOPPED; + common->state = AUDIO_A2DP_STATE_STOPPED; /* disconnect audio path */ - skt_disconnect(out->audio_fd); - out->audio_fd = AUDIO_SKT_DISCONNECTED; + skt_disconnect(common->audio_fd); + common->audio_fd = AUDIO_SKT_DISCONNECTED; return 0; } -static int suspend_audio_datapath(struct a2dp_stream_out *out, bool standby) +static int suspend_audio_datapath(struct a2dp_stream_common *common, bool standby) { - INFO("state %d", out->state); + INFO("state %d", common->state); - if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) + if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) return -1; - if (out->state == AUDIO_A2DP_STATE_STOPPING) + if (common->state == AUDIO_A2DP_STATE_STOPPING) return -1; - if (a2dp_command(out, A2DP_CTRL_CMD_SUSPEND) < 0) + if (a2dp_command(common, A2DP_CTRL_CMD_SUSPEND) < 0) return -1; if (standby) - out->state = AUDIO_A2DP_STATE_STANDBY; + common->state = AUDIO_A2DP_STATE_STANDBY; else - out->state = AUDIO_A2DP_STATE_SUSPENDED; + common->state = AUDIO_A2DP_STATE_SUSPENDED; /* disconnect audio path */ - skt_disconnect(out->audio_fd); + skt_disconnect(common->audio_fd); - out->audio_fd = AUDIO_SKT_DISCONNECTED; + common->audio_fd = AUDIO_SKT_DISCONNECTED; return 0; } -static int check_a2dp_ready(struct a2dp_stream_out *out) -{ - INFO("state %d", out->state); - - if (a2dp_command(out, A2DP_CTRL_CMD_CHECK_READY) < 0) - { - ERROR("check a2dp ready failed"); - return -1; - } - return 0; -} - /***************************************************************************** ** @@ -459,49 +553,49 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; int sent; - DEBUG("write %zu bytes (fd %d)", bytes, out->audio_fd); + DEBUG("write %zu bytes (fd %d)", bytes, out->common.audio_fd); - if (out->state == AUDIO_A2DP_STATE_SUSPENDED) + if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED) { DEBUG("stream suspended"); return -1; } /* only allow autostarting if we are in stopped or standby */ - if ((out->state == AUDIO_A2DP_STATE_STOPPED) || - (out->state == AUDIO_A2DP_STATE_STANDBY)) + if ((out->common.state == AUDIO_A2DP_STATE_STOPPED) || + (out->common.state == AUDIO_A2DP_STATE_STANDBY)) { - pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&out->common.lock); - if (start_audio_datapath(out) < 0) + if (start_audio_datapath(&out->common) < 0) { /* emulate time this write represents to avoid very fast write failures during transition periods or remote suspend */ - int us_delay = calc_audiotime(out->cfg, bytes); + int us_delay = calc_audiotime(out->common.cfg, bytes); DEBUG("emulate a2dp write delay (%d us)", us_delay); usleep(us_delay); - pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->common.lock); return -1; } - pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->common.lock); } - else if (out->state != AUDIO_A2DP_STATE_STARTED) + else if (out->common.state != AUDIO_A2DP_STATE_STARTED) { ERROR("stream not in stopped or standby"); return -1; } - sent = skt_write(out->audio_fd, buffer, bytes); + sent = skt_write(out->common.audio_fd, buffer, bytes); if (sent == -1) { - skt_disconnect(out->audio_fd); - out->audio_fd = AUDIO_SKT_DISCONNECTED; - out->state = AUDIO_A2DP_STATE_STOPPED; + skt_disconnect(out->common.audio_fd); + out->common.audio_fd = AUDIO_SKT_DISCONNECTED; + out->common.state = AUDIO_A2DP_STATE_STOPPED; } DEBUG("wrote %d bytes out of %zu bytes", sent, bytes); @@ -513,9 +607,9 @@ static uint32_t out_get_sample_rate(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("rate %" PRIu32, out->cfg.rate); + DEBUG("rate %" PRIu32,out->common.cfg.rate); - return out->cfg.rate; + return out->common.cfg.rate; } static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) @@ -530,7 +624,7 @@ static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) return -1; } - out->cfg.rate = rate; + out->common.cfg.rate = rate; return 0; } @@ -539,25 +633,25 @@ static size_t out_get_buffer_size(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("buffer_size : %zu", out->buffer_sz); + DEBUG("buffer_size : %zu", out->common.buffer_sz); - return out->buffer_sz; + return out->common.buffer_sz; } static uint32_t out_get_channels(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("channels 0x%" PRIx32, out->cfg.channel_flags); + DEBUG("channels 0x%" PRIx32, out->common.cfg.channel_flags); - return out->cfg.channel_flags; + return out->common.cfg.channel_flags; } static audio_format_t out_get_format(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("format 0x%x", out->cfg.format); - return out->cfg.format; + DEBUG("format 0x%x", out->common.cfg.format); + return out->common.cfg.format; } static int out_set_format(struct audio_stream *stream, audio_format_t format) @@ -575,13 +669,13 @@ static int out_standby(struct audio_stream *stream) FNLOG(); - pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&out->common.lock); - if (out->state == AUDIO_A2DP_STATE_STARTED) - retVal = suspend_audio_datapath(out, true); + if (out->common.state == AUDIO_A2DP_STATE_STARTED) + retVal = suspend_audio_datapath(&out->common, true); else retVal = 0; - pthread_mutex_unlock (&out->lock); + pthread_mutex_unlock(&out->common.lock); return retVal; } @@ -602,9 +696,9 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) int retval; int status = 0; - INFO("state %d", out->state); + INFO("state %d", out->common.state); - pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&out->common.lock); parms = str_parms_create_str(kvpairs); @@ -618,7 +712,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) if (strcmp(keyval, "true") == 0) { DEBUG("stream closing, disallow any writes"); - out->state = AUDIO_A2DP_STATE_STOPPING; + out->common.state = AUDIO_A2DP_STATE_STOPPING; } } @@ -628,21 +722,21 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) { if (strcmp(keyval, "true") == 0) { - if (out->state == AUDIO_A2DP_STATE_STARTED) - status = suspend_audio_datapath(out, false); + if (out->common.state == AUDIO_A2DP_STATE_STARTED) + status = suspend_audio_datapath(&out->common, false); } else { /* Do not start the streaming automatically. If the phone was streaming * prior to being suspended, the next out_write shall trigger the * AVDTP start procedure */ - if (out->state == AUDIO_A2DP_STATE_SUSPENDED) - out->state = AUDIO_A2DP_STATE_STANDBY; + if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED) + out->common.state = AUDIO_A2DP_STATE_STANDBY; /* Irrespective of the state, return 0 */ } } - pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->common.lock); str_parms_destroy(parms); return status; @@ -668,9 +762,9 @@ static uint32_t out_get_latency(const struct audio_stream_out *stream) FNLOG(); - latency_us = ((out->buffer_sz * 1000 ) / + latency_us = ((out->common.buffer_sz * 1000 ) / audio_stream_frame_size(&out->stream.common) / - out->cfg.rate) * 1000; + out->common.cfg.rate) * 1000; return (latency_us / 1000) + 200; @@ -726,19 +820,22 @@ static int out_remove_audio_effect(const struct audio_stream *stream, effect_han static uint32_t in_get_sample_rate(const struct audio_stream *stream) { - UNUSED(stream); + struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream; FNLOG(); - return 8000; + return in->common.cfg.rate; } static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) { - UNUSED(stream); - UNUSED(rate); + struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream; FNLOG(); - return 0; + + if (in->common.cfg.rate > 0 && in->common.cfg.rate == rate) + return 0; + else + return -1; } static size_t in_get_buffer_size(const struct audio_stream *stream) @@ -751,10 +848,10 @@ static size_t in_get_buffer_size(const struct audio_stream *stream) static uint32_t in_get_channels(const struct audio_stream *stream) { - UNUSED(stream); + struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream; FNLOG(); - return AUDIO_CHANNEL_IN_MONO; + return in->common.cfg.channel_flags; } static audio_format_t in_get_format(const struct audio_stream *stream) @@ -771,7 +868,10 @@ static int in_set_format(struct audio_stream *stream, audio_format_t format) UNUSED(format); FNLOG(); - return 0; + if (format == AUDIO_FORMAT_PCM_16_BIT) + return 0; + else + return -1; } static int in_standby(struct audio_stream *stream) @@ -822,12 +922,60 @@ static int in_set_gain(struct audio_stream_in *stream, float gain) static ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes) { - UNUSED(stream); - UNUSED(buffer); - UNUSED(bytes); + struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream; + int read; - FNLOG(); - return bytes; + DEBUG("read %zu bytes, state: %d", bytes, in->common.state); + + if (in->common.state == AUDIO_A2DP_STATE_SUSPENDED) + { + DEBUG("stream suspended"); + return -1; + } + + int us_delay = calc_audiotime(in->common.cfg, bytes); + + /* only allow autostarting if we are in stopped or standby */ + if ((in->common.state == AUDIO_A2DP_STATE_STOPPED) || + (in->common.state == AUDIO_A2DP_STATE_STANDBY)) + { + pthread_mutex_lock(&in->common.lock); + + if (start_audio_datapath(&in->common) < 0) + { + /* emulate time this write represents to avoid very fast write + failures during transition periods or remote suspend */ + + DEBUG("emulate a2dp read delay (%d us)", us_delay); + + usleep(us_delay); + pthread_mutex_unlock(&in->common.lock); + return -1; + } + + pthread_mutex_unlock(&in->common.lock); + } + else if (in->common.state != AUDIO_A2DP_STATE_STARTED) + { + ERROR("stream not in stopped or standby"); + return -1; + } + + read = skt_read(in->common.audio_fd, buffer, bytes, us_delay); + + if (read == -1) + { + skt_disconnect(in->common.audio_fd); + in->common.audio_fd = AUDIO_SKT_DISCONNECTED; + in->common.state = AUDIO_A2DP_STATE_STOPPED; + } else if (read == 0) { + DEBUG("read time out - return zeros"); + memset(buffer, 0, bytes); + read = bytes; + } + + DEBUG("read %d bytes out of %zu bytes", read, bytes); + return read; } static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) @@ -898,7 +1046,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.get_render_position = out_get_render_position; /* initialize a2dp specifics */ - a2dp_stream_out_init(out); + a2dp_stream_common_init(&out->common); + + out->common.cfg.channel_flags = AUDIO_STREAM_DEFAULT_CHANNEL_FLAG; + out->common.cfg.format = AUDIO_STREAM_DEFAULT_FORMAT; + out->common.cfg.rate = AUDIO_STREAM_DEFAULT_RATE; /* set output config values */ if (config) @@ -910,26 +1062,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev, *stream_out = &out->stream; a2dp_dev->output = out; - /* retry logic to catch any timing variations on control channel */ - for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++) - { - /* connect control channel if not already connected */ - if ((out->ctrl_fd = skt_connect(out, A2DP_CTRL_PATH)) > 0) - { - /* success, now check if stack is ready */ - if (check_a2dp_ready(out) == 0) - break; - - ERROR("error : a2dp not ready, wait 250 ms and retry"); - usleep(250000); - skt_disconnect(out->ctrl_fd); - } - - /* ctrl channel not ready, wait a bit */ - usleep(250000); - } - - if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) + a2dp_open_ctrl_path(&out->common); + if (out->common.ctrl_fd == AUDIO_SKT_DISCONNECTED) { ERROR("ctrl socket failed to connect (%s)", strerror(errno)); ret = -1; @@ -953,12 +1087,12 @@ static void adev_close_output_stream(struct audio_hw_device *dev, struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev; struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - INFO("closing output (state %d)", out->state); + INFO("closing output (state %d)", out->common.state); - if ((out->state == AUDIO_A2DP_STATE_STARTED) || (out->state == AUDIO_A2DP_STATE_STOPPING)) - stop_audio_datapath(out); + if ((out->common.state == AUDIO_A2DP_STATE_STARTED) || (out->common.state == AUDIO_A2DP_STATE_STOPPING)) + stop_audio_datapath(&out->common); - skt_disconnect(out->ctrl_fd); + skt_disconnect(out->common.ctrl_fd); free(stream); a2dp_dev->output = NULL; @@ -976,7 +1110,7 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) ERROR("ERROR: set param called even when stream out is null"); return retval; } - INFO("state %d", out->state); + INFO("state %d", out->common.state); retval = out->stream.common.set_parameters((struct audio_stream *)out, kvpairs); @@ -1076,7 +1210,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, struct audio_config *config, struct audio_stream_in **stream_in) { - struct a2dp_audio_device *ladev = (struct a2dp_audio_device *)dev; + struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev; struct a2dp_stream_in *in; int ret; UNUSED(handle); @@ -1106,24 +1240,54 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->stream.read = in_read; in->stream.get_input_frames_lost = in_get_input_frames_lost; + /* initialize a2dp specifics */ + a2dp_stream_common_init(&in->common); + *stream_in = &in->stream; + a2dp_dev->input = in; + + a2dp_open_ctrl_path(&in->common); + if (in->common.ctrl_fd == AUDIO_SKT_DISCONNECTED) + { + ERROR("ctrl socket failed to connect (%s)", strerror(errno)); + ret = -1; + goto err_open; + } + + if (a2dp_read_audio_config(&in->common) < 0) { + ERROR("a2dp_read_audio_config failed (%s)", strerror(errno)); + ret = -1; + goto err_open; + } + + DEBUG("success"); return 0; err_open: free(in); *stream_in = NULL; + a2dp_dev->input = NULL; + ERROR("failed"); return ret; } static void adev_close_input_stream(struct audio_hw_device *dev, - struct audio_stream_in *in) + struct audio_stream_in *stream) { - UNUSED(dev); - UNUSED(in); + struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev; + struct a2dp_stream_in* in = (struct a2dp_stream_in *)stream; + a2dp_state_t state = in->common.state; - FNLOG(); + INFO("closing input (state %d)", state); + + if ((state == AUDIO_A2DP_STATE_STARTED) || (state == AUDIO_A2DP_STATE_STOPPING)) + stop_audio_datapath(&in->common); - return; + skt_disconnect(in->common.ctrl_fd); + free(stream); + a2dp_dev->input = NULL; + + DEBUG("done"); } static int adev_dump(const audio_hw_device_t *device, int fd) diff --git a/audio_a2dp_hw/audio_a2dp_hw.h b/audio_a2dp_hw/audio_a2dp_hw.h index 2015591a1..b4ac85d86 100644 --- a/audio_a2dp_hw/audio_a2dp_hw.h +++ b/audio_a2dp_hw/audio_a2dp_hw.h @@ -46,7 +46,8 @@ typedef enum { A2DP_CTRL_CMD_CHECK_READY, A2DP_CTRL_CMD_START, A2DP_CTRL_CMD_STOP, - A2DP_CTRL_CMD_SUSPEND + A2DP_CTRL_CMD_SUSPEND, + A2DP_CTRL_GET_AUDIO_CONFIG, } tA2DP_CTRL_CMD; typedef enum { diff --git a/btif/include/bluetoothTrack.h b/btif/include/bluetoothTrack.h deleted file mode 100644 index e4e1660ab..000000000 --- a/btif/include/bluetoothTrack.h +++ /dev/null @@ -1,32 +0,0 @@ -/****************************************************************************** - * - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#if defined (__cplusplus) || (cplusplus) -extern "C" { -#endif - -int btCreateTrack(int trackFreq, int channelType); -void btDeleteTrack(); -void btStopTrack(); -void btStartTrack(); -void btPauseTrack(); -int btWriteData(void *audioBuffer, int bufferlen); - -#if defined (__cplusplus) || (cplusplus) -} -#endif diff --git a/btif/include/btif_av.h b/btif/include/btif_av.h index eda9c1822..12174c9ef 100644 --- a/btif/include/btif_av.h +++ b/btif/include/btif_av.h @@ -44,9 +44,7 @@ typedef enum { BTIF_AV_START_STREAM_REQ_EVT, BTIF_AV_STOP_STREAM_REQ_EVT, BTIF_AV_SUSPEND_STREAM_REQ_EVT, - BTIF_AV_RECONFIGURE_REQ_EVT, - BTIF_AV_REQUEST_AUDIO_FOCUS_EVT, - BTIF_AV_REQUEST_ACTIVATE_SINK_EVT, + BTIF_AV_SINK_CONFIG_REQ_EVT, } btif_av_sm_event_t; diff --git a/btif/include/btif_media.h b/btif/include/btif_media.h index a785d340b..f01286bd4 100644 --- a/btif/include/btif_media.h +++ b/btif/include/btif_media.h @@ -98,13 +98,6 @@ typedef struct } tBTIF_MEDIA_SINK_CFG_UPDATE; #endif -typedef enum { - BTIF_MEDIA_AUDIOFOCUS_LOSS = 0, - BTIF_MEDIA_AUDIOFOCUS_GAIN, - BTIF_MEDIA_AUDIOFOCUS_LOSS_TRANSIENT -} btif_media_AudioFocus_state; - - /******************************************************************************* ** Public functions *******************************************************************************/ @@ -281,6 +274,9 @@ void btif_a2dp_set_rx_flush(BOOLEAN enable); void btif_media_check_iop_exceptions(UINT8 *peer_bda); void btif_reset_decoder(UINT8 *p_av); BOOLEAN btif_media_task_start_decoding_req(void); -void btif_a2dp_set_audio_focus_state(btif_media_AudioFocus_state state); + +int btif_a2dp_get_track_frequency(UINT8 frequency); +int btif_a2dp_get_track_channel_count(UINT8 channeltype); +void btif_a2dp_set_peer_sep(UINT8 sep); #endif diff --git a/btif/src/bluetooth.c b/btif/src/bluetooth.c index 9e63d54ef..c0cdc5a83 100644 --- a/btif/src/bluetooth.c +++ b/btif/src/bluetooth.c @@ -79,7 +79,8 @@ extern bthf_interface_t *btif_hf_get_interface(); /* handsfree profile - client */ extern bthf_client_interface_t *btif_hf_client_get_interface(); /* advanced audio profile */ -extern btav_interface_t *btif_av_get_interface(); +extern btav_interface_t *btif_av_get_src_interface(); +extern btav_interface_t *btif_av_get_sink_interface(); /*rfc l2cap*/ extern btsock_interface_t *btif_sock_get_interface(); /* hid host profile */ @@ -328,7 +329,10 @@ static const void* get_profile_interface (const char *profile_id) return btif_pan_get_interface(); if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID)) - return btif_av_get_interface(); + return btif_av_get_src_interface(); + + if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_SINK_ID)) + return btif_av_get_sink_interface(); if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID)) return btif_hh_get_interface(); diff --git a/btif/src/bluetoothTrack.cpp b/btif/src/bluetoothTrack.cpp deleted file mode 100644 index 685780e85..000000000 --- a/btif/src/bluetoothTrack.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/****************************************************************************** - * - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include "bluetoothTrack.h" -#include - -//#define DUMP_PCM_DATA TRUE -#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE)) -FILE *outputPcmSampleFile; -char outputFilename [50] = "/data/misc/bluedroid/output_sample.pcm"; -#endif - -struct BluetoothTrack { - android::sp mTrack; -}; - -typedef struct BluetoothTrack BluetoothTrack; - -BluetoothTrack *track = NULL; - -int btCreateTrack(int trackFreq, int channelType) -{ - int ret = -1; - if (track == NULL) - track = new BluetoothTrack; - track->mTrack = NULL; - track->mTrack = new android::AudioTrack(AUDIO_STREAM_MUSIC, trackFreq, AUDIO_FORMAT_PCM_16_BIT, - channelType, (int)0, (audio_output_flags_t)AUDIO_OUTPUT_FLAG_FAST, NULL, NULL, 0, 0, android::AudioTrack::TRANSFER_SYNC); - if (track->mTrack == NULL) - { - delete track; - track = NULL; - return ret; - } - if (track->mTrack->initCheck() != 0) - { - delete track; - track = NULL; - return ret; - } -#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE)) - outputPcmSampleFile = fopen(outputFilename, "ab"); -#endif - ret = 0; - track->mTrack->setVolume(1, 1); - return ret; -} - -void btStartTrack() -{ - if ((track != NULL) && (track->mTrack.get() != NULL)) - { - track->mTrack->start(); - } -} - - -void btDeleteTrack() -{ - if ((track != NULL) && (track->mTrack.get() != NULL)) - { - track->mTrack.clear(); - delete track; - track = NULL; - } -#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE)) - if (outputPcmSampleFile) - { - fclose(outputPcmSampleFile); - } - outputPcmSampleFile = NULL; -#endif -} - -void btPauseTrack() -{ - if ((track != NULL) && (track->mTrack.get() != NULL)) - { - track->mTrack->pause(); - track->mTrack->flush(); - } -} - -void btStopTrack() -{ - if ((track != NULL) && (track->mTrack.get() != NULL)) - { - track->mTrack->stop(); - } -} - -int btWriteData(void *audioBuffer, int bufferlen) -{ - int retval = -1; - if ((track != NULL) && (track->mTrack.get() != NULL)) - { -#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE)) - if (outputPcmSampleFile) - { - fwrite ((audioBuffer), 1, (size_t)bufferlen, outputPcmSampleFile); - } -#endif - retval = track->mTrack->write(audioBuffer, (size_t)bufferlen); - } - return retval; -} - diff --git a/btif/src/btif_av.c b/btif/src/btif_av.c index 0b7b9d714..24ceb8a53 100644 --- a/btif/src/btif_av.c +++ b/btif/src/btif_av.c @@ -26,6 +26,7 @@ *****************************************************************************/ #include +#include #include "hardware/bt_av.h" #define LOG_TAG "BTIF_AV" @@ -69,12 +70,6 @@ typedef enum { /***************************************************************************** ** Local type definitions ******************************************************************************/ -typedef enum -{ - SEP_SRC = 0x0, - SEP_SNK, - SEP_NOT_OPENED -}tbtif_AV_SEP_TYPE; typedef struct { @@ -83,7 +78,7 @@ typedef struct btif_sm_handle_t sm_handle; UINT8 flags; tBTA_AV_EDR edr; - tbtif_AV_SEP_TYPE sep; /* sep type of peer device */ + UINT8 peer_sep; /* sep type of peer device */ } btif_av_cb_t; typedef struct @@ -91,15 +86,24 @@ typedef struct bt_bdaddr_t *target_bda; uint16_t uuid; } btif_av_connect_req_t; + +typedef struct +{ + int sample_rate; + int channel_count; +} btif_av_sink_config_req_t; + /***************************************************************************** ** Static variables ******************************************************************************/ -static btav_callbacks_t *bt_av_callbacks = NULL; +static btav_callbacks_t *bt_av_src_callbacks = NULL; +static btav_callbacks_t *bt_av_sink_callbacks = NULL; static btif_av_cb_t btif_av_cb; static TIMER_LIST_ENT tle_av_open_on_rc; /* both interface and media task needs to be ready to alloc incoming request */ -#define CHECK_BTAV_INIT() if ((bt_av_callbacks == NULL) || (btif_av_cb.sm_handle == NULL))\ +#define CHECK_BTAV_INIT() if (((bt_av_src_callbacks == NULL) &&(bt_av_sink_callbacks == NULL)) \ + || (btif_av_cb.sm_handle == NULL))\ {\ BTIF_TRACE_WARNING1("%s: BTAV not initialized", __FUNCTION__);\ return BT_STATUS_NOT_READY;\ @@ -191,39 +195,11 @@ const char *dump_av_sm_event_name(btif_av_sm_event_t event) CASE_RETURN_STR(BTIF_AV_START_STREAM_REQ_EVT) CASE_RETURN_STR(BTIF_AV_STOP_STREAM_REQ_EVT) CASE_RETURN_STR(BTIF_AV_SUSPEND_STREAM_REQ_EVT) - CASE_RETURN_STR(BTIF_AV_RECONFIGURE_REQ_EVT) - CASE_RETURN_STR(BTIF_AV_REQUEST_AUDIO_FOCUS_EVT) - CASE_RETURN_STR(BTIF_AV_REQUEST_ACTIVATE_SINK_EVT) + CASE_RETURN_STR(BTIF_AV_SINK_CONFIG_REQ_EVT) default: return "UNKNOWN_EVENT"; } } -/******************************************************************************* -** -** Function btif_av_request_audio_focus -** -** Description send request to gain audio focus -** -** Returns void -** -*******************************************************************************/ -void btif_av_request_audio_focus( BOOLEAN enable) -{ - btif_sm_state_t state; - state= btif_sm_get_state(btif_av_cb.sm_handle); - /* We shld be in started state */ - if (state != BTIF_AV_STATE_STARTED) - return; - /* If we are in started state, suspend shld not have been initiated */ - if ((btif_av_cb.flags & BTIF_AV_FLAG_REMOTE_SUSPEND )|| - (btif_av_cb.flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING)) - return; - if(enable) - { - btif_dispatch_sm_event(BTIF_AV_REQUEST_AUDIO_FOCUS_EVT, NULL, 0); - } -} - /**************************************************************************** ** Local helper functions *****************************************************************************/ @@ -262,6 +238,24 @@ static void btif_initiate_av_open_tmr_hdlr(TIMER_LIST_ENT *tle) ** Static functions ******************************************************************************/ +static void btif_report_connection_state(btav_connection_state_t state, bt_bdaddr_t *bd_addr) +{ + if (btif_av_cb.peer_sep == AVDT_TSEP_SRC && bt_av_sink_callbacks != NULL) { + HAL_CBACK(bt_av_sink_callbacks, connection_state_cb, state, bd_addr); + } else if (btif_av_cb.peer_sep == AVDT_TSEP_SNK && bt_av_src_callbacks != NULL) { + HAL_CBACK(bt_av_src_callbacks, connection_state_cb, state, bd_addr); + } +} + +static void btif_report_audio_state(btav_audio_state_t state, bt_bdaddr_t *bd_addr) +{ + if (btif_av_cb.peer_sep == AVDT_TSEP_SRC && bt_av_sink_callbacks != NULL) { + HAL_CBACK(bt_av_sink_callbacks, audio_state_cb, state, bd_addr); + } else if (btif_av_cb.peer_sep == AVDT_TSEP_SNK && bt_av_src_callbacks != NULL) { + HAL_CBACK(bt_av_src_callbacks, audio_state_cb, state, bd_addr); + } +} + /***************************************************************************** ** ** Function btif_av_state_idle_handler @@ -284,7 +278,6 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data) memset(&btif_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t)); btif_av_cb.flags = 0; btif_av_cb.edr = 0; - btif_av_cb.sep = SEP_NOT_OPENED; btif_a2dp_on_idle(); break; @@ -294,14 +287,6 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data) case BTA_AV_ENABLE_EVT: break; - case BTIF_AV_REQUEST_ACTIVATE_SINK_EVT: - { - int enable = *((int*)p_data); - BTIF_TRACE_DEBUG1(" Active_Sink enable %d", enable) - BTA_AvEnable_Sink(enable); - } - break; - case BTA_AV_REGISTER_EVT: btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl; break; @@ -387,8 +372,7 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data { case BTIF_SM_ENTER_EVT: /* inform the application that we are entering connecting state */ - HAL_CBACK(bt_av_callbacks, connection_state_cb, - BTAV_CONNECTION_STATE_CONNECTING, &(btif_av_cb.peer_bda)); + btif_report_connection_state(BTAV_CONNECTION_STATE_CONNECTING, &(btif_av_cb.peer_bda)); break; case BTIF_SM_EXIT_EVT: @@ -396,8 +380,7 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data case BTA_AV_REJECT_EVT: BTIF_TRACE_DEBUG0(" Received BTA_AV_REJECT_EVT "); - HAL_CBACK(bt_av_callbacks, connection_state_cb, - BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda)); + btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda)); btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE); break; @@ -415,10 +398,8 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data av_state = BTIF_AV_STATE_OPENED; btif_av_cb.edr = p_bta_data->open.edr; - if (p_bta_data->open.sep == AVDT_TSEP_SRC) - btif_av_cb.sep = SEP_SRC; - else if (p_bta_data->open.sep == AVDT_TSEP_SNK) - btif_av_cb.sep = SEP_SNK; + btif_av_cb.peer_sep = p_bta_data->open.sep; + btif_a2dp_set_peer_sep(p_bta_data->open.sep); } else { @@ -429,17 +410,16 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data } /* inform the application of the event */ - HAL_CBACK(bt_av_callbacks, connection_state_cb, - state, &(btif_av_cb.peer_bda)); + btif_report_connection_state(state, &(btif_av_cb.peer_bda)); /* change state to open/idle based on the status */ btif_sm_change_state(btif_av_cb.sm_handle, av_state); - if (btif_av_cb.sep == SEP_SNK) + if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) { /* if queued PLAY command, send it now */ btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, (p_bta_data->open.status == BTA_AV_SUCCESS)); } - else if (btif_av_cb.sep == SEP_SRC) + else if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) { /* if queued PLAY command, send it now */ btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, FALSE); @@ -447,6 +427,20 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data btif_queue_advance(); } break; + case BTIF_AV_SINK_CONFIG_REQ_EVT: + { + btif_av_sink_config_req_t req; + // copy to avoid alignment problems + memcpy(&req, p_data, sizeof(req)); + + BTIF_TRACE_WARNING2("BTIF_AV_SINK_CONFIG_REQ_EVT %d %d", req.sample_rate, + req.channel_count); + if (btif_av_cb.peer_sep == AVDT_TSEP_SRC && bt_av_sink_callbacks != NULL) { + HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(btif_av_cb.peer_bda), + req.sample_rate, req.channel_count); + } + } break; + CHECK_RC_EVENT(event, p_data); default: @@ -478,13 +472,13 @@ static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *p_data switch (event) { case BTIF_SM_ENTER_EVT: - if (btif_av_cb.sep == SEP_SNK) + if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) { /* immediately stop transmission of frames */ btif_a2dp_set_tx_flush(TRUE); /* wait for audioflinger to stop a2dp */ } - if (btif_av_cb.sep == SEP_SRC) + if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) { btif_a2dp_set_rx_flush(TRUE); } @@ -492,18 +486,18 @@ static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *p_data case BTA_AV_STOP_EVT: case BTIF_AV_STOP_STREAM_REQ_EVT: - if (btif_av_cb.sep == SEP_SNK) + if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) { /* immediately flush any pending tx frames while suspend is pending */ btif_a2dp_set_tx_flush(TRUE); } - if (btif_av_cb.sep == SEP_SRC) + if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) { btif_a2dp_set_rx_flush(TRUE); } btif_a2dp_on_stopped(NULL); - break; + break; case BTIF_SM_EXIT_EVT: break; @@ -511,8 +505,7 @@ static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *p_data case BTA_AV_CLOSE_EVT: /* inform the application that we are disconnecting */ - HAL_CBACK(bt_av_callbacks, connection_state_cb, - BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda)); + btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda)); btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE); break; @@ -567,7 +560,7 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) break; case BTIF_AV_START_STREAM_REQ_EVT: - if (btif_av_cb.sep == SEP_SRC) + if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) { BTA_AvStart(); btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_START; @@ -587,7 +580,7 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) return TRUE; /* In case peer is A2DP SRC we do not want to ack commands on UIPC*/ - if (btif_av_cb.sep == SEP_SNK) + if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) { if (btif_a2dp_on_started(&p_av->start, ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) != 0))) @@ -601,14 +594,14 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) if (p_av->start.status != BTA_AV_SUCCESS) return FALSE; - if (btif_av_cb.sep == SEP_SRC) + if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) { btif_a2dp_set_rx_flush(FALSE); /* remove flush state, ready for streaming*/ } /* change state to started, send acknowledgement if start is pending */ if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) { - if (btif_av_cb.sep == SEP_SNK) + if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) btif_a2dp_on_started(NULL, TRUE); /* pending start flag will be cleared when exit current state */ } @@ -618,10 +611,12 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) case BTIF_AV_DISCONNECT_REQ_EVT: BTA_AvClose(btif_av_cb.bta_handle); + if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) { + BTA_AvCloseRc(btif_av_cb.bta_handle); + } /* inform the application that we are disconnecting */ - HAL_CBACK(bt_av_callbacks, connection_state_cb, - BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda)); + btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda)); break; case BTA_AV_CLOSE_EVT: @@ -629,8 +624,7 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) btif_a2dp_on_stopped(NULL); /* inform the application that we are disconnected */ - HAL_CBACK(bt_av_callbacks, connection_state_cb, - BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda)); + btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda)); /* change state to idle, send acknowledgement if start is pending */ if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) { @@ -689,8 +683,7 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data /* we are again in started state, clear any remote suspend flags */ btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND; - HAL_CBACK(bt_av_callbacks, audio_state_cb, - BTAV_AUDIO_STATE_STARTED, &(btif_av_cb.peer_bda)); + btif_report_audio_state(BTAV_AUDIO_STATE_STARTED, &(btif_av_cb.peer_bda)); /* increase the a2dp consumer task priority temporarily when start ** audio playing, to avoid overflow the audio packet queue. */ @@ -706,7 +699,7 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data case BTIF_AV_START_STREAM_REQ_EVT: /* we were remotely started, just ack back the local request */ - if (btif_av_cb.sep == SEP_SNK) + if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) btif_a2dp_on_started(NULL, TRUE); break; @@ -722,14 +715,16 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data always overrides */ btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND; - if (btif_av_cb.sep == SEP_SNK) + if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) { /* immediately stop transmission of frames while suspend is pending */ btif_a2dp_set_tx_flush(TRUE); } - if (btif_av_cb.sep == SEP_SRC) + if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) { btif_a2dp_set_rx_flush(TRUE); + btif_a2dp_on_stopped(NULL); + } BTA_AvStop(TRUE); break; @@ -738,10 +733,12 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data /* request avdtp to close */ BTA_AvClose(btif_av_cb.bta_handle); + if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) { + BTA_AvCloseRc(btif_av_cb.bta_handle); + } /* inform the application that we are disconnecting */ - HAL_CBACK(bt_av_callbacks, connection_state_cb, - BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda)); + btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda)); /* wait in closing state until fully closed */ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_CLOSING); @@ -760,7 +757,7 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data { btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING; - if (btif_av_cb.sep == SEP_SNK) + if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) { /* suspend failed, reset back tx flush state */ btif_a2dp_set_tx_flush(FALSE); @@ -778,13 +775,11 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data if ((btif_av_cb.flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0) btif_av_cb.flags |= BTIF_AV_FLAG_REMOTE_SUSPEND; - HAL_CBACK(bt_av_callbacks, audio_state_cb, - BTAV_AUDIO_STATE_REMOTE_SUSPEND, &(btif_av_cb.peer_bda)); + btif_report_audio_state(BTAV_AUDIO_STATE_REMOTE_SUSPEND, &(btif_av_cb.peer_bda)); } else { - HAL_CBACK(bt_av_callbacks, audio_state_cb, - BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda)); + btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda)); } btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED); @@ -798,8 +793,7 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP; btif_a2dp_on_stopped(&p_av->suspend); - HAL_CBACK(bt_av_callbacks, audio_state_cb, - BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda)); + btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda)); /* if stop was successful, change state to open */ if (p_av->suspend.status == BTA_AV_SUCCESS) @@ -807,11 +801,6 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data break; - case BTIF_AV_REQUEST_AUDIO_FOCUS_EVT: - HAL_CBACK(bt_av_callbacks, audio_focus_request_cb, - 1, &(btif_av_cb.peer_bda)); - break; - case BTA_AV_CLOSE_EVT: btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP; @@ -820,8 +809,7 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data btif_a2dp_on_stopped(NULL); /* inform the application that we are disconnected */ - HAL_CBACK(bt_av_callbacks, connection_state_cb, - BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda)); + btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda)); btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE); break; @@ -857,6 +845,9 @@ static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data) { btif_sm_state_t state; UINT8 que_len; + tA2D_STATUS a2d_status; + tA2D_SBC_CIE sbc_cie; + btif_av_sink_config_req_t config_req; if (event == BTA_AV_MEDIA_DATA_EVT)/* Switch to BTIF_MEDIA context */ { @@ -871,8 +862,21 @@ static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data) return; } - if (event == BTA_AV_MEDIA_SINK_CFG_EVT) /* send a command to BT Media Task */ + if (event == BTA_AV_MEDIA_SINK_CFG_EVT) { + /* send a command to BT Media Task */ btif_reset_decoder((UINT8*)p_data); + + a2d_status = A2D_ParsSbcInfo(&sbc_cie, (UINT8 *)p_data, FALSE); + if (a2d_status == A2D_SUCCESS) { + /* Switch to BTIF context */ + config_req.sample_rate = btif_a2dp_get_track_frequency(sbc_cie.samp_freq); + config_req.channel_count = btif_a2dp_get_track_channel_count(sbc_cie.ch_mode); + btif_transfer_context(btif_av_handle_event, BTIF_AV_SINK_CONFIG_REQ_EVT, + (char*)&config_req, sizeof(config_req), NULL); + } else { + APPL_TRACE_ERROR1("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d", a2d_status); + } + } } /******************************************************************************* ** @@ -884,8 +888,10 @@ static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data) ** *******************************************************************************/ -bt_status_t btif_av_init(void) +bt_status_t btif_av_init() { + btif_av_cb.sm_handle = NULL; + if (btif_av_cb.sm_handle == NULL) { if (btif_a2dp_start_media_task() != GKI_SUCCESS) @@ -898,7 +904,7 @@ bt_status_t btif_av_init(void) btif_a2dp_on_init(); - return BT_STATUS_SUCCESS; + return BT_STATUS_SUCCESS; } return BT_STATUS_DONE; @@ -906,27 +912,63 @@ bt_status_t btif_av_init(void) /******************************************************************************* ** -** Function init +** Function init_src ** -** Description Initializes the AV interface +** Description Initializes the AV interface for source mode ** ** Returns bt_status_t ** *******************************************************************************/ -static bt_status_t init(btav_callbacks_t* callbacks ) +static bt_status_t init_src(btav_callbacks_t* callbacks) { - int status; + bt_status_t status; BTIF_TRACE_EVENT1("%s", __FUNCTION__); - if (bt_av_callbacks) - return BT_STATUS_DONE; + if (bt_av_sink_callbacks != NULL) { + // already did btif_av_init() + status = BT_STATUS_SUCCESS; + } else { + status = btif_av_init(); + } - bt_av_callbacks = callbacks; - btif_av_cb.sm_handle = NULL; + if (status == BT_STATUS_SUCCESS) { + bt_av_src_callbacks = callbacks; + } + + return status; +} + +/******************************************************************************* +** +** Function init_sink +** +** Description Initializes the AV interface for sink mode +** +** Returns bt_status_t +** +*******************************************************************************/ + +static bt_status_t init_sink(btav_callbacks_t* callbacks) +{ + bt_status_t status; + + BTIF_TRACE_EVENT1("%s", __FUNCTION__); + + if (bt_av_src_callbacks != NULL) { + // already did btif_av_init() + status = BT_STATUS_SUCCESS; + } else { + status = btif_av_init(); + } + + if (status == BT_STATUS_SUCCESS) { + bt_av_sink_callbacks = callbacks; + BTA_AvEnable_Sink(TRUE); + } - return btif_av_init(); + return status; } /******************************************************************************* @@ -951,15 +993,15 @@ static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid) return BT_STATUS_SUCCESS; } -static bt_status_t connect_sink(bt_bdaddr_t *bd_addr) +static bt_status_t connect_src(bt_bdaddr_t *bd_addr) { BTIF_TRACE_EVENT1("%s", __FUNCTION__); CHECK_BTAV_INIT(); - return btif_queue_connect(UUID_SERVCLASS_AUDIO_SINK, bd_addr, - connect_int); + + return btif_queue_connect(UUID_SERVCLASS_AUDIO_SINK, bd_addr, connect_int); } -static bt_status_t connect_src(bt_bdaddr_t *bd_addr) +static bt_status_t connect_sink(bt_bdaddr_t *bd_addr) { BTIF_TRACE_EVENT1("%s", __FUNCTION__); CHECK_BTAV_INIT(); @@ -1000,124 +1042,51 @@ static void cleanup(void) { BTIF_TRACE_EVENT1("%s", __FUNCTION__); - if (bt_av_callbacks) - { - btif_a2dp_stop_media_task(); + btif_a2dp_stop_media_task(); - btif_disable_service(BTA_A2DP_SERVICE_ID); - bt_av_callbacks = NULL; + btif_disable_service(BTA_A2DP_SERVICE_ID); - /* Also shut down the AV state machine */ - btif_sm_shutdown(btif_av_cb.sm_handle); - btif_av_cb.sm_handle = NULL; - } - return; + /* Also shut down the AV state machine */ + btif_sm_shutdown(btif_av_cb.sm_handle); + btif_av_cb.sm_handle = NULL; } -/******************************************************************************* -** -** Function is_src -** -** Description Checks if peer device is A2DP SRC -** -** Returns Success in case peer is A2DP Src, FAIL otherwise -** -*******************************************************************************/ -bt_status_t is_src( bt_bdaddr_t *bd_addr ) -{ - BTIF_TRACE_DEBUG0(" isSrc: Check if peer device with bd_addr is audio src or sink"); - if (btif_av_cb.sep == SEP_SRC) - { - BTIF_TRACE_DEBUG0(" Current Peer is SRC"); - return BT_STATUS_SUCCESS; - } - else if (btif_av_cb.sep == SEP_SNK) - { - BTIF_TRACE_DEBUG0(" Current Peer is SNK"); - return BT_STATUS_FAIL; - } - else +static void cleanup_src(void) { + BTIF_TRACE_EVENT1("%s", __FUNCTION__); + + if (bt_av_src_callbacks) { - BTIF_TRACE_DEBUG0(" Stream not opened till now"); - return BT_STATUS_NOT_READY; + bt_av_src_callbacks = NULL; + if (bt_av_sink_callbacks == NULL) + cleanup(); } } -/******************************************************************************* -** -** Function activate_sink -** -** Description Activates/Deactivates A2DP Sink -** -** Returns None -** -*******************************************************************************/ -void activate_sink(int enable) -{ - BTIF_TRACE_DEBUG1(" Activate Sink %d", enable); - btif_dispatch_sm_event(BTIF_AV_REQUEST_ACTIVATE_SINK_EVT, (char*)&enable, sizeof(int)); -} - -/******************************************************************************* -** -** Function suspend_sink -** -** Description Suspends stream in case of A2DP Sink -** -** Returns None -** -*******************************************************************************/ -void suspend_sink() -{ - BTIF_TRACE_DEBUG0(" suspend Stream Suspend called"); - if (btif_av_cb.sep == SEP_SRC) - btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0); -} - -/******************************************************************************* -** -** Function resume_sink -** -** Description Resumes stream in case of A2DP Sink -** -** Returns None -** -*******************************************************************************/ -void resume_sink() -{ - BTIF_TRACE_DEBUG0(" resume Stream called"); - if (btif_av_cb.sep == SEP_SRC) - btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0); -} - -/******************************************************************************* -** -** Function audio_focus_status -** -** Description Updates audio focus state -** -** Returns None -** -*******************************************************************************/ -static void audio_focus_status(int state) -{ - BTIF_TRACE_DEBUG1(" Audio Focus granted %d",state); +static void cleanup_sink(void) { + BTIF_TRACE_EVENT1("%s", __FUNCTION__); - btif_a2dp_set_audio_focus_state(state); + if (bt_av_sink_callbacks) + { + bt_av_sink_callbacks = NULL; + if (bt_av_src_callbacks == NULL) + cleanup(); + } } -static const btav_interface_t bt_av_interface = { +static const btav_interface_t bt_av_src_interface = { sizeof(btav_interface_t), - init, + init_src, connect_src, + disconnect, + cleanup_src, +}; + +static const btav_interface_t bt_av_sink_interface = { + sizeof(btav_interface_t), + init_sink, connect_sink, disconnect, - cleanup, - is_src, - suspend_sink, - resume_sink, - audio_focus_status, - activate_sink, + cleanup_sink, }; /******************************************************************************* @@ -1252,17 +1221,32 @@ bt_status_t btif_av_execute_service(BOOLEAN b_enable) /******************************************************************************* ** -** Function btif_av_get_interface +** Function btif_av_get_src_interface +** +** Description Get the AV callback interface for A2DP source profile +** +** Returns btav_interface_t +** +*******************************************************************************/ +const btav_interface_t *btif_av_get_src_interface(void) +{ + BTIF_TRACE_EVENT1("%s", __FUNCTION__); + return &bt_av_src_interface; +} + +/******************************************************************************* +** +** Function btif_av_get_sink_interface ** -** Description Get the AV callback interface +** Description Get the AV callback interface for A2DP sink profile ** ** Returns btav_interface_t ** *******************************************************************************/ -const btav_interface_t *btif_av_get_interface(void) +const btav_interface_t *btif_av_get_sink_interface(void) { BTIF_TRACE_EVENT1("%s", __FUNCTION__); - return &bt_av_interface; + return &bt_av_sink_interface; } /******************************************************************************* diff --git a/btif/src/btif_core.c b/btif/src/btif_core.c index 455255ad1..9b432cd55 100644 --- a/btif/src/btif_core.c +++ b/btif/src/btif_core.c @@ -611,8 +611,6 @@ void btif_enable_bluetooth_evt(tBTA_STATUS status, BD_ADDR local_bd) #if (BLE_INCLUDED == TRUE ) BTA_BrcmInit(); #endif - /* initialize a2dp service */ - btif_av_init(); /* init rfcomm & l2cap api */ btif_sock_init(); diff --git a/btif/src/btif_media_task.c b/btif/src/btif_media_task.c index e45ddfc69..7e2991714 100644 --- a/btif/src/btif_media_task.c +++ b/btif/src/btif_media_task.c @@ -72,7 +72,6 @@ #endif #include "stdio.h" #include -#include "bluetoothTrack.h" //#define DEBUG_MEDIA_AV_FLOW TRUE @@ -279,9 +278,12 @@ typedef struct UINT8 a2dp_cmd_pending; /* we can have max one command pending */ BOOLEAN tx_flush; /* discards any outgoing data when true */ BOOLEAN rx_flush; /* discards any incoming data when true */ - BOOLEAN is_source; + UINT8 peer_sep; + BOOLEAN data_channel_open; UINT8 frames_to_process; - BOOLEAN rx_audio_focus_gained; + + UINT32 sample_rate; + UINT8 channel_count; #endif } tBTIF_MEDIA_CB; @@ -355,7 +357,6 @@ static void btif_media_task_aa_handle_clear_track(void); #endif static void btif_media_task_aa_handle_start_decoding(void ); #endif -extern void btif_av_request_audio_focus(BOOLEAN enable); BOOLEAN btif_media_task_start_decoding_req(void); BOOLEAN btif_media_task_clear_track(void); /***************************************************************************** @@ -510,6 +511,8 @@ static void btif_recv_ctrl_data(void) /* post start event and wait for audio path to open */ btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0); +//FIXME + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); } else if (btif_av_stream_started_ready()) { @@ -527,8 +530,7 @@ static void btif_recv_ctrl_data(void) break; case A2DP_CTRL_CMD_STOP: - - if (btif_media_cb.is_tx_timer == FALSE) + if (btif_media_cb.peer_sep == AVDT_TSEP_SNK && btif_media_cb.is_tx_timer == FALSE) { /* we are already stopped, just ack back */ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); @@ -536,6 +538,7 @@ static void btif_recv_ctrl_data(void) } btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0); + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); break; case A2DP_CTRL_CMD_SUSPEND: @@ -553,6 +556,17 @@ static void btif_recv_ctrl_data(void) } break; + case A2DP_CTRL_GET_AUDIO_CONFIG: + { + uint32_t sample_rate = btif_media_cb.sample_rate; + uint8_t channel_count = btif_media_cb.channel_count; + + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); + UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, (UINT8 *)&sample_rate, 4); + UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &channel_count, 1); + break; + } + default: APPL_TRACE_ERROR1("UNSUPPORTED CMD (%d)", cmd); a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE); @@ -605,11 +619,15 @@ static void btif_a2dp_data_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event) UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REG_REMOVE_ACTIVE_READSET, NULL); UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO, (void *)A2DP_DATA_READ_POLL_MS); - /* Start the media task to encode SBC */ - btif_media_task_start_aa_req(); - /* make sure we update any changed sbc encoder params */ - btif_a2dp_encoder_update(); + if (btif_media_cb.peer_sep == AVDT_TSEP_SNK) { + /* Start the media task to encode SBC */ + btif_media_task_start_aa_req(); + + /* make sure we update any changed sbc encoder params */ + btif_a2dp_encoder_update(); + } + btif_media_cb.data_channel_open = TRUE; /* ack back when media task is fully started */ break; @@ -617,6 +635,7 @@ static void btif_a2dp_data_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event) case UIPC_CLOSE_EVT: a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); btif_audiopath_detached(); + btif_media_cb.data_channel_open = FALSE; break; default : @@ -860,7 +879,7 @@ void btif_a2dp_setup_codec(void) void btif_a2dp_on_idle(void) { APPL_TRACE_EVENT0("## ON A2DP IDLE ##"); - if(btif_media_cb.is_source) + if (btif_media_cb.peer_sep == AVDT_TSEP_SNK) { /* Make sure media task is stopped */ btif_media_task_stop_aa_req(); @@ -868,16 +887,13 @@ void btif_a2dp_on_idle(void) bta_av_co_init(); #ifdef BTA_AVK_INCLUDED - if (!btif_media_cb.is_source) + if (btif_media_cb.peer_sep == AVDT_TSEP_SRC) { btif_media_cb.rx_flush = TRUE; btif_media_task_aa_rx_flush_req(); btif_media_task_stop_decoding_req(); btif_media_task_clear_track(); APPL_TRACE_DEBUG0("Stopped BT track"); - APPL_TRACE_DEBUG0("Reset to Source role"); - btif_media_cb.is_source = TRUE; - btif_media_cb.rx_audio_focus_gained = BTIF_MEDIA_AUDIOFOCUS_LOSS; } #endif } @@ -1092,11 +1108,13 @@ void btif_a2dp_ack_fail(void) void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av) { APPL_TRACE_EVENT0("## ON A2DP STOPPED ##"); - if ((!btif_media_cb.is_source)) /* Handling for A2DP SINK cases*/ + if (btif_media_cb.peer_sep == AVDT_TSEP_SRC) /* Handling for A2DP SINK cases*/ { btif_media_cb.rx_flush = TRUE; btif_media_task_aa_rx_flush_req(); btif_media_task_stop_decoding_req(); + UIPC_Close(UIPC_CH_ID_AV_AUDIO); + btif_media_cb.data_channel_open = FALSE; return; } /* allow using this api for other than suspend */ @@ -1136,7 +1154,7 @@ void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av) void btif_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av) { APPL_TRACE_EVENT0("## ON A2DP SUSPENDED ##"); - if ((!btif_media_cb.is_source)) + if (btif_media_cb.peer_sep == AVDT_TSEP_SRC) { btif_media_cb.rx_flush = TRUE; btif_media_task_aa_rx_flush_req(); @@ -1174,13 +1192,6 @@ void btif_a2dp_set_tx_flush(BOOLEAN enable) btif_media_cb.tx_flush = enable; } -/* when true media task discards any rx frames */ -void btif_a2dp_set_audio_focus_state(btif_media_AudioFocus_state state) -{ - APPL_TRACE_EVENT1("## Audio_focus_state Rx %d ##", state); - btif_media_cb.rx_audio_focus_gained = state; -} - #ifdef BTA_AVK_INCLUDED /******************************************************************************* ** @@ -1210,18 +1221,7 @@ static void btif_media_task_avk_handle_timer ( void ) btif_media_flush_q(&(btif_media_cb.RxSbcQ)); return; } - if (btif_media_cb.rx_audio_focus_gained == BTIF_MEDIA_AUDIOFOCUS_LOSS_TRANSIENT) - { - APPL_TRACE_DEBUG0("Received Transient Focus Loss, Ignoring"); - return; - } - if (btif_media_cb.rx_audio_focus_gained == BTIF_MEDIA_AUDIOFOCUS_LOSS) - { - /* Send a Audio Focus Request */ - btif_av_request_audio_focus(TRUE); - return; - } num_frames_to_process = btif_media_cb.frames_to_process; APPL_TRACE_DEBUG0(" Process Frames + "); @@ -1338,8 +1338,6 @@ void btif_media_task_init(void) #if (BTA_AV_INCLUDED == TRUE) UIPC_Open(UIPC_CH_ID_AV_CTRL , btif_a2dp_ctrl_cb); #endif - btif_media_cb.is_source = TRUE; - APPL_TRACE_DEBUG0("Reset to Source role"); } /******************************************************************************* ** @@ -1558,14 +1556,18 @@ static void btif_media_task_handle_inc_media(tBT_SBC_HDR*p_msg) OI_STATUS status; int num_sbc_frames = p_msg->num_frames_to_be_processed; UINT32 sbc_frame_len = p_msg->len - 1; - int retwriteAudioTrack = 0; availPcmBytes = 2*sizeof(pcmData); - if ((btif_media_cb.is_source) || (btif_media_cb.rx_flush)) + if ((btif_media_cb.peer_sep == AVDT_TSEP_SNK) || (btif_media_cb.rx_flush)) { APPL_TRACE_DEBUG0(" State Changed happened in this tick "); return; } + + // ignore data if no one is listening + if (!btif_media_cb.data_channel_open) + return; + APPL_TRACE_DEBUG2("Number of sbc frames %d, frame_len %d", num_sbc_frames, sbc_frame_len); for(count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++) @@ -1585,7 +1587,7 @@ static void btif_media_task_handle_inc_media(tBT_SBC_HDR*p_msg) p_msg->len = sbc_frame_len + 1; } - retwriteAudioTrack = btWriteData((void*)pcmData, (2*sizeof(pcmData) - availPcmBytes)); + UIPC_Send(UIPC_CH_ID_AV_AUDIO, 0, (UINT8 *)pcmData, (2*sizeof(pcmData) - availPcmBytes)); } #endif @@ -2107,7 +2109,7 @@ static void btif_media_task_audio_feeding_init(BT_HDR *p_msg) } } -int a2dp_get_track_frequency(UINT8 frequency) { +int btif_a2dp_get_track_frequency(UINT8 frequency) { int freq = 48000; switch (frequency) { case A2D_SBC_IE_SAMP_FREQ_16: @@ -2126,19 +2128,23 @@ int a2dp_get_track_frequency(UINT8 frequency) { return freq; } -int a2dp_get_track_channel_type(UINT8 channeltype) { - int channel = AUDIO_CHANNEL_OUT_MONO; +int btif_a2dp_get_track_channel_count(UINT8 channeltype) { + int count = 1; switch (channeltype) { case A2D_SBC_IE_CH_MD_MONO: - channel = AUDIO_CHANNEL_OUT_MONO; + count = 1; break; case A2D_SBC_IE_CH_MD_DUAL: case A2D_SBC_IE_CH_MD_STEREO: case A2D_SBC_IE_CH_MD_JOINT: - channel = AUDIO_CHANNEL_OUT_STEREO; + count = 2; break; } - return channel; + return count; +} + +void btif_a2dp_set_peer_sep(UINT8 sep) { + btif_media_cb.peer_sep = sep; } /******************************************************************************* @@ -2154,7 +2160,6 @@ static void btif_media_task_aa_handle_stop_decoding(void ) { btif_media_cb.is_rx_timer = FALSE; GKI_stop_timer(BTIF_MEDIA_AVK_TASK_TIMER_ID); - btPauseTrack(); } /******************************************************************************* @@ -2170,7 +2175,6 @@ static void btif_media_task_aa_handle_start_decoding(void ) { if(btif_media_cb.is_rx_timer == TRUE) return; - btStartTrack(); btif_media_cb.is_rx_timer = TRUE; GKI_start_timer(BTIF_MEDIA_AVK_TASK_TIMER_ID, GKI_MS_TO_TICKS(BTIF_SINK_MEDIA_TIME_TICK), TRUE); } @@ -2180,8 +2184,6 @@ static void btif_media_task_aa_handle_start_decoding(void ) static void btif_media_task_aa_handle_clear_track (void) { APPL_TRACE_DEBUG0("btif_media_task_aa_handle_clear_track"); - btStopTrack(); - btDeleteTrack(); } /******************************************************************************* @@ -2213,18 +2215,18 @@ static void btif_media_task_aa_handle_decoder_reset(BT_HDR *p_msg) APPL_TRACE_ERROR1("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d", a2d_status); return; } - btif_media_cb.is_source = FALSE; + + btif_media_cb.sample_rate = btif_a2dp_get_track_frequency(sbc_cie.samp_freq); + btif_media_cb.channel_count = btif_a2dp_get_track_channel_count(sbc_cie.ch_mode); + btif_media_cb.rx_flush = FALSE; APPL_TRACE_DEBUG0("Reset to sink role"); status = OI_CODEC_SBC_DecoderReset(&context, contextData, sizeof(contextData), 2, 2, FALSE); if (!OI_SUCCESS(status)) { APPL_TRACE_ERROR1("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status); } - APPL_TRACE_DEBUG0("A2dpSink: Crate Track"); - if (btCreateTrack(a2dp_get_track_frequency(sbc_cie.samp_freq), a2dp_get_track_channel_type(sbc_cie.ch_mode)) == -1) { - APPL_TRACE_ERROR0("A2dpSink: Track creation fails!!!"); - return; - } + + UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb); switch(sbc_cie.samp_freq) { diff --git a/main/Android.mk b/main/Android.mk index 7379a36e4..2eec58153 100644 --- a/main/Android.mk +++ b/main/Android.mk @@ -46,8 +46,7 @@ LOCAL_SRC_FILES += \ ../btif/src/btif_gatt_test.c \ ../btif/src/btif_config.c \ ../btif/src/btif_config_util.cpp \ - ../btif/src/btif_profile_queue.c \ - ../btif/src/bluetoothTrack.cpp + ../btif/src/btif_profile_queue.c # callouts LOCAL_SRC_FILES+= \ @@ -102,7 +101,6 @@ LOCAL_C_INCLUDES+= . \ $(LOCAL_PATH)/../audio_a2dp_hw \ $(LOCAL_PATH)/../utils/include \ $(bdroid_C_INCLUDES) \ - $(TOP)/frameworks/av/include/media \ external/tinyxml2 LOCAL_CFLAGS += -DBUILDCFG $(bdroid_CFLAGS) -Werror -Wno-error=maybe-uninitialized -Wno-error=uninitialized -Wno-error=unused-parameter -- 2.11.0