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
diff --git a/audio_a2dp_hw/audio_a2dp_hw.c b/audio_a2dp_hw/audio_a2dp_hw.c
index bfd2226..5315b1f 100644
--- a/audio_a2dp_hw/audio_a2dp_hw.c
+++ b/audio_a2dp_hw/audio_a2dp_hw.c
@@ -78,10 +78,12 @@
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;
};
@@ -93,18 +95,23 @@
/* 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;
};
/*****************************************************************************
@@ -188,14 +195,14 @@
**
*****************************************************************************/
-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 %d)", path, out->buffer_sz);
+ INFO("connect to %s (sz %d)", path, buffer_sz);
skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
@@ -207,7 +214,7 @@
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 */
@@ -219,6 +226,38 @@
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;
@@ -266,44 +305,53 @@
**
*****************************************************************************/
-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)
+{
+ int ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL);
+ if (ret < 0)
+ {
+ ERROR("ack failed (%s)", strerror(errno));
+ if (errno == EINTR)
+ {
+ /* retry again */
+ ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL);
+ if (ret < 0)
+ {
+ ERROR("ack failed (%s)", strerror(errno));
+ skt_disconnect(common->ctrl_fd);
+ common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ return -1;
+ }
+ }
+ else
+ {
+ 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(out->ctrl_fd, &cmd, 1, MSG_NOSIGNAL) == -1)
+ if (send(common->ctrl_fd, &cmd, 1, MSG_NOSIGNAL) == -1)
{
ERROR("cmd 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;
}
/* wait for ack byte */
- if (recv(out->ctrl_fd, &ack, 1, MSG_NOSIGNAL) < 0)
- {
- ERROR("ack failed (%s)", strerror(errno));
- if (errno == EINTR)
- {
- /* retry again */
- if (recv(out->ctrl_fd, &ack, 1, MSG_NOSIGNAL) < 0)
- {
- ERROR("ack failed (%s)", strerror(errno));
- skt_disconnect(out->ctrl_fd);
- out->ctrl_fd = AUDIO_SKT_DISCONNECTED;
- return -1;
- }
- }
- else
- {
- skt_disconnect(out->ctrl_fd);
- out->ctrl_fd = AUDIO_SKT_DISCONNECTED;
- return -1;
-
- }
- }
+ if (a2dp_ctrl_receive(common, &ack, 1) < 0)
+ return -1;
DEBUG("A2DP COMMAND %s DONE STATUS %d", dump_a2dp_ctrl_event(cmd), ack);
@@ -313,13 +361,74 @@
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;
@@ -327,124 +436,109 @@
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;
-}
-
/*****************************************************************************
**
@@ -458,49 +552,49 @@
struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
int sent;
- DEBUG("write %d bytes (fd %d)", bytes, out->audio_fd);
+ DEBUG("write %d 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 %d bytes", sent, bytes);
@@ -512,9 +606,9 @@
{
struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
- DEBUG("rate %d", out->cfg.rate);
+ DEBUG("rate %d", 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)
@@ -529,7 +623,7 @@
return -1;
}
- out->cfg.rate = rate;
+ out->common.cfg.rate = rate;
return 0;
}
@@ -538,25 +632,25 @@
{
struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
- DEBUG("buffer_size : %d", out->buffer_sz);
+ DEBUG("buffer_size : %d", 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%x", out->cfg.channel_flags);
+ DEBUG("channels 0x%x", 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)
@@ -574,13 +668,13 @@
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;
}
@@ -601,9 +695,9 @@
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);
@@ -617,7 +711,7 @@
if (strcmp(keyval, "true") == 0)
{
DEBUG("stream closing, disallow any writes");
- out->state = AUDIO_A2DP_STATE_STOPPING;
+ out->common.state = AUDIO_A2DP_STATE_STOPPING;
}
}
@@ -627,21 +721,21 @@
{
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;
@@ -667,9 +761,9 @@
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;
@@ -725,19 +819,22 @@
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)
@@ -750,10 +847,10 @@
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)
@@ -770,7 +867,10 @@
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)
@@ -821,12 +921,60 @@
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)
@@ -897,7 +1045,11 @@
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)
@@ -909,26 +1061,8 @@
*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;
@@ -952,12 +1086,12 @@
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;
@@ -975,7 +1109,7 @@
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);
@@ -1075,7 +1209,7 @@
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);
@@ -1105,24 +1239,54 @@
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);
- return;
+ if ((state == AUDIO_A2DP_STATE_STARTED) || (state == AUDIO_A2DP_STATE_STOPPING))
+ stop_audio_datapath(&in->common);
+
+ 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 2015591..b4ac85d 100644
--- a/audio_a2dp_hw/audio_a2dp_hw.h
+++ b/audio_a2dp_hw/audio_a2dp_hw.h
@@ -46,7 +46,8 @@
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 e4e1660..0000000
--- 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 eda9c18..12174c9 100644
--- a/btif/include/btif_av.h
+++ b/btif/include/btif_av.h
@@ -44,9 +44,7 @@
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 a785d34..f01286b 100644
--- a/btif/include/btif_media.h
+++ b/btif/include/btif_media.h
@@ -98,13 +98,6 @@
} 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_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 9e63d54..c0cdc5a 100644
--- a/btif/src/bluetooth.c
+++ b/btif/src/bluetooth.c
@@ -79,7 +79,8 @@
/* 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 @@
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 685780e..0000000
--- 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 <media/AudioTrack.h>
-
-//#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<android::AudioTrack> 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 7272307..5dcbb66 100644
--- a/btif/src/btif_av.c
+++ b/btif/src/btif_av.c
@@ -26,6 +26,7 @@
*****************************************************************************/
#include <hardware/bluetooth.h>
+#include <system/audio.h>
#include "hardware/bt_av.h"
#define LOG_TAG "BTIF_AV"
@@ -69,12 +70,6 @@
/*****************************************************************************
** Local type definitions
******************************************************************************/
-typedef enum
-{
- SEP_SRC = 0x0,
- SEP_SNK,
- SEP_NOT_OPENED
-}tbtif_AV_SEP_TYPE;
typedef struct
{
@@ -83,7 +78,7 @@
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 @@
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;\
@@ -192,39 +196,11 @@
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
*****************************************************************************/
@@ -263,6 +239,24 @@
** 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
@@ -285,7 +279,6 @@
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;
@@ -295,14 +288,6 @@
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;
@@ -389,8 +374,7 @@
{
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:
@@ -398,8 +382,7 @@
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;
@@ -417,10 +400,8 @@
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
{
@@ -431,17 +412,16 @@
}
/* 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);
@@ -449,6 +429,20 @@
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:
@@ -480,13 +474,13 @@
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);
}
@@ -494,18 +488,18 @@
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;
@@ -513,8 +507,7 @@
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;
@@ -569,7 +562,7 @@
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;
@@ -589,7 +582,7 @@
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)))
@@ -603,14 +596,14 @@
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 */
}
@@ -620,10 +613,12 @@
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:
@@ -631,8 +626,7 @@
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) {
@@ -691,8 +685,7 @@
/* 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. */
@@ -708,7 +701,7 @@
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;
@@ -724,14 +717,16 @@
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;
@@ -740,10 +735,12 @@
/* 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);
@@ -762,7 +759,7 @@
{
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);
@@ -780,13 +777,11 @@
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);
@@ -800,8 +795,7 @@
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)
@@ -809,11 +803,6 @@
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;
@@ -822,8 +811,7 @@
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;
@@ -859,6 +847,9 @@
{
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 */
{
@@ -873,8 +864,21 @@
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);
+ }
+ }
}
/*******************************************************************************
**
@@ -886,8 +890,10 @@
**
*******************************************************************************/
-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)
@@ -900,7 +906,7 @@
btif_a2dp_on_init();
- return BT_STATUS_SUCCESS;
+ return BT_STATUS_SUCCESS;
}
return BT_STATUS_DONE;
@@ -908,27 +914,63 @@
/*******************************************************************************
**
-** 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 btif_av_init();
+ 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 status;
}
/*******************************************************************************
@@ -953,15 +995,15 @@
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();
@@ -1002,124 +1044,51 @@
{
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)
+static void cleanup_src(void) {
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ if (bt_av_src_callbacks)
{
- 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
- {
- 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));
+static void cleanup_sink(void) {
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ if (bt_av_sink_callbacks)
+ {
+ bt_av_sink_callbacks = NULL;
+ if (bt_av_src_callbacks == NULL)
+ cleanup();
+ }
}
-/*******************************************************************************
-**
-** 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);
-
- btif_a2dp_set_audio_focus_state(state);
-}
-
-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,
};
/*******************************************************************************
@@ -1254,17 +1223,32 @@
/*******************************************************************************
**
-** Function btif_av_get_interface
+** Function btif_av_get_src_interface
**
-** Description Get the AV callback interface
+** Description Get the AV callback interface for A2DP source profile
**
** Returns btav_interface_t
**
*******************************************************************************/
-const btav_interface_t *btif_av_get_interface(void)
+const btav_interface_t *btif_av_get_src_interface(void)
{
BTIF_TRACE_EVENT1("%s", __FUNCTION__);
- return &bt_av_interface;
+ return &bt_av_src_interface;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_get_sink_interface
+**
+** Description Get the AV callback interface for A2DP sink profile
+**
+** Returns btav_interface_t
+**
+*******************************************************************************/
+const btav_interface_t *btif_av_get_sink_interface(void)
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ return &bt_av_sink_interface;
}
/*******************************************************************************
diff --git a/btif/src/btif_core.c b/btif/src/btif_core.c
index 8126b6b..6a4d604 100644
--- a/btif/src/btif_core.c
+++ b/btif/src/btif_core.c
@@ -611,8 +611,6 @@
#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 aab8cec..4653081 100644
--- a/btif/src/btif_media_task.c
+++ b/btif/src/btif_media_task.c
@@ -72,7 +72,6 @@
#endif
#include "stdio.h"
#include <dlfcn.h>
-#include "bluetoothTrack.h"
//#define DEBUG_MEDIA_AV_FLOW TRUE
@@ -279,9 +278,12 @@
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 @@
#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 @@
/* 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 @@
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 @@
}
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 @@
}
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 @@
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 @@
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_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 @@
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_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_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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
}
}
-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 @@
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 @@
{
btif_media_cb.is_rx_timer = FALSE;
GKI_stop_timer(BTIF_MEDIA_AVK_TASK_TIMER_ID);
- btPauseTrack();
}
/*******************************************************************************
@@ -2170,7 +2175,6 @@
{
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_clear_track (void)
{
APPL_TRACE_DEBUG0("btif_media_task_aa_handle_clear_track");
- btStopTrack();
- btDeleteTrack();
}
/*******************************************************************************
@@ -2213,18 +2215,18 @@
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 058fdc0..0022dbb 100644
--- a/main/Android.mk
+++ b/main/Android.mk
@@ -20,6 +20,7 @@
# BTIF
LOCAL_SRC_FILES += \
+<<<<<<< HEAD
../btif/src/btif_av.c \
../btif/src/btif_config.c \
../btif/src/btif_config_util.cpp \
@@ -46,8 +47,7 @@
../btif/src/btif_sock_thread.c \
../btif/src/btif_sock_util.c \
../btif/src/btif_storage.c \
- ../btif/src/btif_util.c \
- ../btif/src/bluetoothTrack.cpp.c
+ ../btif/src/btif_util.c
# callouts
LOCAL_SRC_FILES += \
@@ -102,7 +102,6 @@
$(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