OSDN Git Service

More work on A2DP Sink:
authorMike Lockwood <lockwood@google.com>
Fri, 23 May 2014 19:42:24 +0000 (12:42 -0700)
committerMike Lockwood <lockwood@google.com>
Thu, 12 Jun 2014 23:16:41 +0000 (16:16 -0700)
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
audio_a2dp_hw/audio_a2dp_hw.h
btif/include/bluetoothTrack.h [deleted file]
btif/include/btif_av.h
btif/include/btif_media.h
btif/src/bluetooth.c
btif/src/bluetoothTrack.cpp [deleted file]
btif/src/btif_av.c
btif/src/btif_core.c
btif/src/btif_media_task.c
main/Android.mk

index e53ad5d..60feaba 100644 (file)
@@ -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)
index 2015591..b4ac85d 100644 (file)
@@ -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 (file)
index e4e1660..0000000
+++ /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
index eda9c18..12174c9 100644 (file)
@@ -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;
 
 
index a785d34..f01286b 100644 (file)
@@ -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
index 9e63d54..c0cdc5a 100644 (file)
@@ -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 (file)
index 685780e..0000000
+++ /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;
-}
-
index 0b7b9d7..24ceb8a 100644 (file)
@@ -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 @@ 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;
 }
 
 /*******************************************************************************
index 455255a..9b432cd 100644 (file)
@@ -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();
index e45ddfc..7e29917 100644 (file)
@@ -72,7 +72,6 @@
 #endif
 #include "stdio.h"
 #include <dlfcn.h>
-#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)
     {
index 7379a36..2eec581 100644 (file)
@@ -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