Snapshot cdeccf6fdd8c2d494ea2867cb37a025bf8879baf

Change-Id: Ia2de32ccb97a9641462c72363b0a8c4288f4f36d
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..3f42f6a
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH := $(call my-dir)
+
+# Setup bdroid local make variables for handling configuration
+ifneq ($(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR),)
+  bdroid_C_INCLUDES := $(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR)
+  bdroid_CFLAGS := -DHAS_BDROID_BUILDCFG
+else
+  $(warning NO BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR, using only generic configuration)
+  bdroid_C_INCLUDES :=
+  bdroid_CFLAGS := -DHAS_NO_BDROID_BUILDCFG
+endif
+
+include $(call all-subdir-makefiles)
+
+# Cleanup our locals
+bdroid_C_INCLUDES :=
+bdroid_CFLaGS :=
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..b84e1b6
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2007 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 you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/audio_a2dp_hw/Android.mk b/audio_a2dp_hw/Android.mk
new file mode 100644
index 0000000..d98e4bb
--- /dev/null
+++ b/audio_a2dp_hw/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	audio_a2dp_hw.c
+
+LOCAL_C_INCLUDES+= .
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils
+
+LOCAL_SHARED_LIBRARIES += \
+	libpower
+
+LOCAL_MODULE := audio.a2dp.default
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/audio_a2dp_hw/audio_a2dp_hw.c b/audio_a2dp_hw/audio_a2dp_hw.c
new file mode 100644
index 0000000..42e416e
--- /dev/null
+++ b/audio_a2dp_hw/audio_a2dp_hw.c
@@ -0,0 +1,1103 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ *  Filename:      audio_a2dp_hw.c
+ *
+ *  Description:   Implements hal for bluedroid a2dp audio device
+ *
+ *****************************************************************************/
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <cutils/str_parms.h>
+#include <cutils/sockets.h>
+
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <hardware/hardware.h>
+#include "audio_a2dp_hw.h"
+
+#define LOG_TAG "audio_a2dp_hw"
+/* #define LOG_NDEBUG 0 */
+#include <cutils/log.h>
+
+/*****************************************************************************
+**  Constants & Macros
+******************************************************************************/
+
+#define CTRL_CHAN_RETRY_COUNT 3
+#define USEC_PER_SEC 1000000L
+
+#define CASE_RETURN_STR(const) case const: return #const;
+
+#define FNLOG()             ALOGV("%s", __FUNCTION__);
+#define DEBUG(fmt, ...)     ALOGV("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define INFO(fmt, ...)      ALOGI("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define ERROR(fmt, ...)     ALOGE("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+
+#define ASSERTC(cond, msg, val) if (!(cond)) {ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
+
+/*****************************************************************************
+**  Local type definitions
+******************************************************************************/
+
+typedef enum {
+    AUDIO_A2DP_STATE_STARTING,
+    AUDIO_A2DP_STATE_STARTED,
+    AUDIO_A2DP_STATE_STOPPING,
+    AUDIO_A2DP_STATE_STOPPED,
+    AUDIO_A2DP_STATE_SUSPENDED, /* need explicit set param call to resume (suspend=false) */
+    AUDIO_A2DP_STATE_STANDBY    /* allows write to autoresume */
+} a2dp_state_t;
+
+struct a2dp_stream_out;
+
+struct a2dp_audio_device {
+    struct audio_hw_device device;
+    struct a2dp_stream_out *output;
+};
+
+struct a2dp_config {
+    uint32_t                rate;
+    uint32_t                channel_flags;
+    int                     format;
+};
+
+/* move ctrl_fd outside output stream and keep open until HAL unloaded ? */
+
+struct a2dp_stream_out {
+    struct audio_stream_out stream;
+    pthread_mutex_t         lock;
+    int                     ctrl_fd;
+    int                     audio_fd;
+    size_t                  buffer_sz;
+    a2dp_state_t            state;
+    struct a2dp_config      cfg;
+};
+
+struct a2dp_stream_in {
+    struct audio_stream_in stream;
+};
+
+/*****************************************************************************
+**  Static variables
+******************************************************************************/
+
+/*****************************************************************************
+**  Static functions
+******************************************************************************/
+
+static size_t out_get_buffer_size(const struct audio_stream *stream);
+
+/*****************************************************************************
+**  Externs
+******************************************************************************/
+
+/*****************************************************************************
+**  Functions
+******************************************************************************/
+
+/*****************************************************************************
+**   Miscellaneous helper functions
+******************************************************************************/
+
+static const char* dump_a2dp_ctrl_event(char event)
+{
+    switch(event)
+    {
+        CASE_RETURN_STR(A2DP_CTRL_CMD_NONE)
+        CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_READY)
+        CASE_RETURN_STR(A2DP_CTRL_CMD_START)
+        CASE_RETURN_STR(A2DP_CTRL_CMD_STOP)
+        CASE_RETURN_STR(A2DP_CTRL_CMD_SUSPEND)
+        default:
+            return "UNKNOWN MSG ID";
+    }
+}
+
+/* logs timestamp with microsec precision
+   pprev is optional in case a dedicated diff is required */
+static void ts_log(char *tag, int val, struct timespec *pprev_opt)
+{
+    struct timespec now;
+    static struct timespec prev = {0,0};
+    unsigned long long now_us;
+    unsigned long long diff_us;
+
+    clock_gettime(CLOCK_MONOTONIC, &now);
+
+    now_us = now.tv_sec*USEC_PER_SEC + now.tv_nsec/1000;
+
+    if (pprev_opt)
+    {
+        diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
+        *pprev_opt = now;
+        DEBUG("[%s] ts %08lld, *diff %08lld, val %d", tag, now_us, diff_us, val);
+    }
+    else
+    {
+        diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
+        prev = now;
+        DEBUG("[%s] ts %08lld, diff %08lld, val %d", tag, now_us, diff_us, val);
+    }
+}
+
+static int calc_audiotime(struct a2dp_config cfg, int bytes)
+{
+    int chan_count = popcount(cfg.channel_flags);
+
+    ASSERTC(cfg.format == AUDIO_FORMAT_PCM_16_BIT,
+            "unsupported sample sz", cfg.format);
+
+    return bytes*(1000000/(chan_count*2))/cfg.rate;
+}
+
+/*****************************************************************************
+**
+**   bluedroid stack adaptation
+**
+*****************************************************************************/
+
+static int skt_connect(struct a2dp_stream_out *out, char *path)
+{
+    int ret;
+    int skt_fd;
+    struct sockaddr_un remote;
+    int len;
+
+    INFO("connect to %s (sz %d)", path, out->buffer_sz);
+
+    skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+
+    if(socket_local_client_connect(skt_fd, path,
+            ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) < 0)
+    {
+        ERROR("failed to connect (%s)", strerror(errno));
+        close(skt_fd);
+        return -1;
+    }
+
+    len = out->buffer_sz;
+    ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, (int)sizeof(len));
+
+    /* only issue warning if failed */
+    if (ret < 0)
+        ERROR("setsockopt failed (%s)", strerror(errno));
+
+    INFO("connected to stack fd = %d", skt_fd);
+
+    return skt_fd;
+}
+
+static int skt_write(int fd, const void *p, size_t len)
+{
+    int sent;
+    struct pollfd pfd;
+
+    FNLOG();
+
+    pfd.fd = fd;
+    pfd.events = POLLOUT;
+
+    /* poll for 500 ms */
+
+    /* send time out */
+    if (poll(&pfd, 1, 500) == 0)
+        return 0;
+
+    ts_log("skt_write", len, NULL);
+
+    if ((sent = send(fd, p, len, MSG_NOSIGNAL)) == -1)
+    {
+        ERROR("write failed with errno=%d\n", errno);
+        return -1;
+    }
+
+    return sent;
+}
+
+static int skt_disconnect(int fd)
+{
+    INFO("fd %d", fd);
+
+    if (fd != AUDIO_SKT_DISCONNECTED)
+    {
+        shutdown(fd, SHUT_RDWR);
+        close(fd);
+    }
+    return 0;
+}
+
+
+
+/*****************************************************************************
+**
+**  AUDIO CONTROL PATH
+**
+*****************************************************************************/
+
+static int a2dp_command(struct a2dp_stream_out *out, 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)
+    {
+        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)
+    {
+        ERROR("ack failed (%s)", strerror(errno));
+        skt_disconnect(out->ctrl_fd);
+        out->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+        return -1;
+    }
+
+    DEBUG("A2DP COMMAND %s DONE STATUS %d", dump_a2dp_ctrl_event(cmd), ack);
+
+    if (ack != A2DP_CTRL_ACK_SUCCESS)
+        return -1;
+
+    return 0;
+}
+
+/*****************************************************************************
+**
+** AUDIO DATA PATH
+**
+*****************************************************************************/
+
+static void a2dp_stream_out_init(struct a2dp_stream_out *out)
+{
+    pthread_mutexattr_t lock_attr;
+
+    FNLOG();
+
+    pthread_mutexattr_init(&lock_attr);
+    pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
+    pthread_mutex_init(&out->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;
+
+    /* manages max capacity of socket pipe */
+    out->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
+}
+
+static int start_audio_datapath(struct a2dp_stream_out *out)
+{
+    int oldstate = out->state;
+
+    INFO("state %d", out->state);
+
+    if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED)
+        return -1;
+
+    out->state = AUDIO_A2DP_STATE_STARTING;
+
+    if (a2dp_command(out, A2DP_CTRL_CMD_START) < 0)
+    {
+        ERROR("audiopath start failed");
+
+        out->state = oldstate;
+        return -1;
+    }
+
+    /* connect socket if not yet connected */
+    if (out->audio_fd == AUDIO_SKT_DISCONNECTED)
+    {
+        out->audio_fd = skt_connect(out, A2DP_DATA_PATH);
+
+        if (out->audio_fd < 0)
+        {
+            out->state = oldstate;
+            return -1;
+        }
+
+        out->state = AUDIO_A2DP_STATE_STARTED;
+    }
+
+    return 0;
+}
+
+
+static int stop_audio_datapath(struct a2dp_stream_out *out)
+{
+    int oldstate = out->state;
+
+    INFO("state %d", out->state);
+
+    if (out->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;
+
+    if (a2dp_command(out, A2DP_CTRL_CMD_STOP) < 0)
+    {
+        ERROR("audiopath stop failed");
+        out->state = oldstate;
+        return -1;
+    }
+
+    out->state = AUDIO_A2DP_STATE_STOPPED;
+
+    /* disconnect audio path */
+    skt_disconnect(out->audio_fd);
+    out->audio_fd = AUDIO_SKT_DISCONNECTED;
+
+    return 0;
+}
+
+static int suspend_audio_datapath(struct a2dp_stream_out *out, bool standby)
+{
+    INFO("state %d", out->state);
+
+    if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED)
+         return -1;
+
+    if (out->state == AUDIO_A2DP_STATE_STOPPING)
+        return -1;
+
+    if (a2dp_command(out, A2DP_CTRL_CMD_SUSPEND) < 0)
+        return -1;
+
+    if (standby)
+        out->state = AUDIO_A2DP_STATE_STANDBY;
+    else
+        out->state = AUDIO_A2DP_STATE_SUSPENDED;
+
+    /* disconnect audio path */
+    skt_disconnect(out->audio_fd);
+
+    out->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;
+}
+
+
+/*****************************************************************************
+**
+**  audio output callbacks
+**
+*****************************************************************************/
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+                         size_t bytes)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+    int sent;
+
+    DEBUG("write %d bytes (fd %d)", bytes, out->audio_fd);
+
+    if (out->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))
+    {
+        pthread_mutex_lock(&out->lock);
+
+        if (start_audio_datapath(out) < 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);
+
+            DEBUG("emulate a2dp write delay (%d us)", us_delay);
+
+            usleep(us_delay);
+            pthread_mutex_unlock(&out->lock);
+            return -1;
+        }
+
+        pthread_mutex_unlock(&out->lock);
+    }
+    else if (out->state != AUDIO_A2DP_STATE_STARTED)
+    {
+        ERROR("stream not in stopped or standby");
+        return -1;
+    }
+
+    sent = skt_write(out->audio_fd, buffer,  bytes);
+
+    if (sent == -1)
+    {
+        skt_disconnect(out->audio_fd);
+        out->audio_fd = AUDIO_SKT_DISCONNECTED;
+        out->state = AUDIO_A2DP_STATE_STOPPED;
+    }
+
+    DEBUG("wrote %d bytes out of %d bytes", sent, bytes);
+    return sent;
+}
+
+
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    DEBUG("rate %d", out->cfg.rate);
+
+    return out->cfg.rate;
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    DEBUG("out_set_sample_rate : %d", rate);
+
+    if (rate != AUDIO_STREAM_DEFAULT_RATE)
+    {
+        ERROR("only rate %d supported", AUDIO_STREAM_DEFAULT_RATE);
+        return -1;
+    }
+
+    out->cfg.rate = rate;
+
+    return 0;
+}
+
+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 : %d", out->buffer_sz);
+
+    return out->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);
+
+    return out->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;
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+    DEBUG("setting format not yet supported (0x%x)", format);
+    return -ENOSYS;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+    int retval = 0;
+
+    int retVal = 0;
+
+    FNLOG();
+
+    pthread_mutex_lock(&out->lock);
+
+    if (out->state == AUDIO_A2DP_STATE_STARTED)
+        retVal =  suspend_audio_datapath(out, true);
+    else
+        retVal = 0;
+    pthread_mutex_unlock (&out->lock);
+
+    return retVal;
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+    FNLOG();
+    return 0;
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+    struct str_parms *parms;
+    char keyval[16];
+    int retval = 0;
+
+    INFO("state %d", out->state);
+
+    pthread_mutex_lock(&out->lock);
+
+    parms = str_parms_create_str(kvpairs);
+
+    /* dump params */
+    str_parms_dump(parms);
+
+    retval = str_parms_get_str(parms, "closing", keyval, sizeof(keyval));
+
+    if (retval >= 0)
+    {
+        if (strcmp(keyval, "true") == 0)
+        {
+            DEBUG("stream closing, disallow any writes");
+            out->state = AUDIO_A2DP_STATE_STOPPING;
+        }
+    }
+
+    retval = str_parms_get_str(parms, "A2dpSuspended", keyval, sizeof(keyval));
+
+    if (retval >= 0)
+    {
+        if (strcmp(keyval, "true") == 0)
+        {
+            if (out->state == AUDIO_A2DP_STATE_STARTED)
+                retval = suspend_audio_datapath(out, 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;
+            /* Irrespective of the state, return 0 */
+            retval = 0;
+        }
+    }
+
+    pthread_mutex_unlock(&out->lock);
+    str_parms_destroy(parms);
+
+    return retval;
+}
+
+static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    FNLOG();
+
+    /* add populating param here */
+
+    return strdup("");
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+    int latency_us;
+
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    FNLOG();
+
+    latency_us = ((out->buffer_sz * 1000 ) /
+                    audio_stream_frame_size(&out->stream.common) /
+                    out->cfg.rate) * 1000;
+
+
+    return (latency_us / 1000) + 200;
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+                          float right)
+{
+    FNLOG();
+
+    /* volume controlled in audioflinger mixer (digital) */
+
+    return -ENOSYS;
+}
+
+
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+                                   uint32_t *dsp_frames)
+{
+    FNLOG();
+    return -EINVAL;
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    FNLOG();
+    return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    FNLOG();
+    return 0;
+}
+
+/*
+ * AUDIO INPUT STREAM
+ */
+
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+    FNLOG();
+    return 8000;
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+    FNLOG();
+    return 0;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+    FNLOG();
+    return 320;
+}
+
+static uint32_t in_get_channels(const struct audio_stream *stream)
+{
+    FNLOG();
+    return AUDIO_CHANNEL_IN_MONO;
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+    FNLOG();
+    return AUDIO_FORMAT_PCM_16_BIT;
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+    FNLOG();
+    return 0;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+    FNLOG();
+    return 0;
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+    FNLOG();
+    return 0;
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    FNLOG();
+    return 0;
+}
+
+static char * in_get_parameters(const struct audio_stream *stream,
+                                const char *keys)
+{
+    FNLOG();
+    return strdup("");
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+    FNLOG();
+    return 0;
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
+                       size_t bytes)
+{
+    FNLOG();
+    return bytes;
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+    FNLOG();
+    return 0;
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    FNLOG();
+    return 0;
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+    FNLOG();
+
+    return 0;
+}
+
+static int adev_open_output_stream(struct audio_hw_device *dev,
+                                   audio_io_handle_t handle,
+                                   audio_devices_t devices,
+                                   audio_output_flags_t flags,
+                                   struct audio_config *config,
+                                   struct audio_stream_out **stream_out)
+
+{
+    struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
+    struct a2dp_stream_out *out;
+    int ret = 0;
+    int i;
+
+    INFO("opening output");
+
+    out = (struct a2dp_stream_out *)calloc(1, sizeof(struct a2dp_stream_out));
+
+    if (!out)
+        return -ENOMEM;
+
+    out->stream.common.get_sample_rate = out_get_sample_rate;
+    out->stream.common.set_sample_rate = out_set_sample_rate;
+    out->stream.common.get_buffer_size = out_get_buffer_size;
+    out->stream.common.get_channels = out_get_channels;
+    out->stream.common.get_format = out_get_format;
+    out->stream.common.set_format = out_set_format;
+    out->stream.common.standby = out_standby;
+    out->stream.common.dump = out_dump;
+    out->stream.common.set_parameters = out_set_parameters;
+    out->stream.common.get_parameters = out_get_parameters;
+    out->stream.common.add_audio_effect = out_add_audio_effect;
+    out->stream.common.remove_audio_effect = out_remove_audio_effect;
+    out->stream.get_latency = out_get_latency;
+    out->stream.set_volume = out_set_volume;
+    out->stream.write = out_write;
+    out->stream.get_render_position = out_get_render_position;
+
+    /* initialize a2dp specifics */
+    a2dp_stream_out_init(out);
+
+   /* set output config values */
+   if (config)
+   {
+      config->format = out_get_format((const struct audio_stream *)&out->stream);
+      config->sample_rate = out_get_sample_rate((const struct audio_stream *)&out->stream);
+      config->channel_mask = out_get_channels((const struct audio_stream *)&out->stream);
+   }
+    *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)
+    {
+        ERROR("ctrl socket failed to connect (%s)", strerror(errno));
+        ret = -1;
+        goto err_open;
+    }
+
+    DEBUG("success");
+    return 0;
+
+err_open:
+    free(out);
+    *stream_out = NULL;
+    ERROR("failed");
+    return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev,
+                                     struct audio_stream_out *stream)
+{
+    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);
+
+    if ((out->state == AUDIO_A2DP_STATE_STARTED) || (out->state == AUDIO_A2DP_STATE_STOPPING))
+        stop_audio_datapath(out);
+
+    skt_disconnect(out->ctrl_fd);
+    free(stream);
+    a2dp_dev->output = NULL;
+
+    DEBUG("done");
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+    struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
+    struct a2dp_stream_out *out = a2dp_dev->output;
+    int retval = 0;
+
+    if (out == NULL)
+        return retval;
+
+    INFO("state %d", out->state);
+
+    retval = out->stream.common.set_parameters((struct audio_stream *)out, kvpairs);
+
+    return retval;
+}
+
+static char * adev_get_parameters(const struct audio_hw_device *dev,
+                                  const char *keys)
+{
+    struct str_parms *parms;
+
+    FNLOG();
+
+    parms = str_parms_create_str(keys);
+
+    str_parms_dump(parms);
+
+    str_parms_destroy(parms);
+
+    return strdup("");
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+    struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device*)dev;
+
+    FNLOG();
+
+    return 0;
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+    FNLOG();
+
+    return -ENOSYS;
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+{
+    FNLOG();
+
+    return -ENOSYS;
+}
+
+static int adev_set_mode(struct audio_hw_device *dev, int mode)
+{
+    FNLOG();
+
+    return 0;
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+    FNLOG();
+
+    return -ENOSYS;
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+    FNLOG();
+
+    return -ENOSYS;
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+                                         const struct audio_config *config)
+{
+    FNLOG();
+
+    return 320;
+}
+
+static int adev_open_input_stream(struct audio_hw_device *dev,
+                                  audio_io_handle_t handle,
+                                  audio_devices_t devices,
+                                  struct audio_config *config,
+                                  struct audio_stream_in **stream_in)
+{
+    struct a2dp_audio_device *ladev = (struct a2dp_audio_device *)dev;
+    struct a2dp_stream_in *in;
+    int ret;
+
+    FNLOG();
+
+    in = (struct a2dp_stream_in *)calloc(1, sizeof(struct a2dp_stream_in));
+
+    if (!in)
+        return -ENOMEM;
+
+    in->stream.common.get_sample_rate = in_get_sample_rate;
+    in->stream.common.set_sample_rate = in_set_sample_rate;
+    in->stream.common.get_buffer_size = in_get_buffer_size;
+    in->stream.common.get_channels = in_get_channels;
+    in->stream.common.get_format = in_get_format;
+    in->stream.common.set_format = in_set_format;
+    in->stream.common.standby = in_standby;
+    in->stream.common.dump = in_dump;
+    in->stream.common.set_parameters = in_set_parameters;
+    in->stream.common.get_parameters = in_get_parameters;
+    in->stream.common.add_audio_effect = in_add_audio_effect;
+    in->stream.common.remove_audio_effect = in_remove_audio_effect;
+    in->stream.set_gain = in_set_gain;
+    in->stream.read = in_read;
+    in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+    *stream_in = &in->stream;
+    return 0;
+
+err_open:
+    free(in);
+    *stream_in = NULL;
+    return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+                                   struct audio_stream_in *in)
+{
+    FNLOG();
+
+    return;
+}
+
+static int adev_dump(const audio_hw_device_t *device, int fd)
+{
+    FNLOG();
+
+    return 0;
+}
+
+static int adev_close(hw_device_t *device)
+{
+    FNLOG();
+
+    free(device);
+    return 0;
+}
+
+static int adev_open(const hw_module_t* module, const char* name,
+                     hw_device_t** device)
+{
+    struct a2dp_audio_device *adev;
+    int ret;
+
+    INFO(" adev_open in A2dp_hw module");
+    FNLOG();
+
+    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
+    {
+        ERROR("interface %s not matching [%s]", name, AUDIO_HARDWARE_INTERFACE);
+        return -EINVAL;
+    }
+
+    adev = calloc(1, sizeof(struct a2dp_audio_device));
+
+    if (!adev)
+        return -ENOMEM;
+
+    adev->device.common.tag = HARDWARE_DEVICE_TAG;
+    adev->device.common.version = AUDIO_DEVICE_API_VERSION_CURRENT;
+    adev->device.common.module = (struct hw_module_t *) module;
+    adev->device.common.close = adev_close;
+
+    adev->device.init_check = adev_init_check;
+    adev->device.set_voice_volume = adev_set_voice_volume;
+    adev->device.set_master_volume = adev_set_master_volume;
+    adev->device.set_mode = adev_set_mode;
+    adev->device.set_mic_mute = adev_set_mic_mute;
+    adev->device.get_mic_mute = adev_get_mic_mute;
+    adev->device.set_parameters = adev_set_parameters;
+    adev->device.get_parameters = adev_get_parameters;
+    adev->device.get_input_buffer_size = adev_get_input_buffer_size;
+    adev->device.open_output_stream = adev_open_output_stream;
+    adev->device.close_output_stream = adev_close_output_stream;
+    adev->device.open_input_stream = adev_open_input_stream;
+    adev->device.close_input_stream = adev_close_input_stream;
+    adev->device.dump = adev_dump;
+
+    adev->output = NULL;
+
+
+    *device = &adev->device.common;
+
+    return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {
+    .open = adev_open,
+};
+
+struct audio_module HAL_MODULE_INFO_SYM = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .version_major = 1,
+        .version_minor = 0,
+        .id = AUDIO_HARDWARE_MODULE_ID,
+        .name = "A2DP Audio HW HAL",
+        .author = "The Android Open Source Project",
+        .methods = &hal_module_methods,
+    },
+};
+
diff --git a/audio_a2dp_hw/audio_a2dp_hw.h b/audio_a2dp_hw/audio_a2dp_hw.h
new file mode 100644
index 0000000..2015591
--- /dev/null
+++ b/audio_a2dp_hw/audio_a2dp_hw.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ *  Filename:      audio_a2dp_hw.h
+ *
+ *  Description:
+ *
+ *****************************************************************************/
+
+#ifndef AUDIO_A2DP_HW_H
+#define AUDIO_A2DP_HW_H
+
+/*****************************************************************************
+**  Constants & Macros
+******************************************************************************/
+
+#define A2DP_AUDIO_HARDWARE_INTERFACE "audio.a2dp"
+#define A2DP_CTRL_PATH "/data/misc/bluedroid/.a2dp_ctrl"
+#define A2DP_DATA_PATH "/data/misc/bluedroid/.a2dp_data"
+
+#define AUDIO_STREAM_DEFAULT_RATE          44100
+#define AUDIO_STREAM_DEFAULT_FORMAT        AUDIO_FORMAT_PCM_16_BIT
+#define AUDIO_STREAM_DEFAULT_CHANNEL_FLAG  AUDIO_CHANNEL_OUT_STEREO
+#define AUDIO_STREAM_OUTPUT_BUFFER_SZ      (20*512)
+#define AUDIO_SKT_DISCONNECTED             (-1)
+
+typedef enum {
+    A2DP_CTRL_CMD_NONE,
+    A2DP_CTRL_CMD_CHECK_READY,
+    A2DP_CTRL_CMD_START,
+    A2DP_CTRL_CMD_STOP,
+    A2DP_CTRL_CMD_SUSPEND
+} tA2DP_CTRL_CMD;
+
+typedef enum {
+    A2DP_CTRL_ACK_SUCCESS,
+    A2DP_CTRL_ACK_FAILURE
+} tA2DP_CTRL_ACK;
+
+
+/*****************************************************************************
+**  Type definitions for callback functions
+******************************************************************************/
+
+/*****************************************************************************
+**  Type definitions and return values
+******************************************************************************/
+
+/*****************************************************************************
+**  Extern variables and functions
+******************************************************************************/
+
+/*****************************************************************************
+**  Functions
+******************************************************************************/
+
+
+/*****************************************************************************
+**
+** Function
+**
+** Description
+**
+** Returns
+**
+******************************************************************************/
+
+#endif /* A2DP_AUDIO_HW_H */
+
diff --git a/bta/Android.mk b/bta/Android.mk
new file mode 100644
index 0000000..7d1c19e
--- /dev/null
+++ b/bta/Android.mk
@@ -0,0 +1,104 @@
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true)
+LOCAL_CFLAGS += \
+	-DBOARD_HAVE_BLUETOOTH_BCM
+endif
+LOCAL_CFLAGS += -DBUILDCFG $(bdroid_CFLAGS)
+
+LOCAL_PRELINK_MODULE:=false
+LOCAL_SRC_FILES:= \
+    ./dm/bta_dm_ci.c \
+    ./dm/bta_dm_act.c \
+    ./dm/bta_dm_pm.c \
+    ./dm/bta_dm_main.c \
+    ./dm/bta_dm_cfg.c \
+    ./dm/bta_dm_api.c \
+    ./dm/bta_dm_sco.c \
+    ./gatt/bta_gattc_api.c \
+    ./gatt/bta_gatts_act.c \
+    ./gatt/bta_gatts_main.c \
+    ./gatt/bta_gattc_utils.c \
+    ./gatt/bta_gattc_ci.c \
+    ./gatt/bta_gatts_api.c \
+    ./gatt/bta_gattc_main.c \
+    ./gatt/bta_gattc_act.c \
+    ./gatt/bta_gattc_cache.c \
+    ./gatt/bta_gatts_utils.c \
+    ./ag/bta_ag_sdp.c \
+    ./ag/bta_ag_sco.c \
+    ./ag/bta_ag_cfg.c \
+    ./ag/bta_ag_main.c \
+    ./ag/bta_ag_api.c \
+    ./ag/bta_ag_rfc.c \
+    ./ag/bta_ag_act.c \
+    ./ag/bta_ag_cmd.c \
+    ./ag/bta_ag_ci.c \
+    ./ag/bta_ag_at.c \
+    ./hh/bta_hh_cfg.c \
+    ./hh/bta_hh_act.c \
+    ./hh/bta_hh_api.c \
+    ./hh/bta_hh_utils.c \
+    ./hh/bta_hh_main.c \
+    ./pb/bta_pbs_cfg.c \
+    ./fs/bta_fs_ci.c \
+    ./fs/bta_fs_cfg.c \
+    ./pan/bta_pan_main.c \
+    ./pan/bta_pan_ci.c \
+    ./pan/bta_pan_act.c \
+    ./pan/bta_pan_api.c \
+    ./av/bta_av_act.c \
+    ./av/bta_av_ci.c \
+    ./av/bta_av_api.c \
+    ./av/bta_av_aact.c \
+    ./av/bta_av_main.c \
+    ./av/bta_av_cfg.c \
+    ./av/bta_av_ssm.c \
+    ./av/bta_av_sbc.c \
+    ./ar/bta_ar.c \
+    ./hl/bta_hl_act.c \
+    ./hl/bta_hl_api.c \
+    ./hl/bta_hl_main.c \
+    ./hl/bta_hl_utils.c \
+    ./hl/bta_hl_sdp.c \
+    ./hl/bta_hl_ci.c \
+    ./sys/bta_sys_main.c \
+    ./sys/bta_sys_ci.c \
+    ./sys/bta_sys_conn.c \
+    ./sys/bta_sys_cfg.c \
+    ./sys/ptim.c \
+    ./sys/bd.c \
+    ./sys/utl.c \
+    ./jv/bta_jv_act.c \
+    ./jv/bta_jv_cfg.c \
+    ./jv/bta_jv_main.c \
+    ./jv/bta_jv_api.c
+
+LOCAL_MODULE := libbt-brcm_bta
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libcutils libc
+
+LOCAL_C_INCLUDES+= . \
+                   $(LOCAL_PATH)/include \
+                   $(LOCAL_PATH)/sys \
+                   $(LOCAL_PATH)/dm \
+                   $(LOCAL_PATH)/../gki/common \
+                   $(LOCAL_PATH)/../gki/ulinux \
+                   $(LOCAL_PATH)/../include \
+                   $(LOCAL_PATH)/../stack/include \
+                   $(LOCAL_PATH)/../stack/btm \
+                   $(LOCAL_PATH)/../hcis \
+                   $(LOCAL_PATH)/../hcis/patchram \
+                   $(LOCAL_PATH)/../udrv/include \
+                   $(LOCAL_PATH)/../brcm/include \
+                   $(bdroid_C_INCLUDES) \
+
+
+include $(BUILD_STATIC_LIBRARY)
+
+endif  # TARGET_SIMULATOR != true
diff --git a/bta/ag/bta_ag_act.c b/bta/ag/bta_ag_act.c
new file mode 100644
index 0000000..5f72444
--- /dev/null
+++ b/bta/ag/bta_ag_act.c
@@ -0,0 +1,867 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains action functions for the audio gateway.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "port_api.h"
+#include "utl.h"
+#include <string.h>
+#include "bta_dm_int.h"
+#include "l2c_api.h"
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* maximum length of data to read from RFCOMM */
+#define BTA_AG_RFC_READ_MAX     512
+
+/* maximum AT command length */
+#define BTA_AG_CMD_MAX          512
+
+const UINT16 bta_ag_uuid[BTA_AG_NUM_IDX] =
+{
+    UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+    UUID_SERVCLASS_AG_HANDSFREE
+};
+
+const UINT8 bta_ag_sec_id[BTA_AG_NUM_IDX] =
+{
+    BTM_SEC_SERVICE_HEADSET_AG,
+    BTM_SEC_SERVICE_AG_HANDSFREE
+};
+
+const tBTA_SERVICE_ID bta_ag_svc_id[BTA_AG_NUM_IDX] =
+{
+    BTA_HSP_SERVICE_ID,
+    BTA_HFP_SERVICE_ID
+};
+
+const tBTA_SERVICE_MASK bta_ag_svc_mask[BTA_AG_NUM_IDX] =
+{
+    BTA_HSP_SERVICE_MASK,
+    BTA_HFP_SERVICE_MASK
+};
+
+typedef void (*tBTA_AG_ATCMD_CBACK)(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+                                    char *p_arg, INT16 int_arg);
+
+const tBTA_AG_ATCMD_CBACK bta_ag_at_cback_tbl[BTA_AG_NUM_IDX] =
+{
+    bta_ag_at_hsp_cback,
+    bta_ag_at_hfp_cback
+};
+
+/*******************************************************************************
+**
+** Function         bta_ag_cback_open
+**
+** Description      Send open callback event to application.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_cback_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data, tBTA_AG_STATUS status)
+{
+    tBTA_AG_OPEN    open;
+
+    /* call app callback with open event */
+    open.hdr.handle = bta_ag_scb_to_idx(p_scb);
+    open.hdr.app_id = p_scb->app_id;
+    open.status = status;
+    open.service_id = bta_ag_svc_id[p_scb->conn_service];
+    if(p_data)
+    {
+        /* if p_data is provided then we need to pick the bd address from the open api structure */
+        bdcpy(open.bd_addr, p_data->api_open.bd_addr);
+    }
+    else
+    {
+        bdcpy(open.bd_addr, p_scb->peer_addr);
+    }
+
+    (*bta_ag_cb.p_cback)(BTA_AG_OPEN_EVT, (tBTA_AG *) &open);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_register
+**
+** Description      This function initializes values of the AG cb and sets up
+**                  the SDP record for the services.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_register(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_REGISTER reg;
+
+    /* initialize control block */
+    p_scb->reg_services = p_data->api_register.services;
+    p_scb->serv_sec_mask = p_data->api_register.sec_mask;
+    p_scb->features = p_data->api_register.features;
+    p_scb->app_id = p_data->api_register.app_id;
+
+    /* create SDP records */
+    bta_ag_create_records(p_scb, p_data);
+
+    /* start RFCOMM servers */
+    bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+    /* call app callback with register event */
+    reg.hdr.handle = bta_ag_scb_to_idx(p_scb);
+    reg.hdr.app_id = p_scb->app_id;
+    reg.status = BTA_AG_SUCCESS;
+    (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG *) &reg);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_deregister
+**
+** Description      This function removes the sdp records, closes the RFCOMM
+**                  servers, and deallocates the service control block.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_deregister(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* set dealloc */
+    p_scb->dealloc = TRUE;
+
+    /* remove sdp records */
+    bta_ag_del_records(p_scb, p_data);
+
+    /* remove rfcomm servers */
+    bta_ag_close_servers(p_scb, p_scb->reg_services);
+
+    /* dealloc */
+    bta_ag_scb_dealloc(p_scb);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_start_dereg
+**
+** Description      Start a deregister event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_start_dereg(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* set dealloc */
+    p_scb->dealloc = TRUE;
+
+    /* remove sdp records */
+    bta_ag_del_records(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_start_open
+**
+** Description      This starts an AG open.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_start_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    BD_ADDR pending_bd_addr;
+
+    /* store parameters */
+    if (p_data)
+    {
+        bdcpy(p_scb->peer_addr, p_data->api_open.bd_addr);
+        p_scb->open_services = p_data->api_open.services;
+        p_scb->cli_sec_mask = p_data->api_open.sec_mask;
+    }
+
+    /* Check if RFCOMM has any incoming connection to avoid collision. */
+    if (PORT_IsOpening (pending_bd_addr))
+    {
+        /* Let the incoming connection goes through.                        */
+        /* Issue collision for this scb for now.                            */
+        /* We will decide what to do when we find incoming connetion later. */
+        bta_ag_collision_cback (0, BTA_ID_AG, 0, p_scb->peer_addr);
+        return;
+    }
+
+    /* close servers */
+    bta_ag_close_servers(p_scb, p_scb->reg_services);
+
+    /* set role */
+    p_scb->role = BTA_AG_INT;
+
+    /* do service search */
+    bta_ag_do_disc(p_scb, p_scb->open_services);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_disc_int_res
+**
+** Description      This function handles a discovery result when initiator.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_disc_int_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16 event = BTA_AG_DISC_FAIL_EVT;
+
+    APPL_TRACE_DEBUG1 ("bta_ag_disc_int_res: Status: %d", p_data->disc_result.status);
+
+    /* if found service */
+    if (p_data->disc_result.status == SDP_SUCCESS ||
+        p_data->disc_result.status == SDP_DB_FULL)
+    {
+        /* get attributes */
+        if (bta_ag_sdp_find_attr(p_scb, p_scb->open_services))
+        {
+            /* set connected service */
+            p_scb->conn_service = bta_ag_service_to_idx(p_scb->open_services);
+
+            /* send ourselves sdp ok event */
+            event = BTA_AG_DISC_OK_EVT;
+        }
+    }
+
+    /* free discovery db */
+    bta_ag_free_db(p_scb, p_data);
+
+    /* if service not found check if we should search for other service */
+    if ((event == BTA_AG_DISC_FAIL_EVT) &&
+        (p_data->disc_result.status == SDP_SUCCESS ||
+         p_data->disc_result.status == SDP_DB_FULL ||
+         p_data->disc_result.status == SDP_NO_RECS_MATCH))
+    {
+        if ((p_scb->open_services & BTA_HFP_SERVICE_MASK) &&
+            (p_scb->open_services & BTA_HSP_SERVICE_MASK))
+        {
+            /* search for HSP */
+            p_scb->open_services &= ~BTA_HFP_SERVICE_MASK;
+            bta_ag_do_disc(p_scb, p_scb->open_services);
+        }
+        else if ((p_scb->open_services & BTA_HSP_SERVICE_MASK) &&
+                 (p_scb->hsp_version == HSP_VERSION_1_2))
+        {
+            /* search for UUID_SERVCLASS_HEADSET for HSP 1.0 device */
+            p_scb->hsp_version = HSP_VERSION_1_0;
+            bta_ag_do_disc(p_scb, p_scb->open_services);
+        }
+        else
+        {
+            /* send ourselves sdp ok/fail event */
+            bta_ag_sm_execute(p_scb, event, p_data);
+        }
+    }
+    else
+    {
+        /* send ourselves sdp ok/fail event */
+        bta_ag_sm_execute(p_scb, event, p_data);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_disc_acp_res
+**
+** Description      This function handles a discovery result when acceptor.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_disc_acp_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* if found service */
+    if (p_data->disc_result.status == SDP_SUCCESS ||
+        p_data->disc_result.status == SDP_DB_FULL)
+    {
+        /* get attributes */
+        bta_ag_sdp_find_attr(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+    }
+
+    /* free discovery db */
+    bta_ag_free_db(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_disc_fail
+**
+** Description      This function handles a discovery failure.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_disc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* reopen registered servers */
+    bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+    /* reinitialize stuff */
+
+    /* call open cback w. failure */
+    bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_SDP);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_open_fail
+**
+** Description      open connection failed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_open_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* call open cback w. failure */
+    bta_ag_cback_open(p_scb, p_data, BTA_AG_FAIL_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_fail
+**
+** Description      RFCOMM connection failed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* reinitialize stuff */
+    p_scb->conn_handle = 0;
+    p_scb->conn_service = 0;
+    p_scb->peer_features = 0;
+#if (BTM_WBS_INCLUDED == TRUE )
+    p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+    p_scb->sco_codec = BTA_AG_CODEC_NONE;
+#endif
+    p_scb->role = 0;
+    p_scb->svc_conn = FALSE;
+    p_scb->hsp_version = HSP_VERSION_1_2;
+
+    /* reopen registered servers */
+    bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+    /* call open cback w. failure */
+    bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_RFCOMM);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_close
+**
+** Description      RFCOMM connection closed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_HDR    close;
+    tBTA_SERVICE_MASK services;
+    int i, num_active_conn = 0;
+
+#ifdef  _WIN32_WCE
+    /* The BTE RFCOMM automatically removes the connection when closed, but BTW does not */
+    if (p_scb->conn_handle != 0)
+        RFCOMM_RemoveConnection (p_scb->conn_handle);
+#endif
+
+    /* reinitialize stuff */
+    p_scb->conn_service = 0;
+    p_scb->peer_features = 0;
+#if (BTM_WBS_INCLUDED == TRUE )
+    p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+    p_scb->sco_codec = BTA_AG_CODEC_NONE;
+#endif
+    p_scb->role = 0;
+    p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+    p_scb->svc_conn = FALSE;
+    p_scb->hsp_version = HSP_VERSION_1_2;
+    bta_ag_at_reinit(&p_scb->at_cb);
+
+    /* stop timers */
+    bta_sys_stop_timer(&p_scb->act_timer);
+#if (BTM_WBS_INCLUDED == TRUE)
+    bta_sys_stop_timer(&p_scb->cn_timer);
+#endif
+
+    close.handle = bta_ag_scb_to_idx(p_scb);
+    close.app_id = p_scb->app_id;
+
+    bta_sys_conn_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+    /* call close call-out */
+    bta_ag_co_data_close(close.handle);
+
+    /* call close cback */
+    (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG *) &close);
+
+    /* if not deregistering (deallocating) reopen registered servers */
+    if (p_scb->dealloc == FALSE)
+    {
+        /* Clear peer bd_addr so instance can be reused */
+        bdcpy(p_scb->peer_addr, bd_addr_null);
+
+        /* start only unopened server */
+        services = p_scb->reg_services;
+        for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++)
+        {
+            if(p_scb->serv_handle[i])
+                services &= ~((tBTA_SERVICE_MASK)1 << (BTA_HSP_SERVICE_ID + i));
+        }
+        bta_ag_start_servers(p_scb, services);
+
+        p_scb->conn_handle = 0;
+
+        /* Make sure SCO state is BTA_AG_SCO_SHUTDOWN_ST */
+        bta_ag_sco_shutdown(p_scb, NULL);
+
+        /* Check if all the SLCs are down */
+        for (i = 0; i < BTA_AG_NUM_SCB; i++)
+        {
+            if (bta_ag_cb.scb[i].in_use && bta_ag_cb.scb[i].svc_conn)
+                num_active_conn++;
+        }
+
+        if(!num_active_conn)
+        {
+            bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+        }
+
+    }
+    /* else close port and deallocate scb */
+    else
+    {
+        RFCOMM_RemoveServer(p_scb->conn_handle);
+        bta_ag_scb_dealloc(p_scb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_open
+**
+** Description      Handle RFCOMM channel open.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* initialize AT feature variables */
+    p_scb->clip_enabled = FALSE;
+    p_scb->ccwa_enabled = FALSE;
+    p_scb->cmer_enabled = FALSE;
+    p_scb->cmee_enabled = FALSE;
+    p_scb->inband_enabled = ((p_scb->features & BTA_AG_FEAT_INBAND) == BTA_AG_FEAT_INBAND);
+
+    /* set up AT command interpreter */
+    p_scb->at_cb.p_at_tbl = (tBTA_AG_AT_CMD *) bta_ag_at_tbl[p_scb->conn_service];
+    p_scb->at_cb.p_cmd_cback = (tBTA_AG_AT_CMD_CBACK *) bta_ag_at_cback_tbl[p_scb->conn_service];
+    p_scb->at_cb.p_err_cback = (tBTA_AG_AT_ERR_CBACK *) bta_ag_at_err_cback;
+    p_scb->at_cb.p_user = p_scb;
+    p_scb->at_cb.cmd_max_len = BTA_AG_CMD_MAX;
+    bta_ag_at_init(&p_scb->at_cb);
+
+    /* call app open call-out */
+    bta_ag_co_data_open(bta_ag_scb_to_idx(p_scb), bta_ag_svc_id[p_scb->conn_service]);
+
+    bta_sys_conn_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+    bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS);
+
+    if (p_scb->conn_service == BTA_AG_HFP)
+    {
+        /* if hfp start timer for service level conn */
+        bta_sys_start_timer(&p_scb->act_timer, BTA_AG_SVC_TOUT_EVT, p_bta_ag_cfg->conn_tout);
+    }
+    else
+    {
+        /* else service level conn is open */
+        bta_ag_svc_conn_open(p_scb, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_acp_open
+**
+** Description      Handle RFCOMM channel open when accepting connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_acp_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16          lcid;
+    int             i;
+    tBTA_AG_SCB     *ag_scb, *other_scb;
+    BD_ADDR         dev_addr;
+    int             status;
+
+    /* set role */
+    p_scb->role = BTA_AG_ACP;
+
+    APPL_TRACE_DEBUG2 ("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d",
+                       p_scb->serv_handle[0], p_scb->serv_handle[1]);
+
+    /* get bd addr of peer */
+    if (PORT_SUCCESS != (status=PORT_CheckConnection(p_data->rfc.port_handle, dev_addr, &lcid)))
+    {
+        APPL_TRACE_DEBUG1 ("bta_ag_rfc_acp_open error PORT_CheckConnection returned status %d", status);
+    }
+
+    /* Collision Handling */
+    for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++)
+    {
+        if ((ag_scb->in_use) && (ag_scb->colli_tmr_on))
+        {
+            /* stop collision timer */
+            ag_scb->colli_tmr_on = FALSE;
+            bta_sys_stop_timer (&ag_scb->colli_timer);
+
+            if (bdcmp (dev_addr, ag_scb->peer_addr) == 0)
+            {
+                /* If incoming and outgoing device are same, nothing more to do.            */
+                /* Outgoing conn will be aborted because we have successful incoming conn.  */
+            }
+            else
+            {
+                /* Resume outgoing connection. */
+                other_scb = bta_ag_get_other_idle_scb (p_scb);
+                if (other_scb)
+                {
+                    bdcpy(other_scb->peer_addr, ag_scb->peer_addr);
+                    other_scb->open_services = ag_scb->open_services;
+                    other_scb->cli_sec_mask = ag_scb->cli_sec_mask;
+
+                    bta_ag_resume_open (other_scb);
+                }
+            }
+
+            break;
+        }
+    }
+
+    bdcpy (p_scb->peer_addr, dev_addr);
+
+    /* determine connected service from port handle */
+    for (i = 0; i < BTA_AG_NUM_IDX; i++)
+    {
+        APPL_TRACE_DEBUG3 ("bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d",
+                           i, p_scb->serv_handle[i], p_data->rfc.port_handle);
+
+        if (p_scb->serv_handle[i] == p_data->rfc.port_handle)
+        {
+            p_scb->conn_service = i;
+            p_scb->conn_handle = p_data->rfc.port_handle;
+            break;
+        }
+    }
+
+    APPL_TRACE_DEBUG2 ("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d",
+                       p_scb->conn_service, p_scb->conn_handle);
+
+    /* close any unopened server */
+    bta_ag_close_servers(p_scb, (p_scb->reg_services & ~bta_ag_svc_mask[p_scb->conn_service]));
+
+    /* do service discovery to get features */
+    bta_ag_do_disc(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+
+    /* continue with common open processing */
+    bta_ag_rfc_open(p_scb, p_data);
+
+
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_data
+**
+** Description      Read and process data from RFCOMM.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16  len;
+    char    buf[BTA_AG_RFC_READ_MAX];
+
+    memset(buf, 0, BTA_AG_RFC_READ_MAX);
+
+    /* do the following */
+    for(;;)
+    {
+        /* read data from rfcomm; if bad status, we're done */
+        if (PORT_ReadData(p_scb->conn_handle, buf, BTA_AG_RFC_READ_MAX, &len) != PORT_SUCCESS)
+        {
+            break;
+        }
+
+        /* if no data, we're done */
+        if (len == 0)
+        {
+            break;
+        }
+
+        /* run AT command interpreter on data */
+        bta_ag_at_parse(&p_scb->at_cb, buf, len);
+
+        /* no more data to read, we're done */
+        if (len < BTA_AG_RFC_READ_MAX)
+        {
+            break;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_start_close
+**
+** Description      Start the process of closing SCO and RFCOMM connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_start_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* Take the link out of sniff and set L2C idle time to 0 */
+    bta_dm_pm_active(p_scb->peer_addr);
+    L2CA_SetIdleTimeoutByBdAddr(p_scb->peer_addr, 0);
+
+    /* if SCO is open close SCO and wait on RFCOMM close */
+    if (bta_ag_sco_is_open(p_scb))
+    {
+        p_scb->post_sco = BTA_AG_POST_SCO_CLOSE_RFC;
+    }
+    else
+    {
+        p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+        bta_ag_rfc_do_close(p_scb, p_data);
+    }
+
+    /* always do SCO shutdown to handle all SCO corner cases */
+    bta_ag_sco_shutdown(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_post_sco_open
+**
+** Description      Perform post-SCO open action, if any
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_post_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    switch (p_scb->post_sco)
+    {
+        case BTA_AG_POST_SCO_RING:
+            bta_ag_send_ring(p_scb, p_data);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        case BTA_AG_POST_SCO_CALL_CONN:
+            bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        default:
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_post_sco_close
+**
+** Description      Perform post-SCO close action, if any
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_post_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    switch (p_scb->post_sco)
+    {
+        case BTA_AG_POST_SCO_CLOSE_RFC:
+            bta_ag_rfc_do_close(p_scb, p_data);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        case BTA_AG_POST_SCO_CALL_CONN:
+            bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        case BTA_AG_POST_SCO_CALL_ORIG:
+            bta_ag_send_call_inds(p_scb, BTA_AG_OUT_CALL_ORIG_RES);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        case BTA_AG_POST_SCO_CALL_END:
+            bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+            p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+            break;
+
+        case BTA_AG_POST_SCO_CALL_END_INCALL:
+            bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+
+            /* Sending callsetup IND and Ring were defered to after SCO close. */
+            bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_RES);
+
+            if (bta_ag_inband_enabled(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_RING;
+                bta_ag_sco_open(p_scb, p_data);
+            }
+            else
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+                bta_ag_send_ring(p_scb, p_data);
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_svc_conn_open
+**
+** Description      Service level connection opened
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_CONN evt;
+
+    if (!p_scb->svc_conn)
+    {
+        /* set state variable */
+        p_scb->svc_conn = TRUE;
+
+        /* Clear AT+BIA mask from previous SLC if any. */
+        p_scb->bia_masked_out = 0;
+
+        /* stop timer */
+        bta_sys_stop_timer(&p_scb->act_timer);
+
+        /* call callback */
+        evt.hdr.handle = bta_ag_scb_to_idx(p_scb);
+        evt.hdr.app_id = p_scb->app_id;
+        evt.peer_feat = p_scb->peer_features;
+#if (BTM_WBS_INCLUDED == TRUE )
+        evt.peer_codec  = p_scb->peer_codecs;
+#endif
+
+        if ((p_scb->call_ind != BTA_AG_CALL_INACTIVE) ||
+            (p_scb->callsetup_ind != BTA_AG_CALLSETUP_NONE))
+        {
+            bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+        }
+
+        (*bta_ag_cb.p_cback)(BTA_AG_CONN_EVT, (tBTA_AG *) &evt);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_ci_rx_data
+**
+** Description      Send result code
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16 len;
+    tBTA_AG_CI_RX_WRITE *p_rx_write_msg = (tBTA_AG_CI_RX_WRITE *)p_data;
+    char *p_data_area = (char *)(p_rx_write_msg+1);     /* Point to data area after header */
+
+    /* send to RFCOMM */
+    PORT_WriteData(p_scb->conn_handle, p_data_area, strlen(p_data_area), &len);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rcvd_slc_ready
+**
+** Description      Handles SLC ready call-in in case of pass-through mode.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    APPL_TRACE_DEBUG1("bta_ag_rcvd_slc_ready: handle = %d", bta_ag_scb_to_idx(p_scb));
+
+    if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH)
+    {
+        /* In pass-through mode, BTA knows that SLC is ready only through call-in. */
+        bta_ag_svc_conn_open(p_scb, NULL);
+    }
+}
+
diff --git a/bta/ag/bta_ag_api.c b/bta/ag/bta_ag_api.c
new file mode 100644
index 0000000..07dceb9
--- /dev/null
+++ b/bta/ag/bta_ag_api.c
@@ -0,0 +1,323 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the implementation of the API for the audio gateway (AG)
+ *  subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ *  phones.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "gki.h"
+#include <string.h>
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_ag_reg =
+{
+    bta_ag_hdl_event,
+    BTA_AgDisable
+};
+
+/*******************************************************************************
+**
+** Function         BTA_AgEnable
+**
+** Description      Enable the audio gateway service. When the enable
+**                  operation is complete the callback function will be
+**                  called with a BTA_AG_ENABLE_EVT. This function must
+**                  be called before other function in the AG API are
+**                  called.
+**
+** Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+**
+*******************************************************************************/
+tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK *p_cback)
+{
+    tBTA_AG_API_ENABLE  *p_buf;
+    UINT8       idx;
+
+    /* Error if AG is already enabled, or AG is in the middle of disabling. */
+    for (idx = 0; idx < BTA_AG_NUM_SCB; idx++)
+    {
+        if (bta_ag_cb.scb[idx].in_use)
+        {
+            APPL_TRACE_ERROR0 ("BTA_AgEnable: FAILED, AG already enabled.");
+            return BTA_FAILURE;
+        }
+    }
+
+    /* register with BTA system manager */
+    GKI_sched_lock();
+    bta_sys_register(BTA_ID_AG, &bta_ag_reg);
+    GKI_sched_unlock();
+
+    if ((p_buf = (tBTA_AG_API_ENABLE *) GKI_getbuf(sizeof(tBTA_AG_API_ENABLE))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_API_ENABLE_EVT;
+        p_buf->parse_mode = parse_mode;
+        p_buf->p_cback = p_cback;
+        bta_sys_sendmsg(p_buf);
+    }
+
+    return BTA_SUCCESS;
+
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgDisable
+**
+** Description      Disable the audio gateway service
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgDisable(void)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AG_API_DISABLE_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgRegister
+**
+** Description      Register an Audio Gateway service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,tBTA_AG_FEAT features,
+                  char * p_service_names[], UINT8 app_id)
+{
+    tBTA_AG_API_REGISTER    *p_buf;
+    int                     i;
+
+    if ((p_buf = (tBTA_AG_API_REGISTER *) GKI_getbuf(sizeof(tBTA_AG_API_REGISTER))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_API_REGISTER_EVT;
+        p_buf->features = features;
+        p_buf->sec_mask = sec_mask;
+        p_buf->services = services;
+        p_buf->app_id = app_id;
+        for (i = 0; i < BTA_AG_NUM_IDX; i++)
+        {
+            if(p_service_names[i])
+            {
+                BCM_STRNCPY_S(p_buf->p_name[i], BTA_SERVICE_NAME_LEN+1, p_service_names[i], BTA_SERVICE_NAME_LEN);
+                p_buf->p_name[i][BTA_SERVICE_NAME_LEN] = 0;
+            }
+            else
+            {
+                p_buf->p_name[i][0] = 0;
+            }
+        }
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgDeregister
+**
+** Description      Deregister an audio gateway service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgDeregister(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AG_API_DEREGISTER_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgOpen
+**
+** Description      Opens a connection to a headset or hands-free device.
+**                  When connection is open callback function is called
+**                  with a BTA_AG_OPEN_EVT. Only the data connection is
+**                  opened. The audio connection is not opened.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask, tBTA_SERVICE_MASK services)
+{
+    tBTA_AG_API_OPEN  *p_buf;
+
+    if ((p_buf = (tBTA_AG_API_OPEN *) GKI_getbuf(sizeof(tBTA_AG_API_OPEN))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_API_OPEN_EVT;
+        p_buf->hdr.layer_specific = handle;
+        bdcpy(p_buf->bd_addr, bd_addr);
+        p_buf->services = services;
+        p_buf->sec_mask = sec_mask;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgClose
+**
+** Description      Close the current connection to a headset or a handsfree
+**                  Any current audio connection will also be closed.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgClose(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AG_API_CLOSE_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgAudioOpen
+**
+** Description      Opens an audio connection to the currently connected
+**                  headset or hnadsfree.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgAudioOpen(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AG_API_AUDIO_OPEN_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgAudioClose
+**
+** Description      Close the currently active audio connection to a headset
+**                  or hnadsfree. The data connection remains open
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgAudioClose(UINT16 handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AG_API_AUDIO_CLOSE_EVT;
+        p_buf->layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         BTA_AgResult
+**
+** Description      Send an AT result code to a headset or hands-free device.
+**                  This function is only used when the AG parse mode is set
+**                  to BTA_AG_PARSE.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgResult(UINT16 handle, tBTA_AG_RES result, tBTA_AG_RES_DATA *p_data)
+{
+    tBTA_AG_API_RESULT  *p_buf;
+
+    if ((p_buf = (tBTA_AG_API_RESULT *) GKI_getbuf(sizeof(tBTA_AG_API_RESULT))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_API_RESULT_EVT;
+        p_buf->hdr.layer_specific = handle;
+        p_buf->result = result;
+        if(p_data)
+        {
+            memcpy(&p_buf->data, p_data, sizeof(p_buf->data));
+        }
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AgSetCodec
+**
+** Description      Specify the codec type to be used for the subsequent
+**                  audio connection.
+**
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AgSetCodec(UINT16 handle, tBTA_AG_PEER_CODEC codec)
+{
+    tBTA_AG_API_SETCODEC    *p_buf;
+
+    if ((p_buf = (tBTA_AG_API_SETCODEC *) GKI_getbuf(sizeof(tBTA_AG_API_SETCODEC))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_API_SETCODEC_EVT;
+        p_buf->hdr.layer_specific = handle;
+        p_buf->codec = codec;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
diff --git a/bta/ag/bta_ag_at.c b/bta/ag/bta_ag_at.c
new file mode 100644
index 0000000..74d3948
--- /dev/null
+++ b/bta/ag/bta_ag_at.c
@@ -0,0 +1,243 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  BTA AG AT command interpreter.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "gki.h"
+#include "bta_ag_at.h"
+#include "utl.h"
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/******************************************************************************
+**
+** Function         bta_ag_at_init
+**
+** Description      Initialize the AT command parser control block.
+**
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ag_at_init(tBTA_AG_AT_CB *p_cb)
+{
+    p_cb->p_cmd_buf = NULL;
+    p_cb->cmd_pos = 0;
+}
+
+/******************************************************************************
+**
+** Function         bta_ag_at_reinit
+**
+** Description      Re-initialize the AT command parser control block.  This
+**                  function resets the AT command parser state and frees
+**                  any GKI buffer.
+**
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb)
+{
+    if (p_cb->p_cmd_buf != NULL)
+    {
+        GKI_freebuf(p_cb->p_cmd_buf);
+        p_cb->p_cmd_buf = NULL;
+    }
+    p_cb->cmd_pos = 0;
+}
+/******************************************************************************
+**
+** Function         bta_ag_process_at
+**
+** Description      Parse AT commands.  This function will take the input
+**                  character string and parse it for AT commands according to
+**                  the AT command table passed in the control block.
+**
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ag_process_at(tBTA_AG_AT_CB *p_cb)
+{
+    UINT16      idx;
+    UINT8       arg_type;
+    char        *p_arg;
+    INT16       int_arg = 0;
+    /* loop through at command table looking for match */
+    for (idx = 0; p_cb->p_at_tbl[idx].p_cmd[0] != 0; idx++)
+    {
+        if (!utl_strucmp(p_cb->p_at_tbl[idx].p_cmd, p_cb->p_cmd_buf))
+        {
+            break;
+        }
+    }
+
+    /* if there is a match; verify argument type */
+    if (p_cb->p_at_tbl[idx].p_cmd[0] != 0)
+    {
+        /* start of argument is p + strlen matching command */
+        p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd);
+
+        /* if no argument */
+        if (p_arg[0] == 0)
+        {
+            arg_type = BTA_AG_AT_NONE;
+        }
+        /* else if arg is '?' and it is last character */
+        else if (p_arg[0] == '?' && p_arg[1] == 0)
+        {
+            /* we have a read */
+            arg_type = BTA_AG_AT_READ;
+        }
+        /* else if arg is '=' */
+        else if (p_arg[0] == '=' && p_arg[1] != 0)
+        {
+            if (p_arg[1] == '?' && p_arg[2] == 0)
+            {
+                /* we have a test */
+                arg_type = BTA_AG_AT_TEST;
+            }
+            else
+            {
+                /* we have a set */
+                arg_type = BTA_AG_AT_SET;
+
+                /* skip past '=' */
+                p_arg++;
+            }
+        }
+        else
+        /* else it is freeform argument */
+        {
+            arg_type = BTA_AG_AT_FREE;
+        }
+
+        /* if arguments match command capabilities */
+        if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0)
+        {
+            /* if it's a set integer check max, min range */
+            if (arg_type == BTA_AG_AT_SET &&
+                p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT)
+            {
+                int_arg = utl_str2int(p_arg);
+                if (int_arg < (INT16) p_cb->p_at_tbl[idx].min ||
+                    int_arg > (INT16) p_cb->p_at_tbl[idx].max)
+                {
+                    /* arg out of range; error */
+                    (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
+                }
+                else
+                {
+
+                    (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
+                }
+            }
+            else
+            {
+                (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
+            }
+        }
+        /* else error */
+        else
+        {
+            (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
+        }
+    }
+    /* else no match call error callback */
+    else
+    {
+        (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
+    }
+}
+
+/******************************************************************************
+**
+** Function         bta_ag_at_parse
+**
+** Description      Parse AT commands.  This function will take the input
+**                  character string and parse it for AT commands according to
+**                  the AT command table passed in the control block.
+**
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len)
+{
+    int i = 0;
+    char* p_save;
+
+    if (p_cb->p_cmd_buf == NULL)
+    {
+        p_cb->p_cmd_buf = (char *) GKI_getbuf(p_cb->cmd_max_len);
+        p_cb->cmd_pos = 0;
+    }
+
+    for (i = 0; i < len;)
+    {
+        while (p_cb->cmd_pos < p_cb->cmd_max_len-1 && i < len)
+        {
+            /* Skip null characters between AT commands. */
+            if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0))
+            {
+                i++;
+                continue;
+            }
+
+            p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
+            if ( p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' || p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n')
+            {
+                p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
+                if ((p_cb->cmd_pos > 2)                                      &&
+                    (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
+                    (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't'))
+                {
+                    p_save = p_cb->p_cmd_buf;
+                    p_cb->p_cmd_buf += 2;
+                    bta_ag_process_at(p_cb);
+                    p_cb->p_cmd_buf = p_save;
+                }
+
+                p_cb->cmd_pos = 0;
+
+            }
+            else if( p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A || p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B )
+            {
+                p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
+                (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
+                p_cb->cmd_pos = 0;
+            }
+            else
+            {
+                ++p_cb->cmd_pos;
+            }
+        }
+
+        if (i < len)
+            p_cb->cmd_pos = 0;
+    }
+}
+
diff --git a/bta/ag/bta_ag_at.h b/bta/ag/bta_ag_at.h
new file mode 100644
index 0000000..90d7b0f
--- /dev/null
+++ b/bta/ag/bta_ag_at.h
@@ -0,0 +1,121 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Interface file for BTA AG AT command interpreter.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_AT_H
+#define BTA_AG_AT_H
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* AT command argument capabilities */
+#define BTA_AG_AT_NONE          0x01        /* no argument */
+#define BTA_AG_AT_SET           0x02        /* set value */
+#define BTA_AG_AT_READ          0x04        /* read value */
+#define BTA_AG_AT_TEST          0x08        /* test value range */
+#define BTA_AG_AT_FREE          0x10        /* freeform argument */
+
+/* AT command argument format */
+#define BTA_AG_AT_STR           0           /* string */
+#define BTA_AG_AT_INT           1           /* integer */
+
+/*****************************************************************************
+**  Data types
+*****************************************************************************/
+
+/* AT command table element */
+typedef struct
+{
+    const char  *p_cmd;         /* AT command string */
+    UINT8       arg_type;       /* allowable argument type syntax */
+    UINT8       fmt;            /* whether arg is int or string */
+    UINT8       min;            /* minimum value for int arg */
+    INT16       max;            /* maximum value for int arg */
+} tBTA_AG_AT_CMD;
+
+/* callback function executed when command is parsed */
+typedef void (tBTA_AG_AT_CMD_CBACK)(void *p_user, UINT16 cmd, UINT8 arg_type,
+                                    char *p_arg, INT16 int_arg);
+
+/* callback function executed to send "ERROR" result code */
+typedef void (tBTA_AG_AT_ERR_CBACK)(void *p_user, BOOLEAN unknown, char *p_arg);
+
+/* AT command parsing control block */
+typedef struct
+{
+    tBTA_AG_AT_CMD          *p_at_tbl;      /* AT command table */
+    tBTA_AG_AT_CMD_CBACK    *p_cmd_cback;   /* command callback */
+    tBTA_AG_AT_ERR_CBACK    *p_err_cback;   /* error callback */
+    void                    *p_user;        /* user-defined data */
+    char                    *p_cmd_buf;     /* temp parsing buffer */
+    UINT16                  cmd_pos;        /* position in temp buffer */
+    UINT16                  cmd_max_len;    /* length of temp buffer to allocate */
+    UINT8                   state;          /* parsing state */
+} tBTA_AG_AT_CB;
+
+/*****************************************************************************
+**  Function prototypes
+*****************************************************************************/
+
+/*****************************************************************************
+**
+** Function         bta_ag_at_init
+**
+** Description      Initialize the AT command parser control block.
+**
+**
+** Returns          void
+**
+*****************************************************************************/
+extern void bta_ag_at_init(tBTA_AG_AT_CB *p_cb);
+
+/*****************************************************************************
+**
+** Function         bta_ag_at_reinit
+**
+** Description      Re-initialize the AT command parser control block.  This
+**                  function resets the AT command parser state and frees
+**                  any GKI buffer.
+**
+**
+** Returns          void
+**
+*****************************************************************************/
+extern void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb);
+
+/*****************************************************************************
+**
+** Function         bta_ag_at_parse
+**
+** Description      Parse AT commands.  This function will take the input
+**                  character string and parse it for AT commands according to
+**                  the AT command table passed in the control block.
+**
+**
+** Returns          void
+**
+*****************************************************************************/
+extern void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len);
+
+#endif /* BTA_AG_AT_H */
+
diff --git a/bta/ag/bta_ag_cfg.c b/bta/ag/bta_ag_cfg.c
new file mode 100644
index 0000000..e02f9f6
--- /dev/null
+++ b/bta/ag/bta_ag_cfg.c
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains compile-time configurable constants for the audio
+ *  gateway.
+ *
+ ******************************************************************************/
+
+#include "gki.h"
+#include "bta_api.h"
+#include "bta_ag_api.h"
+
+#ifndef BTA_AG_CIND_INFO
+#define BTA_AG_CIND_INFO     "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-3)),(\"signal\",(0-6)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2)),(\"bearer\",(0-7))"
+#endif
+
+#ifndef BTA_AG_CHLD_VAL_ECC
+#define BTA_AG_CHLD_VAL_ECC  "(0,1,1x,2,2x,3,4)"
+#endif
+
+#ifndef BTA_AG_CHLD_VAL
+#define BTA_AG_CHLD_VAL  "(0,1,2,3,4)"
+#endif
+
+#ifndef BTA_AG_CONN_TIMEOUT
+#define BTA_AG_CONN_TIMEOUT     5000
+#endif
+
+#ifndef BTA_AG_SCO_PKT_TYPES
+/* S1 packet type setting from HFP 1.5 spec */
+#define BTA_AG_SCO_PKT_TYPES    /* BTM_SCO_LINK_ALL_PKT_MASK */ (BTM_SCO_LINK_ONLY_MASK          | \
+                                                                 BTM_SCO_PKT_TYPES_MASK_EV3      | \
+                                                                 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
+                                                                 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
+                                                                 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+#endif
+
+const tBTA_AG_CFG bta_ag_cfg =
+{
+    BTA_AG_CIND_INFO,
+    BTA_AG_CONN_TIMEOUT,
+    BTA_AG_SCO_PKT_TYPES,
+    BTA_AG_CHLD_VAL_ECC,
+    BTA_AG_CHLD_VAL
+};
+
+tBTA_AG_CFG *p_bta_ag_cfg = (tBTA_AG_CFG *) &bta_ag_cfg;
diff --git a/bta/ag/bta_ag_ci.c b/bta/ag/bta_ag_ci.c
new file mode 100644
index 0000000..fd39e34
--- /dev/null
+++ b/bta/ag/bta_ag_ci.c
@@ -0,0 +1,98 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the implementation file for audio gateway call-in functions.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_ag_ci.h"
+#include "gki.h"
+
+/******************************************************************************
+**
+** Function         bta_ag_ci_rx_write
+**
+** Description      This function is called to send data to the AG when the AG
+**                  is configured for AT command pass-through.  The function
+**                  copies data to an event buffer and sends it.
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ag_ci_rx_write(UINT16 handle, char *p_data, UINT16 len)
+{
+    tBTA_AG_CI_RX_WRITE *p_buf;
+    UINT16 len_remaining = len;
+    char *p_data_area;
+
+    if (len > (RFCOMM_DATA_POOL_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1))
+        len = RFCOMM_DATA_POOL_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1;
+
+    while (len_remaining)
+    {
+        if (len_remaining < len)
+            len = len_remaining;
+
+        if ((p_buf = (tBTA_AG_CI_RX_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_AG_CI_RX_WRITE) + len + 1))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_CI_RX_WRITE_EVT;
+        p_buf->hdr.layer_specific = handle;
+
+        p_data_area = (char *)(p_buf+1);        /* Point to data area after header */
+        strncpy(p_data_area, p_data, len);
+        p_data_area[len] = 0;
+
+        bta_sys_sendmsg(p_buf);
+        } else {
+        APPL_TRACE_ERROR1("ERROR: Unable to allocate buffer to hold AT response code. len=%i", len);
+            break;
+        }
+
+        len_remaining-=len;
+        p_data+=len;
+    }
+}
+
+/******************************************************************************
+**
+** Function         bta_ag_ci_slc_ready
+**
+** Description      This function is called to notify AG that SLC is up at
+**                  the application. This funcion is only used when the app
+**                  is running in pass-through mode.
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ag_ci_slc_ready(UINT16 handle)
+{
+    tBTA_AG_DATA *p_buf;
+
+    if ((p_buf = (tBTA_AG_DATA *)GKI_getbuf(sizeof(tBTA_AG_DATA))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AG_CI_SLC_READY_EVT;
+        p_buf->hdr.layer_specific = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
diff --git a/bta/ag/bta_ag_cmd.c b/bta/ag/bta_ag_cmd.c
new file mode 100644
index 0000000..d552eed
--- /dev/null
+++ b/bta/ag/bta_ag_cmd.c
@@ -0,0 +1,1836 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains functions for processing AT commands and results.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_ag_at.h"
+#include "port_api.h"
+#include "utl.h"
+#include <stdio.h>
+#include <string.h>
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* ring timeout */
+#define BTA_AG_RING_TOUT        10000
+
+#define BTA_AG_CMD_MAX_VAL      32767  /* Maximum value is signed 16-bit value */
+
+
+
+/* clip type constants */
+#define BTA_AG_CLIP_TYPE_MIN        128
+#define BTA_AG_CLIP_TYPE_MAX        175
+#define BTA_AG_CLIP_TYPE_DEFAULT    129
+#define BTA_AG_CLIP_TYPE_VOIP       255
+
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+#define BTA_AG_AT_MULTI_LEN            2
+#define AT_SET_RES_CB(res_cb, c, p, i) {res_cb.code = c; res_cb.p_arg = p; res_cb.int_arg = i;}
+
+/* type for AT result code block */
+typedef struct
+{
+    UINT8 code;
+    char *p_arg;
+    INT16 int_arg;
+} tBTA_AG_RESULT_CB;
+
+/* type for multiple AT result codes block */
+typedef struct
+{
+    UINT8 num_result;
+    tBTA_AG_RESULT_CB res_cb[BTA_AG_AT_MULTI_LEN];
+} tBTA_AG_MULTI_RESULT_CB;
+#endif
+
+/* enumeration of HSP AT commands matches HSP command interpreter table */
+enum
+{
+    BTA_AG_HS_CMD_CKPD,
+    BTA_AG_HS_CMD_VGS,
+    BTA_AG_HS_CMD_VGM
+};
+
+/* enumeration of HFP AT commands matches HFP command interpreter table */
+enum
+{
+    BTA_AG_HF_CMD_A,
+    BTA_AG_HF_CMD_D,
+    BTA_AG_HF_CMD_VGS,
+    BTA_AG_HF_CMD_VGM,
+    BTA_AG_HF_CMD_CCWA,
+    BTA_AG_HF_CMD_CHLD,
+    BTA_AG_HF_CMD_CHUP,
+    BTA_AG_HF_CMD_CIND,
+    BTA_AG_HF_CMD_CLIP,
+    BTA_AG_HF_CMD_CMER,
+    BTA_AG_HF_CMD_VTS,
+    BTA_AG_HF_CMD_BINP,
+    BTA_AG_HF_CMD_BLDN,
+    BTA_AG_HF_CMD_BVRA,
+    BTA_AG_HF_CMD_BRSF,
+    BTA_AG_HF_CMD_NREC,
+    BTA_AG_HF_CMD_CNUM,
+    BTA_AG_HF_CMD_BTRH,
+    BTA_AG_HF_CMD_CLCC,
+    BTA_AG_HF_CMD_COPS,
+    BTA_AG_HF_CMD_CMEE,
+    BTA_AG_HF_CMD_BIA,
+    BTA_AG_HF_CMD_CBC,
+    BTA_AG_HF_CMD_BCC,
+    BTA_AG_HF_CMD_BCS,
+    BTA_AG_HF_CMD_BAC
+};
+
+/* AT command interpreter table for HSP */
+const tBTA_AG_AT_CMD bta_ag_hsp_cmd[] =
+{
+    {"+CKPD",   BTA_AG_AT_SET,                      BTA_AG_AT_INT, 200, 200},
+    {"+VGS",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,  15},
+    {"+VGM",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,  15},
+    {"",        BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0}
+};
+
+/* AT command interpreter table for HFP */
+const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] =
+{
+    {"A",       BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"D",       (BTA_AG_AT_NONE | BTA_AG_AT_FREE),  BTA_AG_AT_STR,   0,   0},
+    {"+VGS",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,  15},
+    {"+VGM",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,  15},
+    {"+CCWA",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   1},
+    /* Consider CHLD as str to take care of indexes for ECC */
+    {"+CHLD",   (BTA_AG_AT_SET | BTA_AG_AT_TEST),   BTA_AG_AT_STR,   0,   4},
+    {"+CHUP",   BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"+CIND",   (BTA_AG_AT_READ | BTA_AG_AT_TEST),  BTA_AG_AT_STR,   0,   0},
+    {"+CLIP",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   1},
+    {"+CMER",   BTA_AG_AT_SET,                      BTA_AG_AT_STR,   0,   0},
+    {"+VTS",    BTA_AG_AT_SET,                      BTA_AG_AT_STR,   0,   0},
+    {"+BINP",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   1,   1},
+    {"+BLDN",   BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"+BVRA",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   1},
+    {"+BRSF",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   BTA_AG_CMD_MAX_VAL},
+    {"+NREC",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   0},
+    {"+CNUM",   BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"+BTRH",   (BTA_AG_AT_READ | BTA_AG_AT_SET),   BTA_AG_AT_INT,   0,   2},
+    {"+CLCC",   BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"+COPS",   (BTA_AG_AT_READ | BTA_AG_AT_SET),   BTA_AG_AT_STR,   0,   0},
+    {"+CMEE",   BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   1},
+    {"+BIA",    BTA_AG_AT_SET,                      BTA_AG_AT_STR,   0,   20},
+    {"+CBC",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   100},
+    {"+BCC",    BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0},
+    {"+BCS",    BTA_AG_AT_SET,                      BTA_AG_AT_INT,   0,   BTA_AG_CMD_MAX_VAL},
+    {"+BAC",    BTA_AG_AT_SET,                      BTA_AG_AT_STR,   0,   0},
+    {"",        BTA_AG_AT_NONE,                     BTA_AG_AT_STR,   0,   0}
+};
+
+/* AT result code table element */
+typedef struct
+{
+    const char  *p_res;         /* AT result string */
+    UINT8       fmt;            /* whether argument is int or string */
+} tBTA_AG_RESULT;
+
+/* AT result code argument types */
+enum
+{
+    BTA_AG_RES_FMT_NONE,       /* no argument */
+    BTA_AG_RES_FMT_INT,        /* integer argument */
+    BTA_AG_RES_FMT_STR         /* string argument */
+};
+
+/* enumeration of AT result codes, matches constant table */
+enum
+{
+    BTA_AG_RES_OK,
+    BTA_AG_RES_ERROR,
+    BTA_AG_RES_RING,
+    BTA_AG_RES_VGS,
+    BTA_AG_RES_VGM,
+    BTA_AG_RES_CCWA,
+    BTA_AG_RES_CHLD,
+    BTA_AG_RES_CIND,
+    BTA_AG_RES_CLIP,
+    BTA_AG_RES_CIEV,
+    BTA_AG_RES_BINP,
+    BTA_AG_RES_BVRA,
+    BTA_AG_RES_BRSF,
+    BTA_AG_RES_BSIR,
+    BTA_AG_RES_CNUM,
+    BTA_AG_RES_BTRH,
+    BTA_AG_RES_CLCC,
+    BTA_AG_RES_COPS,
+    BTA_AG_RES_CMEE,
+    BTA_AG_RES_BCS,
+    BTA_AG_RES_UNAT
+};
+
+#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
+#define COLON_IDX_4_VGSVGM    4
+#endif
+/* AT result code constant table  (Indexed by result code) */
+const tBTA_AG_RESULT bta_ag_result_tbl[] =
+{
+    {"OK",      BTA_AG_RES_FMT_NONE},
+    {"ERROR",   BTA_AG_RES_FMT_NONE},
+    {"RING",    BTA_AG_RES_FMT_NONE},
+    {"+VGS: ",  BTA_AG_RES_FMT_INT},
+    {"+VGM: ",  BTA_AG_RES_FMT_INT},
+    {"+CCWA: ", BTA_AG_RES_FMT_STR},
+    {"+CHLD: ", BTA_AG_RES_FMT_STR},
+    {"+CIND: ", BTA_AG_RES_FMT_STR},
+    {"+CLIP: ", BTA_AG_RES_FMT_STR},
+    {"+CIEV: ", BTA_AG_RES_FMT_STR},
+    {"+BINP: ", BTA_AG_RES_FMT_STR},
+    {"+BVRA: ", BTA_AG_RES_FMT_INT},
+    {"+BRSF: ", BTA_AG_RES_FMT_INT},
+    {"+BSIR: ", BTA_AG_RES_FMT_INT},
+    {"+CNUM: ", BTA_AG_RES_FMT_STR},
+    {"+BTRH: ", BTA_AG_RES_FMT_INT},
+    {"+CLCC: ", BTA_AG_RES_FMT_STR},
+    {"+COPS: ", BTA_AG_RES_FMT_STR},
+    {"+CME ERROR: ", BTA_AG_RES_FMT_INT},
+    {"+BCS: ",  BTA_AG_RES_FMT_INT},
+    {"",        BTA_AG_RES_FMT_STR}
+};
+
+const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX] =
+{
+    bta_ag_hsp_cmd,
+    bta_ag_hfp_cmd
+};
+
+/* callback event lookup table for HSP */
+const tBTA_AG_EVT bta_ag_hsp_cb_evt[] =
+{
+    BTA_AG_AT_CKPD_EVT,     /* BTA_AG_HS_CMD_CKPD */
+    BTA_AG_SPK_EVT,         /* BTA_AG_HS_CMD_VGS */
+    BTA_AG_MIC_EVT          /* BTA_AG_HS_CMD_VGM */
+};
+
+/* callback event lookup table for HFP  (Indexed by command) */
+const tBTA_AG_EVT bta_ag_hfp_cb_evt[] =
+{
+    BTA_AG_AT_A_EVT,        /* BTA_AG_HF_CMD_A */
+    BTA_AG_AT_D_EVT,        /* BTA_AG_HF_CMD_D */
+    BTA_AG_SPK_EVT,         /* BTA_AG_HF_CMD_VGS */
+    BTA_AG_MIC_EVT,         /* BTA_AG_HF_CMD_VGM */
+    0,                      /* BTA_AG_HF_CMD_CCWA */
+    BTA_AG_AT_CHLD_EVT,     /* BTA_AG_HF_CMD_CHLD */
+    BTA_AG_AT_CHUP_EVT,     /* BTA_AG_HF_CMD_CHUP */
+    BTA_AG_AT_CIND_EVT,     /* BTA_AG_HF_CMD_CIND */
+    0,                      /* BTA_AG_HF_CMD_CLIP */
+    0,                      /* BTA_AG_HF_CMD_CMER */
+    BTA_AG_AT_VTS_EVT,      /* BTA_AG_HF_CMD_VTS */
+    BTA_AG_AT_BINP_EVT,     /* BTA_AG_HF_CMD_BINP */
+    BTA_AG_AT_BLDN_EVT,     /* BTA_AG_HF_CMD_BLDN */
+    BTA_AG_AT_BVRA_EVT,     /* BTA_AG_HF_CMD_BVRA */
+    0,                      /* BTA_AG_HF_CMD_BRSF */
+    BTA_AG_AT_NREC_EVT,     /* BTA_AG_HF_CMD_NREC */
+    BTA_AG_AT_CNUM_EVT,     /* BTA_AG_HF_CMD_CNUM */
+    BTA_AG_AT_BTRH_EVT,     /* BTA_AG_HF_CMD_BTRH */
+    BTA_AG_AT_CLCC_EVT,     /* BTA_AG_HF_CMD_CLCC */
+    BTA_AG_AT_COPS_EVT,     /* BTA_AG_HF_CMD_COPS */
+    0,                      /* BTA_AG_HF_CMD_CMEE */
+    0,                      /* BTA_AG_HF_CMD_BIA */
+    BTA_AG_AT_CBC_EVT,      /* BTA_AG_HF_CMD_CBC */
+    0,                      /* BTA_AG_HF_CMD_BCC */
+    BTA_AG_AT_BCS_EVT,      /* BTA_AG_HF_CMD_BCS */
+    BTA_AG_AT_BAC_EVT       /* BTA_AG_HF_CMD_BAC */
+};
+
+/* translation of API result code values to internal values */
+const UINT8 bta_ag_trans_result[] =
+{
+    BTA_AG_RES_VGS,     /* BTA_AG_SPK_RES */
+    BTA_AG_RES_VGM,     /* BTA_AG_MIC_RES */
+    BTA_AG_RES_BSIR,    /* BTA_AG_INBAND_RING_RES */
+    BTA_AG_RES_CIND,    /* BTA_AG_CIND_RES */
+    BTA_AG_RES_BINP,    /* BTA_AG_BINP_RES */
+    BTA_AG_RES_CIEV,    /* BTA_AG_IND_RES */
+    BTA_AG_RES_BVRA,    /* BTA_AG_BVRA_RES */
+    BTA_AG_RES_CNUM,    /* BTA_AG_CNUM_RES */
+    BTA_AG_RES_BTRH,    /* BTA_AG_BTRH_RES */
+    BTA_AG_RES_CLCC,    /* BTA_AG_CLCC_RES */
+    BTA_AG_RES_COPS,    /* BTA_AG_COPS_RES */
+    0,                  /* BTA_AG_IN_CALL_RES */
+    0,                  /* BTA_AG_IN_CALL_CONN_RES */
+    BTA_AG_RES_CCWA,    /* BTA_AG_CALL_WAIT_RES */
+    0,                  /* BTA_AG_OUT_CALL_ORIG_RES */
+    0,                  /* BTA_AG_OUT_CALL_ALERT_RES */
+    0,                  /* BTA_AG_OUT_CALL_CONN_RES */
+    0,                  /* BTA_AG_CALL_CANCEL_RES */
+    0,                  /* BTA_AG_END_CALL_RES */
+    0,                  /* BTA_AG_IN_CALL_HELD_RES */
+    BTA_AG_RES_UNAT     /* BTA_AG_UNAT_RES */
+};
+
+/* callsetup indicator value lookup table */
+const UINT8 bta_ag_callsetup_ind_tbl[] =
+{
+    0,                          /* BTA_AG_SPK_RES */
+    0,                          /* BTA_AG_MIC_RES */
+    0,                          /* BTA_AG_INBAND_RING_RES */
+    0,                          /* BTA_AG_CIND_RES */
+    0,                          /* BTA_AG_BINP_RES */
+    0,                          /* BTA_AG_IND_RES */
+    0,                          /* BTA_AG_BVRA_RES */
+    0,                          /* BTA_AG_CNUM_RES */
+    0,                          /* BTA_AG_BTRH_RES */
+    0,                          /* BTA_AG_CLCC_RES */
+    0,                          /* BTA_AG_COPS_RES */
+    BTA_AG_CALLSETUP_INCOMING,  /* BTA_AG_IN_CALL_RES */
+    BTA_AG_CALLSETUP_NONE,      /* BTA_AG_IN_CALL_CONN_RES */
+    BTA_AG_CALLSETUP_INCOMING,  /* BTA_AG_CALL_WAIT_RES */
+    BTA_AG_CALLSETUP_OUTGOING,  /* BTA_AG_OUT_CALL_ORIG_RES */
+    BTA_AG_CALLSETUP_ALERTING,  /* BTA_AG_OUT_CALL_ALERT_RES */
+    BTA_AG_CALLSETUP_NONE,      /* BTA_AG_OUT_CALL_CONN_RES */
+    BTA_AG_CALLSETUP_NONE,      /* BTA_AG_CALL_CANCEL_RES */
+    BTA_AG_CALLSETUP_NONE,      /* BTA_AG_END_CALL_RES */
+    BTA_AG_CALLSETUP_NONE       /* BTA_AG_IN_CALL_HELD_RES */
+};
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_result
+**
+** Description      Send an AT result code.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_send_result(tBTA_AG_SCB *p_scb, UINT8 code, char *p_arg,
+                               INT16 int_arg)
+{
+    char    buf[BTA_AG_AT_MAX_LEN + 16];
+    char    *p = buf;
+    UINT16  len;
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+    memset(buf, NULL, sizeof(buf));
+#endif
+    /* init with \r\n */
+    *p++ = '\r';
+    *p++ = '\n';
+
+    /* copy result code string */
+    BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[code].p_res);
+#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
+    if(p_scb->conn_service == BTA_AG_HSP)
+    {
+        /* If HSP then ":"symbol should be changed as "=" for HSP compatibility */
+        switch(code)
+        {
+        case BTA_AG_RES_VGS:
+        case BTA_AG_RES_VGM:
+            if(*(p+COLON_IDX_4_VGSVGM) == ':')
+            {
+                #if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+                APPL_TRACE_DEBUG0("[HSP] ':'symbol is changed as '=' for HSP compatibility");
+                #endif
+                *(p+COLON_IDX_4_VGSVGM) = '=';
+            }
+            break;
+        }
+    }
+#endif
+    p += strlen(bta_ag_result_tbl[code].p_res);
+
+    /* copy argument if any */
+    if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_INT)
+    {
+        p += utl_itoa((UINT16) int_arg, p);
+    }
+    else if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_STR)
+    {
+        BCM_STRCPY_S(p, sizeof(buf), p_arg);
+        p += strlen(p_arg);
+    }
+
+    /* finish with \r\n */
+    *p++ = '\r';
+    *p++ = '\n';
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+    APPL_TRACE_DEBUG1("bta_ag_send_result: %s", buf);
+#endif
+
+    /* send to RFCOMM */
+    PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
+}
+
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         bta_ag_send_multi_result
+**
+** Description      Send multiple AT result codes.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_send_multi_result(tBTA_AG_SCB *p_scb, tBTA_AG_MULTI_RESULT_CB *m_res_cb)
+{
+    char    buf[BTA_AG_AT_MAX_LEN * BTA_AG_AT_MULTI_LEN + 16];
+    char    *p = buf;
+    UINT16  len;
+    UINT8   res_idx = 0;
+
+    if((!m_res_cb) || (m_res_cb->num_result == 0) || (m_res_cb->num_result > BTA_AG_AT_MULTI_LEN))
+    {
+        APPL_TRACE_DEBUG0("m_res_cb is NULL or num_result is out of range.");
+        return;
+    }
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+    memset(buf, NULL, sizeof(buf));
+#endif
+
+    while(res_idx < m_res_cb->num_result)
+    {
+        /* init with \r\n */
+        *p++ = '\r';
+        *p++ = '\n';
+
+        /* copy result code string */
+        BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
+        p += strlen(bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
+
+        /* copy argument if any */
+        if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_INT)
+        {
+            p += utl_itoa((UINT16) m_res_cb->res_cb[res_idx].int_arg, p);
+        }
+        else if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_STR)
+        {
+            BCM_STRCPY_S(p, sizeof(buf), m_res_cb->res_cb[res_idx].p_arg);
+            p += strlen(m_res_cb->res_cb[res_idx].p_arg);
+        }
+
+        /* finish with \r\n */
+        *p++ = '\r';
+        *p++ = '\n';
+
+        res_idx++;
+    }
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+    APPL_TRACE_DEBUG1("send_result: %s", buf);
+#endif
+
+    /* send to RFCOMM */
+    PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_ok
+**
+** Description      Send an OK result code.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_send_ok(tBTA_AG_SCB *p_scb)
+{
+    bta_ag_send_result(p_scb, BTA_AG_RES_OK, NULL, 0);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_error
+**
+** Description      Send an ERROR result code.
+**                      errcode - used to send verbose errocode
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_send_error(tBTA_AG_SCB *p_scb, INT16 errcode)
+{
+    /* If HFP and extended audio gateway error codes are enabled */
+    if (p_scb->conn_service == BTA_AG_HFP && p_scb->cmee_enabled)
+        bta_ag_send_result(p_scb, BTA_AG_RES_CMEE, NULL, errcode);
+    else
+        bta_ag_send_result(p_scb, BTA_AG_RES_ERROR, NULL, 0);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_ind
+**
+** Description      Send an indicator CIEV result code.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_send_ind(tBTA_AG_SCB *p_scb, UINT16 id, UINT16 value, BOOLEAN on_demand)
+{
+    char    str[12];
+    char    *p = str;
+
+    /* If the indicator is masked out, just return */
+    /* Mandatory indicators can not be masked out. */
+    if ((p_scb->bia_masked_out & ((UINT32)1 << id)) &&
+        ((id != BTA_AG_IND_CALL) && (id != BTA_AG_IND_CALLSETUP) && (id != BTA_AG_IND_CALLHELD)))
+        return;
+
+    /* Ensure we do not send duplicate indicators if not requested by app */
+    /* If it was requested by app, transmit CIEV even if it is duplicate. */
+    if (id == BTA_AG_IND_CALL)
+    {
+        if ((value == p_scb->call_ind) && (on_demand == FALSE))
+            return;
+
+        p_scb->call_ind = (UINT8)value;
+    }
+
+    if ((id == BTA_AG_IND_CALLSETUP) && (on_demand == FALSE))
+    {
+        if (value == p_scb->callsetup_ind)
+            return;
+
+        p_scb->callsetup_ind = (UINT8)value;
+    }
+
+    if ((id == BTA_AG_IND_SERVICE) && (on_demand == FALSE))
+    {
+        if (value == p_scb->service_ind)
+            return;
+
+        p_scb->service_ind = (UINT8)value;
+    }
+    if ((id == BTA_AG_IND_SIGNAL) && (on_demand == FALSE))
+    {
+        if (value == p_scb->signal_ind)
+            return;
+
+        p_scb->signal_ind = (UINT8)value;
+    }
+    if ((id == BTA_AG_IND_ROAM) && (on_demand == FALSE))
+    {
+        if (value == p_scb->roam_ind)
+            return;
+
+        p_scb->roam_ind = (UINT8)value;
+    }
+    if ((id == BTA_AG_IND_BATTCHG) && (on_demand == FALSE))
+    {
+        if (value == p_scb->battchg_ind)
+            return;
+
+        p_scb->battchg_ind = (UINT8)value;
+    }
+
+    if ((id == BTA_AG_IND_CALLHELD) && (on_demand == FALSE))
+    {
+        /* call swap could result in sending callheld=1 multiple times */
+        if ((value != 1) && (value == p_scb->callheld_ind))
+            return;
+
+        p_scb->callheld_ind = (UINT8)value;
+    }
+
+    if (p_scb->cmer_enabled)
+    {
+        p += utl_itoa(id, p);
+        *p++ = ',';
+        utl_itoa(value, p);
+        bta_ag_send_result(p_scb, BTA_AG_RES_CIEV, str, 0);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_parse_cmer
+**
+** Description      Parse AT+CMER parameter string.
+**
+**
+** Returns          TRUE if parsed ok, FALSE otherwise.
+**
+*******************************************************************************/
+static BOOLEAN bta_ag_parse_cmer(char *p_s, BOOLEAN *p_enabled)
+{
+    INT16   n[4] = {-1, -1, -1, -1};
+    int     i;
+    char    *p;
+
+    for (i = 0; i < 4; i++)
+    {
+        /* skip to comma delimiter */
+        for (p = p_s; *p != ',' && *p != 0; p++);
+
+        /* get integer value */
+        *p = 0;
+        n[i] = utl_str2int(p_s);
+        p_s = p + 1;
+        if (p_s == 0)
+        {
+            break;
+        }
+    }
+
+    /* process values */
+    if (n[0] < 0 || n[3] < 0)
+    {
+        return FALSE;
+    }
+
+    if ((n[0] == 3) && ((n[3] == 1) || (n[3] == 0)))
+    {
+        *p_enabled = (BOOLEAN) n[3];
+    }
+
+    return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_parse_chld
+**
+** Description      Parse AT+CHLD parameter string.
+**
+**
+** Returns          Returns idx (1-7), or 0 if ECC not enabled or idx doesn't exist
+**
+*******************************************************************************/
+static UINT8 bta_ag_parse_chld(tBTA_AG_SCB *p_scb, char *p_s)
+{
+    UINT8   retval = 0;
+    INT16   idx = -1;
+
+    if (p_s[1] != 0)
+    {
+        /* p_idxstr++;  point to beginning of call number */
+        idx = utl_str2int(&p_s[1]);
+        if (idx != -1 && idx < 255)
+            retval = (UINT8)idx;
+    }
+
+    return (retval);
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function         bta_ag_parse_bac
+**
+** Description      Parse AT+BAC parameter string.
+**
+** Returns          Returns bitmap of supported codecs.
+**
+*******************************************************************************/
+static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB *p_scb, char *p_s)
+{
+    tBTA_AG_PEER_CODEC  retval = BTA_AG_CODEC_NONE;
+    UINT16  uuid_codec;
+    BOOLEAN cont = FALSE;       /* Continue processing */
+    char *p;
+
+    while(p_s)
+    {
+        /* skip to comma delimiter */
+        for(p = p_s; *p != ',' && *p != 0; p++);
+
+        /* get integre value */
+        if (*p != 0)
+        {
+            *p = 0;
+            cont = TRUE;
+        }
+        else
+            cont = FALSE;
+
+        uuid_codec = utl_str2int(p_s);
+        switch(uuid_codec)
+        {
+            case UUID_CODEC_CVSD:   retval |= BTA_AG_CODEC_CVSD;     break;
+            case UUID_CODEC_MSBC:   retval |= BTA_AG_CODEC_MSBC;     break;
+            default:
+                APPL_TRACE_ERROR1("Unknown Codec UUID(%d) received", uuid_codec);
+                return BTA_AG_CODEC_NONE;
+        }
+
+        if (cont)
+            p_s = p + 1;
+        else
+            break;
+    }
+
+    return (retval);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_process_unat_res
+**
+** Description      Process the unat response data and remove extra carriage return
+**                  and line feed
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+
+static void bta_ag_process_unat_res(char *unat_result)
+{
+    UINT8   str_leng;
+    UINT8   i = 0;
+    UINT8   j = 0;
+    UINT8   pairs_of_nl_cr;
+    char    trim_data[BTA_AG_AT_MAX_LEN];
+
+
+
+    str_leng = strlen(unat_result);
+
+    /* If no extra CR and LF, just return */
+    if(str_leng < 4)
+        return;
+
+    /* Remove the carriage return and left feed */
+    while(unat_result[0] =='\r' && unat_result[1] =='\n'
+        && unat_result[str_leng-2] =='\r' && unat_result[str_leng-1] =='\n')
+    {
+        pairs_of_nl_cr = 1;
+        for (i=0;i<(str_leng-4*pairs_of_nl_cr);i++)
+        {
+            trim_data[j++] = unat_result[i+pairs_of_nl_cr*2];
+        }
+        /* Add EOF */
+        trim_data[j] = '\0';
+        str_leng = str_leng - 4;
+        BCM_STRNCPY_S(unat_result, BTA_AG_AT_MAX_LEN+1, trim_data,str_leng+1);
+        i=0;
+        j=0;
+
+        if(str_leng <4)
+            return;
+
+
+    }
+    return;
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_ag_inband_enabled
+**
+** Description      Determine whether in-band ring can be used.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb)
+{
+    /* if feature is enabled and no other scbs connected */
+    if (p_scb->inband_enabled && !bta_ag_other_scb_open(p_scb))
+    {
+        return TRUE;
+    }
+    else
+    {
+        return FALSE;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_call_inds
+**
+** Description      Send call and callsetup indicators.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result)
+{
+    UINT8 call = p_scb->call_ind;
+    UINT8 callsetup;
+
+    /* set new call and callsetup values based on BTA_AgResult */
+    callsetup = bta_ag_callsetup_ind_tbl[result];
+
+    if (result == BTA_AG_END_CALL_RES)
+    {
+        call = BTA_AG_CALL_INACTIVE;
+    }
+    else if (result == BTA_AG_IN_CALL_CONN_RES || result == BTA_AG_OUT_CALL_CONN_RES
+             || result == BTA_AG_IN_CALL_HELD_RES)
+    {
+        call = BTA_AG_CALL_ACTIVE;
+    }
+    else
+    {
+        call = p_scb->call_ind;
+    }
+
+    /* Send indicator function tracks if the values have actually changed */
+    bta_ag_send_ind(p_scb, BTA_AG_IND_CALL, call, FALSE);
+    bta_ag_send_ind(p_scb, BTA_AG_IND_CALLSETUP, callsetup, FALSE);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_at_hsp_cback
+**
+** Description      AT command processing callback for HSP.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+                                char *p_arg, INT16 int_arg)
+{
+    tBTA_AG_VAL val;
+
+    APPL_TRACE_DEBUG4("AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
+                      int_arg, p_arg);
+
+    /* send OK */
+    bta_ag_send_ok(p_scb);
+
+    val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+    val.hdr.app_id = p_scb->app_id;
+    val.num = (UINT16) int_arg;
+    BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+    val.str[BTA_AG_AT_MAX_LEN] = 0;
+
+    /* call callback with event */
+    (*bta_ag_cb.p_cback)(bta_ag_hsp_cb_evt[cmd], (tBTA_AG *) &val);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_at_hfp_cback
+**
+** Description      AT command processing callback for HFP.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+                                char *p_arg, INT16 int_arg)
+{
+    tBTA_AG_VAL     val;
+    tBTA_AG_EVT   event;
+    tBTA_AG_SCB     *ag_scb;
+    UINT32          i, ind_id;
+    UINT32          bia_masked_out;
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_PEER_CODEC  codec_type, codec_sent;
+#endif
+
+    APPL_TRACE_DEBUG4("HFP AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
+                      int_arg, p_arg);
+
+    val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+    val.hdr.app_id = p_scb->app_id;
+    val.num = int_arg;
+    BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+    val.str[BTA_AG_AT_MAX_LEN] = 0;
+
+    event = bta_ag_hfp_cb_evt[cmd];
+
+    switch (cmd)
+    {
+        case BTA_AG_HF_CMD_A:
+        case BTA_AG_HF_CMD_VGS:
+        case BTA_AG_HF_CMD_VGM:
+        case BTA_AG_HF_CMD_CHUP:
+        case BTA_AG_HF_CMD_CBC:
+            /* send OK */
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_HF_CMD_BLDN:
+            /* Do not send OK, App will send error or OK depending on
+            ** last dial number enabled or not */
+            break;
+
+        case BTA_AG_HF_CMD_D:
+            /* Do not send OK for Dial cmds
+            ** Let application decide whether to send OK or ERROR*/
+
+            /* if mem dial cmd, make sure string contains only digits */
+            if(p_arg[0] == '>')
+            {
+                if(!utl_isintstr(p_arg+1))
+                {
+                    event = 0;
+                    bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+                }
+            }
+            else if (p_arg[0] == 'V')   /* ATDV : Dial VoIP Call */
+            {
+                /* We do not check string. Code will be added later if needed. */
+                if(!((p_scb->peer_features & BTA_AG_PEER_FEAT_VOIP) && (p_scb->features & BTA_AG_FEAT_VOIP)))
+                {
+                    event = 0;
+                    bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+                }
+            }
+            /* If dial cmd, make sure string contains only dial digits
+            ** Dial digits are 0-9, A-C, *, #, + */
+            else
+            {
+                if(!utl_isdialstr(p_arg))
+                {
+                    event = 0;
+                    bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+                }
+            }
+            break;
+
+        case BTA_AG_HF_CMD_CCWA:
+            /* store setting */
+            p_scb->ccwa_enabled = (BOOLEAN) int_arg;
+
+            /* send OK */
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_HF_CMD_CHLD:
+            if (arg_type == BTA_AG_AT_TEST)
+            {
+                /* don't call callback */
+                event = 0;
+
+                /* send CHLD string */
+                /* Form string based on supported 1.5 feature */
+                if ((p_scb->peer_version >= HFP_VERSION_1_5) &&
+                    (p_scb->features & BTA_AG_FEAT_ECC) &&
+                    (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))
+                    bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val_ecc, 0);
+                else
+                    bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val, 0);
+
+                /* send OK */
+                bta_ag_send_ok(p_scb);
+
+                /* if service level conn. not already open, now it's open */
+                bta_ag_svc_conn_open(p_scb, NULL);
+
+            }
+            else
+            {
+                val.idx = bta_ag_parse_chld(p_scb, val.str);
+
+                if(val.idx && !((p_scb->features & BTA_AG_FEAT_ECC) && (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC)))
+                {
+                    /* we do not support ECC, but HF is sending us a CHLD with call index*/
+                    event = 0;
+                    bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+
+                }
+                else
+                {
+
+                /* If it is swap between calls, set call held indicator to 3(out of valid 0-2)
+                ** Application will set it back to 1
+                ** callheld indicator will be sent across to the peer. */
+                if(val.str[0] == '2')
+                {
+                    for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++)
+                    {
+                        if (ag_scb->in_use)
+                        {
+                            if((ag_scb->call_ind == BTA_AG_CALL_ACTIVE)
+                                && (ag_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE))
+                                ag_scb->callheld_ind = BTA_AG_CALLHELD_NOACTIVE + 1;
+                        }
+                    }
+                }
+                }
+
+                /* Do not send OK. Let app decide after parsing the val str */
+                /* bta_ag_send_ok(p_scb); */
+            }
+            break;
+
+        case BTA_AG_HF_CMD_CIND:
+            if (arg_type == BTA_AG_AT_TEST)
+            {
+                /* don't call callback */
+                event = 0;
+
+                /* send CIND string, send OK */
+                bta_ag_send_result(p_scb, BTA_AG_RES_CIND, p_bta_ag_cfg->cind_info, 0);
+                bta_ag_send_ok(p_scb);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_CLIP:
+            /* store setting, send OK */
+            p_scb->clip_enabled = (BOOLEAN) int_arg;
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_HF_CMD_CMER:
+            /* if parsed ok store setting, send OK */
+            if (bta_ag_parse_cmer(p_arg, &p_scb->cmer_enabled))
+            {
+                bta_ag_send_ok(p_scb);
+
+                /* if service level conn. not already open and our features and
+                ** peer features do not have 3-way, service level conn. now open
+                */
+                if (!p_scb->svc_conn &&
+                    !((p_scb->features & BTA_AG_FEAT_3WAY) && (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY)))
+                {
+                    bta_ag_svc_conn_open(p_scb, NULL);
+                }
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_VTS:
+            /* check argument */
+            if (strlen(p_arg) == 1)
+            {
+                bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_BINP:
+            /* if feature not set don't call callback, send ERROR */
+            if (!(p_scb->features & BTA_AG_FEAT_VTAG))
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_BVRA:
+            /* if feature not supported don't call callback, send ERROR. App will send OK */
+            if (!(p_scb->features & BTA_AG_FEAT_VREC))
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_BRSF:
+            /* store peer features */
+            p_scb->peer_features = (UINT16) int_arg;
+
+            /* send BRSF, send OK */
+            bta_ag_send_result(p_scb, BTA_AG_RES_BRSF, NULL,
+                               (INT16) (p_scb->features & BTA_AG_BSRF_FEAT_SPEC));
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_HF_CMD_NREC:
+            /* if feature send OK, else don't call callback, send ERROR */
+            if (p_scb->features & BTA_AG_FEAT_ECNR)
+            {
+                bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_BTRH:
+            /* if feature send BTRH, send OK:, else don't call callback, send ERROR */
+            if (p_scb->features & BTA_AG_FEAT_BTRH)
+            {
+                /* If set command; send response and notify app */
+                if (arg_type == BTA_AG_AT_SET)
+                {
+                    for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++)
+                    {
+                        if (ag_scb->in_use)
+                        {
+                            bta_ag_send_result(ag_scb, BTA_AG_RES_BTRH, NULL, int_arg);
+                        }
+                    }
+                    bta_ag_send_ok(p_scb);
+                }
+                else /* Read Command */
+                {
+                    val.num = BTA_AG_BTRH_READ;
+                }
+            }
+            else
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_COPS:
+            if (arg_type == BTA_AG_AT_SET)
+            {
+                /* don't call callback */
+                event = 0;
+
+                /* send OK */
+                bta_ag_send_ok(p_scb);
+            }
+            break;
+
+        case BTA_AG_HF_CMD_CMEE:
+            if (p_scb->features & BTA_AG_FEAT_EXTERR)
+            {
+                /* store setting */
+                p_scb->cmee_enabled = (BOOLEAN) int_arg;
+
+                /* send OK */
+                bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            /* don't call callback */
+            event = 0;
+            break;
+
+        case BTA_AG_HF_CMD_BIA:
+            /* don't call callback */
+            event = 0;
+
+            bia_masked_out = p_scb->bia_masked_out;
+
+            /* Parse the indicator mask */
+            for (i = 0, ind_id = 1; (val.str[i] != 0) && (ind_id <= 20); i++, ind_id++)
+            {
+                if (val.str[i] == ',')
+                    continue;
+
+                if (val.str[i] == '0')
+                    bia_masked_out |= ((UINT32)1 << ind_id);
+                else if (val.str[i] == '1')
+                    bia_masked_out &= ~((UINT32)1 << ind_id);
+                else
+                    break;
+
+                i++;
+                if ( (val.str[i] != 0) && (val.str[i] != ',') )
+                    break;
+            }
+            if (val.str[i] == 0)
+            {
+                p_scb->bia_masked_out = bia_masked_out;
+                bta_ag_send_ok (p_scb);
+            }
+            else
+                bta_ag_send_error (p_scb, BTA_AG_ERR_INVALID_INDEX);
+            break;
+
+        case BTA_AG_HF_CMD_CNUM:
+            break;
+        case BTA_AG_HF_CMD_CLCC:
+            if(!(p_scb->features & BTA_AG_FEAT_ECS))
+            {
+                event = 0;
+                bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+            }
+            break;
+
+#if (BTM_WBS_INCLUDED == TRUE )
+        case BTA_AG_HF_CMD_BAC:
+            bta_ag_send_ok(p_scb);
+
+            /* store available codecs from the peer */
+            if((p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC) && (p_scb->features & BTA_AG_FEAT_CODEC))
+            {
+                p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg);
+                p_scb->codec_updated = TRUE;
+
+                if (p_scb->peer_codecs & BTA_AG_CODEC_MSBC)
+                {
+                    p_scb->sco_codec = UUID_CODEC_MSBC;
+                    APPL_TRACE_DEBUG0("Received AT+BAC, updating sco codec to MSBC");
+                }
+                else
+                {
+                    p_scb->sco_codec = UUID_CODEC_CVSD;
+                    APPL_TRACE_DEBUG0("Received AT+BAC, updating sco codec to CVSD");
+                }
+
+                /* Received BAC while in codec negotiation. */
+                if ((bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST) && (bta_ag_cb.sco.p_curr_scb == p_scb))
+                {
+                    bta_ag_codec_negotiate (p_scb);
+                }
+            }
+            else
+            {
+                p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+                APPL_TRACE_ERROR0("Unexpected CMD:AT+BAC, Codec Negotiation is not supported");
+            }
+            break;
+
+        case BTA_AG_HF_CMD_BCS:
+            /* stop cn timer */
+            bta_sys_stop_timer(&p_scb->cn_timer);
+
+            switch(int_arg)
+            {
+                case UUID_CODEC_CVSD:   codec_type = BTA_AG_CODEC_CVSD;     break;
+                case UUID_CODEC_MSBC:   codec_type = BTA_AG_CODEC_MSBC;     break;
+                default:
+                    APPL_TRACE_ERROR1("Unknown codec_uuid %d", int_arg);
+                    codec_type = 0xFFFF;
+                    break;
+            }
+
+            if (p_scb->codec_fallback)
+                codec_sent = BTA_AG_CODEC_CVSD;
+            else
+                codec_sent = p_scb->sco_codec;
+
+            if(codec_type == codec_sent)
+                bta_ag_sco_codec_nego(p_scb, TRUE);
+            else
+                bta_ag_sco_codec_nego(p_scb, FALSE);
+
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_HF_CMD_BCC:
+            bta_ag_send_ok(p_scb);
+            bta_ag_sco_open(p_scb, NULL);
+            break;
+#endif
+
+        default:
+            break;
+    }
+
+    /* call callback */
+    if (event != 0)
+    {
+        (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &val);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_at_err_cback
+**
+** Description      AT command parser error callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg)
+{
+    tBTA_AG_VAL     val;
+
+    if(unknown && (!strlen(p_arg)))
+    {
+        APPL_TRACE_DEBUG0("Empty AT cmd string received");
+        bta_ag_send_ok(p_scb);
+        return;
+    }
+
+    /* if unknown AT command and configured to pass these to app */
+    if (unknown && (p_scb->features & BTA_AG_FEAT_UNAT))
+    {
+        val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+        val.hdr.app_id = p_scb->app_id;
+        val.num = 0;
+        BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+        val.str[BTA_AG_AT_MAX_LEN] = 0;
+        (*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG *) &val);
+    }
+    else
+    {
+        bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_hsp_result
+**
+** Description      Handle API result for HSP connections.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_hsp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
+{
+    UINT8 code = bta_ag_trans_result[p_result->result];
+
+    APPL_TRACE_DEBUG1("bta_ag_hsp_result : res = %d", p_result->result);
+
+    switch(p_result->result)
+    {
+        case BTA_AG_SPK_RES:
+        case BTA_AG_MIC_RES:
+            bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+            break;
+
+        case BTA_AG_IN_CALL_RES:
+            /* tell sys to stop av if any */
+            bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+            /* if sco already opened or no inband ring send ring now */
+            if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+                (p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            /* else open sco, send ring after sco opened */
+            else
+            {
+                /* HSPv1.2: AG shall not send RING if using in-band ring tone. */
+                if (p_scb->hsp_version >= HSP_VERSION_1_2)
+                    p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+                else
+                    p_scb->post_sco = BTA_AG_POST_SCO_RING;
+
+                bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            break;
+
+        case BTA_AG_IN_CALL_CONN_RES:
+        case BTA_AG_OUT_CALL_ORIG_RES:
+            /* if incoming call connected stop ring timer */
+            if (p_result->result == BTA_AG_IN_CALL_CONN_RES)
+            {
+                bta_sys_stop_timer(&p_scb->act_timer);
+            }
+
+            if (!(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                /* if audio connected to this scb open sco */
+                if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
+                {
+                    bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+                /* else if no audio at call close sco */
+                else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE)
+                {
+                    bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+            }
+            break;
+
+        case BTA_AG_END_CALL_RES:
+            /* stop ring timer */
+            bta_sys_stop_timer(&p_scb->act_timer);
+
+            /* close sco */
+            if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            else
+            {
+                /* if av got suspended by this call, let it resume. */
+                bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+            }
+            break;
+
+        case BTA_AG_INBAND_RING_RES:
+            p_scb->inband_enabled = p_result->data.state;
+            APPL_TRACE_DEBUG1("inband_enabled set to %d", p_scb->inband_enabled);
+            break;
+
+        case BTA_AG_UNAT_RES:
+            if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+            {
+                if (p_result->data.str[0] != 0)
+                {
+                    bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+                }
+
+                if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+                    bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+            }
+            break;
+
+        default:
+            /* ignore all others */
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_hfp_result
+**
+** Description      Handle API result for HFP connections.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_hfp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
+{
+    UINT8 code = bta_ag_trans_result[p_result->result];
+
+    APPL_TRACE_DEBUG1("bta_ag_hfp_result : res = %d", p_result->result);
+
+    switch(p_result->result)
+    {
+        case BTA_AG_SPK_RES:
+        case BTA_AG_MIC_RES:
+            bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+            break;
+
+        case BTA_AG_IN_CALL_RES:
+            /* tell sys to stop av if any */
+            bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+            /* store caller id string.
+             * append type info at the end.
+             * make sure a valid type info is passed.
+             * otherwise add 129 as default type */
+            if ((p_result->data.num < BTA_AG_CLIP_TYPE_MIN) || (p_result->data.num > BTA_AG_CLIP_TYPE_MAX))
+            {
+                if (p_result->data.num != BTA_AG_CLIP_TYPE_VOIP)
+                    p_result->data.num = BTA_AG_CLIP_TYPE_DEFAULT;
+            }
+
+            APPL_TRACE_DEBUG1("CLIP type :%d", p_result->data.num);
+            p_scb->clip[0] = 0;
+            if (p_result->data.str[0] != 0)
+                sprintf(p_scb->clip,"%s,%d", p_result->data.str, p_result->data.num);
+
+            /* send callsetup indicator */
+            if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END)
+            {
+                /* Need to sent 2 callsetup IND's(Call End and Incoming call) after SCO close. */
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_END_INCALL;
+            }
+            else
+            {
+                bta_ag_send_call_inds(p_scb, p_result->result);
+
+                /* if sco already opened or no inband ring send ring now */
+                if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+                    (p_scb->features & BTA_AG_FEAT_NOSCO))
+                {
+                    bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+                /* else open sco, send ring after sco opened */
+                else
+                {
+                    p_scb->post_sco = BTA_AG_POST_SCO_RING;
+                    bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+            }
+            break;
+
+        case BTA_AG_IN_CALL_CONN_RES:
+            /* stop ring timer */
+            bta_sys_stop_timer(&p_scb->act_timer);
+
+            /* if sco not opened and we need to open it, open sco first
+            ** then send indicators
+            */
+            if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+                !bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_CONN;
+                bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            /* else if sco open and we need to close it, close sco first
+            ** then send indicators
+            */
+            else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE &&
+                     bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_CONN;
+                bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            /* else send indicators now */
+            else
+            {
+                bta_ag_send_call_inds(p_scb, p_result->result);
+            }
+            break;
+
+        case BTA_AG_IN_CALL_HELD_RES:
+            /* stop ring timer */
+            bta_sys_stop_timer(&p_scb->act_timer);
+
+            bta_ag_send_call_inds(p_scb, p_result->result);
+
+            break;
+
+        case BTA_AG_OUT_CALL_ORIG_RES:
+            /* if sco open and we need to close it, close sco first
+            ** then send indicators; else send indicators now
+            */
+            if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE &&
+                bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_ORIG;
+                bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            else
+            {
+                bta_ag_send_call_inds(p_scb, p_result->result);
+                if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+                    !(p_scb->features & BTA_AG_FEAT_NOSCO))
+                {
+                    bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+            }
+            break;
+
+        case BTA_AG_OUT_CALL_ALERT_RES:
+            /* send indicators */
+            bta_ag_send_call_inds(p_scb, p_result->result);
+            if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+                !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            break;
+
+        case BTA_AG_OUT_CALL_CONN_RES:
+            /* send indicators */
+            bta_ag_send_call_inds(p_scb, p_result->result);
+
+            /* open or close sco */
+            if (!(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
+                {
+                    bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+                else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE)
+                {
+                    bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+                }
+            }
+            break;
+
+        case BTA_AG_CALL_CANCEL_RES:
+            /* send indicators */
+            bta_ag_send_call_inds(p_scb, p_result->result);
+            break;
+
+        case BTA_AG_END_CALL_RES:
+            /* stop ring timer */
+            bta_sys_stop_timer(&p_scb->act_timer);
+
+            /* if sco open, close sco then send indicator values */
+            if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
+            {
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+                bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+            }
+            else if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END_INCALL)
+            {
+                /* sco closing for outgoing call because of incoming call */
+                /* Send only callsetup end indicator after sco close */
+                p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+            }
+            else
+            {
+                bta_ag_send_call_inds(p_scb, p_result->result);
+
+                /* if av got suspended by this call, let it resume. */
+                bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+            }
+            break;
+
+        case BTA_AG_INBAND_RING_RES:
+            p_scb->inband_enabled = p_result->data.state;
+            APPL_TRACE_DEBUG1("inband_enabled set to %d", p_scb->inband_enabled);
+            bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
+            break;
+
+        case BTA_AG_CIND_RES:
+            /* store local values */
+            p_scb->call_ind = p_result->data.str[0] - '0';
+            p_scb->callsetup_ind = p_result->data.str[2] - '0';
+            p_scb->service_ind = p_result->data.str[4] - '0';
+            p_scb->signal_ind = p_result->data.str[6] - '0';
+            p_scb->roam_ind = p_result->data.str[8] - '0';
+            p_scb->battchg_ind = p_result->data.str[10] - '0';
+            APPL_TRACE_DEBUG2("cind call:%d callsetup:%d", p_scb->call_ind, p_scb->callsetup_ind);
+
+            bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+            bta_ag_send_ok(p_scb);
+            break;
+
+        case BTA_AG_BINP_RES:
+        case BTA_AG_CNUM_RES:
+        case BTA_AG_CLCC_RES:
+        case BTA_AG_COPS_RES:
+            if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+            {
+                if (p_result->data.str[0] != 0)
+                {
+                   bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+                }
+
+                if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+                    bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, p_result->data.errcode);
+            }
+            break;
+
+
+        case BTA_AG_UNAT_RES:
+            if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+            {
+                if (p_result->data.str[0] != 0)
+                {
+                    bta_ag_process_unat_res(p_result->data.str);
+                    APPL_TRACE_DEBUG1("BTA_AG_RES :%s",p_result->data.str);
+                    bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+                }
+
+                if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+                    bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, p_result->data.errcode);
+            }
+            break;
+
+        case BTA_AG_CALL_WAIT_RES:
+            if (p_scb->ccwa_enabled)
+            {
+                bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+            }
+            bta_ag_send_call_inds(p_scb, p_result->result);
+            break;
+
+        case BTA_AG_IND_RES:
+            bta_ag_send_ind(p_scb, p_result->data.ind.id, p_result->data.ind.value, FALSE);
+            break;
+
+        case BTA_AG_BVRA_RES:
+            bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
+            break;
+
+        case BTA_AG_BTRH_RES:
+            if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
+            {
+                /* Don't respond to read if not in response & hold state */
+                if (p_result->data.num != BTA_AG_BTRH_NO_RESP)
+                {
+                    bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+                }
+
+                /* In case of a response to a read request we need to send OK */
+                if (p_result->data.ok_flag == BTA_AG_OK_DONE)
+                    bta_ag_send_ok(p_scb);
+            }
+            else
+            {
+                bta_ag_send_error(p_scb, p_result->data.errcode);
+            }
+            break;
+
+       default:
+            break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_ag_result
+**
+** Description      Handle API result.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    if (p_scb->conn_service == BTA_AG_HSP)
+    {
+        bta_ag_hsp_result(p_scb, &p_data->api_result);
+    }
+    else
+    {
+        bta_ag_hfp_result(p_scb, &p_data->api_result);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_setcodec
+**
+** Description      Handle API SetCodec
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_PEER_CODEC codec_type = p_data->api_setcodec.codec;
+
+    /* Check if the requested codec type is valid */
+    if((codec_type != BTA_AG_CODEC_NONE) &&
+       (codec_type != BTA_AG_CODEC_CVSD) &&
+       (codec_type != BTA_AG_CODEC_MSBC))
+    {
+        APPL_TRACE_ERROR1("bta_ag_setcodec error: unsupported codec type %d", codec_type);
+        return;
+    }
+
+    if((p_scb->peer_codecs & codec_type) || (codec_type == BTA_AG_CODEC_NONE) || (codec_type == BTA_AG_CODEC_CVSD))
+    {
+        p_scb->sco_codec = codec_type;
+        p_scb->codec_updated = TRUE;
+        APPL_TRACE_DEBUG1("bta_ag_setcodec: Updated codec type %d", codec_type);
+    }
+    else
+    {
+        APPL_TRACE_ERROR1("bta_ag_setcodec error: unsupported codec type %d", codec_type);
+    }
+#endif
+}
+
+
+#if (BTM_WBS_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function         bta_ag_send_bcs
+**
+** Description      Send +BCS AT command to peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_send_bcs(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16 codec_uuid;
+
+    if (p_scb->codec_fallback)
+    {
+        codec_uuid = UUID_CODEC_CVSD;
+    }
+    else
+    {
+        switch(p_scb->sco_codec)
+        {
+            case BTA_AG_CODEC_NONE:     codec_uuid = UUID_CODEC_CVSD;   break;
+            case BTA_AG_CODEC_CVSD:     codec_uuid = UUID_CODEC_CVSD;   break;
+            case BTA_AG_CODEC_MSBC:     codec_uuid = UUID_CODEC_MSBC;   break;
+            default:
+                APPL_TRACE_ERROR1("bta_ag_send_bcs: unknown codec %d, use CVSD", p_scb->sco_codec);
+                codec_uuid = UUID_CODEC_CVSD;
+                break;
+        }
+    }
+
+    /* send +BCS */
+    bta_ag_send_result(p_scb, BTA_AG_RES_BCS, NULL, codec_uuid);
+
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_send_ring
+**
+** Description      Send RING result code to peer.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+    tBTA_AG_MULTI_RESULT_CB m_res_cb;
+
+    if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0)
+    {
+        memset(&m_res_cb, NULL, sizeof(tBTA_AG_MULTI_RESULT_CB));
+
+        m_res_cb.num_result = 2;
+        AT_SET_RES_CB(m_res_cb.res_cb[0], BTA_AG_RES_RING, NULL, 0)
+        AT_SET_RES_CB(m_res_cb.res_cb[1], BTA_AG_RES_CLIP, p_scb->clip, 0)
+
+        bta_ag_send_multi_result(p_scb, &m_res_cb);
+    }
+    else
+    {
+        /* send RING ONLY */
+        bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
+    }
+#else
+    /* send RING */
+    bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
+
+    /* if HFP and clip enabled and clip data send CLIP */
+    if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0)
+    {
+        bta_ag_send_result(p_scb, BTA_AG_RES_CLIP, p_scb->clip, 0);
+    }
+#endif
+
+    /* restart ring timer */
+    bta_sys_start_timer(&p_scb->act_timer, BTA_AG_RING_TOUT_EVT, BTA_AG_RING_TOUT);
+}
+
+
diff --git a/bta/ag/bta_ag_int.h b/bta/ag/bta_ag_int.h
new file mode 100644
index 0000000..b0d1b1d
--- /dev/null
+++ b/bta/ag/bta_ag_int.h
@@ -0,0 +1,423 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the private interface file for the BTA audio gateway.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_INT_H
+#define BTA_AG_INT_H
+
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_ag_api.h"
+#include "bta_ag_at.h"
+
+/* Send RING & CLIP in one AT cmd */
+#ifndef BTA_AG_MULTI_RESULT_INCLUDED
+#define BTA_AG_MULTI_RESULT_INCLUDED      FALSE
+#endif
+
+/* Replace : in VGS and VGM for HSP */
+#ifndef BTA_HSP_RESULT_REPLACE_COLON
+#define BTA_HSP_RESULT_REPLACE_COLON      TRUE
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+#define HFP_VERSION_1_1         0x0101
+#define HFP_VERSION_1_5         0x0105
+#define HFP_VERSION_1_6         0x0106
+
+#define HSP_VERSION_1_0         0x0100
+#define HSP_VERSION_1_2         0x0102
+
+/* Number of SCBs (AG service instances that can be registered) */
+#ifndef BTA_AG_NUM_SCB
+#define BTA_AG_NUM_SCB          2
+#endif
+
+/* Timer to wait for retry in case of collision */
+#ifndef BTA_AG_COLLISION_TIMER
+#define BTA_AG_COLLISION_TIMER  2000
+#endif
+
+/* RFCOMM MTU SIZE */
+#define BTA_AG_MTU              256
+
+/* Internal profile indexes */
+#define BTA_AG_HSP              0       /* index for HSP */
+#define BTA_AG_HFP              1       /* index for HFP */
+#define BTA_AG_NUM_IDX          2       /* number of profile indexes */
+
+/* profile role for connection */
+#define BTA_AG_ACP              0       /* accepted connection */
+#define BTA_AG_INT              1       /* initiating connection */
+
+/* feature mask that matches spec */
+#define BTA_AG_BSRF_FEAT_SPEC        (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR    | \
+                                      BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND  | \
+                                      BTA_AG_FEAT_VTAG | BTA_AG_FEAT_REJECT  | \
+                                      BTA_AG_FEAT_ECS  | BTA_AG_FEAT_ECC     | \
+                                      BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_CODEC | \
+                                      BTA_AG_FEAT_VOIP)
+
+#define BTA_AG_SDP_FEAT_SPEC         (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR    | \
+                                      BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND  | \
+                                      BTA_AG_FEAT_VTAG)
+
+enum
+{
+    /* these events are handled by the state machine */
+    BTA_AG_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_AG),
+    BTA_AG_API_DEREGISTER_EVT,
+    BTA_AG_API_OPEN_EVT,
+    BTA_AG_API_CLOSE_EVT,
+    BTA_AG_API_AUDIO_OPEN_EVT,
+    BTA_AG_API_AUDIO_CLOSE_EVT,
+    BTA_AG_API_RESULT_EVT,
+    BTA_AG_API_SETCODEC_EVT,
+    BTA_AG_RFC_OPEN_EVT,
+    BTA_AG_RFC_CLOSE_EVT,
+    BTA_AG_RFC_SRV_CLOSE_EVT,
+    BTA_AG_RFC_DATA_EVT,
+    BTA_AG_SCO_OPEN_EVT,
+    BTA_AG_SCO_CLOSE_EVT,
+    BTA_AG_DISC_ACP_RES_EVT,
+    BTA_AG_DISC_INT_RES_EVT,
+    BTA_AG_DISC_OK_EVT,
+    BTA_AG_DISC_FAIL_EVT,
+    BTA_AG_CI_RX_WRITE_EVT,
+    BTA_AG_RING_TOUT_EVT,
+    BTA_AG_SVC_TOUT_EVT,
+    BTA_AG_CI_SCO_DATA_EVT,
+    BTA_AG_CI_SLC_READY_EVT,
+    BTA_AG_MAX_EVT,
+
+    /* these events are handled outside of the state machine */
+    BTA_AG_API_ENABLE_EVT,
+    BTA_AG_API_DISABLE_EVT
+};
+
+/* Actions to perform after a SCO event */
+enum
+{
+    BTA_AG_POST_SCO_NONE,       /* no action */
+    BTA_AG_POST_SCO_CLOSE_RFC,  /* close RFCOMM channel after SCO closes */
+    BTA_AG_POST_SCO_RING,       /* send RING result code after SCO opens */
+    BTA_AG_POST_SCO_CALL_CONN,  /* send call indicators after SCO opens/closes */
+    BTA_AG_POST_SCO_CALL_ORIG,  /* send call indicators after SCO closes */
+    BTA_AG_POST_SCO_CALL_END,   /* send call indicators after SCO closes */
+    BTA_AG_POST_SCO_CALL_END_INCALL   /* send call indicators for end call & incoming call after SCO closes */
+};
+
+/* sco states */
+enum
+{
+    BTA_AG_SCO_SHUTDOWN_ST,     /* no sco listening, all sco connections closed */
+    BTA_AG_SCO_LISTEN_ST,       /* sco listening */
+#if (BTM_WBS_INCLUDED == TRUE )
+    BTA_AG_SCO_CODEC_ST,        /* sco codec negotiation */
+#endif
+    BTA_AG_SCO_OPENING_ST,      /* sco connection opening */
+    BTA_AG_SCO_OPEN_CL_ST,      /* opening sco connection being closed */
+    BTA_AG_SCO_OPEN_XFER_ST,    /* opening sco connection being transferred */
+    BTA_AG_SCO_OPEN_ST,         /* sco open */
+    BTA_AG_SCO_CLOSING_ST,      /* sco closing */
+    BTA_AG_SCO_CLOSE_OP_ST,     /* closing sco being opened */
+    BTA_AG_SCO_CLOSE_XFER_ST,   /* closing sco being transferred */
+    BTA_AG_SCO_SHUTTING_ST      /* sco shutting down */
+};
+
+/*****************************************************************************
+**  Data types
+*****************************************************************************/
+
+/* data type for BTA_AG_API_ENABLE_EVT */
+typedef struct
+{
+    BT_HDR              hdr;
+    tBTA_AG_PARSE_MODE  parse_mode;
+    tBTA_AG_CBACK      *p_cback;
+} tBTA_AG_API_ENABLE;
+
+/* data type for BTA_AG_API_REGISTER_EVT */
+typedef struct
+{
+    BT_HDR              hdr;
+    char                p_name[2][BTA_SERVICE_NAME_LEN+1];
+    tBTA_SERVICE_MASK   services;
+    tBTA_SEC            sec_mask;
+    tBTA_AG_FEAT        features;
+    UINT8               app_id;
+} tBTA_AG_API_REGISTER;
+
+/* data type for BTA_AG_API_OPEN_EVT */
+typedef struct
+{
+    BT_HDR              hdr;
+    BD_ADDR             bd_addr;
+    tBTA_SERVICE_MASK   services;
+    tBTA_SEC            sec_mask;
+} tBTA_AG_API_OPEN;
+
+/* data type for BTA_AG_API_RESULT_EVT */
+typedef struct
+{
+    BT_HDR            hdr;
+    tBTA_AG_RES       result;
+    tBTA_AG_RES_DATA  data;
+} tBTA_AG_API_RESULT;
+
+/* data type for BTA_AG_API_SETCODEC_EVT */
+typedef struct
+{
+    BT_HDR              hdr;
+    tBTA_AG_PEER_CODEC  codec;
+} tBTA_AG_API_SETCODEC;
+
+/* data type for BTA_AG_DISC_RESULT_EVT */
+typedef struct
+{
+    BT_HDR          hdr;
+    UINT16          status;
+} tBTA_AG_DISC_RESULT;
+
+/* data type for RFCOMM events */
+typedef struct
+{
+    BT_HDR          hdr;
+    UINT16          port_handle;
+} tBTA_AG_RFC;
+
+/* data type for BTA_AG_CI_RX_WRITE_EVT */
+typedef struct
+{
+    BT_HDR          hdr;
+//    char            p_data[BTA_AG_MTU+1];
+} tBTA_AG_CI_RX_WRITE;
+
+/* union of all event datatypes */
+typedef union
+{
+    BT_HDR                  hdr;
+    tBTA_AG_API_ENABLE      api_enable;
+    tBTA_AG_API_REGISTER    api_register;
+    tBTA_AG_API_OPEN        api_open;
+    tBTA_AG_API_RESULT      api_result;
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_API_SETCODEC    api_setcodec;
+#endif
+    tBTA_AG_DISC_RESULT     disc_result;
+    tBTA_AG_RFC             rfc;
+    tBTA_AG_CI_RX_WRITE     ci_rx_write;
+} tBTA_AG_DATA;
+
+/* type for each profile */
+typedef struct
+{
+    UINT32          sdp_handle;
+    UINT8           scn;
+} tBTA_AG_PROFILE;
+
+/* type for each service control block */
+typedef struct
+{
+    char                clip[BTA_AG_AT_MAX_LEN+1]; /* number string used for CLIP */
+    UINT16              serv_handle[BTA_AG_NUM_IDX]; /* RFCOMM server handles */
+    tBTA_AG_AT_CB       at_cb;          /* AT command interpreter */
+    TIMER_LIST_ENT      act_timer;     /* ring timer */
+    BD_ADDR             peer_addr;      /* peer bd address */
+    tSDP_DISCOVERY_DB   *p_disc_db;     /* pointer to discovery database */
+    tBTA_SERVICE_MASK   reg_services;   /* services specified in register API */
+    tBTA_SERVICE_MASK   open_services;  /* services specified in open API */
+    UINT16              conn_handle;    /* RFCOMM handle of connected service */
+    tBTA_SEC            serv_sec_mask;  /* server security mask */
+    tBTA_SEC            cli_sec_mask;   /* client security mask */
+    tBTA_AG_FEAT        features;       /* features registered by application */
+    tBTA_AG_PEER_FEAT   peer_features;  /* peer device features */
+    UINT16              peer_version;   /* profile version of peer device */
+    UINT16              hsp_version;    /* HSP profile version */
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_PEER_CODEC  peer_codecs;    /* codecs for eSCO supported by the peer */
+    tBTA_AG_PEER_CODEC  sco_codec;      /* codec to be used for eSCO connection */
+    tBTA_AG_PEER_CODEC  inuse_codec;    /* codec being used for the current SCO connection */
+    BOOLEAN             codec_updated;  /* set to TRUE whenever the app updates codec type */
+    BOOLEAN             codec_fallback; /* If sco nego fails for mSBC, fallback to CVSD */
+    TIMER_LIST_ENT      cn_timer;       /* codec negotiation timer */
+#endif
+    UINT16              sco_idx;        /* SCO handle */
+    BOOLEAN             in_use;         /* scb in use */
+    BOOLEAN             dealloc;        /* TRUE if service shutting down */
+    BOOLEAN             clip_enabled;   /* set to TRUE if HF enables CLIP reporting */
+    BOOLEAN             ccwa_enabled;   /* set to TRUE if HF enables CCWA reporting */
+    BOOLEAN             cmer_enabled;   /* set to TRUE if HF enables CMER reporting */
+    BOOLEAN             cmee_enabled;   /* set to TRUE if HF enables CME ERROR reporting */
+    BOOLEAN             inband_enabled; /* set to TRUE if inband ring enabled */
+    BOOLEAN             svc_conn;       /* set to TRUE when service level connection up */
+    TIMER_LIST_ENT      colli_timer;    /* Collision timer */
+    BOOLEAN             colli_tmr_on;   /* TRUE if collision timer is active */
+    UINT8               state;          /* state machine state */
+    UINT8               conn_service;   /* connected service */
+    UINT8               peer_scn;       /* peer scn */
+    UINT8               app_id;         /* application id */
+    UINT8               role;           /* initiator/acceptor role */
+    UINT8               post_sco;       /* action to perform after sco event */
+    UINT8               call_ind;       /* CIEV call indicator value */
+    UINT8               callsetup_ind;  /* CIEV callsetup indicator value */
+    UINT8               service_ind;    /* CIEV service indicator value */
+    UINT8               signal_ind;     /* CIEV signal indicator value */
+    UINT8               roam_ind;       /* CIEV roam indicator value */
+    UINT8               battchg_ind;    /* CIEV battery charge indicator value */
+    UINT8               callheld_ind;   /* CIEV call held indicator value */
+    BOOLEAN             retry_with_sco_only; /* indicator to try with SCO only when eSCO fails */
+    UINT32              bia_masked_out; /* indicators HF does not want us to send */
+} tBTA_AG_SCB;
+
+/* type for sco data */
+typedef struct
+{
+    tBTM_ESCO_CONN_REQ_EVT_DATA  conn_data;     /* SCO data for pending conn request */
+    tBTA_AG_SCB                 *p_curr_scb;    /* SCB associated with SCO connection */
+    tBTA_AG_SCB                 *p_xfer_scb;    /* SCB associated with SCO transfer */
+    UINT16                      cur_idx;        /* SCO handle */
+    UINT8                       state;          /* SCO state variable */
+    BOOLEAN                     param_updated;  /* if params were updated to non-default */
+    tBTM_ESCO_PARAMS            params;         /* ESCO parameters */
+} tBTA_AG_SCO_CB;
+
+
+/* type for AG control block */
+typedef struct
+{
+    tBTA_AG_SCB         scb[BTA_AG_NUM_SCB];        /* service control blocks */
+    tBTA_AG_PROFILE     profile[BTA_AG_NUM_IDX];    /* profile-specific data */
+    tBTA_AG_SCO_CB      sco;                        /* SCO data */
+    tBTA_AG_CBACK       *p_cback;                   /* application callback */
+    tBTA_AG_PARSE_MODE  parse_mode;                 /* parse/pass-through mode */
+} tBTA_AG_CB;
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+
+/* constant lookup tables */
+extern const UINT16 bta_ag_uuid[BTA_AG_NUM_IDX];
+extern const UINT8 bta_ag_sec_id[BTA_AG_NUM_IDX];
+extern const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX];
+
+/* control block declaration */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_AG_CB bta_ag_cb;
+#else
+extern tBTA_AG_CB *bta_ag_cb_ptr;
+#define bta_ag_cb (*bta_ag_cb_ptr)
+#endif
+
+/* config struct */
+extern tBTA_AG_CFG *p_bta_ag_cfg;
+
+/*****************************************************************************
+**  Function prototypes
+*****************************************************************************/
+
+/* main functions */
+extern void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb);
+extern UINT16 bta_ag_scb_to_idx(tBTA_AG_SCB *p_scb);
+extern tBTA_AG_SCB *bta_ag_scb_by_idx(UINT16 idx);
+extern UINT8 bta_ag_service_to_idx(tBTA_SERVICE_MASK services);
+extern UINT16 bta_ag_idx_by_bdaddr(BD_ADDR peer_addr);
+extern BOOLEAN bta_ag_other_scb_open(tBTA_AG_SCB *p_curr_scb);
+extern tBTA_AG_SCB *bta_ag_get_other_idle_scb (tBTA_AG_SCB *p_curr_scb);
+extern void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data);
+extern BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg);
+extern void bta_ag_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id,
+                                    UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_ag_resume_open (tBTA_AG_SCB *p_scb);
+
+/* SDP functions */
+extern BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn,
+                                 tBTA_AG_FEAT features, UINT32 sdp_handle);
+extern void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* RFCOMM functions */
+extern void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services);
+extern void bta_ag_close_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services);
+extern BOOLEAN bta_ag_is_server_closed (tBTA_AG_SCB *p_scb);
+extern void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* SCO functions */
+extern BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb);
+extern BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb);
+extern void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data);
+
+/* AT command functions */
+extern void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+                                char *p_arg, INT16 int_arg);
+extern void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+                                char *p_arg, INT16 int_arg);
+extern void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg);
+extern BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb);
+extern void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result);
+
+/* Action functions */
+extern void bta_ag_register(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_deregister(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_dereg(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_int_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_acp_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_open_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_acp_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_listen(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#if (BTM_WBS_INCLUDED == TRUE )
+extern void bta_ag_sco_codec_nego(tBTA_AG_SCB *p_scb, BOOLEAN result);
+extern void bta_ag_codec_negotiate (tBTA_AG_SCB *p_scb);
+#endif
+extern void bta_ag_sco_shutdown(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_post_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_post_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#if (BTM_WBS_INCLUDED == TRUE )
+extern void bta_ag_send_bcs(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#endif
+extern void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param);
+extern void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#endif /* BTA_AG_INT_H */
diff --git a/bta/ag/bta_ag_main.c b/bta/ag/bta_ag_main.c
new file mode 100644
index 0000000..9b28067
--- /dev/null
+++ b/bta/ag/bta_ag_main.c
@@ -0,0 +1,1012 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the main implementation file for the BTA audio gateway.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "bd.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+#ifndef BTA_AG_DEBUG
+#define BTA_AG_DEBUG FALSE
+#endif
+
+#if BTA_AG_DEBUG == TRUE
+static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result);
+static char *bta_ag_state_str(UINT8 state);
+#endif
+
+/* state machine states */
+enum
+{
+    BTA_AG_INIT_ST,
+    BTA_AG_OPENING_ST,
+    BTA_AG_OPEN_ST,
+    BTA_AG_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum
+{
+    BTA_AG_REGISTER,
+    BTA_AG_DEREGISTER,
+    BTA_AG_START_OPEN,
+    BTA_AG_RFC_DO_OPEN,
+    BTA_AG_RFC_DO_CLOSE,
+    BTA_AG_START_DEREG,
+    BTA_AG_START_CLOSE,
+    BTA_AG_RFC_OPEN,
+    BTA_AG_OPEN_FAIL,
+    BTA_AG_RFC_ACP_OPEN,
+    BTA_AG_RFC_CLOSE,
+    BTA_AG_RFC_FAIL,
+    BTA_AG_RFC_DATA,
+    BTA_AG_DISC_INT_RES,
+    BTA_AG_DISC_FAIL,
+    BTA_AG_DISC_ACP_RES,
+    BTA_AG_FREE_DB,
+    BTA_AG_SCO_CONN_OPEN,
+    BTA_AG_SCO_CONN_CLOSE,
+    BTA_AG_SCO_LISTEN,
+    BTA_AG_SCO_OPEN,
+    BTA_AG_SCO_CLOSE,
+    BTA_AG_SCO_SHUTDOWN,
+    BTA_AG_POST_SCO_OPEN,
+    BTA_AG_POST_SCO_CLOSE,
+    BTA_AG_SVC_CONN_OPEN,
+    BTA_AG_RESULT,
+    BTA_AG_SETCODEC,
+    BTA_AG_SEND_RING,
+    BTA_AG_CI_SCO_DATA,
+    BTA_AG_CI_RX_DATA,
+    BTA_AG_RCVD_SLC_READY,
+    BTA_AG_NUM_ACTIONS
+};
+
+#define BTA_AG_IGNORE       BTA_AG_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_AG_ACTION)(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* action functions */
+const tBTA_AG_ACTION bta_ag_action[] =
+{
+    bta_ag_register,
+    bta_ag_deregister,
+    bta_ag_start_open,
+    bta_ag_rfc_do_open,
+    bta_ag_rfc_do_close,
+    bta_ag_start_dereg,
+    bta_ag_start_close,
+    bta_ag_rfc_open,
+    bta_ag_open_fail,
+    bta_ag_rfc_acp_open,
+    bta_ag_rfc_close,
+    bta_ag_rfc_fail,
+    bta_ag_rfc_data,
+    bta_ag_disc_int_res,
+    bta_ag_disc_fail,
+    bta_ag_disc_acp_res,
+    bta_ag_free_db,
+    bta_ag_sco_conn_open,
+    bta_ag_sco_conn_close,
+    bta_ag_sco_listen,
+    bta_ag_sco_open,
+    bta_ag_sco_close,
+    bta_ag_sco_shutdown,
+    bta_ag_post_sco_open,
+    bta_ag_post_sco_close,
+    bta_ag_svc_conn_open,
+    bta_ag_result,
+    bta_ag_setcodec,
+    bta_ag_send_ring,
+    bta_ag_ci_sco_data,
+    bta_ag_ci_rx_data,
+    bta_ag_rcvd_slc_ready
+};
+
+/* state table information */
+#define BTA_AG_ACTIONS              2       /* number of actions */
+#define BTA_AG_NEXT_STATE           2       /* position of next state */
+#define BTA_AG_NUM_COLS             3       /* number of columns in state tables */
+
+/* state table for init state */
+const UINT8 bta_ag_st_init[][BTA_AG_NUM_COLS] =
+{
+/* Event                    Action 1                Action 2                Next state */
+/* API_REGISTER_EVT */      {BTA_AG_REGISTER,       BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_DEREGISTER_EVT */    {BTA_AG_DEREGISTER,     BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_OPEN_EVT */          {BTA_AG_START_OPEN,     BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_CLOSE_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_AUDIO_OPEN_EVT */    {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_AUDIO_CLOSE_EVT */   {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_RESULT_EVT */        {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* API_SETCODEC_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_OPEN_EVT */          {BTA_AG_RFC_ACP_OPEN,   BTA_AG_SCO_LISTEN,      BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */     {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_DATA_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* SCO_OPEN_EVT */          {BTA_AG_SCO_CONN_OPEN,  BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* SCO_CLOSE_EVT */         {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* DISC_ACP_RES_EVT */      {BTA_AG_FREE_DB,        BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* DISC_INT_RES_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* DISC_OK_EVT */           {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* DISC_FAIL_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* CI_RX_WRITE_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RING_TOUT_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* SVC_TOUT_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* CI_SCO_DATA_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* CI_SLC_READY_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_INIT_ST}
+};
+
+/* state table for opening state */
+const UINT8 bta_ag_st_opening[][BTA_AG_NUM_COLS] =
+{
+/* Event                    Action 1                Action 2                Next state */
+/* API_REGISTER_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_DEREGISTER_EVT */    {BTA_AG_RFC_DO_CLOSE,   BTA_AG_START_DEREG,     BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */          {BTA_AG_OPEN_FAIL,      BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_CLOSE_EVT */         {BTA_AG_RFC_DO_CLOSE,   BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */    {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_AUDIO_CLOSE_EVT */   {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_RESULT_EVT */        {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* API_SETCODEC_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* RFC_OPEN_EVT */          {BTA_AG_RFC_OPEN,       BTA_AG_SCO_LISTEN,      BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */         {BTA_AG_RFC_FAIL,       BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */     {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* RFC_DATA_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* SCO_OPEN_EVT */          {BTA_AG_SCO_CONN_OPEN,  BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* SCO_CLOSE_EVT */         {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* DISC_ACP_RES_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* DISC_INT_RES_EVT */      {BTA_AG_DISC_INT_RES,   BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* DISC_OK_EVT */           {BTA_AG_RFC_DO_OPEN,    BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* DISC_FAIL_EVT */         {BTA_AG_DISC_FAIL,      BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* CI_RX_WRITE_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* RING_TOUT_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* SVC_TOUT_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* CI_SCO_DATA_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST},
+/* CI_SLC_READY_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPENING_ST}
+};
+
+/* state table for open state */
+const UINT8 bta_ag_st_open[][BTA_AG_NUM_COLS] =
+{
+/* Event                    Action 1                Action 2                Next state */
+/* API_REGISTER_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* API_DEREGISTER_EVT */    {BTA_AG_START_CLOSE,    BTA_AG_START_DEREG,     BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */          {BTA_AG_OPEN_FAIL,      BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* API_CLOSE_EVT */         {BTA_AG_START_CLOSE,    BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */    {BTA_AG_SCO_OPEN,       BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* API_AUDIO_CLOSE_EVT */   {BTA_AG_SCO_CLOSE,      BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* API_RESULT_EVT */        {BTA_AG_RESULT,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* API_SETCODEC_EVT */      {BTA_AG_SETCODEC,       BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* RFC_OPEN_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */         {BTA_AG_RFC_CLOSE,      BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */     {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* RFC_DATA_EVT */          {BTA_AG_RFC_DATA,       BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* SCO_OPEN_EVT */          {BTA_AG_SCO_CONN_OPEN,  BTA_AG_POST_SCO_OPEN,   BTA_AG_OPEN_ST},
+/* SCO_CLOSE_EVT */         {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE,  BTA_AG_OPEN_ST},
+/* DISC_ACP_RES_EVT */      {BTA_AG_DISC_ACP_RES,   BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* DISC_INT_RES_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* DISC_OK_EVT */           {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* DISC_FAIL_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* CI_RX_WRITE_EVT */       {BTA_AG_CI_RX_DATA,     BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* RING_TOUT_EVT */         {BTA_AG_SEND_RING,      BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* SVC_TOUT_EVT */          {BTA_AG_START_CLOSE,    BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* CI_SCO_DATA_EVT */       {BTA_AG_CI_SCO_DATA,    BTA_AG_IGNORE,          BTA_AG_OPEN_ST},
+/* CI_SLC_READY_EVT */      {BTA_AG_RCVD_SLC_READY, BTA_AG_IGNORE,          BTA_AG_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 bta_ag_st_closing[][BTA_AG_NUM_COLS] =
+{
+/* Event                    Action 1                Action 2                Next state */
+/* API_REGISTER_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_DEREGISTER_EVT */    {BTA_AG_START_DEREG,    BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */          {BTA_AG_OPEN_FAIL,      BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_CLOSE_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */    {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_AUDIO_CLOSE_EVT */   {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_RESULT_EVT */        {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* API_SETCODEC_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* RFC_OPEN_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* RFC_CLOSE_EVT */         {BTA_AG_RFC_CLOSE,      BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */     {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* RFC_DATA_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* SCO_OPEN_EVT */          {BTA_AG_SCO_CONN_OPEN,  BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* SCO_CLOSE_EVT */         {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE,  BTA_AG_CLOSING_ST},
+/* DISC_ACP_RES_EVT */      {BTA_AG_FREE_DB,        BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* DISC_INT_RES_EVT */      {BTA_AG_FREE_DB,        BTA_AG_IGNORE,          BTA_AG_INIT_ST},
+/* DISC_OK_EVT */           {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* DISC_FAIL_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* CI_RX_WRITE_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* RING_TOUT_EVT */         {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* SVC_TOUT_EVT */          {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* CI_SCO_DATA_EVT */       {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST},
+/* CI_SLC_READY_EVT */      {BTA_AG_IGNORE,         BTA_AG_IGNORE,          BTA_AG_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_AG_ST_TBL)[BTA_AG_NUM_COLS];
+
+/* state table */
+const tBTA_AG_ST_TBL bta_ag_st_tbl[] =
+{
+    bta_ag_st_init,
+    bta_ag_st_opening,
+    bta_ag_st_open,
+    bta_ag_st_closing
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* AG control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_AG_CB  bta_ag_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_timer_cback
+**
+** Description      AG timer callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_timer_cback(void *p)
+{
+    BT_HDR          *p_buf;
+    TIMER_LIST_ENT  *p_tle = (TIMER_LIST_ENT *) p;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = p_tle->event;
+        p_buf->layer_specific = bta_ag_scb_to_idx((tBTA_AG_SCB *) p_tle->param);
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_scb_alloc
+**
+** Description      Allocate an AG service control block.
+**
+**
+** Returns          pointer to the scb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+static tBTA_AG_SCB *bta_ag_scb_alloc(void)
+{
+    tBTA_AG_SCB     *p_scb = &bta_ag_cb.scb[0];
+    int             i;
+
+    for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+    {
+        if (!p_scb->in_use)
+        {
+            /* initialize variables */
+            p_scb->in_use = TRUE;
+            p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+            /* set up timers */
+            p_scb->act_timer.param = (UINT32) p_scb;
+            p_scb->act_timer.p_cback = bta_ag_timer_cback;
+
+            APPL_TRACE_DEBUG1("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb));
+            break;
+        }
+    }
+
+    if (i == BTA_AG_NUM_SCB)
+    {
+        /* out of scbs */
+        p_scb = NULL;
+        APPL_TRACE_WARNING0("Out of ag scbs");
+    }
+    return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_scb_dealloc
+**
+** Description      Deallocate a service control block.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb)
+{
+    UINT8   idx;
+    BOOLEAN allocated = FALSE;
+
+    APPL_TRACE_DEBUG1("bta_ag_scb_dealloc %d", bta_ag_scb_to_idx(p_scb));
+
+    /* stop timers */
+    bta_sys_stop_timer(&p_scb->act_timer);
+#if (BTM_WBS_INCLUDED == TRUE)
+    bta_sys_stop_timer(&p_scb->cn_timer);
+#endif
+
+    /* initialize control block */
+    memset(p_scb, 0, sizeof(tBTA_AG_SCB));
+    p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+    /* If all scbs are deallocated, callback with disable event */
+    if (!bta_sys_is_register (BTA_ID_AG))
+    {
+        for (idx = 0; idx < BTA_AG_NUM_SCB; idx++)
+        {
+            if (bta_ag_cb.scb[idx].in_use)
+            {
+                allocated = TRUE;
+                break;
+            }
+        }
+
+        if (!allocated)
+        {
+            (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+        }
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_scb_to_idx
+**
+** Description      Given a pointer to an scb, return its index.
+**
+**
+** Returns          Index of scb.
+**
+*******************************************************************************/
+UINT16 bta_ag_scb_to_idx(tBTA_AG_SCB *p_scb)
+{
+    /* use array arithmetic to determine index */
+    return ((UINT16) (p_scb - bta_ag_cb.scb)) + 1;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_scb_by_idx
+**
+** Description      Given an scb index return pointer to scb.
+**
+**
+** Returns          Pointer to scb or NULL if not allocated.
+**
+*******************************************************************************/
+tBTA_AG_SCB *bta_ag_scb_by_idx(UINT16 idx)
+{
+    tBTA_AG_SCB     *p_scb;
+
+    /* verify index */
+    if (idx > 0 && idx <= BTA_AG_NUM_SCB)
+    {
+        p_scb = &bta_ag_cb.scb[idx - 1];
+        if (!p_scb->in_use)
+        {
+            p_scb = NULL;
+            APPL_TRACE_WARNING1("ag scb idx %d not allocated", idx);
+        }
+    }
+    else
+    {
+        p_scb = NULL;
+        APPL_TRACE_DEBUG1("ag scb idx %d out of range", idx);
+    }
+    return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_service_to_idx
+**
+** Description      Given a BTA service mask convert to profile index.
+**
+**
+** Returns          Profile ndex of scb.
+**
+*******************************************************************************/
+UINT8 bta_ag_service_to_idx(tBTA_SERVICE_MASK services)
+{
+    if (services & BTA_HFP_SERVICE_MASK)
+    {
+        return BTA_AG_HFP;
+    }
+    else
+    {
+        return BTA_AG_HSP;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_idx_by_bdaddr
+**
+** Description      Find SCB associated with peer BD address.
+**
+**
+** Returns          Index of SCB or zero if none found.
+**
+*******************************************************************************/
+UINT16 bta_ag_idx_by_bdaddr(BD_ADDR peer_addr)
+{
+    tBTA_AG_SCB     *p_scb = &bta_ag_cb.scb[0];
+    UINT16          i;
+
+    if (peer_addr != NULL)
+    {
+        for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+        {
+            if (p_scb->in_use && !bdcmp(peer_addr, p_scb->peer_addr))
+            {
+                return (i + 1);
+            }
+        }
+    }
+
+    /* no scb found */
+    APPL_TRACE_WARNING0("No ag scb for peer addr");
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_other_scb_open
+**
+** Description      Check whether any other scb is in open state.
+**
+**
+** Returns          TRUE if another scb is in open state, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_other_scb_open(tBTA_AG_SCB *p_curr_scb)
+{
+    tBTA_AG_SCB     *p_scb = &bta_ag_cb.scb[0];
+    int             i;
+
+    for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+    {
+        if (p_scb->in_use && p_scb != p_curr_scb && p_scb->state == BTA_AG_OPEN_ST)
+        {
+            return TRUE;
+        }
+    }
+
+    /* no other scb found */
+    APPL_TRACE_DEBUG0("No other ag scb open");
+    return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_get_other_idle_scb
+**
+** Description      Return other scb if it is in INIT st.
+**
+**
+** Returns          Pointer to other scb if INIT st, NULL otherwise.
+**
+*******************************************************************************/
+tBTA_AG_SCB *bta_ag_get_other_idle_scb (tBTA_AG_SCB *p_curr_scb)
+{
+    tBTA_AG_SCB     *p_scb = &bta_ag_cb.scb[0];
+    UINT8   xx;
+
+    for (xx = 0; xx < BTA_AG_NUM_SCB; xx++, p_scb++)
+    {
+        if (p_scb->in_use && (p_scb != p_curr_scb) && (p_scb->state == BTA_AG_INIT_ST))
+        {
+            return p_scb;
+        }
+    }
+
+    /* no other scb found */
+    APPL_TRACE_DEBUG0("bta_ag_get_other_idle_scb: No idle AG scb");
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_colli_timer_cback
+**
+** Description      AG connection collision timer callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_colli_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+    tBTA_AG_SCB *p_scb;
+
+    APPL_TRACE_DEBUG0 ("bta_ag_colli_timer_cback");
+
+    if (p_tle)
+    {
+        p_scb = (tBTA_AG_SCB *)p_tle->param;
+
+        if (p_scb)
+        {
+            p_scb->colli_tmr_on = FALSE;
+
+            /* If the peer haven't opened AG connection     */
+            /* we will restart opening process.             */
+            bta_ag_resume_open (p_scb);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_collision_cback
+**
+** Description      Get notified about collision.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id,
+                                    UINT8 app_id, BD_ADDR peer_addr)
+{
+    UINT16  handle;
+    tBTA_AG_SCB *p_scb;
+
+    /* Check if we have opening scb for the peer device. */
+    handle = bta_ag_idx_by_bdaddr (peer_addr);
+    p_scb = bta_ag_scb_by_idx (handle);
+
+    if (p_scb && (p_scb->state == BTA_AG_OPENING_ST))
+    {
+        if (id == BTA_ID_SYS)   /* ACL collision */
+        {
+            APPL_TRACE_WARNING0 ("AG found collision (ACL) ...");
+        }
+        else if (id == BTA_ID_AG)   /* RFCOMM collision */
+        {
+            APPL_TRACE_WARNING0 ("AG found collision (RFCOMM) ...");
+        }
+        else
+        {
+            APPL_TRACE_WARNING0 ("AG found collision (\?\?\?) ...");
+        }
+
+        p_scb->state = BTA_AG_INIT_ST;
+
+        /* Cancel SDP if it had been started. */
+        if(p_scb->p_disc_db)
+        {
+            (void)SDP_CancelServiceSearch (p_scb->p_disc_db);
+            bta_ag_free_db(p_scb, NULL);
+        }
+
+        /* reopen registered servers */
+        /* Collision may be detected before or after we close servers. */
+        if (bta_ag_is_server_closed (p_scb))
+            bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+        /* Start timer to han */
+        p_scb->colli_timer.p_cback = (TIMER_CBACK*)&bta_ag_colli_timer_cback;
+        p_scb->colli_timer.param = (INT32)p_scb;
+        bta_sys_start_timer(&p_scb->colli_timer, 0, BTA_AG_COLLISION_TIMER);
+        p_scb->colli_tmr_on = TRUE;
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_resume_open
+**
+** Description      Resume opening process.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_resume_open (tBTA_AG_SCB *p_scb)
+{
+    if (p_scb)
+    {
+        APPL_TRACE_DEBUG1 ("bta_ag_resume_open, Handle(%d)", bta_ag_scb_to_idx(p_scb));
+
+        /* resume opening process.  */
+        if (p_scb->state == BTA_AG_INIT_ST)
+        {
+            p_scb->state = BTA_AG_OPENING_ST;
+            bta_ag_start_open (p_scb, NULL);
+        }
+    }
+    else
+    {
+        APPL_TRACE_ERROR0 ("bta_ag_resume_open, Null p_scb");
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_api_enable
+**
+** Description      Handle an API enable event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_api_enable(tBTA_AG_DATA *p_data)
+{
+    /* initialize control block */
+    memset(&bta_ag_cb, 0, sizeof(tBTA_AG_CB));
+
+    /* store callback function */
+    bta_ag_cb.p_cback = p_data->api_enable.p_cback;
+    bta_ag_cb.parse_mode = p_data->api_enable.parse_mode;
+
+    /* call init call-out */
+    bta_ag_co_init();
+
+    bta_sys_collision_register (BTA_ID_AG, bta_ag_collision_cback);
+
+    /* call callback with enable event */
+    (*bta_ag_cb.p_cback)(BTA_AG_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_api_disable
+**
+** Description      Handle an API disable event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_api_disable(tBTA_AG_DATA *p_data)
+{
+    /* deregister all scbs in use */
+    tBTA_AG_SCB     *p_scb = &bta_ag_cb.scb[0];
+    BOOLEAN         do_dereg = FALSE;
+    int             i;
+
+    if (!bta_sys_is_register (BTA_ID_AG))
+    {
+        APPL_TRACE_ERROR0("BTA AG is already disabled, ignoring ...");
+        return;
+    }
+
+    /* De-register with BTA system manager */
+    GKI_sched_lock();
+    bta_sys_deregister(BTA_ID_AG);
+    GKI_sched_unlock();
+
+    for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++)
+    {
+        if (p_scb->in_use)
+        {
+            bta_ag_sm_execute(p_scb, BTA_AG_API_DEREGISTER_EVT, p_data);
+            do_dereg = TRUE;
+        }
+    }
+
+    if (!do_dereg)
+    {
+        /* Done, send callback evt to app */
+        (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+    }
+
+    bta_sys_collision_register (BTA_ID_AG, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_api_register
+**
+** Description      Handle an API event registers a new service.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_api_register(tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_SCB     *p_scb;
+    tBTA_AG_REGISTER reg;
+
+    /* allocate an scb */
+    if ((p_scb = bta_ag_scb_alloc()) != NULL)
+    {
+        bta_ag_sm_execute(p_scb, p_data->hdr.event, p_data);
+    }
+    else
+    {
+        reg.status = BTA_AG_FAIL_RESOURCES;
+        (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG *) &reg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_api_result
+**
+** Description      Handle an API result event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_api_result(tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_SCB     *p_scb;
+    int             i;
+
+    if (p_data->hdr.layer_specific != BTA_AG_HANDLE_ALL)
+    {
+        if ((p_scb = bta_ag_scb_by_idx(p_data->hdr.layer_specific)) != NULL)
+        {
+            bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+        }
+    }
+    else
+    {
+        for (i = 0, p_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, p_scb++)
+        {
+            if (p_scb->in_use)
+            {
+                bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sm_execute
+**
+** Description      State machine event handling function for AG
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_ST_TBL      state_table;
+    UINT8               action;
+    int                 i;
+
+#if BTA_AG_DEBUG == TRUE
+    UINT16  in_event = event;
+    UINT8   in_state = p_scb->state;
+
+    /* Ignore displaying of AT results when not connected (Ignored in state machine) */
+    if (in_event != BTA_AG_API_RESULT_EVT || p_scb->state == BTA_AG_OPEN_ST)
+    {
+        APPL_TRACE_EVENT5("AG evt (hdl 0x%04x): State %d (%s), Event 0x%04x (%s)",
+                           bta_ag_scb_to_idx(p_scb),
+                           p_scb->state, bta_ag_state_str(p_scb->state),
+                           event, bta_ag_evt_str(event, p_data->api_result.result));
+    }
+#else
+    APPL_TRACE_EVENT3("AG evt (hdl 0x%04x): State %d, Event 0x%04x",
+                      bta_ag_scb_to_idx(p_scb), p_scb->state, event);
+#endif
+
+    event &= 0x00FF;
+    if (event >= (BTA_AG_MAX_EVT & 0x00FF))
+    {
+        APPL_TRACE_ERROR0("AG evt out of range, ignoring...");
+        return;
+    }
+
+    /* look up the state table for the current state */
+    state_table = bta_ag_st_tbl[p_scb->state];
+
+    /* set next state */
+    p_scb->state = state_table[event][BTA_AG_NEXT_STATE];
+
+    /* execute action functions */
+    for (i = 0; i < BTA_AG_ACTIONS; i++)
+    {
+        if ((action = state_table[event][i]) != BTA_AG_IGNORE)
+        {
+            (*bta_ag_action[action])(p_scb, p_data);
+        }
+        else
+        {
+            break;
+        }
+    }
+#if BTA_AG_DEBUG == TRUE
+    if (p_scb->state != in_state)
+    {
+        APPL_TRACE_EVENT3("BTA AG State Change: [%s] -> [%s] after Event [%s]",
+                      bta_ag_state_str(in_state),
+                      bta_ag_state_str(p_scb->state),
+                      bta_ag_evt_str(in_event, p_data->api_result.result));
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_hdl_event
+**
+** Description      Data gateway main event handling function.
+**
+**
+** Returns          BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg)
+{
+    tBTA_AG_SCB *p_scb;
+
+    switch (p_msg->event)
+    {
+        /* handle enable event */
+        case BTA_AG_API_ENABLE_EVT:
+            bta_ag_api_enable((tBTA_AG_DATA *) p_msg);
+            break;
+
+        /* handle disable event */
+        case BTA_AG_API_DISABLE_EVT:
+            bta_ag_api_disable((tBTA_AG_DATA *) p_msg);
+            break;
+
+        /* handle register event */
+        case BTA_AG_API_REGISTER_EVT:
+            bta_ag_api_register((tBTA_AG_DATA *) p_msg);
+            break;
+
+        /* handle result event */
+        case BTA_AG_API_RESULT_EVT:
+            bta_ag_api_result((tBTA_AG_DATA *) p_msg);
+            break;
+
+        /* all others reference scb by handle */
+        default:
+            if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL)
+            {
+                bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA *) p_msg);
+            }
+            break;
+    }
+    return TRUE;
+}
+
+#if BTA_AG_DEBUG == TRUE
+static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result)
+{
+    switch (event)
+    {
+    case BTA_AG_API_REGISTER_EVT:
+        return "Register Request";
+    case BTA_AG_API_DEREGISTER_EVT:
+        return "Deregister Request";
+    case BTA_AG_API_OPEN_EVT:
+        return "Open SLC Request";
+    case BTA_AG_API_CLOSE_EVT:
+        return "Close SLC Request";
+    case BTA_AG_API_AUDIO_OPEN_EVT:
+        return "Open Audio Request";
+    case BTA_AG_API_AUDIO_CLOSE_EVT:
+        return "Close Audio Request";
+    case BTA_AG_API_RESULT_EVT:
+        switch (result)
+        {
+        case BTA_AG_SPK_RES:            return ("AT Result  BTA_AG_SPK_RES");
+        case BTA_AG_MIC_RES:            return ("AT Result  BTA_AG_MIC_RES");
+        case BTA_AG_INBAND_RING_RES:    return ("AT Result  BTA_AG_INBAND_RING_RES");
+        case BTA_AG_CIND_RES:           return ("AT Result  BTA_AG_CIND_RES");
+        case BTA_AG_BINP_RES:           return ("AT Result  BTA_AG_BINP_RES");
+        case BTA_AG_IND_RES:            return ("AT Result  BTA_AG_IND_RES");
+        case BTA_AG_BVRA_RES:           return ("AT Result  BTA_AG_BVRA_RES");
+        case BTA_AG_CNUM_RES:           return ("AT Result  BTA_AG_CNUM_RES");
+        case BTA_AG_BTRH_RES:           return ("AT Result  BTA_AG_BTRH_RES");
+        case BTA_AG_CLCC_RES:           return ("AT Result  BTA_AG_CLCC_RES");
+        case BTA_AG_COPS_RES:           return ("AT Result  BTA_AG_COPS_RES");
+        case BTA_AG_IN_CALL_RES:        return ("AT Result  BTA_AG_IN_CALL_RES");
+        case BTA_AG_IN_CALL_CONN_RES:   return ("AT Result  BTA_AG_IN_CALL_CONN_RES");
+        case BTA_AG_CALL_WAIT_RES:      return ("AT Result  BTA_AG_CALL_WAIT_RES");
+        case BTA_AG_OUT_CALL_ORIG_RES:  return ("AT Result  BTA_AG_OUT_CALL_ORIG_RES");
+        case BTA_AG_OUT_CALL_ALERT_RES: return ("AT Result  BTA_AG_OUT_CALL_ALERT_RES");
+        case BTA_AG_OUT_CALL_CONN_RES:  return ("AT Result  BTA_AG_OUT_CALL_CONN_RES");
+        case BTA_AG_CALL_CANCEL_RES:    return ("AT Result  BTA_AG_CALL_CANCEL_RES");
+        case BTA_AG_END_CALL_RES:       return ("AT Result  BTA_AG_END_CALL_RES");
+        case BTA_AG_UNAT_RES:           return ("AT Result  BTA_AG_UNAT_RES");
+        default:                        return ("Unknown AG Result");
+        }
+    case BTA_AG_API_SETCODEC_EVT:
+        return "Set Codec Request";
+    case BTA_AG_RFC_OPEN_EVT:
+        return "RFC Opened";
+    case BTA_AG_RFC_CLOSE_EVT:
+        return "RFC Closed";
+    case BTA_AG_RFC_SRV_CLOSE_EVT:
+        return "RFC SRV Closed";
+    case BTA_AG_RFC_DATA_EVT:
+        return "RFC Data";
+    case BTA_AG_SCO_OPEN_EVT:
+        return "Audio Opened";
+    case BTA_AG_SCO_CLOSE_EVT:
+        return "Audio Closed";
+    case BTA_AG_DISC_ACP_RES_EVT:
+        return "Discovery ACP Result";
+    case BTA_AG_DISC_INT_RES_EVT:
+        return "Discovery INT Result";
+    case BTA_AG_DISC_OK_EVT:
+        return "Discovery OK";
+    case BTA_AG_DISC_FAIL_EVT:
+        return "Discovery Failed";
+    case BTA_AG_CI_RX_WRITE_EVT:
+        return "CI RX Write";
+    case BTA_AG_RING_TOUT_EVT:
+        return "Ring Timeout";
+    case BTA_AG_SVC_TOUT_EVT:
+        return "Service Timeout";
+    case BTA_AG_API_ENABLE_EVT:
+        return "Enable AG";
+    case BTA_AG_API_DISABLE_EVT:
+        return "Disable AG";
+    case BTA_AG_CI_SCO_DATA_EVT:
+        return "SCO data Callin";
+    case BTA_AG_CI_SLC_READY_EVT:
+        return "SLC Ready Callin";
+    default:
+        return "Unknown AG Event";
+    }
+}
+
+static char *bta_ag_state_str(UINT8 state)
+{
+    switch (state)
+    {
+    case BTA_AG_INIT_ST:
+        return "Initial";
+    case BTA_AG_OPENING_ST:
+        return "Opening";
+    case BTA_AG_OPEN_ST:
+        return "Open";
+    case BTA_AG_CLOSING_ST:
+        return "Closing";
+    default:
+        return "Unknown AG State";
+    }
+}
+
+#endif
diff --git a/bta/ag/bta_ag_rfc.c b/bta/ag/bta_ag_rfc.c
new file mode 100644
index 0000000..3575020
--- /dev/null
+++ b/bta/ag/bta_ag_rfc.c
@@ -0,0 +1,441 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains the audio gateway functions controlling the RFCOMM
+ *  connections.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_ag_co.h"
+#include "btm_api.h"
+#include "port_api.h"
+#include "rfcdefs.h"
+#include "gki.h"
+#include "bd.h"
+
+/* Event mask for RfCOMM port callback */
+#define BTA_AG_PORT_EV_MASK         PORT_EV_RXCHAR
+
+/* each scb has its own rfcomm callbacks */
+void bta_ag_port_cback_1(UINT32 code, UINT16 port_handle);
+void bta_ag_port_cback_2(UINT32 code, UINT16 port_handle);
+void bta_ag_port_cback_3(UINT32 code, UINT16 port_handle);
+
+void bta_ag_mgmt_cback_1(UINT32 code, UINT16 port_handle);
+void bta_ag_mgmt_cback_2(UINT32 code, UINT16 port_handle);
+void bta_ag_mgmt_cback_3(UINT32 code, UINT16 port_handle);
+
+int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len);
+int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len);
+int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len);
+
+/* rfcomm callback function tables */
+typedef tPORT_CALLBACK *tBTA_AG_PORT_CBACK;
+const tBTA_AG_PORT_CBACK bta_ag_port_cback_tbl[] =
+{
+    bta_ag_port_cback_1,
+    bta_ag_port_cback_2,
+    bta_ag_port_cback_3
+};
+
+const tBTA_AG_PORT_CBACK bta_ag_mgmt_cback_tbl[] =
+{
+    bta_ag_mgmt_cback_1,
+    bta_ag_mgmt_cback_2,
+    bta_ag_mgmt_cback_3
+};
+
+typedef tPORT_DATA_CALLBACK *tBTA_AG_DATA_CBACK;
+const tBTA_AG_DATA_CBACK bta_ag_data_cback_tbl[] =
+{
+    bta_ag_data_cback_1,
+    bta_ag_data_cback_2,
+    bta_ag_data_cback_3
+};
+
+/*******************************************************************************
+**
+** Function         bta_ag_port_cback
+**
+** Description      RFCOMM Port callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_port_cback(UINT32 code, UINT16 port_handle, UINT16 handle)
+{
+    BT_HDR      *p_buf;
+    tBTA_AG_SCB *p_scb;
+
+    if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL)
+    {
+        /* ignore port events for port handles other than connected handle */
+        if (port_handle != p_scb->conn_handle)
+        {
+            APPL_TRACE_DEBUG3("ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d",
+                              port_handle, p_scb->conn_handle, handle);
+            return;
+        }
+
+        if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+        {
+            p_buf->event = BTA_AG_RFC_DATA_EVT;
+            p_buf->layer_specific = handle;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_mgmt_cback
+**
+** Description      RFCOMM management callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_mgmt_cback(UINT32 code, UINT16 port_handle, UINT16 handle)
+{
+    tBTA_AG_RFC     *p_buf;
+    tBTA_AG_SCB     *p_scb;
+    UINT16          event;
+    UINT8           i;
+    BOOLEAN         found_handle = FALSE;
+
+    APPL_TRACE_DEBUG3("ag_mgmt_cback : code = %d, port_handle = %d, handle = %d",
+                        code, port_handle, handle);
+
+    if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL)
+    {
+        /* ignore close event for port handles other than connected handle */
+        if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle))
+        {
+            APPL_TRACE_DEBUG1("ag_mgmt_cback ignoring handle:%d", port_handle);
+            return;
+        }
+
+        if (code == PORT_SUCCESS)
+        {
+            if (p_scb->conn_handle)     /* Outgoing connection */
+            {
+                if (port_handle == p_scb->conn_handle)
+                    found_handle = TRUE;
+            }
+            else                        /* Incoming connection */
+            {
+                for (i = 0; i < BTA_AG_NUM_IDX; i++)
+                {
+                    if (port_handle == p_scb->serv_handle[i])
+                        found_handle = TRUE;
+                }
+            }
+
+            if (!found_handle)
+            {
+                APPL_TRACE_ERROR1 ("bta_ag_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle);
+                return;
+            }
+
+            event = BTA_AG_RFC_OPEN_EVT;
+        }
+        /* distinguish server close events */
+        else if (port_handle == p_scb->conn_handle)
+        {
+            event = BTA_AG_RFC_CLOSE_EVT;
+        }
+        else
+        {
+            event = BTA_AG_RFC_SRV_CLOSE_EVT;
+        }
+
+        if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL)
+        {
+            p_buf->hdr.event = event;
+            p_buf->hdr.layer_specific = handle;
+            p_buf->port_handle = port_handle;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_data_cback
+**
+** Description      RFCOMM data callback
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static int bta_ag_data_cback(UINT16 port_handle, void *p_data, UINT16 len, UINT16 handle)
+{
+    /* call data call-out directly */
+    bta_ag_co_tx_write(handle, (UINT8 *) p_data, len);
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_port_cback_1 to 3
+**                  bta_ag_mgmt_cback_1 to 3
+**
+** Description      RFCOMM callback functions.  This is an easy way to
+**                  distinguish scb from the callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_mgmt_cback_1(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 1);}
+void bta_ag_mgmt_cback_2(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 2);}
+void bta_ag_mgmt_cback_3(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 3);}
+void bta_ag_port_cback_1(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 1);}
+void bta_ag_port_cback_2(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 2);}
+void bta_ag_port_cback_3(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 3);}
+
+/*******************************************************************************
+**
+** Function         bta_ag_data_cback_1 to 3
+**
+** Description      RFCOMM data callback functions.  This is an easy way to
+**                  distinguish scb from the callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len)
+{
+    return bta_ag_data_cback(port_handle, p_data, len, 1);
+}
+int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len)
+{
+    return bta_ag_data_cback(port_handle, p_data, len, 2);
+}
+int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len)
+{
+    return bta_ag_data_cback(port_handle, p_data, len, 3);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_setup_port
+**
+** Description      Setup RFCOMM port for use by AG.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_setup_port(tBTA_AG_SCB *p_scb, UINT16 handle)
+{
+    UINT16 i = bta_ag_scb_to_idx(p_scb) - 1;
+
+    /* set up data callback if using pass through mode */
+    if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH)
+    {
+        PORT_SetDataCallback(handle, bta_ag_data_cback_tbl[i]);
+    }
+
+    PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK);
+    PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[i]);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_start_servers
+**
+** Description      Setup RFCOMM servers for use by AG.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services)
+{
+    int i;
+    int bta_ag_port_status;
+
+    services >>= BTA_HSP_SERVICE_ID;
+    for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1)
+    {
+        /* if service is set in mask */
+        if (services & 1)
+        {
+            BTM_SetSecurityLevel(FALSE, "", bta_ag_sec_id[i], p_scb->serv_sec_mask,
+                BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_ag_cb.profile[i].scn);
+
+            bta_ag_port_status =  RFCOMM_CreateConnection(bta_ag_uuid[i], bta_ag_cb.profile[i].scn,
+                TRUE, BTA_AG_MTU, (UINT8 *) bd_addr_any, &(p_scb->serv_handle[i]),
+                bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+
+            if( bta_ag_port_status  == PORT_SUCCESS )
+            {
+                bta_ag_setup_port(p_scb, p_scb->serv_handle[i]);
+            }
+            else
+            {
+                /* TODO: CR#137125 to handle to error properly */
+                APPL_TRACE_DEBUG1("bta_ag_start_servers: RFCOMM_CreateConnection returned error:%d", bta_ag_port_status);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_close_servers
+**
+** Description      Close RFCOMM servers port for use by AG.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_close_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services)
+{
+    int i;
+
+    services >>= BTA_HSP_SERVICE_ID;
+    for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1)
+    {
+        /* if service is set in mask */
+        if (services & 1)
+        {
+            RFCOMM_RemoveServer(p_scb->serv_handle[i]);
+            p_scb->serv_handle[i] = 0;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_is_server_closed
+**
+** Description      Returns TRUE if all servers are closed.
+**
+**
+** Returns          TRUE if all servers are closed, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN bta_ag_is_server_closed (tBTA_AG_SCB *p_scb)
+{
+    UINT8 xx;
+    BOOLEAN is_closed = TRUE;
+
+    for (xx = 0; xx < BTA_AG_NUM_IDX; xx++)
+    {
+        if (p_scb->serv_handle[xx] != 0)
+            is_closed = FALSE;
+    }
+
+    return is_closed;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_do_open
+**
+** Description      Open an RFCOMM connection to the peer device.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    BTM_SetSecurityLevel(TRUE, "", bta_ag_sec_id[p_scb->conn_service],
+        p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, p_scb->peer_scn);
+
+    if (RFCOMM_CreateConnection(bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn,
+            FALSE, BTA_AG_MTU, p_scb->peer_addr, &(p_scb->conn_handle),
+            bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) == PORT_SUCCESS)
+    {
+        bta_ag_setup_port(p_scb, p_scb->conn_handle);
+        APPL_TRACE_DEBUG1("bta_ag_rfc_do_open : conn_handle = %d", p_scb->conn_handle);
+    }
+    /* RFCOMM create connection failed; send ourselves RFCOMM close event */
+    else
+    {
+        bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_rfc_do_close
+**
+** Description      Close RFCOMM connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_RFC     *p_buf;
+
+    if (p_scb->conn_handle)
+    {
+        RFCOMM_RemoveConnection(p_scb->conn_handle);
+    }
+    else
+    {
+        /* Close API was called while AG is in Opening state.               */
+        /* Need to trigger the state machine to send callback to the app    */
+        /* and move back to INIT state.                                     */
+        if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL)
+        {
+            p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT;
+            p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb);
+            bta_sys_sendmsg(p_buf);
+        }
+
+        /* Cancel SDP if it had been started. */
+        /*
+        if(p_scb->p_disc_db)
+        {
+            (void)SDP_CancelServiceSearch (p_scb->p_disc_db);
+        }
+        */
+    }
+
+#ifdef _WIN32_WCE
+    {
+        /* Windows versions of RFCOMM does NOT generate a closed callback when we close */
+        tPORT_CALLBACK *rfc_mgmt_cback = bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1];
+
+        if (rfc_mgmt_cback)
+        {
+            (rfc_mgmt_cback)(PORT_CLOSED, p_scb->conn_handle);
+        }
+    }
+#endif
+}
+
diff --git a/bta/ag/bta_ag_sco.c b/bta/ag/bta_ag_sco.c
new file mode 100644
index 0000000..0c811b4
--- /dev/null
+++ b/bta/ag/bta_ag_sco.c
@@ -0,0 +1,1662 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains functions for managing the SCO connection used in AG.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+#include "bta_dm_co.h"
+#endif
+#include "bta_ag_int.h"
+#include "btm_api.h"
+#include "gki.h"
+
+#ifndef BTA_AG_SCO_DEBUG
+#define BTA_AG_SCO_DEBUG FALSE
+#endif
+
+#ifndef BTA_AG_CODEC_NEGO_TIMEOUT
+#define BTA_AG_CODEC_NEGO_TIMEOUT   3000
+#endif
+
+#if BTA_AG_SCO_DEBUG == TRUE
+static char *bta_ag_sco_evt_str(UINT8 event);
+static char *bta_ag_sco_state_str(UINT8 state);
+#endif
+
+#define BTA_AG_NO_EDR_ESCO  (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | \
+                             BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
+                             BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
+                             BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+
+/* sco events */
+enum
+{
+    BTA_AG_SCO_LISTEN_E,        /* listen request */
+    BTA_AG_SCO_OPEN_E,          /* open request */
+    BTA_AG_SCO_XFER_E,          /* transfer request */
+#if (BTM_WBS_INCLUDED == TRUE )
+    BTA_AG_SCO_CN_DONE_E,       /* codec negotiation done */
+    BTA_AG_SCO_REOPEN_E,        /* Retry with other codec when failed */
+#endif
+    BTA_AG_SCO_CLOSE_E,         /* close request */
+    BTA_AG_SCO_SHUTDOWN_E,      /* shutdown request */
+    BTA_AG_SCO_CONN_OPEN_E,     /* sco open */
+    BTA_AG_SCO_CONN_CLOSE_E,    /* sco closed */
+    BTA_AG_SCO_CI_DATA_E        /* SCO data ready */
+};
+
+#if (BTM_WBS_INCLUDED == TRUE )
+#define BTA_AG_NUM_CODECS   2
+static const tBTM_ESCO_PARAMS bta_ag_esco_params[BTA_AG_NUM_CODECS] =
+{
+    /* CVSD */
+    {
+        BTM_64KBITS_RATE,                   /* TX Bandwidth (64 kbits/sec)              */
+        BTM_64KBITS_RATE,                   /* RX Bandwidth (64 kbits/sec)              */
+        0x000a,                             /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3)  */
+        BTM_VOICE_SETTING_CVSD,             /* Inp Linear, Air CVSD, 2s Comp, 16bit     */
+       (BTM_SCO_PKT_TYPES_MASK_HV1      +  /* Packet Types                             */
+        BTM_SCO_PKT_TYPES_MASK_HV2      +
+        BTM_SCO_PKT_TYPES_MASK_HV3      +
+        BTM_SCO_PKT_TYPES_MASK_EV3      +
+        BTM_SCO_PKT_TYPES_MASK_EV4      +
+        BTM_SCO_PKT_TYPES_MASK_EV5      +
+        BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
+        BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+        BTM_ESCO_RETRANS_POWER       /* Retransmission effort                      */
+    },
+    /* mSBC */
+    {
+        BTM_64KBITS_RATE,                   /* TX Bandwidth (64 kbits/sec), 8000        */
+        BTM_64KBITS_RATE,                   /* RX Bandwidth (64 kbits/sec), 8000        */
+        13,                                 /* 13 ms                                    */
+        BTM_VOICE_SETTING_TRANS,            /* Inp Linear, Transparent, 2s Comp, 16bit  */
+       (BTM_SCO_PKT_TYPES_MASK_EV3      |   /* Packet Types : EV3 + 2-EV3               */
+        BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+        BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+        BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+        BTM_ESCO_RETRANS_QUALITY       /* Retransmission effort                      */
+    }
+};
+#else
+static const tBTM_ESCO_PARAMS bta_ag_esco_params =
+{
+    BTM_64KBITS_RATE,                   /* TX Bandwidth (64 kbits/sec)              */
+    BTM_64KBITS_RATE,                   /* RX Bandwidth (64 kbits/sec)              */
+    0x000a,                             /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3)  */
+    0x0060,                             /* Inp Linear, Air CVSD, 2s Comp, 16bit     */
+    (BTM_SCO_PKT_TYPES_MASK_HV1      +  /* Packet Types                             */
+     BTM_SCO_PKT_TYPES_MASK_HV2      +
+     BTM_SCO_PKT_TYPES_MASK_HV3      +
+     BTM_SCO_PKT_TYPES_MASK_EV3      +
+     BTM_SCO_PKT_TYPES_MASK_EV4      +
+     BTM_SCO_PKT_TYPES_MASK_EV5      +
+     BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
+     BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+     BTM_ESCO_RETRANS_POWER       /* Retransmission effort                      */
+};
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_conn_cback
+**
+** Description      BTM SCO connection callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_sco_conn_cback(UINT16 sco_idx)
+{
+    UINT16  handle;
+    BT_HDR  *p_buf;
+    tBTA_AG_SCB *p_scb;
+
+    /* match callback to scb; first check current sco scb */
+    if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use)
+    {
+        handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+    }
+    /* then check for scb connected to this peer */
+    else
+    {
+        /* Check if SLC is up */
+        handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_idx));
+        p_scb = bta_ag_scb_by_idx(handle);
+        if(p_scb && !p_scb->svc_conn)
+            handle = 0;
+    }
+
+    if (handle != 0)
+    {
+        if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+        {
+            p_buf->event = BTA_AG_SCO_OPEN_EVT;
+            p_buf->layer_specific = handle;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+    /* no match found; disconnect sco, init sco variables */
+    else
+    {
+        bta_ag_cb.sco.p_curr_scb = NULL;
+        bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+        BTM_RemoveSco(sco_idx);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_disc_cback
+**
+** Description      BTM SCO disconnection callback.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_sco_disc_cback(UINT16 sco_idx)
+{
+    BT_HDR  *p_buf;
+    UINT16  handle = 0;
+
+    APPL_TRACE_DEBUG3 ("bta_ag_sco_disc_cback(): sco_idx: 0x%x  p_cur_scb: 0x%08x  sco.state: %d", sco_idx, bta_ag_cb.sco.p_curr_scb, bta_ag_cb.sco.state);
+
+    APPL_TRACE_DEBUG4 ("bta_ag_sco_disc_cback(): scb[0] addr: 0x%08x  in_use: %u  sco_idx: 0x%x  sco state: %u",
+                       &bta_ag_cb.scb[0], bta_ag_cb.scb[0].in_use, bta_ag_cb.scb[0].sco_idx, bta_ag_cb.scb[0].state);
+    APPL_TRACE_DEBUG4 ("bta_ag_sco_disc_cback(): scb[1] addr: 0x%08x  in_use: %u  sco_idx: 0x%x  sco state: %u",
+                       &bta_ag_cb.scb[1], bta_ag_cb.scb[1].in_use, bta_ag_cb.scb[1].sco_idx, bta_ag_cb.scb[1].state);
+
+    /* match callback to scb */
+    if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use)
+    {
+        /* We only care about callbacks for the active SCO */
+        if (bta_ag_cb.sco.p_curr_scb->sco_idx != sco_idx)
+        {
+            if (bta_ag_cb.sco.p_curr_scb->sco_idx != 0xFFFF)
+                return;
+        }
+        handle  = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+    }
+
+    if (handle != 0)
+    {
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+        tBTM_STATUS status = BTM_ConfigScoPath(BTM_SCO_ROUTE_PCM, NULL, NULL, TRUE);
+        APPL_TRACE_DEBUG1("bta_ag_sco_disc_cback sco close config status = %d", status);
+	    /* SCO clean up here */
+        bta_dm_sco_co_close();
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE )
+        /* Restore settings */
+        if(bta_ag_cb.sco.p_curr_scb->inuse_codec == BTA_AG_CODEC_MSBC)
+        {
+            BTM_SetWBSCodec (BTM_SCO_CODEC_NONE);
+            BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD);
+
+            /* If SCO open was initiated by AG and failed for mSBC, try CVSD again. */
+            if (bta_ag_sco_is_opening (bta_ag_cb.sco.p_curr_scb))
+            {
+                bta_ag_cb.sco.p_curr_scb->codec_fallback = TRUE;
+                APPL_TRACE_DEBUG0("Fallback to CVSD");
+            }
+        }
+
+        bta_ag_cb.sco.p_curr_scb->inuse_codec = BTA_AG_CODEC_NONE;
+#endif
+
+        if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+        {
+            p_buf->event = BTA_AG_SCO_CLOSE_EVT;
+            p_buf->layer_specific = handle;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+    /* no match found */
+    else
+    {
+        APPL_TRACE_DEBUG0("no scb for ag_sco_disc_cback");
+
+        /* sco could be closed after scb dealloc'ed */
+        if (bta_ag_cb.sco.p_curr_scb != NULL)
+        {
+            bta_ag_cb.sco.p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+            bta_ag_cb.sco.p_curr_scb = NULL;
+            bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+        }
+    }
+}
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function         bta_ag_sco_read_cback
+**
+** Description      Callback function is the callback function for incoming
+**                  SCO data over HCI.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_sco_read_cback (UINT16 sco_inx, BT_HDR *p_data, tBTM_SCO_DATA_FLAG status)
+{
+    if (status != BTM_SCO_DATA_CORRECT)
+    {
+        APPL_TRACE_DEBUG1("bta_ag_sco_read_cback: status(%d)", status);
+    }
+
+    /* Callout function must free the data. */
+    bta_dm_sco_co_in_data (p_data, status);
+}
+#endif
+/*******************************************************************************
+**
+** Function         bta_ag_remove_sco
+**
+** Description      Removes the specified SCO from the system.
+**                  If only_active is TRUE, then SCO is only removed if connected
+**
+** Returns          BOOLEAN   - TRUE if Sco removal was started
+**
+*******************************************************************************/
+static BOOLEAN bta_ag_remove_sco(tBTA_AG_SCB *p_scb, BOOLEAN only_active)
+{
+    BOOLEAN     removed_started = FALSE;
+    tBTM_STATUS	status;
+
+    if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+    {
+        if (!only_active || p_scb->sco_idx == bta_ag_cb.sco.cur_idx)
+        {
+            status = BTM_RemoveSco(p_scb->sco_idx);
+
+            APPL_TRACE_DEBUG2("ag remove sco: inx 0x%04x, status:0x%x", p_scb->sco_idx, status);
+
+            if (status == BTM_CMD_STARTED)
+            {
+                /* Sco is connected; set current control block */
+                bta_ag_cb.sco.p_curr_scb = p_scb;
+
+                removed_started = TRUE;
+            }
+            /* If no connection reset the sco handle */
+            else if ( (status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR) )
+            {
+                p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+            }
+        }
+    }
+    return removed_started;
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_ag_esco_connreq_cback
+**
+** Description      BTM eSCO connection requests and eSCO change requests
+**                  Only the connection requests are processed by BTA.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data)
+{
+    tBTA_AG_SCB         *p_scb;
+    UINT16               handle;
+    UINT16               sco_inx = p_data->conn_evt.sco_inx;
+
+    /* Only process connection requests */
+    if (event == BTM_ESCO_CONN_REQ_EVT)
+    {
+        if ((handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_inx))) != 0 &&
+            ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) && p_scb->svc_conn)
+        {
+            p_scb->sco_idx = sco_inx;
+
+            /* If no other SCO active, allow this one */
+            if (!bta_ag_cb.sco.p_curr_scb)
+            {
+                APPL_TRACE_EVENT1("bta_ag_esco_connreq_cback: Accept Conn Request (sco_inx 0x%04x)", sco_inx);
+                bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+
+                bta_ag_cb.sco.state = BTA_AG_SCO_OPENING_ST;
+                bta_ag_cb.sco.p_curr_scb = p_scb;
+                bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+            }
+            else    /* Begin a transfer: Close current SCO before responding */
+            {
+                APPL_TRACE_DEBUG0("bta_ag_esco_connreq_cback: Begin XFER");
+                bta_ag_cb.sco.p_xfer_scb = p_scb;
+                bta_ag_cb.sco.conn_data = p_data->conn_evt;
+                bta_ag_cb.sco.state = BTA_AG_SCO_OPEN_XFER_ST;
+
+                if (!bta_ag_remove_sco(bta_ag_cb.sco.p_curr_scb, TRUE))
+                {
+                    APPL_TRACE_ERROR1("bta_ag_esco_connreq_cback: Nothing to remove so accept Conn Request (sco_inx 0x%04x)", sco_inx);
+                    bta_ag_cb.sco.p_xfer_scb = NULL;
+                    bta_ag_cb.sco.state = BTA_AG_SCO_LISTEN_ST;
+
+                    bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+                }
+            }
+        }
+        /* If error occurred send reject response immediately */
+        else
+        {
+            APPL_TRACE_WARNING0("no scb for bta_ag_esco_connreq_cback or no resources");
+            BTM_EScoConnRsp(p_data->conn_evt.sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, NULL);
+        }
+    }
+    /* Received a change in the esco link */
+    else if (event == BTM_ESCO_CHG_EVT)
+    {
+        APPL_TRACE_EVENT5("eSCO change event (inx %d): rtrans %d, rxlen %d, txlen %d, txint %d",
+            p_data->chg_evt.sco_inx,
+            p_data->chg_evt.retrans_window, p_data->chg_evt.rx_pkt_len,
+            p_data->chg_evt.tx_pkt_len, p_data->chg_evt.tx_interval);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_cback_sco
+**
+** Description      Call application callback function with SCO event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_cback_sco(tBTA_AG_SCB *p_scb, UINT8 event)
+{
+    tBTA_AG_HDR    sco;
+
+    sco.handle = bta_ag_scb_to_idx(p_scb);
+    sco.app_id = p_scb->app_id;
+
+    /* call close cback */
+    (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &sco);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_create_sco
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_create_sco(tBTA_AG_SCB *p_scb, BOOLEAN is_orig)
+{
+    tBTM_STATUS       status;
+    UINT8            *p_bd_addr = NULL;
+    tBTM_ESCO_PARAMS params;
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_PEER_CODEC  esco_codec = BTM_SCO_CODEC_CVSD;
+    int codec_index = 0;
+#endif
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    tBTM_SCO_ROUTE_TYPE sco_route;
+    tBTA_CODEC_INFO     codec_info = {BTA_SCO_CODEC_PCM};
+    UINT32              pcm_sample_rate;
+#endif
+
+    /* Make sure this sco handle is not already in use */
+    if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+    {
+        APPL_TRACE_WARNING1("bta_ag_create_sco: Index 0x%04x Already In Use!",
+                             p_scb->sco_idx);
+        return;
+    }
+
+#if (BTM_WBS_INCLUDED == TRUE )
+    if ((p_scb->sco_codec == BTM_SCO_CODEC_MSBC) &&
+        !p_scb->codec_fallback &&
+        !p_scb->retry_with_sco_only)
+        esco_codec = BTM_SCO_CODEC_MSBC;
+
+    if (p_scb->codec_fallback)
+    {
+        p_scb->codec_fallback = FALSE;
+
+        /* Force AG to send +BCS for the next audio connection. */
+        p_scb->codec_updated = TRUE;
+    }
+
+    if (esco_codec == BTM_SCO_CODEC_MSBC)
+        codec_index = esco_codec - 1;
+
+    params = bta_ag_esco_params[codec_index];
+#else
+    params = bta_ag_esco_params;
+#endif
+
+    if(bta_ag_cb.sco.param_updated) /* If we do not use the default parameters */
+        params = bta_ag_cb.sco.params;
+
+    if(!bta_ag_cb.sco.param_updated)
+    {
+#if (BTM_WBS_INCLUDED == TRUE)
+        if (!codec_index)   /* For non-WBS */
+#endif
+        {
+            /* Use the application packet types (5 slot EV packets not allowed) */
+            params.packet_types = p_bta_ag_cfg->sco_pkt_types     |
+                                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+                                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV5;
+        }
+    }
+
+    /* if initiating set current scb and peer bd addr */
+    if (is_orig)
+    {
+        /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
+        /* Need to find out from SIG if HSP can use eSCO; for now use SCO */
+        if (p_scb->conn_service == BTA_AG_HFP && p_scb->peer_version >= HFP_VERSION_1_5 && !p_scb->retry_with_sco_only)
+        {
+
+            BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, &params);
+            /* If ESCO or EDR ESCO, retry with SCO only in case of failure */
+            if((params.packet_types & BTM_ESCO_LINK_ONLY_MASK)
+               ||!((params.packet_types & ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^ BTA_AG_NO_EDR_ESCO))
+            {
+#if (BTM_WBS_INCLUDED == TRUE )
+                if (esco_codec != BTA_AG_CODEC_MSBC)
+                {
+                    p_scb->retry_with_sco_only = TRUE;
+                    APPL_TRACE_API0("Setting retry_with_sco_only to TRUE");
+                }
+                else    /* Do not use SCO when using mSBC */
+                {
+                    p_scb->retry_with_sco_only = FALSE;
+                    APPL_TRACE_API0("Setting retry_with_sco_only to FALSE");
+                }
+#else
+                p_scb->retry_with_sco_only = TRUE;
+                APPL_TRACE_API0("Setting retry_with_sco_only to TRUE");
+#endif
+            }
+        }
+        else
+        {
+            if(p_scb->retry_with_sco_only)
+                APPL_TRACE_API0("retrying with SCO only");
+            p_scb->retry_with_sco_only = FALSE;
+
+            BTM_SetEScoMode(BTM_LINK_TYPE_SCO, &params);
+        }
+
+        bta_ag_cb.sco.p_curr_scb = p_scb;
+
+        /* tell sys to stop av if any */
+        bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+        /* Allow any platform specific pre-SCO set up to take place */
+        bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+#if (BTM_WBS_INCLUDED == TRUE)
+        if (esco_codec == BTA_AG_CODEC_MSBC)
+            pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_16K;
+        else
+#endif
+            pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K;
+
+        sco_route = bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id);
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE )
+        if (esco_codec == BTA_AG_CODEC_MSBC)
+        {
+            /* Enable mSBC codec in fw */
+            BTM_SetWBSCodec (esco_codec);
+        }
+
+        /* Specify PCM input for SBC codec in fw */
+        BTM_ConfigI2SPCM (esco_codec, (UINT8)HCI_BRCM_I2SPCM_IS_DEFAULT_ROLE, (UINT8)HCI_BRCM_I2SPCM_SAMPLE_DEFAULT, (UINT8)HCI_BRCM_I2SPCM_CLOCK_DEFAULT);
+
+        /* This setting may not be necessary */
+        /* To be verified with stable 2049 boards */
+        if (esco_codec == BTA_AG_CODEC_MSBC)
+            BTM_WriteVoiceSettings (BTM_VOICE_SETTING_TRANS);
+        else
+            BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD);
+
+        /* save the current codec because sco_codec can be updated while SCO is open. */
+        p_scb->inuse_codec = esco_codec;
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+        /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
+        BTM_ConfigScoPath(sco_route, bta_ag_sco_read_cback, NULL, TRUE);
+#endif
+        bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+    }
+    else
+        p_scb->retry_with_sco_only = FALSE;
+
+    p_bd_addr = p_scb->peer_addr;
+
+    status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types,
+                           &p_scb->sco_idx, bta_ag_sco_conn_cback,
+                           bta_ag_sco_disc_cback);
+    if (status == BTM_CMD_STARTED)
+    {
+        if (!is_orig)
+        {
+            BTM_RegForEScoEvts(p_scb->sco_idx, bta_ag_esco_connreq_cback);
+        }
+        else    /* Initiating the connection, set the current sco handle */
+        {
+            bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+        }
+    }
+
+    APPL_TRACE_API4("ag create sco: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
+                      is_orig, p_scb->sco_idx, status, params.packet_types);
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function         bta_ag_cn_timer_cback
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_cn_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+    tBTA_AG_SCB *p_scb;
+
+    if (p_tle)
+    {
+        p_scb = (tBTA_AG_SCB *)p_tle->param;
+
+        if (p_scb)
+        {
+            /* Announce that codec negotiation failed. */
+            bta_ag_sco_codec_nego(p_scb, FALSE);
+
+            /* call app callback */
+            bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_codec_negotiate
+**
+** Description      Initiate codec negotiation by sending AT command.
+**                  If not necessary, skip negotiation.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_codec_negotiate(tBTA_AG_SCB *p_scb)
+{
+    bta_ag_cb.sco.p_curr_scb = p_scb;
+
+    if (p_scb->codec_updated || p_scb->codec_fallback)
+    {
+        /* Change the power mode to Active until sco open is completed. */
+        bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+        /* Send +BCS to the peer */
+        bta_ag_send_bcs(p_scb, NULL);
+
+        /* Start timer to handle timeout */
+        p_scb->cn_timer.p_cback = (TIMER_CBACK*)&bta_ag_cn_timer_cback;
+        p_scb->cn_timer.param = (INT32)p_scb;
+        bta_sys_start_timer(&p_scb->cn_timer, 0, BTA_AG_CODEC_NEGO_TIMEOUT);
+    }
+    else
+    {
+        /* use same codec type as previous SCO connection, skip codec negotiation */
+        bta_ag_sco_codec_nego(p_scb, TRUE);
+    }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_event
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_sco_event(tBTA_AG_SCB *p_scb, UINT8 event)
+{
+    tBTA_AG_SCO_CB *p_sco = &bta_ag_cb.sco;
+#if (BTM_WBS_INCLUDED == TRUE )
+    tBTA_AG_SCB *p_cn_scb = NULL;   /* For codec negotiation */
+#endif
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    BT_HDR  *p_buf;
+#endif
+#if BTA_AG_SCO_DEBUG == TRUE
+    UINT8   in_state = p_sco->state;
+
+    APPL_TRACE_EVENT5("BTA ag sco evt (hdl 0x%04x): State %d (%s), Event %d (%s)",
+                        p_scb->sco_idx,
+                        p_sco->state, bta_ag_sco_state_str(p_sco->state),
+                        event, bta_ag_sco_evt_str(event));
+#else
+    APPL_TRACE_EVENT3("BTA ag sco evt (hdl 0x%04x): State %d, Event %d",
+                      p_scb->sco_idx, p_sco->state, event);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    if (event == BTA_AG_SCO_CI_DATA_E)
+    {
+        while (TRUE)
+        {
+            bta_dm_sco_co_out_data(&p_buf);
+            if (p_buf)
+            {
+                if (p_sco->state == BTA_AG_SCO_OPEN_ST)
+                    BTM_WriteScoData(p_sco->p_curr_scb->sco_idx, p_buf);
+                else
+                    GKI_freebuf(p_buf);
+            }
+            else
+                break;
+        }
+
+        return;
+    }
+#endif
+
+    switch (p_sco->state)
+    {
+        case BTA_AG_SCO_SHUTDOWN_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_SHUTDOWN_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_LISTEN_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection (Additional channel) */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    break;
+
+                case BTA_AG_SCO_OPEN_E:
+                    /* remove listening connection */
+                    bta_ag_remove_sco(p_scb, FALSE);
+
+#if (BTM_WBS_INCLUDED == TRUE )
+                    /* start codec negotiation */
+                    p_sco->state = BTA_AG_SCO_CODEC_ST;
+                    p_cn_scb = p_scb;
+#else
+                    /* create sco connection to peer */
+                    bta_ag_create_sco(p_scb, TRUE);
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* remove listening connection */
+                    bta_ag_remove_sco(p_scb, FALSE);
+
+                    if (p_scb == p_sco->p_curr_scb)
+                        p_sco->p_curr_scb = NULL;
+
+                    /* If last SCO instance then finish shutting down */
+                    if (!bta_ag_other_scb_open(p_scb))
+                    {
+                        p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+                    }
+                    break;
+
+                case BTA_AG_SCO_CLOSE_E:
+                    /* remove listening connection */
+                    /* Ignore the event. We need to keep listening SCO for the active SLC */
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* sco failed; create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+#if (BTM_WBS_INCLUDED == TRUE )
+        case BTA_AG_SCO_CODEC_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection (Additional channel) */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    break;
+
+                case BTA_AG_SCO_CN_DONE_E:
+                    /* create sco connection to peer */
+                    bta_ag_create_sco(p_scb, TRUE);
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+                    break;
+
+                case BTA_AG_SCO_XFER_E:
+                    /* save xfer scb */
+                    p_sco->p_xfer_scb = p_scb;
+                    p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* remove listening connection */
+                    bta_ag_remove_sco(p_scb, FALSE);
+
+                    if (p_scb == p_sco->p_curr_scb)
+                        p_sco->p_curr_scb = NULL;
+
+                    /* If last SCO instance then finish shutting down */
+                    if (!bta_ag_other_scb_open(p_scb))
+                    {
+                        p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+                    }
+                    break;
+
+                case BTA_AG_SCO_CLOSE_E:
+                    /* sco open is not started yet. just go back to listening */
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* sco failed; create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_CODEC_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+#endif
+
+        case BTA_AG_SCO_OPENING_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* second headset has now joined */
+                    /* create sco listen connection (Additional channel) */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        bta_ag_create_sco(p_scb, FALSE);
+                    }
+                    break;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+                case BTA_AG_SCO_REOPEN_E:
+                    /* start codec negotiation */
+                    p_sco->state = BTA_AG_SCO_CODEC_ST;
+                    p_cn_scb = p_scb;
+                    break;
+#endif
+
+                case BTA_AG_SCO_XFER_E:
+                    /* save xfer scb */
+                    p_sco->p_xfer_scb = p_scb;
+                    p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+                    break;
+
+                case BTA_AG_SCO_CLOSE_E:
+                    p_sco->state = BTA_AG_SCO_OPEN_CL_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* If not opening scb, just close it */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        /* remove listening connection */
+                        bta_ag_remove_sco(p_scb, FALSE);
+                    }
+                    else
+                        p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+                    break;
+
+                case BTA_AG_SCO_CONN_OPEN_E:
+                    p_sco->state = BTA_AG_SCO_OPEN_ST;
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* sco failed; create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_OPENING_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_OPEN_CL_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_XFER_E:
+                    /* save xfer scb */
+                    p_sco->p_xfer_scb = p_scb;
+
+                    p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+                    break;
+
+                case BTA_AG_SCO_OPEN_E:
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* If not opening scb, just close it */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        /* remove listening connection */
+                        bta_ag_remove_sco(p_scb, FALSE);
+                    }
+                    else
+                        p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+                    break;
+
+                case BTA_AG_SCO_CONN_OPEN_E:
+                    /* close sco connection */
+                    bta_ag_remove_sco(p_scb, TRUE);
+
+                    p_sco->state = BTA_AG_SCO_CLOSING_ST;
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* sco failed; create sco listen connection */
+
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_CL_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_OPEN_XFER_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_CLOSE_E:
+                    /* close sco connection */
+                    bta_ag_remove_sco(p_scb, TRUE);
+
+                    p_sco->state = BTA_AG_SCO_CLOSING_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* remove all connection */
+                    bta_ag_remove_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* closed sco; place in listen mode and
+                       accept the transferred connection */
+                    bta_ag_create_sco(p_scb, FALSE);    /* Back into listen mode */
+
+                    /* Accept sco connection with xfer scb */
+                    bta_ag_sco_conn_rsp(p_sco->p_xfer_scb, &p_sco->conn_data);
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+                    p_sco->p_curr_scb = p_sco->p_xfer_scb;
+                    p_sco->cur_idx = p_sco->p_xfer_scb->sco_idx;
+                    p_sco->p_xfer_scb = NULL;
+                     break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_XFER_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_OPEN_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* second headset has now joined */
+                    /* create sco listen connection (Additional channel) */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        bta_ag_create_sco(p_scb, FALSE);
+                    }
+                    break;
+
+                case BTA_AG_SCO_XFER_E:
+                    /* close current sco connection */
+                    bta_ag_remove_sco(p_sco->p_curr_scb, TRUE);
+
+                    /* save xfer scb */
+                    p_sco->p_xfer_scb = p_scb;
+
+                    p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+                    break;
+
+                case BTA_AG_SCO_CLOSE_E:
+                    /* close sco connection if active */
+                    if (bta_ag_remove_sco(p_scb, TRUE))
+                    {
+                        p_sco->state = BTA_AG_SCO_CLOSING_ST;
+                    }
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* remove all listening connections */
+                    bta_ag_remove_sco(p_scb, FALSE);
+
+                    /* If SCO was active on this scb, close it */
+                    if (p_scb == p_sco->p_curr_scb)
+                    {
+                        p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+                    }
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* peer closed sco; create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_CLOSING_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection (Additional channel) */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        bta_ag_create_sco(p_scb, FALSE);
+                    }
+                    break;
+
+                case BTA_AG_SCO_OPEN_E:
+                    p_sco->state = BTA_AG_SCO_CLOSE_OP_ST;
+                    break;
+
+                case BTA_AG_SCO_XFER_E:
+                    /* save xfer scb */
+                    p_sco->p_xfer_scb = p_scb;
+
+                    p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* If not closing scb, just close it */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        /* remove listening connection */
+                        bta_ag_remove_sco(p_scb, FALSE);
+                    }
+                    else
+                        p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* peer closed sco; create sco listen connection */
+                    bta_ag_create_sco(p_scb, FALSE);
+
+                    p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSING_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_CLOSE_OP_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_CLOSE_E:
+                    p_sco->state = BTA_AG_SCO_CLOSING_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+#if (BTM_WBS_INCLUDED == TRUE )
+                    /* start codec negotiation */
+                    p_sco->state = BTA_AG_SCO_CODEC_ST;
+                    p_cn_scb = p_scb;
+#else
+                    /* open sco connection */
+                    bta_ag_create_sco(p_scb, TRUE);
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+                    break;
+
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection (Additional channel) */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        bta_ag_create_sco(p_scb, FALSE);
+                    }
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSE_OP_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_CLOSE_XFER_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_CONN_OPEN_E:
+                    /* close sco connection so headset can be transferred
+                       Probably entered this state from "opening state" */
+                    bta_ag_remove_sco(p_scb, TRUE);
+                    break;
+
+                case BTA_AG_SCO_CLOSE_E:
+                    /* clear xfer scb */
+                    p_sco->p_xfer_scb = NULL;
+
+                    p_sco->state = BTA_AG_SCO_CLOSING_ST;
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    /* clear xfer scb */
+                    p_sco->p_xfer_scb = NULL;
+
+                    p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* closed sco; place old sco in listen mode,
+                       take current sco out of listen, and
+                       create originating sco for current */
+                    bta_ag_create_sco(p_scb, FALSE);
+                    bta_ag_remove_sco(p_sco->p_xfer_scb, FALSE);
+
+#if (BTM_WBS_INCLUDED == TRUE )
+                    /* start codec negotiation */
+                    p_sco->state = BTA_AG_SCO_CODEC_ST;
+                    p_cn_scb = p_sco->p_xfer_scb;
+                    p_sco->p_xfer_scb = NULL;
+#else
+                    /* create sco connection to peer */
+                    bta_ag_create_sco(p_sco->p_xfer_scb, TRUE);
+                    p_sco->p_xfer_scb = NULL;
+                    p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSE_XFER_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        case BTA_AG_SCO_SHUTTING_ST:
+            switch (event)
+            {
+                case BTA_AG_SCO_CONN_OPEN_E:
+                    /* close sco connection; wait for conn close event */
+                    bta_ag_remove_sco(p_scb, TRUE);
+                    break;
+
+                case BTA_AG_SCO_CONN_CLOSE_E:
+                    /* If last SCO instance then finish shutting down */
+                    if (!bta_ag_other_scb_open(p_scb))
+                    {
+                        p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+                    }
+                    else    /* Other instance is still listening */
+                    {
+                        p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    }
+
+                    if (p_scb == p_sco->p_curr_scb)
+                    {
+                        p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+                        p_sco->p_curr_scb = NULL;
+                    }
+                    break;
+
+                case BTA_AG_SCO_LISTEN_E:
+                    /* create sco listen connection (Additional channel) */
+                    if (p_scb != p_sco->p_curr_scb)
+                    {
+                        bta_ag_create_sco(p_scb, FALSE);
+                    }
+                    break;
+
+                case BTA_AG_SCO_SHUTDOWN_E:
+                    if (!bta_ag_other_scb_open(p_scb))
+                    {
+                        p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+                    }
+                    else    /* Other instance is still listening */
+                    {
+                        p_sco->state = BTA_AG_SCO_LISTEN_ST;
+                    }
+
+                    if (p_scb == p_sco->p_curr_scb)
+                    {
+                        p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+                        p_sco->p_curr_scb = NULL;
+                    }
+                    break;
+
+                default:
+                    APPL_TRACE_WARNING1("BTA_AG_SCO_SHUTTING_ST: Ignoring event %d", event);
+                    break;
+            }
+            break;
+
+        default:
+            break;
+    }
+#if BTA_AG_SCO_DEBUG == TRUE
+    if (p_sco->state != in_state)
+    {
+        APPL_TRACE_EVENT3("BTA AG SCO State Change: [%s] -> [%s] after Event [%s]",
+                      bta_ag_sco_state_str(in_state),
+                      bta_ag_sco_state_str(p_sco->state),
+                      bta_ag_sco_evt_str(event));
+    }
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE )
+    if (p_cn_scb)
+    {
+        bta_ag_codec_negotiate(p_cn_scb);
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_is_open
+**
+** Description      Check if sco is open for this scb.
+**
+**
+** Returns          TRUE if sco open for this scb, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb)
+{
+    return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_ST) &&
+            (bta_ag_cb.sco.p_curr_scb == p_scb));
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_is_opening
+**
+** Description      Check if sco is in Opening state.
+**
+**
+** Returns          TRUE if sco is in Opening state for this scb, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb)
+{
+#if (BTM_WBS_INCLUDED == TRUE )
+    return (((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) ||
+            (bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST)) &&
+            (bta_ag_cb.sco.p_curr_scb == p_scb));
+#else
+    return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) &&
+            (bta_ag_cb.sco.p_curr_scb == p_scb));
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_listen
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_listen(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_LISTEN_E);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_open
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT8 event;
+
+    /* if another scb using sco, this is a transfer */
+    if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb != p_scb)
+    {
+        event = BTA_AG_SCO_XFER_E;
+    }
+    /* else it is an open */
+    else
+    {
+        event = BTA_AG_SCO_OPEN_E;
+    }
+
+    bta_ag_sco_event(p_scb, event);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_close
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    /* if scb is in use */
+#if (BTM_WBS_INCLUDED == TRUE )
+    /* sco_idx is not allocated in SCO_CODEC_ST, we still need to move to listening state. */
+    if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) || (bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST))
+#else
+    if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+#endif
+    {
+        APPL_TRACE_DEBUG1("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx);
+        bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+    }
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_codec_nego
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_codec_nego(tBTA_AG_SCB *p_scb, BOOLEAN result)
+{
+    if(result == TRUE)
+    {
+        /* Subsequent sco connection will skip codec negotiation */
+        p_scb->codec_updated = FALSE;
+
+        bta_ag_sco_event(p_scb, BTA_AG_SCO_CN_DONE_E);
+    }
+    else    /* codec negotiation failed */
+        bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_shutdown
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_shutdown(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_SHUTDOWN_E);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_conn_open
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_OPEN_E);
+
+    bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+    bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_ON);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    /* open SCO codec if SCO is routed through transport */
+    bta_dm_sco_co_open(bta_ag_scb_to_idx(p_scb), BTA_SCO_OUT_PKT_SIZE, BTA_AG_CI_SCO_DATA_EVT);
+#endif
+
+    /* call app callback */
+    bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_OPEN_EVT);
+
+    p_scb->retry_with_sco_only = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_conn_close
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    UINT16 handle = bta_ag_scb_to_idx(p_scb);
+
+    /* clear current scb */
+    bta_ag_cb.sco.p_curr_scb = NULL;
+    p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+    /* codec_fallback is set when AG is initiator and connection failed for mSBC. */
+    if (p_scb->codec_fallback && p_scb->svc_conn)
+    {
+        bta_ag_sco_event(p_scb, BTA_AG_SCO_REOPEN_E);
+    }
+    else if (p_scb->retry_with_sco_only && p_scb->svc_conn)
+    {
+        /* retry_with_sco_only is set when AG is initiator and connection failed for eSCO */
+        bta_ag_create_sco(p_scb, TRUE);
+    }
+#else
+    /* retry_with_sco_only, will be set only when AG is initiator
+    ** and AG is first trying to establish an eSCO connection */
+    if (p_scb->retry_with_sco_only && p_scb->svc_conn)
+    {
+        bta_ag_create_sco(p_scb, TRUE);
+    }
+#endif
+    else
+    {
+        /* Indicate if the closing of audio is because of transfer */
+        if (bta_ag_cb.sco.p_xfer_scb)
+            bta_ag_co_audio_state(handle, p_scb->app_id, BTA_AG_CO_AUD_STATE_OFF_XFER);
+        else
+            bta_ag_co_audio_state(handle, p_scb->app_id, BTA_AG_CO_AUD_STATE_OFF);
+
+        bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_CLOSE_E);
+
+        bta_sys_sco_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+        /* if av got suspended by this call, let it resume. */
+        /* In case call stays alive regardless of sco, av should not be affected. */
+        if(((p_scb->call_ind == BTA_AG_CALL_INACTIVE) && (p_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE))
+            || (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END))
+        {
+            bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+        }
+
+        /* call app callback */
+        bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+    }
+    p_scb->retry_with_sco_only = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sco_conn_rsp
+**
+** Description      Process the SCO connection request
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data)
+{
+    tBTM_ESCO_PARAMS    resp;
+    UINT8               hci_status = HCI_SUCCESS;
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    tBTA_CODEC_INFO     codec_info = {BTA_SCO_CODEC_PCM};
+    UINT32              pcm_sample_rate;
+#endif
+
+    if (bta_ag_cb.sco.state == BTA_AG_SCO_LISTEN_ST     ||
+        bta_ag_cb.sco.state == BTA_AG_SCO_CLOSE_XFER_ST ||
+        bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_XFER_ST)
+    {
+        /* If script overrided sco parameter by BTA_CMD_SET_ESCO_PARAM */
+        if (bta_ag_cb.sco.param_updated)
+        {
+            resp = bta_ag_cb.sco.params;
+        }
+        else
+        {
+            resp.rx_bw = BTM_64KBITS_RATE;
+            resp.tx_bw = BTM_64KBITS_RATE;
+            resp.max_latency = 10;
+            resp.voice_contfmt = 0x60;
+            resp.retrans_effort = BTM_ESCO_RETRANS_POWER;
+
+            if (p_data->link_type == BTM_LINK_TYPE_SCO)
+            {
+                resp.packet_types = (BTM_SCO_LINK_ONLY_MASK          |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+            }
+            else    /* Allow controller to use all types available except 5-slot EDR */
+            {
+                resp.packet_types = (BTM_SCO_LINK_ALL_PKT_MASK |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+                                     BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+            }
+        }
+
+        /* tell sys to stop av if any */
+        bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+        /* Allow any platform specific pre-SCO set up to take place */
+        bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP);
+
+#if (BTM_WBS_INCLUDED == TRUE )
+        /* When HS initiated SCO, it cannot be WBS. */
+        BTM_ConfigI2SPCM (BTM_SCO_CODEC_CVSD, (UINT8)HCI_BRCM_I2SPCM_IS_DEFAULT_ROLE, (UINT8)HCI_BRCM_I2SPCM_SAMPLE_DEFAULT, (UINT8)HCI_BRCM_I2SPCM_CLOCK_DEFAULT);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+        pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K;
+
+        /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
+        BTM_ConfigScoPath(bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id),
+            bta_ag_sco_read_cback, NULL, TRUE);
+#endif
+    }
+    else
+        hci_status = HCI_ERR_HOST_REJECT_DEVICE;
+
+#if (BTM_WBS_INCLUDED == TRUE )
+    /* If SCO open was initiated from HS, it must be CVSD */
+    p_scb->inuse_codec = BTA_AG_CODEC_NONE;
+#endif
+
+    BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_ci_sco_data
+**
+** Description      Process the SCO data ready callin event
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_CI_DATA_E);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_set_esco_param
+**
+** Description      Update esco parameters from script wrapper.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param)
+{
+    if(set_reset == FALSE)    /* reset the parameters to default */
+    {
+        bta_ag_cb.sco.param_updated = FALSE;
+        APPL_TRACE_DEBUG0("bta_ag_set_esco_param : Resetting ESCO parameters to default");
+    }
+    else
+    {
+        bta_ag_cb.sco.param_updated = TRUE;
+        bta_ag_cb.sco.params = *param;
+        APPL_TRACE_DEBUG0("bta_ag_set_esco_param : Setting ESCO parameters");
+    }
+}
+
+/*******************************************************************************
+**  Debugging functions
+*******************************************************************************/
+
+#if BTA_AG_SCO_DEBUG == TRUE
+static char *bta_ag_sco_evt_str(UINT8 event)
+{
+    switch (event)
+    {
+    case BTA_AG_SCO_LISTEN_E:
+        return "Listen Request";
+    case BTA_AG_SCO_OPEN_E:
+        return "Open Request";
+    case BTA_AG_SCO_XFER_E:
+        return "Transfer Request";
+#if (BTM_WBS_INCLUDED == TRUE )
+    case BTA_AG_SCO_CN_DONE_E:
+        return "Codec Negotiation Done";
+    case BTA_AG_SCO_REOPEN_E:
+        return "Reopen Request";
+#endif
+    case BTA_AG_SCO_CLOSE_E:
+        return "Close Request";
+    case BTA_AG_SCO_SHUTDOWN_E:
+        return "Shutdown Request";
+    case BTA_AG_SCO_CONN_OPEN_E:
+        return "Opened";
+    case BTA_AG_SCO_CONN_CLOSE_E:
+        return "Closed";
+    case BTA_AG_SCO_CI_DATA_E  :
+        return "Sco Data";
+    default:
+        return "Unknown SCO Event";
+    }
+}
+
+static char *bta_ag_sco_state_str(UINT8 state)
+{
+    switch (state)
+    {
+    case BTA_AG_SCO_SHUTDOWN_ST:
+        return "Shutdown";
+    case BTA_AG_SCO_LISTEN_ST:
+        return "Listening";
+#if (BTM_WBS_INCLUDED == TRUE )
+    case BTA_AG_SCO_CODEC_ST:
+        return "Codec Negotiation";
+#endif
+    case BTA_AG_SCO_OPENING_ST:
+        return "Opening";
+    case BTA_AG_SCO_OPEN_CL_ST:
+        return "Open while closing";
+    case BTA_AG_SCO_OPEN_XFER_ST:
+        return "Opening while Transferring";
+    case BTA_AG_SCO_OPEN_ST:
+        return "Open";
+    case BTA_AG_SCO_CLOSING_ST:
+        return "Closing";
+    case BTA_AG_SCO_CLOSE_OP_ST:
+        return "Close while Opening";
+    case BTA_AG_SCO_CLOSE_XFER_ST:
+        return "Close while Transferring";
+    case BTA_AG_SCO_SHUTTING_ST:
+        return "Shutting Down";
+    default:
+        return "Unknown SCO State";
+    }
+}
+
+#endif
diff --git a/bta/ag/bta_ag_sdp.c b/bta/ag/bta_ag_sdp.c
new file mode 100644
index 0000000..d708cf2
--- /dev/null
+++ b/bta/ag/bta_ag_sdp.c
@@ -0,0 +1,500 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains the audio gateway functions performing SDP
+ *  operations.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "sdp_api.h"
+#include "btm_api.h"
+#include "gki.h"
+
+/* Number of protocol elements in protocol element list. */
+#define BTA_AG_NUM_PROTO_ELEMS      2
+
+/* Number of elements in service class id list. */
+#define BTA_AG_NUM_SVC_ELEMS        2
+
+/* size of database for service discovery */
+#ifndef BTA_AG_DISC_BUF_SIZE
+#define BTA_AG_DISC_BUF_SIZE        GKI_MAX_BUF_SIZE
+#endif
+
+/* declare sdp callback functions */
+void bta_ag_sdp_cback_1(UINT16 status);
+void bta_ag_sdp_cback_2(UINT16 status);
+void bta_ag_sdp_cback_3(UINT16 status);
+
+/* SDP callback function table */
+typedef tSDP_DISC_CMPL_CB *tBTA_AG_SDP_CBACK;
+const tBTA_AG_SDP_CBACK bta_ag_sdp_cback_tbl[] =
+{
+    bta_ag_sdp_cback_1,
+    bta_ag_sdp_cback_2,
+    bta_ag_sdp_cback_3
+};
+
+/*******************************************************************************
+**
+** Function         bta_ag_sdp_cback
+**
+** Description      SDP callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ag_sdp_cback(UINT16 status, UINT8 idx)
+{
+    tBTA_AG_DISC_RESULT *p_buf;
+    UINT16              event;
+    tBTA_AG_SCB         *p_scb;
+
+    APPL_TRACE_DEBUG1("bta_ag_sdp_cback status:0x%x", status);
+
+    if ((p_scb = bta_ag_scb_by_idx(idx)) != NULL)
+    {
+        /* set event according to int/acp */
+        if (p_scb->role == BTA_AG_ACP)
+        {
+            event = BTA_AG_DISC_ACP_RES_EVT;
+        }
+        else
+        {
+            event = BTA_AG_DISC_INT_RES_EVT;
+        }
+
+        if ((p_buf = (tBTA_AG_DISC_RESULT *) GKI_getbuf(sizeof(tBTA_AG_DISC_RESULT))) != NULL)
+        {
+            p_buf->hdr.event = event;
+            p_buf->hdr.layer_specific = idx;
+            p_buf->status = status;
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sdp_cback_1 to 3
+**
+** Description      SDP callback functions.  Since there is no way to
+**                  distinguish scb from the callback we need separate
+**                  callbacks for each scb.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_sdp_cback_1(UINT16 status) {bta_ag_sdp_cback(status, 1);}
+void bta_ag_sdp_cback_2(UINT16 status) {bta_ag_sdp_cback(status, 2);}
+void bta_ag_sdp_cback_3(UINT16 status) {bta_ag_sdp_cback(status, 3);}
+
+/******************************************************************************
+**
+** Function         bta_ag_add_record
+**
+** Description      This function is called by a server application to add
+**                  HSP or HFP information to an SDP record.  Prior to
+**                  calling this function the application must call
+**                  SDP_CreateRecord() to create an SDP record.
+**
+** Returns          TRUE if function execution succeeded,
+**                  FALSE if function execution failed.
+**
+******************************************************************************/
+BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn,
+                          tBTA_AG_FEAT features, UINT32 sdp_handle)
+{
+    tSDP_PROTOCOL_ELEM  proto_elem_list[BTA_AG_NUM_PROTO_ELEMS];
+    UINT16              svc_class_id_list[BTA_AG_NUM_SVC_ELEMS];
+    UINT16              browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+    UINT16              version;
+    UINT16              profile_uuid;
+    UINT8               network;
+    BOOLEAN             result = TRUE;
+    BOOLEAN             codec_supported = FALSE;
+    UINT8               buf[2];
+
+    APPL_TRACE_DEBUG1("bta_ag_add_record uuid: %x", service_uuid);
+
+    memset( proto_elem_list, 0 , BTA_AG_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM));
+
+    /* add the protocol element sequence */
+    proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    proto_elem_list[0].num_params = 0;
+    proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+    proto_elem_list[1].num_params = 1;
+    proto_elem_list[1].params[0] = scn;
+    result &= SDP_AddProtocolList(sdp_handle, BTA_AG_NUM_PROTO_ELEMS, proto_elem_list);
+
+    /* add service class id list */
+    svc_class_id_list[0] = service_uuid;
+    svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
+    result &= SDP_AddServiceClassIdList(sdp_handle, BTA_AG_NUM_SVC_ELEMS, svc_class_id_list);
+
+    /* add profile descriptor list */
+    if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE)
+    {
+        profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
+        version = HFP_VERSION_1_6;
+    }
+    else
+    {
+        profile_uuid = UUID_SERVCLASS_HEADSET;
+        version = HSP_VERSION_1_2;
+    }
+    result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
+
+    /* add service name */
+    if (p_service_name != NULL && p_service_name[0] != 0)
+    {
+        result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+                    (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
+    }
+
+    /* add features and network */
+    if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE)
+    {
+        network = (features & BTA_AG_FEAT_REJECT) ? 1 : 0;
+        result &= SDP_AddAttribute(sdp_handle, ATTR_ID_DATA_STORES_OR_NETWORK,
+                    UINT_DESC_TYPE, 1, &network);
+
+        if (features & BTA_AG_FEAT_CODEC)
+            codec_supported = TRUE;
+
+        features &= BTA_AG_SDP_FEAT_SPEC;
+
+        /* Codec bit position is different in SDP and in BRSF */
+        if (codec_supported)
+            features |= 0x0020;
+
+        UINT16_TO_BE_FIELD(buf, features);
+        result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf);
+    }
+
+    /* add browse group list */
+    result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_create_records
+**
+** Description      Create SDP records for registered services.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    int                 i;
+    tBTA_SERVICE_MASK   services;
+
+    services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+    for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1)
+    {
+        /* if service is set in mask */
+        if (services & 1)
+        {
+            /* add sdp record if not already registered */
+            if (bta_ag_cb.profile[i].sdp_handle == 0)
+            {
+                bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord();
+                bta_ag_cb.profile[i].scn = BTM_AllocateSCN();
+                bta_ag_add_record(bta_ag_uuid[i], p_data->api_register.p_name[i],
+                    bta_ag_cb.profile[i].scn, p_data->api_register.features,
+                    bta_ag_cb.profile[i].sdp_handle);
+                bta_sys_add_uuid(bta_ag_uuid[i]);
+            }
+        }
+    }
+
+    p_scb->hsp_version = HSP_VERSION_1_2;
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_del_records
+**
+** Description      Delete SDP records for any registered services.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    tBTA_AG_SCB         *p = &bta_ag_cb.scb[0];
+    tBTA_SERVICE_MASK   services;
+    tBTA_SERVICE_MASK   others = 0;
+    int                 i;
+
+    /* get services of all other registered servers */
+    for (i = 0; i < BTA_AG_NUM_IDX; i++, p++)
+    {
+        if (p_scb == p)
+        {
+            continue;
+        }
+
+        if (p->in_use && p->dealloc == FALSE)
+        {
+            others |= p->reg_services;
+        }
+    }
+
+    others >>= BTA_HSP_SERVICE_ID;
+    services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+    for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1, others >>= 1)
+    {
+        /* if service registered for this scb and not registered for any other scb */
+        if (((services & 1) == 1) && ((others & 1) == 0))
+        {
+            APPL_TRACE_DEBUG1("bta_ag_del_records %d", i);
+            if (bta_ag_cb.profile[i].sdp_handle != 0)
+            {
+                SDP_DeleteRecord(bta_ag_cb.profile[i].sdp_handle);
+                bta_ag_cb.profile[i].sdp_handle = 0;
+            }
+            BTM_FreeSCN(bta_ag_cb.profile[i].scn);
+            BTM_SecClrService(bta_ag_sec_id[i]);
+            bta_sys_remove_uuid(bta_ag_uuid[i]);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_sdp_find_attr
+**
+** Description      Process SDP discovery results to find requested attributes
+**                  for requested service.
+**
+**
+** Returns          TRUE if results found, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service)
+{
+    tSDP_DISC_REC       *p_rec = NULL;
+    tSDP_DISC_ATTR      *p_attr;
+    tSDP_PROTOCOL_ELEM  pe;
+    UINT16              uuid;
+    BOOLEAN             result = FALSE;
+
+    if (service & BTA_HFP_SERVICE_MASK)
+    {
+        uuid = UUID_SERVCLASS_HF_HANDSFREE;
+        p_scb->peer_version = HFP_VERSION_1_1;   /* Default version */
+    }
+    else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
+    {
+        uuid = UUID_SERVCLASS_HEADSET_HS;
+        p_scb->peer_version = 0x0100;   /* Default version */
+    }
+    else
+    {
+        return result;
+    }
+
+    /* loop through all records we found */
+    while (TRUE)
+    {
+        /* get next record; if none found, we're done */
+        if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL)
+        {
+            if (uuid == UUID_SERVCLASS_HEADSET_HS)
+            {
+                /* Search again in case the peer device is HSP v1.0 */
+                uuid = UUID_SERVCLASS_HEADSET;
+                if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL)
+                {
+                    break;
+                }
+            }
+            else
+                break;
+        }
+
+        /* get scn from proto desc list if initiator */
+        if (p_scb->role == BTA_AG_INT)
+        {
+            if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+            {
+                p_scb->peer_scn = (UINT8) pe.params[0];
+            }
+            else
+            {
+                continue;
+            }
+        }
+
+        /* get profile version (if failure, version parameter is not updated) */
+        SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version);
+
+        /* get features if HFP */
+        if (service & BTA_HFP_SERVICE_MASK)
+        {
+            if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL)
+            {
+                /* Found attribute. Get value. */
+                /* There might be race condition between SDP and BRSF.  */
+                /* Do not update if we already received BRSF.           */
+                if (p_scb->peer_features == 0)
+                    p_scb->peer_features = p_attr->attr_value.v.u16;
+            }
+        }
+        else    /* HSP */
+        {
+            if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL)) != NULL)
+            {
+                /* Remote volume control of HSP */
+                if (p_attr->attr_value.v.u8)
+                    p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL;
+                else
+                    p_scb->peer_features &= ~BTA_AG_PEER_FEAT_VOL;
+            }
+
+        }
+
+        /* found what we needed */
+        result = TRUE;
+        break;
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_do_disc
+**
+** Description      Do service discovery.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service)
+{
+    tSDP_UUID       uuid_list[2];
+    UINT16          num_uuid = 1;
+    UINT16          attr_list[4];
+    UINT8           num_attr;
+    BOOLEAN         db_inited = FALSE;
+
+    /* HFP initiator; get proto list and features */
+    if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
+    {
+        attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+        attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+        attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+        attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
+        num_attr = 4;
+        uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+    }
+    /* HFP acceptor; get features */
+    else if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_ACP)
+    {
+        attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+        attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
+        attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
+        num_attr = 3;
+        uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+    }
+    /* HSP initiator; get proto list */
+    else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT)
+    {
+        attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+        attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+        attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+        attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL;
+        num_attr = 4;
+
+        uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET;        /* Legacy from HSP v1.0 */
+        if (p_scb->hsp_version >= HSP_VERSION_1_2)
+        {
+            uuid_list[1].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS;
+            num_uuid = 2;
+        }
+    }
+    /* HSP acceptor; no discovery */
+    else
+    {
+        return;
+    }
+
+    /* allocate buffer for sdp database */
+    p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AG_DISC_BUF_SIZE);
+
+    if(p_scb->p_disc_db)
+    {
+        /* set up service discovery database; attr happens to be attr_list len */
+        uuid_list[0].len = LEN_UUID_16;
+        uuid_list[1].len = LEN_UUID_16;
+        db_inited = SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE, num_uuid,
+                            uuid_list, num_attr, attr_list);
+    }
+
+    if(db_inited)
+    {
+        /*Service discovery not initiated */
+        db_inited = SDP_ServiceSearchAttributeRequest(p_scb->peer_addr, p_scb->p_disc_db,
+                                      bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+    }
+
+    if(!db_inited)
+    {
+        /*free discover db */
+        bta_ag_free_db(p_scb, NULL);
+        /* sent failed event */
+        bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, NULL);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_ag_free_db
+**
+** Description      Free discovery database.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+    if (p_scb->p_disc_db != NULL)
+    {
+        GKI_freebuf(p_scb->p_disc_db);
+        p_scb->p_disc_db = NULL;
+    }
+}
diff --git a/bta/ar/bta_ar.c b/bta/ar/bta_ar.c
new file mode 100644
index 0000000..89b732a
--- /dev/null
+++ b/bta/ar/bta_ar.c
@@ -0,0 +1,348 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2008-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the implementation for the audio/video registration module.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta_ar_api.h"
+#include "bta_ar_int.h"
+
+
+/* AV control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_AR_CB  bta_ar_cb;
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_ar_id
+**
+** Description      This function maps sys_id to ar id mask.
+**
+** Returns          void
+**
+*******************************************************************************/
+static UINT8 bta_ar_id(tBTA_SYS_ID sys_id)
+{
+    UINT8   mask = 0;
+    if (sys_id == BTA_ID_AV)
+    {
+        mask = BTA_AR_AV_MASK;
+    }
+    else if (sys_id == BTA_ID_AVK)
+    {
+        mask = BTA_AR_AVK_MASK;
+    }
+
+    return mask;
+}
+
+/*******************************************************************************
+**
+** Function         bta_ar_init
+**
+** Description      This function is called to register to AVDTP.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ar_init(void)
+{
+    /* initialize control block */
+    memset(&bta_ar_cb, 0, sizeof(tBTA_AR_CB));
+}
+
+/*******************************************************************************
+**
+** Function         bta_ar_reg_avdt
+**
+** Description      This function is called to register to AVDTP.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_ar_avdt_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+    /* route the AVDT registration callback to av or avk */
+    if (bta_ar_cb.p_av_conn_cback)
+        (*bta_ar_cb.p_av_conn_cback)(handle, bd_addr, event, p_data);
+    if (bta_ar_cb.p_avk_conn_cback)
+        (*bta_ar_cb.p_avk_conn_cback)(handle, bd_addr, event, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_ar_reg_avdt
+**
+** Description      AR module registration to AVDT.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ar_reg_avdt(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback, tBTA_SYS_ID sys_id)
+{
+    UINT8   mask = 0;
+
+    if (sys_id == BTA_ID_AV)
+    {
+        bta_ar_cb.p_av_conn_cback = p_cback;
+        mask = BTA_AR_AV_MASK;
+    }
+    else if (sys_id == BTA_ID_AVK)
+    {
+        bta_ar_cb.p_avk_conn_cback = p_cback;
+        mask = BTA_AR_AVK_MASK;
+    }
+#if (BTA_AR_DEBUG == TRUE)
+    else
+    {
+        APPL_TRACE_ERROR1("bta_ar_reg_avdt: the registration is from wrong sys_id:%d", sys_id);
+    }
+#endif
+
+    if (mask)
+    {
+        if (bta_ar_cb.avdt_registered == 0)
+        {
+            AVDT_Register(p_reg, bta_ar_avdt_cback);
+        }
+        bta_ar_cb.avdt_registered |= mask;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ar_dereg_avdt
+**
+** Description      This function is called to de-register from AVDTP.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ar_dereg_avdt(tBTA_SYS_ID sys_id)
+{
+    UINT8   mask = 0;
+
+    if (sys_id == BTA_ID_AV)
+    {
+        bta_ar_cb.p_av_conn_cback = NULL;
+        mask = BTA_AR_AV_MASK;
+    }
+    else if (sys_id == BTA_ID_AVK)
+    {
+        bta_ar_cb.p_avk_conn_cback = NULL;
+        mask = BTA_AR_AVK_MASK;
+    }
+    bta_ar_cb.avdt_registered &= ~mask;
+
+    if (bta_ar_cb.avdt_registered == 0)
+        AVDT_Deregister();
+}
+
+/*******************************************************************************
+**
+** Function         bta_ar_avdt_conn
+**
+** Description      This function is called to let ar know that some AVDTP profile
+**                  is connected for this sys_id.
+**                  If the other sys modules started a timer for PENDING_EVT,
+**                  the timer can be stopped now.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, BD_ADDR bd_addr)
+{
+    UINT8       event = BTA_AR_AVDT_CONN_EVT;
+    tAVDT_CTRL  data;
+
+    if (sys_id == BTA_ID_AV)
+    {
+        if (bta_ar_cb.p_avk_conn_cback)
+        {
+            (*bta_ar_cb.p_avk_conn_cback)(0, bd_addr, event, &data);
+        }
+    }
+    else if (sys_id == BTA_ID_AVK)
+    {
+        if (bta_ar_cb.p_av_conn_cback)
+        {
+            (*bta_ar_cb.p_av_conn_cback)(0, bd_addr, event, &data);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ar_reg_avct
+**
+** Description      This function is called to register to AVCTP.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ar_reg_avct(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask, tBTA_SYS_ID sys_id)
+{
+    UINT8   mask = bta_ar_id (sys_id);
+
+    if (mask)
+    {
+        if (bta_ar_cb.avct_registered == 0)
+        {
+            AVCT_Register(mtu, mtu_br, sec_mask);
+        }
+        bta_ar_cb.avct_registered |= mask;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_ar_dereg_avct
+**
+** Description      This function is called to deregister from AVCTP.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_ar_dereg_avct(tBTA_SYS_ID sys_id)
+{
+    UINT8   mask = bta_ar_id (sys_id);
+
+    bta_ar_cb.avct_registered &= ~mask;
+
+    if (bta_ar_cb.avct_registered == 0)
+        AVCT_Deregister();
+}
+
+/******************************************************************************
+**
+** Function         bta_ar_reg_avrc
+**
+** Description      This function is called to register an SDP record for AVRCP.
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ar_reg_avrc(UINT16 service_uuid, char *service_name, char *provider_name,
+					 UINT16 categories, tBTA_SYS_ID sys_id)
+{
+    UINT8   mask = bta_ar_id (sys_id);
+    UINT8   temp[8], *p;
+
+    if (!mask || !categories)
+        return;
+
+    if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+    {
+        if (bta_ar_cb.sdp_tg_handle == 0)
+        {
+            bta_ar_cb.tg_registered = mask;
+            bta_ar_cb.sdp_tg_handle = SDP_CreateRecord();
+            AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_tg_handle);
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+            bta_sys_add_uuid(service_uuid);
+#endif
+        }
+        /* only one TG is allowed (first-come, first-served).
+         * If sdp_tg_handle is non-0, ignore this request */
+    }
+    else if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) || (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_CONTROL))
+    {
+        bta_ar_cb.ct_categories [mask - 1] = categories;
+        categories = bta_ar_cb.ct_categories[0]|bta_ar_cb.ct_categories[1];
+        if (bta_ar_cb.sdp_ct_handle == 0)
+        {
+            bta_ar_cb.sdp_ct_handle = SDP_CreateRecord();
+            AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_ct_handle);
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+            bta_sys_add_uuid(service_uuid);
+#endif
+        }
+        else
+        {
+            /* multiple CTs are allowed.
+             * Change supported categories on the second one */
+            p = temp;
+            UINT16_TO_BE_STREAM(p, categories);
+            SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
+                      (UINT32)2, (UINT8*)temp);
+        }
+    }
+}
+
+/******************************************************************************
+**
+** Function         bta_ar_dereg_avrc
+**
+** Description      This function is called to de-register/delete an SDP record for AVRCP.
+**
+** Returns          void
+**
+******************************************************************************/
+void bta_ar_dereg_avrc(UINT16 service_uuid, tBTA_SYS_ID sys_id)
+{
+    UINT8   mask = bta_ar_id (sys_id);
+    UINT16  categories = 0;
+    UINT8   temp[8], *p;
+
+    if (!mask)
+        return;
+
+    if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+    {
+        if (bta_ar_cb.sdp_tg_handle && mask == bta_ar_cb.tg_registered)
+        {
+            bta_ar_cb.tg_registered = 0;
+            SDP_DeleteRecord(bta_ar_cb.sdp_tg_handle);
+            bta_ar_cb.sdp_tg_handle = 0;
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+            bta_sys_remove_uuid(service_uuid);
+#endif
+        }
+    }
+    else if (service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL)
+    {
+        if (bta_ar_cb.sdp_ct_handle)
+        {
+            bta_ar_cb.ct_categories [mask - 1] = 0;
+            categories = bta_ar_cb.ct_categories[0]|bta_ar_cb.ct_categories[1];
+            if (!categories)
+            {
+                /* no CT is still registered - cleaup */
+                SDP_DeleteRecord(bta_ar_cb.sdp_ct_handle);
+                bta_ar_cb.sdp_ct_handle = 0;
+#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE)
+                bta_sys_remove_uuid(service_uuid);
+#endif
+            }
+            else
+            {
+                /* change supported categories to the remaning one */
+                p = temp;
+                UINT16_TO_BE_STREAM(p, categories);
+                SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
+                          (UINT32)2, (UINT8*)temp);
+            }
+        }
+    }
+
+}
diff --git a/bta/ar/bta_ar_int.h b/bta/ar/bta_ar_int.h
new file mode 100644
index 0000000..d230448
--- /dev/null
+++ b/bta/ar/bta_ar_int.h
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2008-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the private interface file for the BTA audio/video registration
+ *  module.
+ *
+ ******************************************************************************/
+#ifndef BTA_AR_INT_H
+#define BTA_AR_INT_H
+
+#include "bta_av_api.h"
+
+
+#ifndef BTA_AR_DEBUG
+#define BTA_AR_DEBUG    FALSE
+#endif
+
+#define BTA_AR_AV_MASK      0x01
+#define BTA_AR_AVK_MASK     0x02
+
+/* data associated with BTA_AR */
+typedef struct
+{
+    tAVDT_CTRL_CBACK *p_av_conn_cback;       /* av connection callback function */
+    tAVDT_CTRL_CBACK *p_avk_conn_cback;      /* avk connection callback function */
+    UINT8           avdt_registered;
+    UINT8           avct_registered;
+	UINT32          sdp_tg_handle;
+	UINT32          sdp_ct_handle;
+    UINT16          ct_categories[2];
+    UINT8           tg_registered;
+    tBTA_AV_HNDL    hndl;       /* Handle associated with the stream that rejected the connection. */
+} tBTA_AR_CB;
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+
+/* control block declaration */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_AR_CB bta_ar_cb;
+#else
+extern tBTA_AR_CB *bta_ar_cb_ptr;
+#define bta_ar_cb (*bta_ar_cb_ptr)
+#endif
+
+#endif /* BTA_AR_INT_H */
diff --git a/bta/av/bta_av_aact.c b/bta/av/bta_av_aact.c
new file mode 100644
index 0000000..741a5a0
--- /dev/null
+++ b/bta/av/bta_av_aact.c
@@ -0,0 +1,2733 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains action functions for advanced audio/video stream
+ *  state machine. these functions are shared by both audio and video
+ *  streams.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bta_av_int.h"
+#include "avdt_api.h"
+#include "bd.h"
+#include "utl.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* the delay time in milliseconds to start service discovery on AVRCP */
+#ifndef BTA_AV_RC_DISC_TIME_VAL
+#define BTA_AV_RC_DISC_TIME_VAL     3500
+#endif
+
+/* the timer in milliseconds to guard against link busy and AVDT_CloseReq failed to be sent */
+#ifndef BTA_AV_CLOSE_REQ_TIME_VAL
+#define BTA_AV_CLOSE_REQ_TIME_VAL   4000
+#endif
+
+/* number to retry on reconfigure failure - some headsets requirs this number to be more than 1 */
+#ifndef BTA_AV_RECONFIG_RETRY
+#define BTA_AV_RECONFIG_RETRY       6
+#endif
+
+/* state machine states */
+enum
+{
+    BTA_AV_INIT_SST,
+    BTA_AV_INCOMING_SST,
+    BTA_AV_OPENING_SST,
+    BTA_AV_OPEN_SST,
+    BTA_AV_RCFG_SST,
+    BTA_AV_CLOSING_SST
+};
+
+
+/* the call out functions for audio stream */
+const tBTA_AV_CO_FUNCTS bta_av_a2d_cos =
+{
+    bta_av_co_audio_init,
+    bta_av_co_audio_disc_res,
+    bta_av_co_audio_getconfig,
+    bta_av_co_audio_setconfig,
+    bta_av_co_audio_open,
+    bta_av_co_audio_close,
+    bta_av_co_audio_start,
+    bta_av_co_audio_stop,
+    bta_av_co_audio_src_data_path,
+    bta_av_co_audio_delay
+};
+
+/* ssm action functions for audio stream */
+const tBTA_AV_SACT bta_av_a2d_action[] =
+{
+    bta_av_do_disc_a2d,     /* BTA_AV_DO_DISC  */
+    bta_av_cleanup,         /* BTA_AV_CLEANUP */
+    bta_av_free_sdb,        /* BTA_AV_FREE_SDB */
+    bta_av_config_ind,      /* BTA_AV_CONFIG_IND */
+    bta_av_disconnect_req,  /* BTA_AV_DISCONNECT_REQ */
+    bta_av_security_req,    /* BTA_AV_SECURITY_REQ */
+    bta_av_security_rsp,    /* BTA_AV_SECURITY_RSP */
+    bta_av_setconfig_rsp,   /* BTA_AV_SETCONFIG_RSP */
+    bta_av_st_rc_timer,     /* BTA_AV_ST_RC_TIMER */
+    bta_av_str_opened,      /* BTA_AV_STR_OPENED */
+    bta_av_security_ind,    /* BTA_AV_SECURITY_IND */
+    bta_av_security_cfm,    /* BTA_AV_SECURITY_CFM */
+    bta_av_do_close,        /* BTA_AV_DO_CLOSE */
+    bta_av_connect_req,     /* BTA_AV_CONNECT_REQ */
+    bta_av_sdp_failed,      /* BTA_AV_SDP_FAILED */
+    bta_av_disc_results,    /* BTA_AV_DISC_RESULTS */
+    bta_av_disc_res_as_acp, /* BTA_AV_DISC_RES_AS_ACP */
+    bta_av_open_failed,     /* BTA_AV_OPEN_FAILED */
+    bta_av_getcap_results,  /* BTA_AV_GETCAP_RESULTS */
+    bta_av_setconfig_rej,   /* BTA_AV_SETCONFIG_REJ */
+    bta_av_discover_req,    /* BTA_AV_DISCOVER_REQ */
+    bta_av_conn_failed,     /* BTA_AV_CONN_FAILED */
+    bta_av_do_start,        /* BTA_AV_DO_START */
+    bta_av_str_stopped,     /* BTA_AV_STR_STOPPED */
+    bta_av_reconfig,        /* BTA_AV_RECONFIG */
+    bta_av_data_path,       /* BTA_AV_DATA_PATH */
+    bta_av_start_ok,        /* BTA_AV_START_OK */
+    bta_av_start_failed,    /* BTA_AV_START_FAILED */
+    bta_av_str_closed,      /* BTA_AV_STR_CLOSED */
+    bta_av_clr_cong,        /* BTA_AV_CLR_CONG */
+    bta_av_suspend_cfm,     /* BTA_AV_SUSPEND_CFM */
+    bta_av_rcfg_str_ok,     /* BTA_AV_RCFG_STR_OK */
+    bta_av_rcfg_failed,     /* BTA_AV_RCFG_FAILED */
+    bta_av_rcfg_connect,    /* BTA_AV_RCFG_CONNECT */
+    bta_av_rcfg_discntd,    /* BTA_AV_RCFG_DISCNTD */
+    bta_av_suspend_cont,    /* BTA_AV_SUSPEND_CONT */
+    bta_av_rcfg_cfm,        /* BTA_AV_RCFG_CFM */
+    bta_av_rcfg_open,       /* BTA_AV_RCFG_OPEN */
+    bta_av_security_rej,    /* BTA_AV_SECURITY_REJ */
+    bta_av_open_rc,         /* BTA_AV_OPEN_RC */
+    bta_av_chk_2nd_start,   /* BTA_AV_CHK_2ND_START */
+    bta_av_save_caps,       /* BTA_AV_SAVE_CAPS */
+    bta_av_set_use_rc,      /* BTA_AV_SET_USE_RC */
+    bta_av_cco_close,       /* BTA_AV_CCO_CLOSE */
+    bta_av_switch_role,     /* BTA_AV_SWITCH_ROLE */
+    bta_av_role_res,        /* BTA_AV_ROLE_RES */
+    bta_av_delay_co,        /* BTA_AV_DELAY_CO */
+    bta_av_open_at_inc,     /* BTA_AV_OPEN_AT_INC */
+    NULL
+};
+
+/* these tables translate AVDT events to SSM events */
+static const UINT16 bta_av_stream_evt_ok[] = {
+    BTA_AV_STR_DISC_OK_EVT,         /* AVDT_DISCOVER_CFM_EVT */
+    BTA_AV_STR_GETCAP_OK_EVT,       /* AVDT_GETCAP_CFM_EVT */
+    BTA_AV_STR_OPEN_OK_EVT,         /* AVDT_OPEN_CFM_EVT */
+    BTA_AV_STR_OPEN_OK_EVT,         /* AVDT_OPEN_IND_EVT */
+    BTA_AV_STR_CONFIG_IND_EVT,      /* AVDT_CONFIG_IND_EVT */
+    BTA_AV_STR_START_OK_EVT,        /* AVDT_START_CFM_EVT */
+    BTA_AV_STR_START_OK_EVT,        /* AVDT_START_IND_EVT */
+    BTA_AV_STR_SUSPEND_CFM_EVT,     /* AVDT_SUSPEND_CFM_EVT */
+    BTA_AV_STR_SUSPEND_CFM_EVT,     /* AVDT_SUSPEND_IND_EVT */
+    BTA_AV_STR_CLOSE_EVT,           /* AVDT_CLOSE_CFM_EVT */
+    BTA_AV_STR_CLOSE_EVT,           /* AVDT_CLOSE_IND_EVT */
+    BTA_AV_STR_RECONFIG_CFM_EVT,    /* AVDT_RECONFIG_CFM_EVT */
+    0,                              /* AVDT_RECONFIG_IND_EVT */
+    BTA_AV_STR_SECURITY_CFM_EVT,    /* AVDT_SECURITY_CFM_EVT */
+    BTA_AV_STR_SECURITY_IND_EVT,    /* AVDT_SECURITY_IND_EVT */
+    BTA_AV_STR_WRITE_CFM_EVT,       /* AVDT_WRITE_CFM_EVT */
+    BTA_AV_AVDT_CONNECT_EVT,        /* AVDT_CONNECT_IND_EVT */
+    BTA_AV_AVDT_DISCONNECT_EVT,     /* AVDT_DISCONNECT_IND_EVT */
+#if (AVDT_REPORTING == TRUE)
+    BTA_AV_AVDT_RPT_CONN_EVT,       /* AVDT_REPORT_CONN_EVT */
+    BTA_AV_AVDT_RPT_CONN_EVT,       /* AVDT_REPORT_DISCONN_EVT */
+#endif
+    BTA_AV_AVDT_DELAY_RPT_EVT,      /* AVDT_DELAY_REPORT_EVT */
+    0                               /* AVDT_DELAY_REPORT_CFM_EVT */
+};
+
+static const UINT16 bta_av_stream_evt_fail[] = {
+    BTA_AV_STR_DISC_FAIL_EVT,       /* AVDT_DISCOVER_CFM_EVT */
+    BTA_AV_STR_GETCAP_FAIL_EVT,     /* AVDT_GETCAP_CFM_EVT */
+    BTA_AV_STR_OPEN_FAIL_EVT,       /* AVDT_OPEN_CFM_EVT */
+    BTA_AV_STR_OPEN_OK_EVT,         /* AVDT_OPEN_IND_EVT */
+    BTA_AV_STR_CONFIG_IND_EVT,      /* AVDT_CONFIG_IND_EVT */
+    BTA_AV_STR_START_FAIL_EVT,      /* AVDT_START_CFM_EVT */
+    BTA_AV_STR_START_OK_EVT,        /* AVDT_START_IND_EVT */
+    BTA_AV_STR_SUSPEND_CFM_EVT,     /* AVDT_SUSPEND_CFM_EVT */
+    BTA_AV_STR_SUSPEND_CFM_EVT,     /* AVDT_SUSPEND_IND_EVT */
+    BTA_AV_STR_CLOSE_EVT,           /* AVDT_CLOSE_CFM_EVT */
+    BTA_AV_STR_CLOSE_EVT,           /* AVDT_CLOSE_IND_EVT */
+    BTA_AV_STR_RECONFIG_CFM_EVT,    /* AVDT_RECONFIG_CFM_EVT */
+    0,                              /* AVDT_RECONFIG_IND_EVT */
+    BTA_AV_STR_SECURITY_CFM_EVT,    /* AVDT_SECURITY_CFM_EVT */
+    BTA_AV_STR_SECURITY_IND_EVT,    /* AVDT_SECURITY_IND_EVT */
+    BTA_AV_STR_WRITE_CFM_EVT,       /* AVDT_WRITE_CFM_EVT */
+    BTA_AV_AVDT_CONNECT_EVT,        /* AVDT_CONNECT_IND_EVT */
+    BTA_AV_AVDT_DISCONNECT_EVT,     /* AVDT_DISCONNECT_IND_EVT */
+#if (AVDT_REPORTING == TRUE)
+    BTA_AV_AVDT_RPT_CONN_EVT,       /* AVDT_REPORT_CONN_EVT */
+    BTA_AV_AVDT_RPT_CONN_EVT,       /* AVDT_REPORT_DISCONN_EVT */
+#endif
+    BTA_AV_AVDT_DELAY_RPT_EVT,      /* AVDT_DELAY_REPORT_EVT */
+    0                               /* AVDT_DELAY_REPORT_CFM_EVT */
+};
+
+static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+static void bta_av_stream1_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+#if BTA_AV_NUM_STRS > 2
+static void bta_av_stream2_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+#endif
+#if BTA_AV_NUM_STRS > 3
+static void bta_av_stream3_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+#endif
+#if BTA_AV_NUM_STRS > 4
+static void bta_av_stream4_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+#endif
+#if BTA_AV_NUM_STRS > 5
+static void bta_av_stream5_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
+#endif
+/* the array of callback functions to receive events from AVDT control channel */
+tAVDT_CTRL_CBACK * const bta_av_dt_cback[] =
+{
+    bta_av_stream0_cback
+    ,bta_av_stream1_cback
+#if BTA_AV_NUM_STRS > 2
+    ,bta_av_stream2_cback
+#endif
+#if BTA_AV_NUM_STRS > 3
+    ,bta_av_stream3_cback
+#endif
+#if BTA_AV_NUM_STRS > 4
+    ,bta_av_stream4_cback
+#endif
+#if BTA_AV_NUM_STRS > 5
+    ,bta_av_stream5_cback
+#endif
+};
+
+/*******************************************************************************
+**
+** Function         bta_av_save_addr
+**
+** Description      copy the bd_addr and maybe reset the supported flags
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_save_addr(tBTA_AV_SCB *p_scb, const BD_ADDR b)
+{
+    APPL_TRACE_DEBUG2("bta_av_save_addr r:%d, s:%d",
+        p_scb->recfg_sup, p_scb->suspend_sup);
+    if(bdcmp(p_scb->peer_addr, b) != 0)
+    {
+        APPL_TRACE_ERROR0("reset flags");
+        /* a new addr, reset the supported flags */
+        p_scb->recfg_sup    = TRUE;
+        p_scb->suspend_sup  = TRUE;
+    }
+
+    /* do this copy anyway, just in case the first addr matches
+     * the control block one by accident */
+    bdcpy(p_scb->peer_addr, b);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_st_rc_timer
+**
+** Description      start the AVRC timer if no RC connection & CT is supported &
+**                  RC is used or
+**                  as ACP (we do not really know if we want AVRC)
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+
+    APPL_TRACE_DEBUG2("bta_av_st_rc_timer rc_handle:%d, use_rc: %d",
+        p_scb->rc_handle, p_scb->use_rc);
+    /* for outgoing RC connection as INT/CT */
+    if( (p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) &&
+        /*(bta_av_cb.features & BTA_AV_FEAT_RCCT) &&*/
+        (p_scb->use_rc == TRUE || (p_scb->role & BTA_AV_ROLE_AD_ACP)) )
+    {
+        if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0)
+            bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL);
+        else
+            p_scb->wait |= BTA_AV_WAIT_CHECK_RC;
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_next_getcap
+**
+** Description      The function gets the capabilities of the next available
+**                  stream found in the discovery results.
+**
+** Returns          TRUE if we sent request to AVDT, FALSE otherwise.
+**
+*******************************************************************************/
+static BOOLEAN bta_av_next_getcap(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    int     i;
+    tAVDT_GETCAP_REQ    *p_req;
+    BOOLEAN     sent_cmd = FALSE;
+
+    for (i = p_scb->sep_info_idx; i < p_scb->num_seps; i++)
+    {
+        /* steam not in use, is a sink, and is the right media type (audio/video) */
+        if ((p_scb->sep_info[i].in_use == FALSE) &&
+            (p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
+            (p_scb->sep_info[i].media_type == p_scb->media_type))
+        {
+            p_scb->sep_info_idx = i;
+
+            /* we got a stream; get its capabilities */
+            if (p_scb->p_cap == NULL)
+            {
+                p_scb->p_cap = (tAVDT_CFG *) GKI_getbuf(sizeof(tAVDT_CFG));
+            }
+            if (p_scb->p_cap == NULL)
+            {
+                i = p_scb->num_seps;
+                break;
+            }
+            if (p_scb->avdt_version >= AVDT_VERSION_SYNC)
+            {
+                p_req = AVDT_GetAllCapReq;
+            }
+            else
+            {
+                p_req = AVDT_GetCapReq;
+            }
+            (*p_req)(p_scb->peer_addr,
+                           p_scb->sep_info[i].seid,
+                           p_scb->p_cap, bta_av_dt_cback[p_scb->hdi]);
+            sent_cmd = TRUE;
+            break;
+        }
+    }
+
+    /* if no streams available then stream open fails */
+    if (!sent_cmd)
+    {
+        bta_av_ssm_execute(p_scb, BTA_AV_STR_GETCAP_FAIL_EVT, p_data);
+    }
+
+    return sent_cmd;
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_proc_stream_evt
+**
+** Description      Utility function to compose stream events.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_proc_stream_evt(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data, int index)
+{
+    tBTA_AV_STR_MSG     *p_msg;
+    UINT16              sec_len = 0;
+    tBTA_AV_SCB         *p_scb = bta_av_cb.p_scb[index];
+    int                 xx;
+
+    if (p_data)
+    {
+        if (event == AVDT_SECURITY_IND_EVT)
+        {
+            sec_len = (p_data->security_ind.len < BTA_AV_SECURITY_MAX_LEN) ?
+                       p_data->security_ind.len : BTA_AV_SECURITY_MAX_LEN;
+        }
+        else if (event == AVDT_SECURITY_CFM_EVT && p_data->hdr.err_code == 0)
+        {
+            sec_len = (p_data->security_cfm.len < BTA_AV_SECURITY_MAX_LEN) ?
+                       p_data->security_cfm.len : BTA_AV_SECURITY_MAX_LEN;
+        }
+    }
+
+    if (p_scb && (p_msg = (tBTA_AV_STR_MSG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_STR_MSG) + sec_len))) != NULL)
+    {
+
+        /* copy event data, bd addr, and handle to event message buffer */
+        p_msg->hdr.offset = 0;
+
+        if (bd_addr != NULL)
+        {
+            bdcpy(p_msg->bd_addr, bd_addr);
+            APPL_TRACE_DEBUG6("  bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+                          bd_addr[0], bd_addr[1],
+                          bd_addr[2], bd_addr[3],
+                          bd_addr[4], bd_addr[5]);
+        }
+
+        if (p_data != NULL)
+        {
+            memcpy(&p_msg->msg, p_data, sizeof (tAVDT_CTRL));
+            /* copy config params to event message buffer */
+            switch (event)
+            {
+            case AVDT_CONFIG_IND_EVT:
+            /* We might have 2 SEP signallings(A2DP + VDP) with one peer device on one L2CAP.
+             * If we already have a signalling connection with the bd_addr and the streaming
+             * SST is at INIT state, change it to INCOMING state to handle the signalling
+             * from the 2nd SEP.                                                                */
+            if ((bta_av_find_lcb(bd_addr, BTA_AV_LCB_FIND) != NULL) && (bta_av_is_scb_init(p_scb)))
+            {
+                bta_av_set_scb_sst_incoming (p_scb);
+
+                /* When ACP_CONNECT_EVT was received, we put first available scb to incoming state.
+                 * Later when we receive AVDT_CONFIG_IND_EVT, we use a new p_scb and set its state to
+                 * incoming which we do it above.
+                 * We also have to set the old p_scb state to init to be used later             */
+                for (xx = 0; xx < BTA_AV_NUM_STRS; xx++)
+                {
+                    if ((bta_av_cb.p_scb[xx]) && (xx != index))
+                    {
+                        if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST)
+                        {
+                            bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST;
+                            bta_av_cb.p_scb[xx]->coll_mask = 0;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            memcpy(&p_msg->cfg, p_data->config_ind.p_cfg, sizeof(tAVDT_CFG));
+            break;
+
+            case AVDT_SECURITY_IND_EVT:
+                p_msg->msg.security_ind.p_data = (UINT8 *) (p_msg + 1);
+                memcpy(p_msg->msg.security_ind.p_data, p_data->security_ind.p_data, sec_len);
+                break;
+
+            case AVDT_SECURITY_CFM_EVT:
+                p_msg->msg.security_cfm.p_data = (UINT8 *) (p_msg + 1);
+                if (p_data->hdr.err_code == 0)
+                {
+                    memcpy(p_msg->msg.security_cfm.p_data, p_data->security_cfm.p_data, sec_len);
+                }
+                break;
+            case AVDT_SUSPEND_IND_EVT:
+                    p_msg->msg.hdr.err_code = 0;
+                break;
+
+            default:
+                break;
+            }
+        }
+        else
+            p_msg->msg.hdr.err_code = 0;
+
+        /* look up application event */
+        if ((p_data == NULL) || (p_data->hdr.err_code == 0))
+        {
+            p_msg->hdr.event = bta_av_stream_evt_ok[event];
+        }
+        else
+        {
+            p_msg->hdr.event = bta_av_stream_evt_fail[event];
+        }
+
+        p_msg->initiator = FALSE;
+        if (event == AVDT_SUSPEND_CFM_EVT)
+            p_msg->initiator = TRUE;
+
+        APPL_TRACE_EVENT1("hndl:x%x", p_scb->hndl);
+        p_msg->hdr.layer_specific = p_scb->hndl;
+        p_msg->handle   = handle;
+        p_msg->avdt_event = event;
+        bta_sys_sendmsg(p_msg);
+    }
+
+/* coverity[var_deref_model]: Variable "p_data" tracked as NULL was passed to function "bta_av_conn_cback" that dereferences it.
+ * false-positive: bta_av_conn_cback only processes AVDT_CONNECT_IND_EVT and AVDT_DISCONNECT_IND_EVT event
+ *                 these 2 events always have associated p_data
+ */
+    bta_av_conn_cback(handle, bd_addr, event, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_stream0_cback
+**
+** Description      This is the AVDTP callback function for stream events.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+    APPL_TRACE_EVENT2("bta_av_stream0_cback avdt_handle: %d event=0x%x", handle, event);
+    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 0);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_stream1_cback
+**
+** Description      This is the AVDTP callback function for stream events.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_stream1_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+    APPL_TRACE_EVENT2("bta_av_stream1_cback avdt_handle: %d event=0x%x", handle, event);
+    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 1);
+}
+
+#if BTA_AV_NUM_STRS > 2
+/*******************************************************************************
+**
+** Function         bta_av_stream2_cback
+**
+** Description      This is the AVDTP callback function for stream events.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_stream2_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+    APPL_TRACE_EVENT2("bta_av_stream2_cback avdt_handle: %d event=0x%x", handle, event);
+    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 2);
+}
+#endif
+
+#if BTA_AV_NUM_STRS > 3
+/*******************************************************************************
+**
+** Function         bta_av_stream3_cback
+**
+** Description      This is the AVDTP callback function for stream events.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_stream3_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+    APPL_TRACE_EVENT2("bta_av_stream3_cback avdt_handle: %d event=0x%x", handle, event);
+    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 3);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_av_stream4_cback
+**
+** Description      This is the AVDTP callback function for stream events.
+**
+** Returns          void
+**
+*******************************************************************************/
+#if BTA_AV_NUM_STRS > 4
+static void bta_av_stream4_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+    APPL_TRACE_EVENT2("bta_av_stream4_cback avdt_handle: %d event=0x%x", handle, event);
+    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 4);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_av_stream5_cback
+**
+** Description      This is the AVDTP callback function for stream events.
+**
+** Returns          void
+**
+*******************************************************************************/
+#if BTA_AV_NUM_STRS > 5
+static void bta_av_stream5_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
+{
+    APPL_TRACE_EVENT2("bta_av_stream5_cback avdt_handle: %d event=0x%x", handle, event);
+    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 5);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         bta_av_a2d_sdp_cback
+**
+** Description      A2DP service discovery callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_a2d_sdp_cback(BOOLEAN found, tA2D_Service *p_service)
+{
+    tBTA_AV_SDP_RES *p_msg;
+    tBTA_AV_SCB     *p_scb;
+
+    if ((p_msg = (tBTA_AV_SDP_RES *) GKI_getbuf(sizeof(tBTA_AV_SDP_RES))) != NULL)
+    {
+        p_msg->hdr.event = (found) ? BTA_AV_SDP_DISC_OK_EVT : BTA_AV_SDP_DISC_FAIL_EVT;
+
+        p_scb = bta_av_hndl_to_scb(bta_av_cb.handle);
+        if (p_scb)
+        {
+            if (found && (p_service != NULL))
+                p_scb->avdt_version = p_service->avdt_version;
+            else
+                p_scb->avdt_version = 0x00;
+
+            p_msg->hdr.layer_specific = bta_av_cb.handle;
+            bta_sys_sendmsg(p_msg);
+        }
+        else
+        {
+            APPL_TRACE_ERROR1 ("bta_av_a2d_sdp_cback, no scb found for handle(0x%x)", bta_av_cb.handle);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_adjust_seps_idx
+**
+** Description      adjust the sep_idx
+**
+** Returns
+**
+*******************************************************************************/
+static void bta_av_adjust_seps_idx(tBTA_AV_SCB *p_scb)
+{
+    int             xx;
+
+    APPL_TRACE_DEBUG1("bta_av_adjust_seps_idx codec_type: %d", p_scb->codec_type);
+    for(xx=0; xx<BTA_AV_MAX_SEPS; xx++)
+    {
+        APPL_TRACE_DEBUG2("av_handle: %d codec_type: %d",
+            p_scb->seps[xx].av_handle, p_scb->seps[xx].codec_type);
+        if(p_scb->seps[xx].av_handle && p_scb->codec_type == p_scb->seps[xx].codec_type)
+        {
+            p_scb->sep_idx      = xx;
+            p_scb->avdt_handle  = p_scb->seps[xx].av_handle;
+            break;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_switch_role
+**
+** Description      Switch role was not started and a timer was started.
+**                  another attempt to switch role now - still opening.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_switch_role (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_RS_RES      switch_res = BTA_AV_RS_NONE;
+    tBTA_AV_API_OPEN  *p_buf = &p_scb->q_info.open;
+
+    APPL_TRACE_DEBUG1("bta_av_switch_role wait:x%x", p_scb->wait);
+    if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START)
+        p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RETRY;
+
+    /* clear the masks set when the timer is started */
+    p_scb->wait &= ~(BTA_AV_WAIT_ROLE_SW_RES_OPEN|BTA_AV_WAIT_ROLE_SW_RES_START);
+
+    if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN)
+    {
+        if (bta_av_switch_if_needed(p_scb) || !bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT))
+        {
+            p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+        }
+        else
+        {
+            /* this should not happen in theory. Just in case...
+             * continue to do_disc_a2d */
+            switch_res = BTA_AV_RS_DONE;
+        }
+    }
+    else
+    {
+        /* report failure on OPEN */
+        switch_res = BTA_AV_RS_FAIL;
+    }
+
+    if (switch_res != BTA_AV_RS_NONE)
+    {
+        if (bta_av_cb.rs_idx == (p_scb->hdi + 1))
+        {
+            bta_av_cb.rs_idx = 0;
+        }
+        p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_RETRY;
+        p_scb->q_tag = 0;
+        p_buf->switch_res = switch_res;
+        bta_av_do_disc_a2d(p_scb, (tBTA_AV_DATA *)p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_role_res
+**
+** Description      Handle the role changed event
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_role_res (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    BOOLEAN         initiator = FALSE;
+    tBTA_AV_START   start;
+    tBTA_AV_OPEN    av_open;
+
+    APPL_TRACE_DEBUG3("bta_av_role_res q_tag:%d, wait:x%x, role:x%x", p_scb->q_tag, p_scb->wait, p_scb->role);
+    if (p_scb->role & BTA_AV_ROLE_START_INT)
+        initiator = TRUE;
+
+    if (p_scb->q_tag == BTA_AV_Q_TAG_START)
+    {
+        if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_STARTED)
+        {
+            p_scb->role &= ~BTA_AV_ROLE_START_INT;
+            p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+            if (p_data->role_res.hci_status != HCI_SUCCESS)
+            {
+                bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+                /* start failed because of role switch. */
+                start.chnl   = p_scb->chnl;
+                start.status = BTA_AV_FAIL_ROLE;
+                start.hndl   = p_scb->hndl;
+                start.initiator = initiator;
+                (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
+            }
+            else
+            {
+                bta_av_start_ok(p_scb, p_data);
+            }
+        }
+        else if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START)
+            p_scb->wait |= BTA_AV_WAIT_ROLE_SW_FAILED;
+    }
+    else if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN)
+    {
+        if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_OPEN)
+        {
+            p_scb->role &= ~BTA_AV_ROLE_START_INT;
+            p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+
+            if (p_data->role_res.hci_status != HCI_SUCCESS)
+            {
+                /* Open failed because of role switch. */
+                bdcpy(av_open.bd_addr, p_scb->peer_addr);
+                av_open.chnl   = p_scb->chnl;
+                av_open.hndl   = p_scb->hndl;
+                start.status = BTA_AV_FAIL_ROLE;
+                (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *)&av_open);
+            }
+            else
+            {
+                /* Continue av open process */
+                p_scb->q_info.open.switch_res = BTA_AV_RS_DONE;
+                bta_av_do_disc_a2d (p_scb, (tBTA_AV_DATA *)&(p_scb->q_info.open));
+            }
+        }
+        else
+        {
+            APPL_TRACE_WARNING2 ("Unexpected role switch event: q_tag = %d wait = %d", p_scb->q_tag, p_scb->wait);
+        }
+    }
+
+    APPL_TRACE_DEBUG2("wait:x%x, role:x%x", p_scb->wait, p_scb->role);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_delay_co
+**
+** Description      Call the delay call-out function to report the delay report
+**                  from SNK
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_delay_co (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    p_scb->p_cos->delay(p_scb->hndl, p_data->str_msg.msg.delay_rpt_cmd.delay);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_do_disc_a2d
+**
+** Description      Do service discovery for A2DP.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_do_disc_a2d (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    BOOLEAN     ok_continue = FALSE;
+    tA2D_SDP_DB_PARAMS  db_params;
+    UINT16              attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
+                                       ATTR_ID_PROTOCOL_DESC_LIST,
+                                       ATTR_ID_BT_PROFILE_DESC_LIST};
+
+    APPL_TRACE_DEBUG3("bta_av_do_disc_a2d use_rc: %d rs:%d, oc:%d",
+        p_data->api_open.use_rc, p_data->api_open.switch_res, bta_av_cb.audio_open_cnt);
+
+    memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
+
+    switch(p_data->api_open.switch_res)
+    {
+    case BTA_AV_RS_NONE:
+        if (bta_av_switch_if_needed(p_scb) || !bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT))
+        {
+            /* waiting for role switch result. save the api to control block */
+            memcpy(&p_scb->q_info.open, &p_data->api_open, sizeof(tBTA_AV_API_OPEN));
+            p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+            p_scb->q_tag = BTA_AV_Q_TAG_OPEN;
+        }
+        else
+        {
+            ok_continue = TRUE;
+        }
+        break;
+
+    case BTA_AV_RS_FAIL:
+        /* report a new failure event  */
+        p_scb->open_status = BTA_AV_FAIL_ROLE;
+        bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_FAIL_EVT, NULL);
+        break;
+
+    case BTA_AV_RS_OK:
+        p_data = (tBTA_AV_DATA *)&p_scb->q_info.open;
+        /* continue to open if link role is ok */
+        if (bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT))
+        {
+            ok_continue = TRUE;
+        }
+        else
+        {
+            p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+        }
+        break;
+
+    case BTA_AV_RS_DONE:
+        ok_continue = TRUE;
+        break;
+    }
+
+    APPL_TRACE_DEBUG3("ok_continue: %d wait:x%x, q_tag: %d", ok_continue, p_scb->wait, p_scb->q_tag);
+    if (!ok_continue)
+        return;
+
+    /* clear the role switch bits */
+    p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+
+    if (p_scb->wait & BTA_AV_WAIT_CHECK_RC)
+    {
+        p_scb->wait &= ~BTA_AV_WAIT_CHECK_RC;
+        bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL);
+    }
+
+    if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
+    {
+    L2CA_SetDesireRole(L2CAP_ROLE_DISALLOW_SWITCH);
+
+    if (bta_av_cb.audio_open_cnt == 1)
+    {
+        /* there's already an A2DP connection. do not allow switch */
+        bta_sys_clear_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH);
+    }
+    }
+    /* store peer addr other parameters */
+    bta_av_save_addr(p_scb, p_data->api_open.bd_addr);
+    p_scb->sec_mask = p_data->api_open.sec_mask;
+    p_scb->use_rc = p_data->api_open.use_rc;
+
+    bta_sys_app_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+
+    /* allocate discovery database */
+    if (p_scb->p_disc_db == NULL)
+    {
+        p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AV_DISC_BUF_SIZE);
+    }
+
+    /* only one A2D find service is active at a time */
+    bta_av_cb.handle = p_scb->hndl;
+
+    if(p_scb->p_disc_db)
+    {
+        /* set up parameters */
+        db_params.db_len = BTA_AV_DISC_BUF_SIZE;
+        db_params.num_attr = 3;
+        db_params.p_db = p_scb->p_disc_db;
+        db_params.p_attrs = attr_list;
+
+        if(A2D_FindService(UUID_SERVCLASS_AUDIO_SINK, p_scb->peer_addr, &db_params,
+                        bta_av_a2d_sdp_cback) == A2D_SUCCESS)
+        {
+            return;
+        }
+    }
+
+    /* when the code reaches here, either the DB is NULL
+     * or A2D_FindService is not successful */
+    bta_av_a2d_sdp_cback(FALSE, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_cleanup
+**
+** Description      cleanup AV stream control block.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_cleanup(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_CONN_CHG msg;
+    int             xx;
+    UINT8           role = BTA_AV_ROLE_AD_INT;
+
+    APPL_TRACE_DEBUG0("bta_av_cleanup");
+
+    /* free any buffers */
+    utl_freebuf((void **) &p_scb->p_cap);
+    utl_freebuf((void **) &p_scb->p_disc_db);
+    p_scb->avdt_version = 0;
+
+    /* initialize some control block variables */
+    p_scb->open_status = BTA_AV_SUCCESS;
+
+    /* if de-registering shut everything down */
+    msg.hdr.layer_specific  = p_scb->hndl;
+    p_scb->started  = FALSE;
+    p_scb->cong = FALSE;
+    p_scb->role = role;
+    p_scb->cur_psc_mask = 0;
+    p_scb->wait = 0;
+    p_scb->num_disc_snks = 0;
+    bta_sys_stop_timer(&p_scb->timer);
+    if (p_scb->deregistring)
+    {
+        /* remove stream */
+        for(xx=0; xx<BTA_AV_MAX_SEPS; xx++)
+        {
+            if(p_scb->seps[xx].av_handle)
+                AVDT_RemoveStream(p_scb->seps[xx].av_handle);
+            p_scb->seps[xx].av_handle = 0;
+        }
+
+        bta_av_dereg_comp((tBTA_AV_DATA *) &msg);
+    }
+    else
+    {
+        /* report stream closed to main SM */
+        msg.is_up = FALSE;
+        bdcpy(msg.peer_addr, p_scb->peer_addr);
+        bta_av_conn_chg((tBTA_AV_DATA *) &msg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_free_sdb
+**
+** Description      Free service discovery db buffer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_free_sdb(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    utl_freebuf((void **) &p_scb->p_disc_db);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_config_ind
+**
+** Description      Handle a stream configuration indication from the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_config_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_CI_SETCONFIG setconfig;
+    tAVDT_SEP_INFO       *p_info;
+    tAVDT_CFG            *p_evt_cfg = &p_data->str_msg.cfg;
+    UINT8   psc_mask = (p_evt_cfg->psc_mask | p_scb->cfg.psc_mask);
+
+    p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
+    memcpy(p_scb->cfg.codec_info, p_evt_cfg->codec_info, AVDT_CODEC_SIZE);
+    p_scb->codec_type = p_evt_cfg->codec_info[BTA_AV_CODEC_TYPE_IDX];
+    bta_av_save_addr(p_scb, p_data->str_msg.bd_addr);
+
+    /* Clear collision mask */
+    p_scb->coll_mask = 0;
+    bta_sys_stop_timer(&bta_av_cb.acp_sig_tmr);
+
+    /* if no codec parameters in configuration, fail */
+    if ((p_evt_cfg->num_codec == 0) ||
+    /* or the peer requests for a service we do not support */
+        ((psc_mask != p_scb->cfg.psc_mask) &&
+        (psc_mask != (p_scb->cfg.psc_mask&~AVDT_PSC_DELAY_RPT))) )
+    {
+        setconfig.hndl      = p_scb->hndl; /* we may not need this */
+        setconfig.err_code  = AVDT_ERR_UNSUP_CFG;
+        bta_av_ssm_execute(p_scb, BTA_AV_CI_SETCONFIG_FAIL_EVT, (tBTA_AV_DATA *) &setconfig);
+    }
+    else
+    {
+        p_info = &p_scb->sep_info[0];
+        p_info->in_use = 0;
+        p_info->media_type = p_scb->media_type;
+        p_info->seid = p_data->str_msg.msg.config_ind.int_seid;
+        p_info->tsep = AVDT_TSEP_SNK;
+        p_scb->role      |= BTA_AV_ROLE_AD_ACP;
+        p_scb->cur_psc_mask = p_evt_cfg->psc_mask;
+        if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
+            p_scb->use_rc = TRUE;
+        else
+            p_scb->use_rc = FALSE;
+
+        p_scb->num_seps  = 1;
+        p_scb->sep_info_idx = 0;
+        APPL_TRACE_DEBUG3("bta_av_config_ind: SEID: %d use_rc: %d cur_psc_mask:0x%x", p_info->seid, p_scb->use_rc, p_scb->cur_psc_mask);
+
+        p_scb->p_cos->setcfg(p_scb->hndl, p_scb->codec_type,
+                             p_evt_cfg->codec_info,
+                             p_info->seid,
+                             p_scb->peer_addr,
+                             p_evt_cfg->num_protect,
+                             p_evt_cfg->protect_info);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_disconnect_req
+**
+** Description      Disconnect AVDTP connection.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_disconnect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_RCB *p_rcb;
+    APPL_TRACE_DEBUG1("bta_av_disconnect_req conn_lcb: 0x%x", bta_av_cb.conn_lcb);
+
+    bta_sys_stop_timer(&bta_av_cb.sig_tmr);
+    bta_sys_stop_timer(&p_scb->timer);
+    if(bta_av_cb.conn_lcb)
+    {
+        p_rcb = bta_av_get_rcb_by_shdl((UINT8)(p_scb->hdi + 1));
+        if (p_rcb)
+            bta_av_del_rc(p_rcb);
+        AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+    }
+    else
+    {
+        bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_security_req
+**
+** Description      Send an AVDTP security request.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_security_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
+    {
+        AVDT_SecurityReq(p_scb->avdt_handle, p_data->api_protect_req.p_data,
+                         p_data->api_protect_req.len);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_security_rsp
+**
+** Description      Send an AVDTP security response.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_security_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
+    {
+        AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->api_protect_rsp.error_code,
+                         p_data->api_protect_rsp.p_data, p_data->api_protect_rsp.len);
+    }
+    else
+    {
+        AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC,
+                     NULL, 0);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_setconfig_rsp
+**
+** Description      setconfig is OK
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    UINT8   num = p_data->ci_setconfig.num_seid + 1;
+    UINT8   *p_seid = p_data->ci_setconfig.p_seid;
+    int     i;
+
+    /* we like this codec_type. find the sep_idx */
+    bta_av_adjust_seps_idx(p_scb);
+    APPL_TRACE_DEBUG2("bta_av_setconfig_rsp: sep_idx: %d cur_psc_mask:0x%x", p_scb->sep_idx, p_scb->cur_psc_mask);
+    AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->ci_setconfig.err_code,
+                   p_data->ci_setconfig.category);
+
+    bta_sys_stop_timer(&bta_av_cb.sig_tmr);
+
+    if(p_data->ci_setconfig.err_code == AVDT_SUCCESS)
+    {
+        p_scb->wait = BTA_AV_WAIT_ACP_CAPS_ON;
+        if(p_data->ci_setconfig.recfg_needed)
+            p_scb->role |= BTA_AV_ROLE_SUSPEND_OPT;
+        APPL_TRACE_ERROR3("bta_av_setconfig_rsp recfg_needed:%d role:x%x num:%d",
+            p_data->ci_setconfig.recfg_needed, p_scb->role, num);
+        /* callout module tells BTA the number of "good" SEPs and their SEIDs.
+         * getcap on these SEID */
+        p_scb->num_seps = num;
+
+        if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT)
+            p_scb->avdt_version = AVDT_VERSION_SYNC;
+
+
+        if (p_scb->codec_type == BTA_AV_CODEC_SBC || num > 1)
+        {
+            /* if SBC is used by the SNK as INT, discover req is not sent in bta_av_config_ind.
+             * call disc_res now */
+            p_scb->p_cos->disc_res(p_scb->hndl, num, num, p_scb->peer_addr);
+        }
+        else
+        {
+            /* we do not know the peer device and it is using non-SBC codec
+             * we need to know all the SEPs on SNK */
+            bta_av_discover_req(p_scb, NULL);
+            return;
+        }
+
+        for (i = 1; i < num; i++)
+        {
+            APPL_TRACE_DEBUG2("sep_info[%d] SEID: %d", i, p_seid[i-1]);
+            /* initialize the sep_info[] to get capabilities */
+            p_scb->sep_info[i].in_use = FALSE;
+            p_scb->sep_info[i].tsep = AVDT_TSEP_SNK;
+            p_scb->sep_info[i].media_type = p_scb->media_type;
+            p_scb->sep_info[i].seid = p_seid[i-1];
+        }
+        bta_av_next_getcap(p_scb, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_str_opened
+**
+** Description      Stream opened OK (incoming/outgoing).
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_CONN_CHG msg;
+    tBTA_AV_OPEN    open;
+    UINT8 *p;
+    UINT16 mtu;
+
+    msg.hdr.layer_specific = p_scb->hndl;
+    msg.is_up = TRUE;
+    bdcpy(msg.peer_addr, p_scb->peer_addr);
+    p_scb->l2c_cid      = AVDT_GetL2CapChannel(p_scb->avdt_handle);
+    bta_av_conn_chg((tBTA_AV_DATA *) &msg);
+    /* set the congestion flag, so AV would not send media packets by accident */
+    p_scb->cong = TRUE;
+
+
+    p_scb->stream_mtu = p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE;
+    mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
+    APPL_TRACE_DEBUG3("bta_av_str_opened l2c_cid: 0x%x stream_mtu: %d mtu: %d",
+        p_scb->l2c_cid, p_scb->stream_mtu, mtu);
+    if(mtu == 0 || mtu > p_scb->stream_mtu)
+        mtu = p_scb->stream_mtu;
+
+    /* Set the media channel as medium priority */
+    L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_MEDIUM);
+    L2CA_SetChnlFlushability (p_scb->l2c_cid, TRUE);
+
+    bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+    memset(&p_scb->q_info, 0, sizeof(tBTA_AV_Q_INFO));
+
+    p_scb->l2c_bufs = 0;
+    p_scb->p_cos->open(p_scb->hndl,
+        p_scb->codec_type, p_scb->cfg.codec_info, mtu);
+
+    {
+        /* TODO check if other audio channel is open.
+         * If yes, check if reconfig is needed
+         * Rigt now we do not do this kind of checking.
+         * BTA-AV is INT for 2nd audio connection.
+         * The application needs to make sure the current codec_info is proper.
+         * If one audio connection is open and another SNK attempts to connect to AV,
+         * the connection will be rejected.
+         */
+        /* check if other audio channel is started. If yes, start */
+        bdcpy(open.bd_addr, p_scb->peer_addr);
+        open.chnl   = p_scb->chnl;
+        open.hndl   = p_scb->hndl;
+        open.status = BTA_AV_SUCCESS;
+        open.starting = bta_av_chk_start(p_scb);
+        open.edr    = 0;
+        if( NULL != (p = BTM_ReadRemoteFeatures(p_scb->peer_addr)))
+        {
+            if(HCI_EDR_ACL_2MPS_SUPPORTED(p))
+                open.edr |= BTA_AV_EDR_2MBPS;
+            if(HCI_EDR_ACL_3MPS_SUPPORTED(p))
+                open.edr |= BTA_AV_EDR_3MBPS;
+        }
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+        bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr);
+#endif
+        (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *) &open);
+        if(open.starting)
+        {
+            bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_security_ind
+**
+** Description      Handle an AVDTP security indication.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_security_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_PROTECT_REQ protect_req;
+
+    p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
+
+    if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
+    {
+        protect_req.chnl    = p_scb->chnl;
+        protect_req.hndl    = p_scb->hndl;
+        /*
+        APPL_TRACE_EVENT1("sec ind handle: x%x", protect_req.hndl);
+        */
+        protect_req.p_data  = p_data->str_msg.msg.security_ind.p_data;
+        protect_req.len     = p_data->str_msg.msg.security_ind.len;
+
+        (*bta_av_cb.p_cback)(BTA_AV_PROTECT_REQ_EVT, (tBTA_AV *) &protect_req);
+    }
+    /* app doesn't support security indication; respond with failure */
+    else
+    {
+        AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC, NULL, 0);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_security_cfm
+**
+** Description      Handle an AVDTP security confirm.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_security_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_PROTECT_RSP protect_rsp;
+
+    if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
+    {
+        protect_rsp.chnl    = p_scb->chnl;
+        protect_rsp.hndl    = p_scb->hndl;
+        protect_rsp.p_data  = p_data->str_msg.msg.security_cfm.p_data;
+        protect_rsp.len     = p_data->str_msg.msg.security_cfm.len;
+        protect_rsp.err_code= p_data->str_msg.msg.hdr.err_code;
+
+        (*bta_av_cb.p_cback)(BTA_AV_PROTECT_RSP_EVT, (tBTA_AV *) &protect_rsp);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_do_close
+**
+** Description      Close stream.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_do_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    /* stop stream if started */
+    if (p_scb->co_started)
+    {
+        bta_av_str_stopped(p_scb, NULL);
+    }
+    bta_sys_stop_timer(&bta_av_cb.sig_tmr);
+
+    /* close stream */
+    p_scb->started = FALSE;
+
+    /* drop the buffers queued in L2CAP */
+    L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+
+    AVDT_CloseReq(p_scb->avdt_handle);
+    /* just in case that the link is congested, link is flow controled by peer or
+     * for whatever reason the the close request can not be sent in time.
+     * when this timer expires, AVDT_DisconnectReq will be called to disconnect the link
+     */
+    bta_sys_start_timer(&p_scb->timer,
+                        (UINT16)BTA_AV_API_CLOSE_EVT,
+                        BTA_AV_CLOSE_REQ_TIME_VAL);
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_connect_req
+**
+** Description      Connect AVDTP connection.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_connect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    utl_freebuf((void **) &p_scb->p_disc_db);
+
+    if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR)
+    {
+        /* SNK initiated L2C connection while SRC was doing SDP.    */
+        /* Wait until timeout to check if SNK starts signalling.    */
+        APPL_TRACE_EVENT1("bta_av_connect_req: coll_mask = 0x%2X", p_scb->coll_mask);
+        return;
+    }
+
+    AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_sdp_failed
+**
+** Description      Service discovery failed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_sdp_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    if (!p_scb->open_status)
+        p_scb->open_status = BTA_AV_FAIL_SDP;
+
+    utl_freebuf((void **) &p_scb->p_disc_db);
+    bta_av_str_closed(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_disc_results
+**
+** Description      Handle the AVDTP discover results.  Search through the
+**                  results and find the first available stream, and get
+**                  its capabilities.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_disc_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    UINT8 num_snks = 0, i;
+
+    /* store number of stream endpoints returned */
+    p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
+
+    for (i = 0; i < p_scb->num_seps; i++)
+    {
+        /* steam not in use, is a sink, and is audio */
+        if ((p_scb->sep_info[i].in_use == FALSE) &&
+            (p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
+            (p_scb->sep_info[i].media_type == p_scb->media_type))
+        {
+            num_snks++;
+        }
+    }
+
+    p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, p_scb->peer_addr);
+    p_scb->num_disc_snks = num_snks;
+
+    /* if we got any */
+    if (p_scb->num_seps > 0)
+    {
+        /* initialize index into discovery results */
+        p_scb->sep_info_idx = 0;
+
+        /* get the capabilities of the first available stream */
+        bta_av_next_getcap(p_scb, p_data);
+    }
+    /* else we got discover response but with no streams; we're done */
+    else
+    {
+        bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_disc_res_as_acp
+**
+** Description      Handle the AVDTP discover results.  Search through the
+**                  results and find the first available stream, and get
+**                  its capabilities.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_disc_res_as_acp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    UINT8 num_snks = 0, i;
+
+    /* store number of stream endpoints returned */
+    p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
+
+
+
+    for (i = 0; i < p_scb->num_seps; i++)
+    {
+        /* steam is a sink, and is audio */
+        if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
+            (p_scb->sep_info[i].media_type == p_scb->media_type))
+        {
+            p_scb->sep_info[i].in_use = FALSE;
+            num_snks++;
+        }
+    }
+
+    p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, p_scb->peer_addr);
+    p_scb->num_disc_snks = num_snks;
+
+    /* if we got any */
+    if (p_scb->num_seps > 0)
+    {
+        /* initialize index into discovery results */
+        p_scb->sep_info_idx = 0;
+
+        /* get the capabilities of the first available stream */
+        bta_av_next_getcap(p_scb, p_data);
+    }
+    /* else we got discover response but with no streams; we're done */
+    else
+    {
+        bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_save_caps
+**
+** Description      report the SNK SEP capabilities to application
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_save_caps(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tAVDT_CFG   cfg;
+    tAVDT_SEP_INFO  *p_info = &p_scb->sep_info[p_scb->sep_info_idx];
+    UINT8       old_wait = p_scb->wait;
+    BOOLEAN     getcap_done = FALSE;
+
+    APPL_TRACE_DEBUG3("bta_av_save_caps num_seps:%d sep_info_idx:%d wait:x%x",
+        p_scb->num_seps, p_scb->sep_info_idx, p_scb->wait);
+    memcpy(&cfg, p_scb->p_cap, sizeof(tAVDT_CFG));
+    /* let application know the capability of the SNK */
+    p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info[BTA_AV_CODEC_TYPE_IDX],
+        cfg.codec_info, &p_scb->sep_info_idx, p_info->seid,
+        &cfg.num_protect, cfg.protect_info);
+
+    p_scb->sep_info_idx++;
+    if(p_scb->num_seps > p_scb->sep_info_idx)
+    {
+        /* Some devices have seps at the end of the discover list, which is not */
+        /* matching media type(video not audio).                                */
+        /* In this case, we are done with getcap without sending another        */
+        /* request to AVDT.                                                     */
+        if (!bta_av_next_getcap(p_scb, p_data))
+            getcap_done = TRUE;
+    }
+    else
+        getcap_done = TRUE;
+
+    if (getcap_done)
+    {
+        /* we are done getting capabilities. restore the p_cb->sep_info_idx */
+        p_scb->sep_info_idx = 0;
+        p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON|BTA_AV_WAIT_ACP_CAPS_STARTED);
+        if (old_wait & BTA_AV_WAIT_ACP_CAPS_STARTED)
+        {
+            bta_av_start_ok (p_scb, NULL);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_set_use_rc
+**
+** Description      set to use AVRC for this stream control block.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_set_use_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    p_scb->use_rc = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_cco_close
+**
+** Description      call close call-out function.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_cco_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    UINT16 mtu;
+    mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
+
+    p_scb->p_cos->close(p_scb->hndl, p_scb->codec_type, mtu);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_open_failed
+**
+** Description      Failed to open an AVDT stream
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    p_scb->open_status = BTA_AV_FAIL_STREAM;
+    bta_av_cco_close(p_scb, p_data);
+    AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_getcap_results
+**
+** Description      Handle the AVDTP get capabilities results.  Check the codec
+**                  type and see if it matches ours.  If it does not, get the
+**                  capabilities of the next stream, if any.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tAVDT_CFG   cfg;
+    UINT8       media_type;
+    tAVDT_SEP_INFO  *p_info = &p_scb->sep_info[p_scb->sep_info_idx];
+
+    memcpy(&cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
+    cfg.num_codec = 1;
+    cfg.num_protect = p_scb->p_cap->num_protect;
+    memcpy(cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
+    memcpy(cfg.protect_info, p_scb->p_cap->protect_info, AVDT_PROTECT_SIZE);
+    media_type = p_scb->p_cap->codec_info[BTA_AV_MEDIA_TYPE_IDX] >> 4;
+
+    APPL_TRACE_DEBUG1("num_codec %d", p_scb->p_cap->num_codec);
+    APPL_TRACE_DEBUG2("media type x%x, x%x", media_type, p_scb->media_type);
+#if AVDT_MULTIPLEXING == TRUE
+    APPL_TRACE_DEBUG2("mux x%x, x%x", cfg.mux_mask, p_scb->p_cap->mux_mask);
+#endif
+
+    /* if codec present and we get a codec configuration */
+    if ((p_scb->p_cap->num_codec != 0) &&
+        (media_type == p_scb->media_type) &&
+        (p_scb->p_cos->getcfg(p_scb->hndl, p_scb->p_cap->codec_info[BTA_AV_CODEC_TYPE_IDX],
+            cfg.codec_info, &p_scb->sep_info_idx, p_info->seid,
+            &cfg.num_protect, cfg.protect_info) == 0))
+    {
+#if AVDT_MULTIPLEXING == TRUE
+        cfg.mux_mask &= p_scb->p_cap->mux_mask;
+        APPL_TRACE_DEBUG1("mux_mask used x%x", cfg.mux_mask);
+#endif
+        /* save copy of codec type and configuration */
+        p_scb->codec_type = cfg.codec_info[BTA_AV_CODEC_TYPE_IDX];
+        memcpy(&p_scb->cfg, &cfg, sizeof(tAVDT_CFG));
+        bta_av_adjust_seps_idx(p_scb);
+        /* use only the services peer supports */
+        cfg.psc_mask &= p_scb->p_cap->psc_mask;
+        p_scb->cur_psc_mask = cfg.psc_mask;
+
+        /* open the stream */
+        AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr,
+                     p_scb->sep_info[p_scb->sep_info_idx].seid, &cfg);
+
+        if (!bta_av_is_rcfg_sst(p_scb))
+        {
+            /* free capabilities buffer */
+            utl_freebuf((void **) &p_scb->p_cap);
+        }
+    }
+    else
+    {
+        /* try the next stream, if any */
+        p_scb->sep_info_idx++;
+        bta_av_next_getcap(p_scb, p_data);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_setconfig_rej
+**
+** Description      Send AVDTP set config reject.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_setconfig_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_REJECT reject;
+
+    APPL_TRACE_DEBUG0("bta_av_setconfig_rej");
+    AVDT_ConfigRsp(p_data->str_msg.handle, p_data->str_msg.msg.hdr.label, AVDT_ERR_BAD_STATE, 0);
+    bdcpy(reject.bd_addr, p_data->str_msg.bd_addr);
+    reject.hndl = p_scb->hndl;
+    (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV *) &reject);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_discover_req
+**
+** Description      Send an AVDTP discover request to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_discover_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    /* send avdtp discover request */
+
+    AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_conn_failed
+**
+** Description      AVDTP connection failed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_conn_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    p_scb->open_status = BTA_AV_FAIL_STREAM;
+    bta_av_str_closed(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_do_start
+**
+** Description      Start stream.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_do_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    UINT8 policy = HCI_ENABLE_SNIFF_MODE;
+    UINT8       cur_role;
+
+    APPL_TRACE_DEBUG3("bta_av_do_start sco_occupied:%d, role:x%x, started:%d", bta_av_cb.sco_occupied, p_scb->role, p_scb->started);
+    if (bta_av_cb.sco_occupied)
+    {
+        bta_av_start_failed(p_scb, p_data);
+        return;
+    }
+
+    /* disallow role switch during streaming, only if we are the master role
+     * i.e. allow role switch, if we are slave.
+     * It would not hurt us, if the peer device wants us to be master */
+    if ((BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS) &&
+        (cur_role == BTM_ROLE_MASTER) )
+    {
+        policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+    }
+
+    bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+    if ((p_scb->started == FALSE) && ((p_scb->role & BTA_AV_ROLE_START_INT) == 0))
+    {
+        p_scb->role |= BTA_AV_ROLE_START_INT;
+        bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+
+        AVDT_StartReq(&p_scb->avdt_handle, 1);
+    }
+    else
+    {
+        bta_av_start_ok(p_scb, NULL);
+    }
+    APPL_TRACE_DEBUG2("started %d role:x%x", p_scb->started, p_scb->role);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_str_stopped
+**
+** Description      Stream stopped.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_SUSPEND suspend_rsp;
+    UINT8   start = p_scb->started;
+    BOOLEAN sus_evt = TRUE;
+    BT_HDR  *p_buf;
+    UINT8 policy = HCI_ENABLE_SNIFF_MODE;
+
+    APPL_TRACE_ERROR2("bta_av_str_stopped:audio_open_cnt=%d, p_data %x",
+            bta_av_cb.audio_open_cnt, p_data);
+
+    bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+    if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
+        policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+    bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+    if(p_scb->co_started)
+    {
+        bta_av_stream_chg(p_scb, FALSE);
+        p_scb->co_started = FALSE;
+
+        p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
+        L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
+    }
+
+    /* if q_info.a2d is not empty, drop it now */
+    if(BTA_AV_CHNL_AUDIO == p_scb->chnl)
+    {
+        while((p_buf = (BT_HDR*)GKI_dequeue (&p_scb->q_info.a2d)) != NULL)
+        GKI_freebuf(p_buf);
+
+    /* drop the audio buffers queued in L2CAP */
+        if(p_data && p_data->api_stop.flush)
+            L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+    }
+
+    suspend_rsp.chnl = p_scb->chnl;
+    suspend_rsp.hndl = p_scb->hndl;
+
+    if (p_data && p_data->api_stop.suspend)
+    {
+        APPL_TRACE_DEBUG2("suspending: %d, sup:%d", start, p_scb->suspend_sup);
+        if ((start)  && (p_scb->suspend_sup))
+        {
+            sus_evt = FALSE;
+            p_scb->l2c_bufs = 0;
+            AVDT_SuspendReq(&p_scb->avdt_handle, 1);
+        }
+
+        if(sus_evt)
+        {
+            suspend_rsp.status = BTA_AV_SUCCESS;
+            suspend_rsp.initiator = TRUE;
+            (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV *) &suspend_rsp);
+        }
+    }
+    else
+    {
+        suspend_rsp.status = BTA_AV_SUCCESS;
+        suspend_rsp.initiator = TRUE;
+        APPL_TRACE_EVENT1("bta_av_str_stopped status %d", suspend_rsp.status);
+
+        (*bta_av_cb.p_cback)(BTA_AV_STOP_EVT, (tBTA_AV *) &suspend_rsp);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_reconfig
+**
+** Description      process the reconfigure request.
+**                  save the parameter in control block and
+**                  suspend, reconfigure or close the stream
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_reconfig (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tAVDT_CFG   *p_cfg;
+    tBTA_AV_API_STOP    stop;
+    tBTA_AV_RECONFIG    evt;
+    tBTA_AV_API_RCFG    *p_rcfg = &p_data->api_reconfig;
+
+    APPL_TRACE_DEBUG4("bta_av_reconfig r:%d, s:%d idx: %d (o:%d)",
+        p_scb->recfg_sup, p_scb->suspend_sup,
+        p_scb->rcfg_idx, p_scb->sep_info_idx);
+
+    p_scb->num_recfg = 0;
+    /* store the new configuration in control block */
+    if (p_scb->p_cap == NULL)
+    {
+        p_scb->p_cap = (tAVDT_CFG *) GKI_getbuf(sizeof(tAVDT_CFG));
+    }
+    if((p_cfg = p_scb->p_cap) == NULL)
+    {
+        /* report failure */
+        evt.status = BTA_AV_FAIL_RESOURCES;
+        evt.chnl   = p_scb->chnl;
+        evt.hndl   = p_scb->hndl;
+        (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+
+        /* this event is not possible in this state.
+         * use it to bring the SSM back to open state */
+        bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_OK_EVT, NULL);
+        return;
+    }
+
+    /*if(bta_av_cb.features & BTA_AV_FEAT_RCCT)*/
+        bta_sys_stop_timer(&p_scb->timer);
+
+    memcpy(p_cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
+    p_cfg->num_protect = p_rcfg->num_protect;
+    memcpy(p_cfg->codec_info, p_rcfg->codec_info, AVDT_CODEC_SIZE);
+    memcpy(p_cfg->protect_info, p_rcfg->p_protect_info, p_rcfg->num_protect);
+    p_scb->rcfg_idx = p_rcfg->sep_info_idx;
+    p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+
+    /* if the requested index differs from the current one, we can only close/open */
+    if ((p_scb->rcfg_idx == p_scb->sep_info_idx) &&
+        (p_rcfg->suspend)&& (p_scb->recfg_sup) && (p_scb->suspend_sup))
+    {
+        if(p_scb->started)
+        {
+            stop.flush   = FALSE;
+            stop.suspend = TRUE;
+            bta_av_str_stopped(p_scb, (tBTA_AV_DATA *)&stop);
+        }
+        else
+        {
+            APPL_TRACE_DEBUG0("Reconfig");
+            AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
+            p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+        }
+    }
+    else
+    {
+        /* close the stream */
+        APPL_TRACE_DEBUG1("close/open num_protect: %d", p_cfg->num_protect);
+        if(p_scb->started)
+            bta_av_str_stopped(p_scb, NULL);
+            p_scb->started = FALSE;
+
+            /* drop the buffers queued in L2CAP */
+            L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+
+            AVDT_CloseReq(p_scb->avdt_handle);
+
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_data_path
+**
+** Description      Handle stream data path.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_data_path (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    BT_HDR  *p_buf;
+    UINT32  data_len;
+    UINT32  timestamp;
+    BOOLEAN new_buf = FALSE;
+    UINT8   m_pt = 0x60 | p_scb->codec_type;
+
+    if (!p_scb->cong)
+    {
+        /*
+        APPL_TRACE_ERROR1("q: %d", p_scb->l2c_bufs);
+        */
+        //Always get the current number of bufs que'd up
+        p_scb->l2c_bufs = (UINT8)L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_GET);
+
+        p_buf = (BT_HDR *)GKI_dequeue (&p_scb->q_info.a2d);
+        if(p_buf)
+        {
+            /* use q_info.a2d data, read the timestamp */
+            timestamp = *(UINT32 *)(p_buf + 1);
+        }
+        else
+        {
+            new_buf = TRUE;
+            /* q_info.a2d empty, call co_data, dup data to other channels */
+            p_buf = (BT_HDR *)p_scb->p_cos->data(p_scb->codec_type, &data_len,
+                                             &timestamp);
+
+            if (p_buf)
+            {
+                /* use the offset area for the time stamp */
+                *(UINT32 *)(p_buf + 1) = timestamp;
+
+                /* dup the data to other channels */
+                bta_av_dup_audio_buf(p_scb, p_buf);
+            }
+        }
+
+        if(p_buf)
+        {
+            if(p_scb->l2c_bufs < (BTA_AV_QUEUE_DATA_CHK_NUM))
+            {
+                /* there's a buffer, just queue it to L2CAP */
+                /*  There's no need to increment it here, it is always read from L2CAP see above */
+                /* p_scb->l2c_bufs++; */
+                /*
+                APPL_TRACE_ERROR1("qw: %d", p_scb->l2c_bufs);
+                */
+                AVDT_WriteReq(p_scb->avdt_handle, p_buf, timestamp, m_pt);
+                p_scb->cong = TRUE;
+            }
+            else
+            {
+                /* there's a buffer, but L2CAP does not seem to be moving data */
+                if(new_buf)
+                {
+                    /* just got this buffer from co_data,
+                     * put it in queue */
+                    GKI_enqueue(&p_scb->q_info.a2d, p_buf);
+                }
+                else
+                {
+                    /* just dequeue it from the q_info.a2d */
+                    if(p_scb->q_info.a2d.count < 3)
+                    {
+                        /* put it back to the queue */
+                        GKI_enqueue_head (&p_scb->q_info.a2d, p_buf);
+                    }
+                    else
+                    {
+                        /* too many buffers in q_info.a2d, drop it. */
+                        bta_av_co_audio_drop(p_scb->hndl);
+                        GKI_freebuf(p_buf);
+                    }
+                }
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_start_ok
+**
+** Description      Stream started.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_START   start;
+    tBTA_AV_API_STOP stop;
+    BOOLEAN         initiator = FALSE;
+    BOOLEAN         suspend = FALSE;
+    UINT16          flush_to;
+    UINT8           new_role = p_scb->role;
+    BT_HDR          hdr;
+
+    APPL_TRACE_DEBUG2("bta_av_start_ok wait:x%x, role:x%x", p_scb->wait, p_scb->role);
+
+    p_scb->started = TRUE;
+    if (p_scb->sco_suspend)
+    {
+        p_scb->sco_suspend = FALSE;
+    }
+
+    if (new_role & BTA_AV_ROLE_START_INT)
+        initiator = TRUE;
+
+    if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_FAILED)
+    {
+        /* role switch has failed */
+        p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_FAILED;
+        p_data = (tBTA_AV_DATA *)&hdr;
+        hdr.offset = BTA_AV_RS_FAIL;
+    }
+    APPL_TRACE_DEBUG1("wait:x%x", p_scb->wait);
+
+    if (p_data && (p_data->hdr.offset != BTA_AV_RS_NONE))
+    {
+        p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+        if (p_data->hdr.offset == BTA_AV_RS_FAIL)
+        {
+            bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+            start.chnl   = p_scb->chnl;
+            start.status = BTA_AV_FAIL_ROLE;
+            start.hndl   = p_scb->hndl;
+            start.initiator = initiator;
+            (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
+            return;
+        }
+    }
+
+    if (!bta_av_link_role_ok(p_scb, A2D_SET_ONE_BIT))
+        p_scb->q_tag = BTA_AV_Q_TAG_START;
+    else
+    {
+        /* The wait flag may be set here while we are already master on the link */
+        /* this could happen if a role switch complete event occurred during reconfig */
+        /* if we are now master on the link, there is no need to wait for the role switch, */
+        /* complete anymore so we can clear the wait for role switch flag */
+        p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+    }
+
+    if (p_scb->wait & (BTA_AV_WAIT_ROLE_SW_RES_OPEN|BTA_AV_WAIT_ROLE_SW_RES_START))
+    {
+        p_scb->wait |= BTA_AV_WAIT_ROLE_SW_STARTED;
+        p_scb->q_tag = BTA_AV_Q_TAG_START;
+    }
+
+    if (p_scb->wait & BTA_AV_WAIT_ACP_CAPS_ON)
+    {
+        p_scb->wait |= BTA_AV_WAIT_ACP_CAPS_STARTED;
+    }
+
+    if (p_scb->wait)
+    {
+        APPL_TRACE_DEBUG2("wait:x%x q_tag:%d- not started", p_scb->wait, p_scb->q_tag);
+        return;
+    }
+
+    /* tell role manager to check M/S role */
+    bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+
+    bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+
+    if(p_scb->media_type == AVDT_MEDIA_AUDIO)
+    {
+        /* in normal logic, conns should be bta_av_cb.audio_count - 1,
+         * However, bta_av_stream_chg is not called to increase bta_av_cb.audio_count yet.
+         * If the code were to be re-arranged for some reasons, this number may need to be changed
+         */
+        p_scb->co_started = bta_av_cb.audio_open_cnt;
+        flush_to = p_bta_av_cfg->p_audio_flush_to[p_scb->co_started - 1];
+    }
+    else
+    {
+        flush_to = p_bta_av_cfg->video_flush_to;
+    }
+    L2CA_SetFlushTimeout(p_scb->peer_addr, flush_to );
+
+    /* clear the congestion flag */
+    p_scb->cong = FALSE;
+
+    if (new_role & BTA_AV_ROLE_START_INT)
+    {
+        new_role &= ~BTA_AV_ROLE_START_INT;
+    }
+    else if ((new_role & BTA_AV_ROLE_AD_ACP) && (new_role & BTA_AV_ROLE_SUSPEND_OPT))
+    {
+        suspend = TRUE;
+    }
+
+    if (!suspend)
+    {
+        p_scb->q_tag = BTA_AV_Q_TAG_STREAM;
+        bta_av_stream_chg(p_scb, TRUE);
+    }
+
+    {
+        p_scb->role = new_role;
+        p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
+        p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
+
+        p_scb->p_cos->start(p_scb->hndl, p_scb->codec_type);
+        p_scb->co_started = TRUE;
+
+        APPL_TRACE_DEBUG3("bta_av_start_ok suspending: %d, role:x%x, init %d",
+            suspend, p_scb->role, initiator);
+
+        start.suspending = suspend;
+        start.initiator = initiator;
+        start.chnl   = p_scb->chnl;
+        start.status = BTA_AV_SUCCESS;
+        start.hndl   = p_scb->hndl;
+        (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
+
+        if(suspend)
+        {
+            p_scb->role |= BTA_AV_ROLE_SUSPEND;
+            p_scb->cong = TRUE;  /* do not allow the media data to go through */
+            /* do not duplicate the media packets to this channel */
+            p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
+            p_scb->co_started = FALSE;
+            stop.flush   = FALSE;
+            stop.suspend = TRUE;
+            bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA *)&stop);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_start_failed
+**
+** Description      Stream start failed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_start_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_START   start;
+
+    if(p_scb->started == FALSE && p_scb->co_started == FALSE)
+    {
+        /* if start failed, clear role */
+        p_scb->role &= ~BTA_AV_ROLE_START_INT;
+
+        bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+        start.chnl   = p_scb->chnl;
+        start.status = BTA_AV_FAIL;
+        start.initiator = TRUE;
+        start.hndl   = p_scb->hndl;
+        (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
+    }
+
+    bta_sys_set_policy(BTA_ID_AV, (HCI_ENABLE_SNIFF_MODE|HCI_ENABLE_MASTER_SLAVE_SWITCH), p_scb->peer_addr);
+    p_scb->sco_suspend = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_str_closed
+**
+** Description      Stream closed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_str_closed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV     data;
+    tBTA_AV_EVT event;
+    UINT16      mtu;
+    UINT8 policy = HCI_ENABLE_SNIFF_MODE;
+
+    if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
+        policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+    bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+    if (bta_av_cb.audio_open_cnt <= 1)
+    {
+        /* last connection - restore the allow switch flag */
+        L2CA_SetDesireRole(L2CAP_ROLE_ALLOW_SWITCH);
+    }
+
+    if (p_scb->open_status)
+    {
+        /* must be failure when opening the stream */
+        bdcpy(data.open.bd_addr, p_scb->peer_addr);
+        data.open.status = p_scb->open_status;
+        data.open.chnl   = p_scb->chnl;
+        data.open.hndl   = p_scb->hndl;
+        event = BTA_AV_OPEN_EVT;
+        p_scb->open_status = BTA_AV_SUCCESS;
+
+        bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+        bta_av_cleanup(p_scb, p_data);
+        (*bta_av_cb.p_cback)(event, &data);
+    }
+    else
+    {
+        /* do stop if we were started */
+        if (p_scb->co_started)
+        {
+            bta_av_str_stopped(p_scb, NULL);
+        }
+
+        /* Update common mtu shared by remaining connectons */
+        mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
+
+        {
+            p_scb->p_cos->close(p_scb->hndl, p_scb->codec_type, mtu);
+            data.close.chnl = p_scb->chnl;
+            data.close.hndl = p_scb->hndl;
+            event = BTA_AV_CLOSE_EVT;
+
+            bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+            bta_av_cleanup(p_scb, p_data);
+            (*bta_av_cb.p_cback)(event, &data);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_clr_cong
+**
+** Description      Clear stream congestion flag.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_clr_cong (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    if(p_scb->co_started)
+        p_scb->cong = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_suspend_cfm
+**
+** Description      process the suspend response
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_suspend_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_SUSPEND suspend_rsp;
+    UINT8           err_code = p_data->str_msg.msg.hdr.err_code;
+    UINT8 policy = HCI_ENABLE_SNIFF_MODE;
+
+    APPL_TRACE_DEBUG2 ("bta_av_suspend_cfm:audio_open_cnt = %d, err_code = %d",
+        bta_av_cb.audio_open_cnt, err_code);
+
+    suspend_rsp.status = BTA_AV_SUCCESS;
+    if(err_code)
+    {
+        p_scb->suspend_sup = FALSE;
+        suspend_rsp.status = BTA_AV_FAIL;
+
+        APPL_TRACE_ERROR0 ("bta_av_suspend_cfm: suspend failed, closing connection");
+
+        /* SUSPEND failed. Close connection. */
+        bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL);
+    }
+    else
+    {
+        /* only set started to FALSE when suspend is successful */
+        p_scb->started = FALSE;
+    }
+
+    if(p_scb->role & BTA_AV_ROLE_SUSPEND)
+    {
+        p_scb->role &= ~BTA_AV_ROLE_SUSPEND;
+        p_scb->cong = FALSE;
+    }
+
+    bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+    if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
+        policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+    bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+    /* in case that we received suspend_ind, we may need to call co_stop here */
+    if(p_scb->co_started)
+    {
+        bta_av_stream_chg(p_scb, FALSE);
+
+        {
+            p_scb->co_started = FALSE;
+            p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
+        }
+        L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
+    }
+
+    {
+        suspend_rsp.chnl = p_scb->chnl;
+        suspend_rsp.hndl = p_scb->hndl;
+        suspend_rsp.initiator = p_data->str_msg.initiator;
+        (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV *) &suspend_rsp);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rcfg_str_ok
+**
+** Description      report reconfigure successful
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rcfg_str_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_RECONFIG    evt;
+
+    p_scb->l2c_cid      = AVDT_GetL2CapChannel(p_scb->avdt_handle);
+    APPL_TRACE_DEBUG1("bta_av_rcfg_str_ok: l2c_cid: %d", p_scb->l2c_cid);
+
+    /* rc listen */
+    bta_av_st_rc_timer(p_scb, NULL);
+    utl_freebuf((void **)&p_scb->p_cap);
+
+    /* No need to keep the role bits once reconfig is done. */
+    p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
+    p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
+    p_scb->role &= ~BTA_AV_ROLE_START_INT;
+
+    {
+        /* reconfigure success  */
+        evt.status = BTA_AV_SUCCESS;
+        evt.chnl   = p_scb->chnl;
+        evt.hndl   = p_scb->hndl;
+        (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rcfg_failed
+**
+** Description      process reconfigure failed
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rcfg_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_RECONFIG evt;
+
+    APPL_TRACE_DEBUG2("bta_av_rcfg_failed num_recfg: %d, conn_lcb:0x%x",
+        p_scb->num_recfg, bta_av_cb.conn_lcb);
+    if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY)
+    {
+        bta_av_cco_close(p_scb, p_data);
+        /* report failure */
+        evt.status = BTA_AV_FAIL_STREAM;
+        evt.chnl   = p_scb->chnl;
+        evt.hndl   = p_scb->hndl;
+        (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+        /* go to closing state */
+        bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL);
+    }
+    else
+    {
+        /* open failed. try again */
+        p_scb->num_recfg++;
+        if(bta_av_cb.conn_lcb)
+        {
+            AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+        }
+        else
+        {
+            bta_av_connect_req(p_scb, NULL);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rcfg_connect
+**
+** Description      stream closed. reconnect the stream
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rcfg_connect (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    p_scb->cong    = FALSE;
+    p_scb->num_recfg++;
+    APPL_TRACE_DEBUG1("bta_av_rcfg_connect num_recfg: %d", p_scb->num_recfg);
+    if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY)
+    {
+        /* let bta_av_rcfg_failed report fail */
+        bta_av_rcfg_failed(p_scb, NULL);
+    }
+    else
+        AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rcfg_discntd
+**
+** Description      AVDT disconnected. reconnect the stream
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rcfg_discntd (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_RECONFIG    evt;
+
+    APPL_TRACE_DEBUG1("bta_av_rcfg_discntd num_recfg: %d", p_scb->num_recfg);
+    p_scb->num_recfg++;
+    if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY)
+    {
+        /* report failure */
+        evt.status = BTA_AV_FAIL_STREAM;
+        evt.chnl   = p_scb->chnl;
+        evt.hndl   = p_scb->hndl;
+        (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+        /* report close event & go to init state */
+        bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
+    }
+    else
+        AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_suspend_cont
+**
+** Description      received the suspend response.
+**                  continue to reconfigure the stream
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_suspend_cont (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    UINT8       err_code = p_data->str_msg.msg.hdr.err_code;
+    tBTA_AV_RECONFIG    evt;
+
+    p_scb->started = FALSE;
+    p_scb->cong    = FALSE;
+    if(err_code)
+    {
+        if(AVDT_ERR_CONNECT == err_code)
+        {
+            /* report failure */
+            evt.status = BTA_AV_FAIL;
+            (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+            bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
+        }
+        else
+        {
+            APPL_TRACE_ERROR0("suspend rejected, try close");
+            p_scb->suspend_sup = FALSE;
+
+            /* drop the buffers queued in L2CAP */
+            L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+
+            AVDT_CloseReq(p_scb->avdt_handle);
+        }
+    }
+    else
+    {
+        APPL_TRACE_DEBUG0("bta_av_suspend_cont calling AVDT_ReconfigReq");
+        /* reconfig the stream */
+
+        AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
+        p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rcfg_cfm
+**
+** Description      if reconfigure is successful, report the event
+**                  otherwise, close the stream.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rcfg_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    UINT8   err_code = p_data->str_msg.msg.hdr.err_code;
+
+    /*
+    APPL_TRACE_DEBUG0("bta_av_rcfg_cfm");
+    */
+    if(err_code)
+    {
+        APPL_TRACE_ERROR0("reconfig rejected, try close");
+        p_scb->recfg_sup = FALSE;
+        /* started flag is FALSE when reconfigure command is sent */
+        /* drop the buffers queued in L2CAP */
+        L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+        AVDT_CloseReq(p_scb->avdt_handle);
+    }
+    else
+    {
+        /* take the SSM back to OPEN state */
+        bta_av_ssm_execute(p_scb, BTA_AV_STR_OPEN_OK_EVT, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rcfg_open
+**
+** Description      AVDT is connected. open the stream with the new configuration
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rcfg_open (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    APPL_TRACE_DEBUG1("bta_av_rcfg_open, num_disc_snks = %d", p_scb->num_disc_snks);
+
+    if (p_scb->num_disc_snks == 0)
+    {
+        /* Need to update call-out module so that it will be ready for discover */
+        p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
+
+        /* send avdtp discover request */
+        AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]);
+    }
+    else
+    {
+        p_scb->codec_type = p_scb->p_cap->codec_info[BTA_AV_CODEC_TYPE_IDX];
+        memcpy(p_scb->cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
+        /* we may choose to use a different SEP at reconfig.
+         * adjust the sep_idx now */
+        bta_av_adjust_seps_idx(p_scb);
+
+        /* open the stream with the new config */
+        p_scb->sep_info_idx = p_scb->rcfg_idx;
+        AVDT_OpenReq(p_scb->avdt_handle, p_scb->peer_addr,
+                     p_scb->sep_info[p_scb->sep_info_idx].seid, p_scb->p_cap);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_security_rej
+**
+** Description      Send an AVDTP security reject.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_security_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_BAD_STATE,
+                     NULL, 0);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_chk_2nd_start
+**
+** Description      check if this is 2nd stream and if it needs to be started.
+**                  This function needs to be kept very similar to bta_av_chk_start
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_chk_2nd_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_SCB *p_scbi;
+    int i;
+    BOOLEAN new_started = FALSE;
+
+
+    if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2))
+    {
+        /* more than one audio channel is connected */
+        if (!(p_scb->role & BTA_AV_ROLE_SUSPEND_OPT))
+        {
+            /* this channel does not need to be reconfigured.
+             * if there is other channel streaming, start the stream now */
+            for(i=0; i<BTA_AV_NUM_STRS; i++)
+            {
+                p_scbi = bta_av_cb.p_scb[i];
+                if(p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started)
+                {
+                    if (!new_started)
+                    {
+                        /* start the new stream */
+                        new_started = TRUE;
+                        bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
+                    }
+                    /* may need to update the flush timeout of this already started stream */
+                    if (p_scbi->co_started != bta_av_cb.audio_open_cnt)
+                    {
+                        p_scbi->co_started = bta_av_cb.audio_open_cnt;
+                        L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] );
+                    }
+                }
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_open_rc
+**
+** Description      Send a message to main SM to open RC channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_open_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_START   start;
+
+    APPL_TRACE_DEBUG3("bta_av_open_rc use_rc: %d, wait: x%x role:x%x", p_scb->use_rc, p_scb->wait, p_scb->role);
+    if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) && (p_scb->q_tag == BTA_AV_Q_TAG_START))
+    {
+        /* waiting for role switch for some reason & the timer expires */
+        if (!bta_av_link_role_ok(p_scb, A2D_SET_ONE_BIT))
+        {
+            APPL_TRACE_ERROR0 ("failed to start streaming for role management reasons!!");
+            bta_sys_stop_timer(&p_scb->timer);
+            start.chnl   = p_scb->chnl;
+            start.status = BTA_AV_FAIL_ROLE;
+            start.initiator = TRUE;
+            start.hndl   = p_scb->hndl;
+            p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+            bta_av_cb.rs_idx = 0;
+            (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
+        }
+        else
+        {
+            /* role switch is done. continue to start streaming */
+            bta_av_cb.rs_idx = 0;
+            p_data->hdr.offset = BTA_AV_RS_OK;
+            bta_av_start_ok (p_scb, p_data);
+        }
+        return;
+    }
+
+    if(p_scb->use_rc == TRUE || (p_scb->role & BTA_AV_ROLE_AD_ACP) )
+    {
+        if(bta_av_cb.disc)
+        {
+            /* AVRC discover db is in use */
+            if(p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE)
+            {
+                /* AVRC channel is not connected. delay a little bit */
+                if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0)
+                    bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL);
+                else
+                    p_scb->wait |= BTA_AV_WAIT_CHECK_RC;
+            }
+        }
+        else
+        {
+            /* use main SM for AVRC SDP activities */
+            bta_av_rc_disc((UINT8)(p_scb->hdi + 1));
+        }
+    }
+    else
+    {
+        if(BTA_AV_RC_HANDLE_NONE != p_scb->rc_handle)
+        {
+            /* the open API said that this handle does not want a RC connection.
+             * disconnect it now */
+            AVRC_Close(p_scb->rc_handle);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_open_at_inc
+**
+** Description      This function is called if API open is called by application
+**                  while state-machine is at incoming state.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_open_at_inc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_API_OPEN  *p_buf;
+
+    memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
+
+    if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR)
+    {
+        p_scb->coll_mask |= BTA_AV_COLL_API_CALLED;
+
+        /* API open will be handled at timeout if SNK did not start signalling. */
+        /* API open will be ignored if SNK starts signalling.                   */
+    }
+    else
+    {
+        /* SNK did not start signalling, API was called N seconds timeout. */
+        /* We need to switch to INIT state and start opening connection. */
+        p_scb->coll_mask = 0;
+        bta_av_set_scb_sst_init (p_scb);
+
+        if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL)
+        {
+            memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
+            bta_sys_sendmsg(p_buf);
+        }
+    }
+}
+
+#endif /* BTA_AV_INCLUDED */
diff --git a/bta/av/bta_av_act.c b/bta/av/bta_av_act.c
new file mode 100644
index 0000000..a47921a
--- /dev/null
+++ b/bta/av/bta_av_act.c
@@ -0,0 +1,1941 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains action functions for advanced audio/video main state
+ *  machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bta_av_api.h"
+#include "bta_av_int.h"
+#include "avdt_api.h"
+#include "bd.h"
+#include "utl.h"
+#include "l2c_api.h"
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+/* the timer in milliseconds to wait for open req after setconfig for incoming connections */
+#ifndef BTA_AV_SIG_TIME_VAL
+#define BTA_AV_SIG_TIME_VAL 8000
+#endif
+
+/* In millisec to wait for signalling from SNK when it is initiated from SNK.   */
+/* If not, we will start signalling from SRC.                                   */
+#ifndef BTA_AV_ACP_SIG_TIME_VAL
+#define BTA_AV_ACP_SIG_TIME_VAL 2000
+#endif
+
+static void bta_av_acp_sig_timer_cback (TIMER_LIST_ENT *p_tle);
+
+/*******************************************************************************
+**
+** Function         bta_av_get_rcb_by_shdl
+**
+** Description      find the RCB associated with the given SCB handle.
+**
+** Returns          tBTA_AV_RCB
+**
+*******************************************************************************/
+tBTA_AV_RCB * bta_av_get_rcb_by_shdl(UINT8 shdl)
+{
+    tBTA_AV_RCB *p_rcb = NULL;
+    int         i;
+
+    for (i=0; i<BTA_AV_NUM_RCB; i++)
+    {
+        if (bta_av_cb.rcb[i].shdl == shdl && bta_av_cb.rcb[i].handle != BTA_AV_RC_HANDLE_NONE)
+        {
+            p_rcb = &bta_av_cb.rcb[i];
+            break;
+        }
+    }
+    return p_rcb;
+}
+#define BTA_AV_STS_NO_RSP       0xFF    /* a number not used by tAVRC_STS */
+
+/*******************************************************************************
+**
+** Function         bta_av_del_rc
+**
+** Description      delete the given AVRC handle.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_del_rc(tBTA_AV_RCB *p_rcb)
+{
+    tBTA_AV_SCB  *p_scb;
+    UINT8        rc_handle;      /* connected AVRCP handle */
+
+    if(p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
+    {
+        if(p_rcb->shdl)
+        {
+            p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+            if(p_scb)
+            {
+                APPL_TRACE_DEBUG3("bta_av_del_rc shdl:%d, srch:%d rc_handle:%d", p_rcb->shdl,
+                                  p_scb->rc_handle, p_rcb->handle);
+                if(p_scb->rc_handle == p_rcb->handle)
+                    p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
+                /* just in case the RC timer is active
+                if(bta_av_cb.features & BTA_AV_FEAT_RCCT && p_scb->chnl == BTA_AV_CHNL_AUDIO) */
+                    bta_sys_stop_timer(&p_scb->timer);
+            }
+        }
+
+        APPL_TRACE_EVENT4("bta_av_del_rc  handle: %d status=0x%x, rc_acp_handle:%d, idx:%d",
+            p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, bta_av_cb.rc_acp_idx);
+        rc_handle = p_rcb->handle;
+        if(!(p_rcb->status & BTA_AV_RC_CONN_MASK) ||
+            ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT) )
+        {
+            p_rcb->status = 0;
+            p_rcb->handle = BTA_AV_RC_HANDLE_NONE;
+            p_rcb->shdl = 0;
+            p_rcb->lidx = 0;
+        }
+        /* else ACP && connected. do not clear the handle yet */
+        AVRC_Close(rc_handle);
+        if (rc_handle == bta_av_cb.rc_acp_handle)
+            bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;
+        APPL_TRACE_EVENT4("end del_rc handle: %d status=0x%x, rc_acp_handle:%d, lidx:%d",
+            p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, p_rcb->lidx);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_av_close_all_rc
+**
+** Description      close the all AVRC handle.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_close_all_rc(tBTA_AV_CB *p_cb)
+{
+    int i;
+
+    for(i=0; i<BTA_AV_NUM_RCB; i++)
+    {
+        if ((p_cb->disabling == TRUE) || (bta_av_cb.rcb[i].shdl != 0))
+            bta_av_del_rc(&bta_av_cb.rcb[i]);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_del_sdp_rec
+**
+** Description      delete the given SDP record handle.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_del_sdp_rec(UINT32 *p_sdp_handle)
+{
+    if(*p_sdp_handle != 0)
+    {
+        SDP_DeleteRecord(*p_sdp_handle);
+        *p_sdp_handle = 0;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_avrc_sdp_cback
+**
+** Description      AVRCP service discovery callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_avrc_sdp_cback(UINT16 status)
+{
+    BT_HDR *p_msg;
+
+    if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_msg->event = BTA_AV_SDP_AVRC_DISC_EVT;
+        bta_sys_sendmsg(p_msg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_ctrl_cback
+**
+** Description      AVRCP control callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_rc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result, BD_ADDR peer_addr)
+{
+    tBTA_AV_RC_CONN_CHG *p_msg;
+    UINT16 msg_event = 0;
+
+#if (defined(BTA_AV_MIN_DEBUG_TRACES) && BTA_AV_MIN_DEBUG_TRACES == TRUE)
+    APPL_TRACE_EVENT2("rc_ctrl handle: %d event=0x%x", handle, event);
+#else
+    APPL_TRACE_EVENT2("bta_av_rc_ctrl_cback handle: %d event=0x%x", handle, event);
+#endif
+    if (event == AVRC_OPEN_IND_EVT)
+    {
+        /* save handle of opened connection
+        bta_av_cb.rc_handle = handle;*/
+
+        msg_event = BTA_AV_AVRC_OPEN_EVT;
+    }
+    else if (event == AVRC_CLOSE_IND_EVT)
+    {
+        msg_event = BTA_AV_AVRC_CLOSE_EVT;
+    }
+
+    if (msg_event)
+    {
+        if ((p_msg = (tBTA_AV_RC_CONN_CHG *) GKI_getbuf(sizeof(tBTA_AV_RC_CONN_CHG))) != NULL)
+        {
+            p_msg->hdr.event = msg_event;
+            p_msg->handle    = handle;
+            if(peer_addr)
+                bdcpy(p_msg->peer_addr, peer_addr);
+            bta_sys_sendmsg(p_msg);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_msg_cback
+**
+** Description      AVRCP message callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_rc_msg_cback(UINT8 handle, UINT8 label, UINT8 opcode, tAVRC_MSG *p_msg)
+{
+    tBTA_AV_RC_MSG  *p_buf;
+    UINT8           *p_data = NULL;
+    UINT8           **p_p_data = NULL;
+    UINT16          data_len = 0;
+
+#if (defined(BTA_AV_MIN_DEBUG_TRACES) && BTA_AV_MIN_DEBUG_TRACES == TRUE)
+    APPL_TRACE_ERROR2("rc_msg handle: %d opcode=0x%x", handle, opcode);
+#else
+    APPL_TRACE_EVENT2("bta_av_rc_msg_cback handle: %d opcode=0x%x", handle, opcode);
+#endif
+    /* determine size of buffer we need */
+    if (opcode == AVRC_OP_VENDOR && p_msg->vendor.p_vendor_data != NULL)
+    {
+        p_data = p_msg->vendor.p_vendor_data;
+        p_p_data = &p_msg->vendor.p_vendor_data;
+        data_len = (UINT16) p_msg->vendor.vendor_len;
+    }
+    else if (opcode == AVRC_OP_PASS_THRU && p_msg->pass.p_pass_data != NULL)
+    {
+        p_data = p_msg->pass.p_pass_data;
+        p_p_data = &p_msg->pass.p_pass_data;
+        data_len = (UINT16) p_msg->pass.pass_len;
+    }
+
+    if ((p_buf = (tBTA_AV_RC_MSG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_RC_MSG) + data_len))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_AVRC_MSG_EVT;
+        p_buf->handle = handle;
+        p_buf->label = label;
+        p_buf->opcode = opcode;
+        memcpy(&p_buf->msg, p_msg, sizeof(tAVRC_MSG));
+        if (p_data != NULL)
+        {
+            memcpy((UINT8 *)(p_buf + 1), p_data, data_len);
+            *p_p_data = (UINT8 *)(p_buf + 1);
+        }
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_create
+**
+** Description      alloc RCB and call AVRC_Open
+**
+** Returns          the created rc handle
+**
+*******************************************************************************/
+UINT8 bta_av_rc_create(tBTA_AV_CB *p_cb, UINT8 role, UINT8 shdl, UINT8 lidx)
+{
+    tAVRC_CONN_CB ccb;
+    BD_ADDR_PTR   bda = (BD_ADDR_PTR)bd_addr_any;
+    UINT8         status = BTA_AV_RC_ROLE_ACP;
+    tBTA_AV_SCB  *p_scb = p_cb->p_scb[shdl - 1];
+    int i;
+    UINT8   rc_handle;
+    tBTA_AV_RCB *p_rcb;
+
+    if(role == AVCT_INT)
+    {
+        bda = p_scb->peer_addr;
+        status = BTA_AV_RC_ROLE_INT;
+    }
+    else
+    {
+        if ((p_rcb = bta_av_get_rcb_by_shdl(shdl)) != NULL )
+        {
+            APPL_TRACE_ERROR1("bta_av_rc_create ACP handle exist for shdl:%d", shdl);
+            return p_rcb->handle;
+        }
+    }
+
+    ccb.p_ctrl_cback = bta_av_rc_ctrl_cback;
+    ccb.p_msg_cback = bta_av_rc_msg_cback;
+    ccb.company_id = p_bta_av_cfg->company_id;
+    ccb.conn = role;
+    /* note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL */
+    ccb.control = p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | AVRC_CT_PASSIVE);
+
+
+    if (AVRC_Open(&rc_handle, &ccb, bda) != AVRC_SUCCESS)
+        return BTA_AV_RC_HANDLE_NONE;
+
+    i = rc_handle;
+    p_rcb = &p_cb->rcb[i];
+
+    if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
+    {
+        APPL_TRACE_ERROR1("bta_av_rc_create found duplicated handle:%d", rc_handle);
+    }
+
+    p_rcb->handle = rc_handle;
+    p_rcb->status = status;
+    p_rcb->shdl = shdl;
+    p_rcb->lidx = lidx;
+    p_rcb->peer_features = 0;
+    if(lidx == (BTA_AV_NUM_LINKS + 1))
+    {
+        /* this LIDX is reserved for the AVRCP ACP connection */
+        p_cb->rc_acp_handle = p_rcb->handle;
+        p_cb->rc_acp_idx = (i + 1);
+        APPL_TRACE_DEBUG2("rc_acp_handle:%d idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+    }
+    APPL_TRACE_DEBUG6("create %d, role: %d, shdl:%d, rc_handle:%d, lidx:%d, status:0x%x",
+        i, role, shdl, p_rcb->handle, lidx, p_rcb->status);
+
+    return rc_handle;
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_valid_group_navi_msg
+**
+** Description      Check if it is Group Navigation Msg for Metadata
+**
+** Returns          BTA_AV_RSP_ACCEPT or BTA_AV_RSP_NOT_IMPL.
+**
+*******************************************************************************/
+static tBTA_AV_CODE bta_av_group_navi_supported(UINT8 len, UINT8 *p_data)
+{
+    tBTA_AV_CODE ret=BTA_AV_RSP_NOT_IMPL;
+    UINT8 *p_ptr = p_data;
+    UINT16 u16;
+    UINT32 u32;
+
+    if (p_bta_av_cfg->avrc_group && len == BTA_GROUP_NAVI_MSG_OP_DATA_LEN)
+    {
+        BTA_AV_BE_STREAM_TO_CO_ID(u32, p_ptr);
+        BE_STREAM_TO_UINT16(u16, p_ptr);
+
+        if (u32 == AVRC_CO_METADATA)
+        {
+            if (u16 <= AVRC_PDU_PREV_GROUP)
+                ret = BTA_AV_RSP_ACCEPT;
+            else
+                ret = BTA_AV_RSP_REJ;
+        }
+    }
+
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_op_supported
+**
+** Description      Check if remote control operation is supported.
+**
+** Returns          BTA_AV_RSP_ACCEPT of supported, BTA_AV_RSP_NOT_IMPL if not.
+**
+*******************************************************************************/
+static tBTA_AV_CODE bta_av_op_supported(tBTA_AV_RC rc_id)
+{
+    tBTA_AV_CODE ret_code = BTA_AV_RSP_NOT_IMPL;
+
+    if (p_bta_av_rc_id)
+    {
+        if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F)))
+        {
+            ret_code = BTA_AV_RSP_ACCEPT;
+        }
+        else if ((p_bta_av_cfg->rc_pass_rsp == BTA_AV_RSP_INTERIM) && p_bta_av_rc_id_ac)
+        {
+            if (p_bta_av_rc_id_ac[rc_id >> 4] & (1 << (rc_id & 0x0F)))
+            {
+                ret_code = BTA_AV_RSP_INTERIM;
+            }
+        }
+    }
+    return ret_code;
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_find_lcb
+**
+** Description      Given BD_addr, find the associated LCB.
+**
+** Returns          NULL, if not found.
+**
+*******************************************************************************/
+tBTA_AV_LCB * bta_av_find_lcb(BD_ADDR addr, UINT8 op)
+{
+    tBTA_AV_CB   *p_cb = &bta_av_cb;
+    int     xx;
+    UINT8   mask;
+    tBTA_AV_LCB *p_lcb = NULL;
+
+    for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
+    {
+        mask = 1 << xx; /* the used mask for this lcb */
+        if((mask & p_cb->conn_lcb) && 0 ==( bdcmp(p_cb->lcb[xx].addr, addr)))
+        {
+            p_lcb = &p_cb->lcb[xx];
+            if(op == BTA_AV_LCB_FREE)
+            {
+                p_cb->conn_lcb &= ~mask; /* clear the connect mask */
+                APPL_TRACE_DEBUG1("conn_lcb: 0x%x", p_cb->conn_lcb);
+            }
+            break;
+        }
+    }
+    return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_opened
+**
+** Description      Set AVRCP state to opened.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_opened(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_RC_OPEN rc_open;
+    tBTA_AV_SCB     *p_scb;
+    int         i;
+    UINT8       shdl = 0;
+    tBTA_AV_LCB *p_lcb;
+    tBTA_AV_RCB *p_rcb;
+    UINT8       tmp;
+    UINT8       disc = 0;
+
+    /* find the SCB & stop the timer */
+    for(i=0; i<BTA_AV_NUM_STRS; i++)
+    {
+        p_scb = p_cb->p_scb[i];
+        if(p_scb && bdcmp(p_scb->peer_addr, p_data->rc_conn_chg.peer_addr) == 0)
+        {
+            p_scb->rc_handle = p_data->rc_conn_chg.handle;
+            APPL_TRACE_DEBUG2("bta_av_rc_opened shdl:%d, srch %d", i + 1, p_scb->rc_handle);
+            shdl = i+1;
+            APPL_TRACE_ERROR1("use_rc:%d", p_scb->use_rc);
+            bta_sys_stop_timer(&p_scb->timer);
+            disc = p_scb->hndl;
+            break;
+        }
+    }
+
+    i = p_data->rc_conn_chg.handle;
+    if (p_cb->rcb[i].handle == BTA_AV_RC_HANDLE_NONE)
+    {
+        APPL_TRACE_ERROR1("not a valid handle:%d any more", i);
+        return;
+    }
+
+
+    if (p_cb->rcb[i].lidx == (BTA_AV_NUM_LINKS + 1) && shdl != 0)
+    {
+        /* rc is opened on the RC only ACP channel, but is for a specific
+         * SCB -> need to switch RCBs */
+        p_rcb = bta_av_get_rcb_by_shdl(shdl);
+        if (p_rcb)
+        {
+            p_rcb->shdl = p_cb->rcb[i].shdl;
+            tmp         = p_rcb->lidx;
+            p_rcb->lidx = p_cb->rcb[i].lidx;
+            p_cb->rcb[i].lidx = tmp;
+            p_cb->rc_acp_handle = p_rcb->handle;
+            p_cb->rc_acp_idx = (p_rcb - p_cb->rcb) + 1;
+            APPL_TRACE_DEBUG2("switching RCB rc_acp_handle:%d idx:%d",
+                               p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+        }
+    }
+
+    p_cb->rcb[i].shdl = shdl;
+    rc_open.rc_handle = i;
+    APPL_TRACE_ERROR4("bta_av_rc_opened rcb[%d] shdl:%d lidx:%d/%d",
+            i, shdl, p_cb->rcb[i].lidx, p_cb->lcb[BTA_AV_NUM_LINKS].lidx);
+    p_cb->rcb[i].status |= BTA_AV_RC_CONN_MASK;
+
+    if(!shdl && 0 == p_cb->lcb[BTA_AV_NUM_LINKS].lidx)
+    {
+        /* no associated SCB -> connected to an RC only device
+         * update the index to the extra LCB */
+        p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
+        bdcpy(p_lcb->addr, p_data->rc_conn_chg.peer_addr);
+        APPL_TRACE_DEBUG6("rc_only bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+                      p_lcb->addr[0], p_lcb->addr[1],
+                      p_lcb->addr[2], p_lcb->addr[3],
+                      p_lcb->addr[4], p_lcb->addr[5]);
+        p_lcb->lidx = BTA_AV_NUM_LINKS + 1;
+            p_cb->rcb[i].lidx = p_lcb->lidx;
+        p_lcb->conn_msk = 1;
+        APPL_TRACE_ERROR3("rcb[%d].lidx=%d, lcb.conn_msk=x%x",
+            i, p_cb->rcb[i].lidx, p_lcb->conn_msk);
+        disc = p_data->rc_conn_chg.handle|BTA_AV_CHNL_MSK;
+    }
+
+    bdcpy(rc_open.peer_addr, p_data->rc_conn_chg.peer_addr);
+    rc_open.peer_features = p_cb->rcb[i].peer_features;
+    rc_open.status = BTA_AV_SUCCESS;
+    APPL_TRACE_DEBUG2("local features:x%x peer_features:x%x", p_cb->features,
+                      rc_open.peer_features);
+    if(rc_open.peer_features == 0)
+    {
+        /* we have not done SDP on peer RC capabilities.
+         * peer must have initiated the RC connection */
+        rc_open.peer_features = BTA_AV_FEAT_RCCT;
+        bta_av_rc_disc(disc);
+    }
+    (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open);
+
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_remote_cmd
+**
+** Description      Send an AVRCP remote control command.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_remote_cmd(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_RCB    *p_rcb;
+    if (p_cb->features & BTA_AV_FEAT_RCCT)
+    {
+        if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+        {
+            p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+            if(p_rcb->status & BTA_AV_RC_CONN_MASK)
+            {
+                AVRC_PassCmd(p_rcb->handle, p_data->api_remote_cmd.label,
+                     &p_data->api_remote_cmd.msg);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_vendor_cmd
+**
+** Description      Send an AVRCP vendor specific command.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_vendor_cmd(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_RCB    *p_rcb;
+    if ( (p_cb->features & (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) ==
+         (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR))
+    {
+        if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+        {
+            p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+            AVRC_VendorCmd(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_vendor_rsp
+**
+** Description      Send an AVRCP vendor specific response.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_vendor_rsp(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_RCB    *p_rcb;
+    if ( (p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) ==
+         (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR))
+    {
+        if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+        {
+            p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+            AVRC_VendorRsp(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_meta_rsp
+**
+** Description      Send an AVRCP metadata/advanced control command/response.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_meta_rsp(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_RCB *p_rcb;
+    BOOLEAN         free = TRUE;
+
+    if ((p_cb->features & BTA_AV_FEAT_METADATA) && (p_data->hdr.layer_specific < BTA_AV_NUM_RCB))
+    {
+        if ((p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCTG)) ||
+            (!p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCCT)) )
+        {
+            p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+            AVRC_MsgReq(p_rcb->handle, p_data->api_meta_rsp.label, p_data->api_meta_rsp.rsp_code,
+                                      p_data->api_meta_rsp.p_pkt);
+            free = FALSE;
+        }
+    }
+
+    if (free)
+        GKI_freebuf (p_data->api_meta_rsp.p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_free_rsp
+**
+** Description      free an AVRCP metadata command buffer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_free_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+    GKI_freebuf (p_data->api_meta_rsp.p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_meta_req
+**
+** Description      Send an AVRCP metadata command.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_free_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+}
+
+
+
+/*******************************************************************************
+**
+** Function         bta_av_chk_notif_evt_id
+**
+** Description      make sure the requested player id is valid.
+**
+** Returns          BTA_AV_STS_NO_RSP, if no error
+**
+*******************************************************************************/
+static tAVRC_STS bta_av_chk_notif_evt_id(tAVRC_MSG_VENDOR *p_vendor)
+{
+    tAVRC_STS   status = BTA_AV_STS_NO_RSP;
+    UINT8       xx;
+    UINT16      u16;
+    UINT8       *p = p_vendor->p_vendor_data + 2;
+
+    BE_STREAM_TO_UINT16 (u16, p);
+    /* double check the fixed length */
+    if ((u16 != 5) || (p_vendor->vendor_len != 9))
+    {
+        status = AVRC_STS_INTERNAL_ERR;
+    }
+    else
+    {
+        /* make sure the player_id is valid */
+        for (xx=0; xx<p_bta_av_cfg->num_evt_ids; xx++)
+        {
+            if (*p == p_bta_av_cfg->p_meta_evt_ids[xx])
+            {
+                break;
+            }
+        }
+        if (xx == p_bta_av_cfg->num_evt_ids)
+        {
+            status = AVRC_STS_BAD_PARAM;
+        }
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_proc_meta_cmd
+**
+** Description      Process an AVRCP metadata command from the peer.
+**
+** Returns          TRUE to respond immediately
+**
+*******************************************************************************/
+tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE  *p_rc_rsp, tBTA_AV_RC_MSG *p_msg, UINT8 *p_ctype)
+{
+    tBTA_AV_EVT evt = BTA_AV_META_MSG_EVT;
+    UINT8       u8, pdu, *p;
+    UINT16      u16;
+    tAVRC_MSG_VENDOR    *p_vendor = &p_msg->msg.vendor;
+
+    pdu = *(p_vendor->p_vendor_data);
+    p_rc_rsp->pdu = pdu;
+    *p_ctype = AVRC_RSP_REJ;
+    /* Metadata messages only use PANEL sub-unit type */
+    if (p_vendor->hdr.subunit_type != AVRC_SUB_PANEL)
+    {
+        APPL_TRACE_DEBUG0("SUBUNIT must be PANEL");
+        /* reject it */
+        evt=0;
+        p_vendor->hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+        AVRC_VendorRsp(p_msg->handle, p_msg->label, &p_msg->msg.vendor);
+    }
+    else
+    {
+        switch (pdu)
+        {
+        case AVRC_PDU_GET_CAPABILITIES:
+            /* process GetCapabilities command without reporting the event to app */
+            evt = 0;
+            u8 = *(p_vendor->p_vendor_data + 4);
+            p = p_vendor->p_vendor_data + 2;
+            p_rc_rsp->get_caps.capability_id = u8;
+            BE_STREAM_TO_UINT16 (u16, p);
+            if ((u16 != 1) || (p_vendor->vendor_len != 5))
+            {
+                p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
+            }
+            else
+            {
+                p_rc_rsp->get_caps.status = AVRC_STS_NO_ERROR;
+                if (u8 == AVRC_CAP_COMPANY_ID)
+                {
+                    *p_ctype = AVRC_RSP_IMPL_STBL;
+                    p_rc_rsp->get_caps.count = p_bta_av_cfg->num_co_ids;
+                    memcpy(p_rc_rsp->get_caps.param.company_id, p_bta_av_cfg->p_meta_co_ids,
+                           (p_bta_av_cfg->num_co_ids << 2));
+                }
+                else if (u8 == AVRC_CAP_EVENTS_SUPPORTED)
+                {
+                    *p_ctype = AVRC_RSP_IMPL_STBL;
+                    p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids;
+                    memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids,
+                           p_bta_av_cfg->num_evt_ids);
+                }
+                else
+                {
+                    APPL_TRACE_DEBUG1("Invalid capability ID: 0x%x", u8);
+                    /* reject - unknown capability ID */
+                    p_rc_rsp->get_caps.status = AVRC_STS_BAD_PARAM;
+                }
+            }
+            break;
+
+
+        case AVRC_PDU_REGISTER_NOTIFICATION:
+            /* make sure the event_id is implemented */
+            p_rc_rsp->rsp.status = bta_av_chk_notif_evt_id (p_vendor);
+            if (p_rc_rsp->rsp.status != BTA_AV_STS_NO_RSP)
+                evt = 0;
+            break;
+
+        }
+    }
+
+    return evt;
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_msg
+**
+** Description      Process an AVRCP message from the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_EVT evt = 0;
+    tBTA_AV     av;
+    BT_HDR      *p_pkt = NULL;
+    tAVRC_MSG_VENDOR    *p_vendor = &p_data->rc_msg.msg.vendor;
+
+    if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU)
+    {
+    /* if this is a pass thru command */
+        if (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_CTRL)
+        {
+        /* check if operation is supported */
+            if (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR)
+            {
+                p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+            }
+            else
+            {
+                p_data->rc_msg.msg.hdr.ctype = bta_av_op_supported(p_data->rc_msg.msg.pass.op_id);
+            }
+
+            /* send response */
+            if (p_data->rc_msg.msg.hdr.ctype != BTA_AV_RSP_INTERIM)
+                AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.pass);
+
+            /* set up for callback if supported */
+            if (p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_ACCEPT || p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_INTERIM)
+            {
+                evt = BTA_AV_REMOTE_CMD_EVT;
+                av.remote_cmd.rc_id = p_data->rc_msg.msg.pass.op_id;
+                av.remote_cmd.key_state = p_data->rc_msg.msg.pass.state;
+                av.remote_cmd.p_data = p_data->rc_msg.msg.pass.p_pass_data;
+                av.remote_cmd.len = p_data->rc_msg.msg.pass.pass_len;
+                memcpy(&av.remote_cmd.hdr, &p_data->rc_msg.msg.hdr, sizeof (tAVRC_HDR));
+                av.remote_cmd.label = p_data->rc_msg.label;
+            }
+        }
+        /* else if this is a pass thru response */
+        else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT)
+        {
+            /* set up for callback */
+            evt = BTA_AV_REMOTE_RSP_EVT;
+            av.remote_rsp.rc_id = p_data->rc_msg.msg.pass.op_id;
+            av.remote_rsp.key_state = p_data->rc_msg.msg.pass.state;
+            av.remote_rsp.rsp_code = p_data->rc_msg.msg.hdr.ctype;
+            av.remote_rsp.label = p_data->rc_msg.label;
+        }
+        /* must be a bad ctype -> reject*/
+        else
+        {
+            p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ;
+            AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.pass);
+        }
+    }
+    /* else if this is a vendor specific command or response */
+    else if (p_data->rc_msg.opcode == AVRC_OP_VENDOR)
+    {
+        /* set up for callback */
+        av.vendor_cmd.code = p_data->rc_msg.msg.hdr.ctype;
+        av.vendor_cmd.company_id = p_vendor->company_id;
+        av.vendor_cmd.label = p_data->rc_msg.label;
+        av.vendor_cmd.p_data = p_vendor->p_vendor_data;
+        av.vendor_cmd.len = p_vendor->vendor_len;
+
+        /* if configured to support vendor specific and it's a command */
+        if ((p_cb->features & BTA_AV_FEAT_VENDOR)  &&
+            p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ)
+        {
+                evt = BTA_AV_VENDOR_CMD_EVT;
+        }
+        /* else if configured to support vendor specific and it's a response */
+        else if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
+                 p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT)
+        {
+                evt = BTA_AV_VENDOR_RSP_EVT;
+
+        }
+        /* else if not configured to support vendor specific and it's a command */
+        else if (!(p_cb->features & BTA_AV_FEAT_VENDOR)  &&
+            p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ)
+        {
+           if(p_data->rc_msg.msg.vendor.p_vendor_data[0] == AVRC_PDU_INVALID)
+           {
+           /* reject it */
+              p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ;
+              p_data->rc_msg.msg.vendor.p_vendor_data[4] = AVRC_STS_BAD_CMD;
+           }
+           else
+              p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+           AVRC_VendorRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.vendor);
+        }
+    }
+
+    /* call callback */
+    if (evt != 0)
+    {
+        av.remote_cmd.rc_handle = p_data->rc_msg.handle;
+        (*p_cb->p_cback)(evt, &av);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_close
+**
+** Description      close the specified AVRC handle.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+    UINT16 handle = p_data->hdr.layer_specific;
+    tBTA_AV_SCB  *p_scb;
+    tBTA_AV_RCB *p_rcb;
+
+    if(handle < BTA_AV_NUM_RCB)
+    {
+        p_rcb = &p_cb->rcb[handle];
+
+        APPL_TRACE_DEBUG2("bta_av_rc_close handle: %d, status=0x%x", p_rcb->handle, p_rcb->status);
+        if(p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
+        {
+            if(p_rcb->shdl)
+            {
+                p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+                if(p_scb)
+                {
+                    /* just in case the RC timer is active
+                    if(bta_av_cb.features & BTA_AV_FEAT_RCCT &&
+                       p_scb->chnl == BTA_AV_CHNL_AUDIO) */
+                        bta_sys_stop_timer(&p_scb->timer);
+                }
+            }
+
+            AVRC_Close(p_rcb->handle);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_get_shdl
+**
+** Returns          The index to p_scb[]
+**
+*******************************************************************************/
+static UINT8 bta_av_get_shdl(tBTA_AV_SCB *p_scb)
+{
+    int     i;
+    UINT8   shdl = 0;
+    /* find the SCB & stop the timer */
+    for(i=0; i<BTA_AV_NUM_STRS; i++)
+    {
+        if(p_scb == bta_av_cb.p_scb[i])
+        {
+            shdl = i+1;
+            break;
+        }
+    }
+    return shdl;
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_stream_chg
+**
+** Description      audio streaming status changed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_stream_chg(tBTA_AV_SCB *p_scb, BOOLEAN started)
+{
+    UINT8   started_msk;
+    int     i;
+    UINT8   *p_streams;
+    BOOLEAN no_streams = FALSE;
+    tBTA_AV_SCB *p_scbi;
+
+    started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+    APPL_TRACE_DEBUG3 ("bta_av_stream_chg started:%d started_msk:x%x chnl:x%x", started,
+                                                  started_msk, p_scb->chnl);
+    if (BTA_AV_CHNL_AUDIO == p_scb->chnl)
+        p_streams = &bta_av_cb.audio_streams;
+    else
+        p_streams = &bta_av_cb.video_streams;
+
+    if (started)
+    {
+        /* Let L2CAP know this channel is processed with high priority */
+        L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_HIGH);
+        (*p_streams) |= started_msk;
+    }
+    else
+    {
+        (*p_streams) &= ~started_msk;
+    }
+
+    if (!started)
+    {
+        i=0;
+        if (BTA_AV_CHNL_AUDIO == p_scb->chnl)
+        {
+            if (bta_av_cb.video_streams == 0)
+                no_streams = TRUE;
+        }
+        else
+        {
+            no_streams = TRUE;
+            if ( bta_av_cb.audio_streams )
+            {
+                for (; i<BTA_AV_NUM_STRS; i++)
+                {
+                    p_scbi = bta_av_cb.p_scb[i];
+                    /* scb is used and started */
+                    if ( p_scbi && (bta_av_cb.audio_streams & BTA_AV_HNDL_TO_MSK(i))
+                        && bdcmp(p_scbi->peer_addr, p_scb->peer_addr) == 0)
+                    {
+                        no_streams = FALSE;
+                        break;
+                    }
+                }
+
+            }
+        }
+
+        APPL_TRACE_DEBUG4 ("no_streams:%d i:%d, audio_streams:x%x, video_streams:x%x", no_streams, i,
+                           bta_av_cb.audio_streams, bta_av_cb.video_streams);
+        if (no_streams)
+        {
+            /* Let L2CAP know this channel is processed with low priority */
+            L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_NORMAL);
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_av_conn_chg
+**
+** Description      connetion status changed.
+**                  Open an AVRCP acceptor channel, if new conn.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_conn_chg(tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_CB   *p_cb = &bta_av_cb;
+    tBTA_AV_SCB     *p_scb;
+    tBTA_AV_SCB     *p_scbi;
+    UINT8   mask;
+    UINT8   conn_msk;
+    UINT8   old_msk;
+    int i;
+    int index = (p_data->hdr.layer_specific & BTA_AV_HNDL_MSK) - 1;
+    tBTA_AV_LCB *p_lcb;
+    tBTA_AV_LCB *p_lcb_rc;
+    tBTA_AV_RCB *p_rcb, *p_rcb2;
+    BOOLEAN     chk_restore = FALSE;
+
+    p_scb = p_cb->p_scb[index];
+
+    mask = BTA_AV_HNDL_TO_MSK(index);
+    p_lcb = bta_av_find_lcb(p_data->conn_chg.peer_addr, BTA_AV_LCB_FIND);
+    conn_msk = 1 << (index + 1);
+    if(p_data->conn_chg.is_up)
+    {
+        /* set the conned mask for this channel */
+        if(p_scb)
+        {
+            if(p_lcb)
+            {
+                p_lcb->conn_msk |= conn_msk;
+                for (i=0; i<BTA_AV_NUM_RCB; i++)
+                {
+                    if (bta_av_cb.rcb[i].lidx == p_lcb->lidx)
+                    {
+                        bta_av_cb.rcb[i].shdl = index + 1;
+                        APPL_TRACE_DEBUG5("conn_chg up[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i,
+                                          bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status,
+                                          bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
+                        break;
+                    }
+                }
+            }
+            if (p_scb->chnl == BTA_AV_CHNL_AUDIO)
+            {
+                old_msk = p_cb->conn_audio;
+                p_cb->conn_audio |= mask;
+            }
+            else
+            {
+                old_msk = p_cb->conn_video;
+                p_cb->conn_video |= mask;
+            }
+
+            if ((old_msk & mask) == 0)
+            {
+                /* increase the audio open count, if not set yet */
+                bta_av_cb.audio_open_cnt++;
+            }
+
+
+            APPL_TRACE_DEBUG2("rc_acp_handle:%d rc_acp_idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+            /* check if the AVRCP ACP channel is already connected */
+            if(p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE && p_cb->rc_acp_idx)
+            {
+                p_lcb_rc = &p_cb->lcb[BTA_AV_NUM_LINKS];
+                APPL_TRACE_DEBUG1("rc_acp is connected && conn_chg on same addr p_lcb_rc->conn_msk:x%x",
+                                  p_lcb_rc->conn_msk);
+                /* check if the RC is connected to the scb addr */
+                APPL_TRACE_DEBUG6 ("p_lcb_rc->addr: %02x:%02x:%02x:%02x:%02x:%02x",
+                       p_lcb_rc->addr[0], p_lcb_rc->addr[1], p_lcb_rc->addr[2], p_lcb_rc->addr[3],
+                       p_lcb_rc->addr[4], p_lcb_rc->addr[5]);
+                APPL_TRACE_DEBUG6 ("conn_chg.peer_addr: %02x:%02x:%02x:%02x:%02x:%02x",
+                       p_data->conn_chg.peer_addr[0], p_data->conn_chg.peer_addr[1],
+                       p_data->conn_chg.peer_addr[2],
+                       p_data->conn_chg.peer_addr[3], p_data->conn_chg.peer_addr[4],
+                       p_data->conn_chg.peer_addr[5]);
+                if (p_lcb_rc->conn_msk && bdcmp(p_lcb_rc->addr, p_data->conn_chg.peer_addr) == 0)
+                {
+                    /* AVRCP is already connected.
+                     * need to update the association betwen SCB and RCB */
+                    p_lcb_rc->conn_msk = 0; /* indicate RC ONLY is not connected */
+                    p_lcb_rc->lidx = 0;
+                    p_scb->rc_handle = p_cb->rc_acp_handle;
+                    p_rcb = &p_cb->rcb[p_cb->rc_acp_idx - 1];
+                    p_rcb->shdl = bta_av_get_shdl(p_scb);
+                    APPL_TRACE_DEBUG3("update rc_acp shdl:%d/%d srch:%d", index + 1, p_rcb->shdl,
+                                      p_scb->rc_handle );
+
+                    p_rcb2 = bta_av_get_rcb_by_shdl(p_rcb->shdl);
+                    if (p_rcb2)
+                    {
+                        /* found the RCB that was created to associated with this SCB */
+                        p_cb->rc_acp_handle = p_rcb2->handle;
+                        p_cb->rc_acp_idx = (p_rcb2 - p_cb->rcb) + 1;
+                        APPL_TRACE_DEBUG2("new rc_acp_handle:%d, idx:%d", p_cb->rc_acp_handle,
+                                           p_cb->rc_acp_idx);
+                        p_rcb2->lidx = (BTA_AV_NUM_LINKS + 1);
+                        APPL_TRACE_DEBUG3("rc2 handle:%d lidx:%d/%d",p_rcb2->handle, p_rcb2->lidx,
+                                          p_cb->lcb[p_rcb2->lidx-1].lidx);
+                    }
+                    p_rcb->lidx = p_lcb->lidx;
+                    APPL_TRACE_DEBUG3("rc handle:%d lidx:%d/%d",p_rcb->handle, p_rcb->lidx,
+                                      p_cb->lcb[p_rcb->lidx-1].lidx);
+                }
+            }
+        }
+    }
+    else
+    {
+        if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt)
+        {
+            /* this channel is still marked as open. decrease the count */
+            bta_av_cb.audio_open_cnt--;
+        }
+
+        /* clear the conned mask for this channel */
+        p_cb->conn_audio &= ~mask;
+        p_cb->conn_video &= ~mask;
+        if(p_scb)
+        {
+            /* the stream is closed.
+             * clear the peer address, so it would not mess up the AVRCP for the next round of operation */
+            bdcpy(p_scb->peer_addr, bd_addr_null);
+            if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
+            {
+                if(p_lcb)
+                {
+                    p_lcb->conn_msk &= ~conn_msk;
+                }
+                /* audio channel is down. make sure the INT channel is down */
+                /* just in case the RC timer is active
+                if(p_cb->features & BTA_AV_FEAT_RCCT) */
+                {
+                    bta_sys_stop_timer(&p_scb->timer);
+                }
+                /* one audio channel goes down. check if we need to restore high priority */
+                chk_restore = TRUE;
+            }
+        }
+
+        APPL_TRACE_DEBUG1("bta_av_conn_chg shdl:%d", index + 1);
+        for (i=0; i<BTA_AV_NUM_RCB; i++)
+        {
+            APPL_TRACE_DEBUG5("conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i,
+                              bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status,
+                              bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
+            if(bta_av_cb.rcb[i].shdl == index + 1)
+            {
+                bta_av_del_rc(&bta_av_cb.rcb[i]);
+                break;
+            }
+        }
+
+        if(p_cb->conn_audio == 0 && p_cb->conn_video == 0)
+        {
+            /* if both channels are not connected,
+             * close all RC channels */
+            bta_av_close_all_rc(p_cb);
+        }
+
+        /* if the AVRCP is no longer listening, create the listening channel */
+        if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE && bta_av_cb.features & BTA_AV_FEAT_RCTG)
+            bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+    }
+
+    APPL_TRACE_DEBUG6("bta_av_conn_chg audio:%x video:%x up:%d conn_msk:0x%x chk_restore:%d audio_open_cnt:%d",
+        p_cb->conn_audio, p_cb->conn_video, p_data->conn_chg.is_up, conn_msk, chk_restore, p_cb->audio_open_cnt);
+
+    if (chk_restore)
+    {
+        if (p_cb->audio_open_cnt == 1)
+        {
+            /* one audio channel goes down and there's one audio channel remains open.
+             * restore the switch role in default link policy */
+            bta_sys_set_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH);
+            /* allow role switch, if this is the last connection */
+            bta_av_restore_switch();
+        }
+        if (p_cb->audio_open_cnt)
+        {
+            /* adjust flush timeout settings to longer period */
+            for (i=0; i<BTA_AV_NUM_STRS; i++)
+            {
+                p_scbi = bta_av_cb.p_scb[i];
+                if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started)
+                {
+                    /* may need to update the flush timeout of this already started stream */
+                    if (p_scbi->co_started != bta_av_cb.audio_open_cnt)
+                    {
+                        p_scbi->co_started = bta_av_cb.audio_open_cnt;
+                        L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] );
+                    }
+                }
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_disable
+**
+** Description      disable AV.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_disable(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
+{
+    BT_HDR  hdr;
+    UINT16  xx;
+
+    p_cb->disabling = TRUE;
+
+    bta_av_close_all_rc(p_cb);
+
+    utl_freebuf((void **) &p_cb->p_disc_db);
+
+    /* disable audio/video - de-register all channels,
+     * expect BTA_AV_DEREG_COMP_EVT when deregister is complete */
+    for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
+    {
+        hdr.layer_specific = xx + 1;
+        bta_av_api_deregister((tBTA_AV_DATA *)&hdr);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_api_disconnect
+**
+** Description      .
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_api_disconnect(tBTA_AV_DATA *p_data)
+{
+    AVDT_DisconnectReq(p_data->api_discnt.bd_addr, bta_av_conn_cback);
+    bta_sys_stop_timer(&bta_av_cb.sig_tmr);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_sig_chg
+**
+** Description      process AVDT signal channel up/down.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_sig_chg(tBTA_AV_DATA *p_data)
+{
+    UINT16 event = p_data->str_msg.hdr.layer_specific;
+    tBTA_AV_CB   *p_cb = &bta_av_cb;
+    int     xx;
+    UINT8   mask;
+    tBTA_AV_LCB *p_lcb = NULL;
+
+    APPL_TRACE_DEBUG1("bta_av_sig_chg event: %d", event);
+    if(event == AVDT_CONNECT_IND_EVT)
+    {
+        p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND);
+        if(!p_lcb)
+        {
+            /* if the address does not have an LCB yet, alloc one */
+            for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
+            {
+                mask = 1 << xx;
+                APPL_TRACE_DEBUG1("conn_lcb: 0x%x", p_cb->conn_lcb);
+                if(!(mask & p_cb->conn_lcb))
+                {
+                    if (!p_cb->p_scb[xx])
+                    {
+                        /* We do not have scb for this avdt connection.     */
+                        /* Silently close the connection.                   */
+                        APPL_TRACE_ERROR0("av scb not available for avdt connection");
+                        AVDT_DisconnectReq (p_data->str_msg.bd_addr, NULL);
+                        return;
+                    }
+
+                    p_lcb = &p_cb->lcb[xx];
+                    p_lcb->lidx = xx + 1;
+                    bdcpy(p_lcb->addr, p_data->str_msg.bd_addr);
+                    p_lcb->conn_msk = 0; /* clear the connect mask */
+                    /* start listening when the signal channel is open */
+                    if (p_cb->features & BTA_AV_FEAT_RCTG)
+                    {
+                        bta_av_rc_create(p_cb, AVCT_ACP, 0, p_lcb->lidx);
+                    }
+                    /* this entry is not used yet. */
+                    p_cb->conn_lcb |= mask;     /* mark it as used */
+                    APPL_TRACE_DEBUG1("start sig timer %d", p_data->hdr.offset);
+                    if (p_data->hdr.offset == AVDT_ACP)
+                    {
+                        APPL_TRACE_DEBUG1("Incoming L2CAP acquired, set state as incoming", NULL);
+                        bdcpy(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr);
+                        p_cb->p_scb[xx]->use_rc = TRUE;     /* allowing RC for incoming connection */
+                        bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_ACP_CONNECT_EVT, p_data);
+
+                        /* The Pending Event should be sent as soon as the L2CAP signalling channel
+                         * is set up, which is NOW. Earlier this was done only after
+                         * BTA_AV_SIG_TIME_VAL milliseconds.
+                         * The following function shall send the event and start the recurring timer
+                         */
+                        bta_av_sig_timer(NULL);
+
+                        /* Possible collision : need to avoid outgoing processing while the timer is running */
+                        p_cb->p_scb[xx]->coll_mask = BTA_AV_COLL_INC_TMR;
+
+                        p_cb->acp_sig_tmr.param = (UINT32)xx;
+                        p_cb->acp_sig_tmr.p_cback = (TIMER_CBACK*)&bta_av_acp_sig_timer_cback;
+                        bta_sys_start_timer(&p_cb->acp_sig_tmr, 0, BTA_AV_ACP_SIG_TIME_VAL);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+    else if (event == BTA_AR_AVDT_CONN_EVT)
+    {
+        bta_sys_stop_timer(&bta_av_cb.sig_tmr);
+    }
+#endif
+    else
+    {
+        /* disconnected. */
+        p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FREE);
+        if(p_lcb && p_lcb->conn_msk)
+        {
+            APPL_TRACE_DEBUG1("conn_msk: 0x%x", p_lcb->conn_msk);
+            /* clean up ssm  */
+            for(xx=0; xx < BTA_AV_NUM_STRS; xx++)
+            {
+                mask = 1 << (xx + 1);
+                if ((mask & p_lcb->conn_msk) && (p_cb->p_scb[xx]) &&
+                    (bdcmp(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr) == 0))
+                {
+                    bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_AVDT_DISCONNECT_EVT, NULL);
+                }
+            }
+        }
+    }
+    APPL_TRACE_DEBUG1("conn_lcb: 0x%x", p_cb->conn_lcb);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_sig_timer
+**
+** Description      process the signal channel timer. This timer is started
+**                  when the AVDTP signal channel is connected. If no profile
+**                  is connected, the timer goes off every BTA_AV_SIG_TIME_VAL
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_sig_timer(tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_CB   *p_cb = &bta_av_cb;
+    int     xx;
+    UINT8   mask;
+    tBTA_AV_LCB *p_lcb = NULL;
+    tBTA_AV_PEND pend;
+
+    APPL_TRACE_DEBUG0("bta_av_sig_timer");
+    for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
+    {
+        mask = 1 << xx;
+        if(mask & p_cb->conn_lcb)
+        {
+            /* this entry is used. check if it is connected */
+            p_lcb = &p_cb->lcb[xx];
+            if(!p_lcb->conn_msk)
+            {
+                bta_sys_start_timer(&p_cb->sig_tmr, BTA_AV_SIG_TIMER_EVT, BTA_AV_SIG_TIME_VAL);
+                bdcpy(pend.bd_addr, p_lcb->addr);
+                (*p_cb->p_cback)(BTA_AV_PENDING_EVT, (tBTA_AV *) &pend);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_acp_sig_timer_cback
+**
+** Description      Process the timeout when SRC is accepting connection
+**                  and SNK did not start signalling.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_av_acp_sig_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+    UINT8   inx = (UINT8)p_tle->param;
+    tBTA_AV_CB  *p_cb = &bta_av_cb;
+    tBTA_AV_SCB *p_scb = p_cb->p_scb[inx];
+    tBTA_AV_API_OPEN  *p_buf;
+
+    if (p_scb)
+    {
+        APPL_TRACE_DEBUG1("bta_av_acp_sig_timer_cback, coll_mask = 0x%02X", p_scb->coll_mask);
+
+        if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR)
+        {
+            p_scb->coll_mask &= ~BTA_AV_COLL_INC_TMR;
+
+            if (bta_av_is_scb_opening(p_scb))
+            {
+                if (p_scb->p_disc_db)
+                {
+                    /* We are still doing SDP. Run the timer again. */
+                    p_scb->coll_mask |= BTA_AV_COLL_INC_TMR;
+
+                    p_cb->acp_sig_tmr.param = (UINT32)inx;
+                    p_cb->acp_sig_tmr.p_cback = (TIMER_CBACK *)&bta_av_acp_sig_timer_cback;
+                    bta_sys_start_timer(&p_cb->acp_sig_tmr, 0, BTA_AV_ACP_SIG_TIME_VAL);
+                }
+                else
+                {
+                    /* SNK did not start signalling, resume signalling process. */
+                    bta_av_discover_req (p_scb, NULL);
+                }
+            }
+            else if (bta_av_is_scb_incoming(p_scb))
+            {
+                /* Stay in incoming state if SNK does not start signalling */
+
+                /* API open was called right after SNK opened L2C connection. */
+                if (p_scb->coll_mask & BTA_AV_COLL_API_CALLED)
+                {
+                    p_scb->coll_mask &= ~BTA_AV_COLL_API_CALLED;
+
+                    /* BTA_AV_API_OPEN_EVT */
+                    if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL)
+                    {
+                        memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
+                        bta_sys_sendmsg(p_buf);
+                    }
+                }
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_check_peer_features
+**
+** Description      checks
+**
+** Returns          void
+**
+*******************************************************************************/
+tBTA_AV_FEAT bta_av_check_peer_features (UINT16 service_uuid)
+{
+    tBTA_AV_FEAT peer_features = 0;
+    tBTA_AV_CB   *p_cb = &bta_av_cb;
+    tSDP_DISC_REC       *p_rec = NULL;
+    tSDP_DISC_ATTR      *p_attr;
+    UINT16              peer_rc_version=0;
+    UINT16              categories = 0;
+
+    APPL_TRACE_DEBUG1("bta_av_check_peer_features service_uuid:x%x", service_uuid);
+    /* loop through all records we found */
+    while (TRUE)
+    {
+        /* get next record; if none found, we're done */
+        if ((p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec)) == NULL)
+        {
+            break;
+        }
+
+        if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) != NULL)
+        {
+            /* find peer features */
+            if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL))
+            {
+                peer_features |= BTA_AV_FEAT_RCCT;
+            }
+            if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL))
+            {
+                peer_features |= BTA_AV_FEAT_RCTG;
+            }
+        }
+
+        if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL)
+        {
+            /* get profile version (if failure, version parameter is not updated) */
+            SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version);
+            APPL_TRACE_DEBUG1("peer_rc_version 0x%x", peer_rc_version);
+
+            if (peer_rc_version >= AVRC_REV_1_3)
+                peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
+
+            if (peer_rc_version >= AVRC_REV_1_4)
+            {
+                peer_features |= (BTA_AV_FEAT_ADV_CTRL);
+                /* get supported categories */
+                if ((p_attr = SDP_FindAttributeInRec(p_rec,
+                                ATTR_ID_SUPPORTED_FEATURES)) != NULL)
+                {
+                    categories = p_attr->attr_value.v.u16;
+                    if (categories & AVRC_SUPF_CT_BROWSE)
+                        peer_features |= (BTA_AV_FEAT_BROWSE);
+                }
+            }
+        }
+    }
+    APPL_TRACE_DEBUG1("peer_features:x%x", peer_features);
+    return peer_features;
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_disc_done
+**
+** Description      Handle AVRCP service discovery results.  If matching
+**                  service found, open AVRCP connection.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_CB   *p_cb = &bta_av_cb;
+    tBTA_AV_SCB  *p_scb = NULL;
+    tBTA_AV_LCB  *p_lcb;
+    tBTA_AV_RC_OPEN rc_open;
+    tBTA_AV_RC_FEAT rc_feat;
+    UINT8               rc_handle;
+    tBTA_AV_FEAT        peer_features;  /* peer features mask */
+
+    APPL_TRACE_DEBUG1("bta_av_rc_disc_done disc:x%x", p_cb->disc);
+    if (!p_cb->disc)
+    {
+        return;
+    }
+
+    if ((p_cb->disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK)
+    {
+        /* this is the rc handle/index to tBTA_AV_RCB */
+        rc_handle = p_cb->disc & (~BTA_AV_CHNL_MSK);
+    }
+    else
+    {
+        p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1];
+        if (p_scb)
+            rc_handle = p_scb->rc_handle;
+        else
+        {
+            p_cb->disc = 0;
+            return;
+        }
+    }
+
+    APPL_TRACE_DEBUG1("rc_handle %d", rc_handle);
+    peer_features = bta_av_check_peer_features (UUID_SERVCLASS_AV_REMOTE_CONTROL);
+    if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) && ((peer_features&BTA_AV_FEAT_ADV_CTRL) == 0))
+    {
+        /* if we support advance control and peer does not, check their support on TG role
+         * some implementation uses 1.3 on CT ans 1.4 on TG */
+        peer_features |= bta_av_check_peer_features (UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+    }
+
+    p_cb->disc = 0;
+    utl_freebuf((void **) &p_cb->p_disc_db);
+
+    APPL_TRACE_DEBUG2("peer_features 0x%x, features 0x%x", peer_features, p_cb->features);
+
+    /* if we have no rc connection */
+    if (rc_handle == BTA_AV_RC_HANDLE_NONE)
+    {
+        if (p_scb)
+        {
+            /* if peer remote control service matches ours and USE_RC is TRUE */
+            if ((((p_cb->features & BTA_AV_FEAT_RCCT) && (peer_features & BTA_AV_FEAT_RCTG)) ||
+                 ((p_cb->features & BTA_AV_FEAT_RCTG) && (peer_features & BTA_AV_FEAT_RCCT))) )
+            {
+                p_lcb = bta_av_find_lcb(p_scb->peer_addr, BTA_AV_LCB_FIND);
+                if(p_lcb)
+                {
+                    rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (UINT8)(p_scb->hdi + 1), p_lcb->lidx);
+                    p_cb->rcb[rc_handle].peer_features = peer_features;
+                }
+#if (BT_USE_TRACES == TRUE || BT_TRACE_APPL == TRUE)
+                else
+                {
+                    APPL_TRACE_ERROR0("can not find LCB!!");
+                }
+#endif
+            }
+            else if(p_scb->use_rc)
+            {
+                /* can not find AVRC on peer device. report failure */
+                p_scb->use_rc = FALSE;
+                bdcpy(rc_open.peer_addr, p_scb->peer_addr);
+                rc_open.peer_features = 0;
+                rc_open.status = BTA_AV_FAIL_SDP;
+                (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open);
+            }
+        }
+    }
+    else
+    {
+        p_cb->rcb[rc_handle].peer_features = peer_features;
+        rc_feat.rc_handle =  rc_handle;
+        rc_feat.peer_features = peer_features;
+        (*p_cb->p_cback)(BTA_AV_RC_FEAT_EVT, (tBTA_AV *) &rc_feat);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_closed
+**
+** Description      Set AVRCP state to closed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_closed(tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_CB   *p_cb = &bta_av_cb;
+    tBTA_AV_RC_CLOSE rc_close;
+    tBTA_AV_RC_CONN_CHG *p_msg = (tBTA_AV_RC_CONN_CHG *)p_data;
+    tBTA_AV_RCB    *p_rcb;
+    tBTA_AV_SCB    *p_scb;
+    int i;
+    BOOLEAN conn = FALSE;
+    tBTA_AV_LCB *p_lcb;
+
+    rc_close.rc_handle = BTA_AV_RC_HANDLE_NONE;
+    APPL_TRACE_DEBUG1("bta_av_rc_closed rc_handle:%d", p_msg->handle);
+    for(i=0; i<BTA_AV_NUM_RCB; i++)
+    {
+        p_rcb = &p_cb->rcb[i];
+        APPL_TRACE_DEBUG3("bta_av_rc_closed rcb[%d] rc_handle:%d, status=0x%x", i, p_rcb->handle, p_rcb->status);
+        if(p_rcb->handle == p_msg->handle)
+        {
+            rc_close.rc_handle = i;
+            p_rcb->status &= ~BTA_AV_RC_CONN_MASK;
+            p_rcb->peer_features = 0;
+            APPL_TRACE_DEBUG2("       shdl:%d, lidx:%d", p_rcb->shdl, p_rcb->lidx);
+            if(p_rcb->shdl)
+            {
+                p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+                if(p_scb)
+                {
+                    bdcpy(rc_close.peer_addr, p_scb->peer_addr);
+                    if(p_scb->rc_handle == p_rcb->handle)
+                        p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
+                    APPL_TRACE_DEBUG2("shdl:%d, srch:%d", p_rcb->shdl, p_scb->rc_handle);
+                }
+                p_rcb->shdl = 0;
+            }
+            else if(p_rcb->lidx == (BTA_AV_NUM_LINKS + 1) )
+            {
+                /* if the RCB uses the extra LCB, use the addr for event and clean it */
+                p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
+                bdcpy(rc_close.peer_addr, p_msg->peer_addr);
+                APPL_TRACE_DEBUG6("rc_only closed bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+                              p_msg->peer_addr[0], p_msg->peer_addr[1],
+                              p_msg->peer_addr[2], p_msg->peer_addr[3],
+                              p_msg->peer_addr[4], p_msg->peer_addr[5]);
+                p_lcb->conn_msk = 0;
+                p_lcb->lidx = 0;
+            }
+            p_rcb->lidx = 0;
+
+            if((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)
+            {
+                /* AVCT CCB is deallocated */
+                p_rcb->handle = BTA_AV_RC_HANDLE_NONE;
+                p_rcb->status = 0;
+            }
+            else
+            {
+                /* AVCT CCB is still there. dealloc */
+                bta_av_del_rc(p_rcb);
+
+                /* if the AVRCP is no longer listening, create the listening channel */
+                if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE && bta_av_cb.features & BTA_AV_FEAT_RCTG)
+                    bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+            }
+        }
+        else if((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) && (p_rcb->status & BTA_AV_RC_CONN_MASK))
+        {
+            /* at least one channel is still connected */
+            conn = TRUE;
+        }
+    }
+
+    if(!conn)
+    {
+        /* no AVRC channels are connected, go back to INIT state */
+        bta_av_sm_execute(p_cb, BTA_AV_AVRC_NONE_EVT, NULL);
+    }
+
+    if (rc_close.rc_handle == BTA_AV_RC_HANDLE_NONE)
+    {
+        rc_close.rc_handle = p_msg->handle;
+        bdcpy(rc_close.peer_addr, p_msg->peer_addr);
+    }
+    (*p_cb->p_cback)(BTA_AV_RC_CLOSE_EVT, (tBTA_AV *) &rc_close);
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_rc_disc
+**
+** Description      start AVRC SDP discovery.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_rc_disc(UINT8 disc)
+{
+    tBTA_AV_CB   *p_cb = &bta_av_cb;
+    tAVRC_SDP_DB_PARAMS db_params;
+      UINT16              attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
+                                       ATTR_ID_BT_PROFILE_DESC_LIST,
+                                       ATTR_ID_SUPPORTED_FEATURES};
+    UINT8       hdi;
+    tBTA_AV_SCB *p_scb;
+    UINT8       *p_addr = NULL;
+    UINT8       rc_handle;
+
+    APPL_TRACE_DEBUG2("bta_av_rc_disc 0x%x, %d", disc, bta_av_cb.disc);
+    if ((bta_av_cb.disc != 0) || (disc == 0))
+        return;
+
+    if ((disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK)
+    {
+        /* this is the rc handle/index to tBTA_AV_RCB */
+        rc_handle = disc & (~BTA_AV_CHNL_MSK);
+        if (p_cb->rcb[rc_handle].lidx)
+        {
+            p_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx-1].addr;
+        }
+    }
+    else
+    {
+        hdi = (disc & BTA_AV_HNDL_MSK) - 1;
+        p_scb = p_cb->p_scb[hdi];
+
+        if (p_scb)
+        {
+            APPL_TRACE_DEBUG1("rc_handle %d", p_scb->rc_handle);
+            p_addr = p_scb->peer_addr;
+        }
+    }
+
+    if (p_addr)
+    {
+        /* allocate discovery database */
+        if (p_cb->p_disc_db == NULL)
+        {
+            p_cb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AV_DISC_BUF_SIZE);
+        }
+
+        if (p_cb->p_disc_db)
+        {
+            /* set up parameters */
+            db_params.db_len = BTA_AV_DISC_BUF_SIZE;
+            db_params.num_attr = 3;
+            db_params.p_db = p_cb->p_disc_db;
+            db_params.p_attrs = attr_list;
+
+            /* searching for UUID_SERVCLASS_AV_REMOTE_CONTROL gets both TG and CT */
+            if (AVRC_FindService(UUID_SERVCLASS_AV_REMOTE_CONTROL, p_addr, &db_params,
+                            bta_av_avrc_sdp_cback) == AVRC_SUCCESS)
+            {
+                p_cb->disc = disc;
+                APPL_TRACE_DEBUG1("disc %d", p_cb->disc);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_dereg_comp
+**
+** Description      deregister complete. free the stream control block.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_dereg_comp(tBTA_AV_DATA *p_data)
+{
+    tBTA_AV_CB   *p_cb = &bta_av_cb;
+    tBTA_AV_SCB  *p_scb;
+    tBTA_UTL_COD    cod;
+    UINT8   mask;
+    BT_HDR  *p_buf;
+
+    /* find the stream control block */
+    p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
+
+    if(p_scb)
+    {
+        APPL_TRACE_DEBUG2("deregistered %d(h%d)", p_scb->chnl, p_scb->hndl);
+        mask = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+        if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
+        {
+            p_cb->reg_audio  &= ~mask;
+            if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt)
+            {
+                /* this channel is still marked as open. decrease the count */
+                bta_av_cb.audio_open_cnt--;
+            }
+            p_cb->conn_audio &= ~mask;
+
+            if (p_scb->q_tag == BTA_AV_Q_TAG_STREAM)
+            {
+            /* make sure no buffers are in q_info.a2d */
+            while((p_buf = (BT_HDR*)GKI_dequeue (&p_scb->q_info.a2d)) != NULL)
+                GKI_freebuf(p_buf);
+            }
+
+            /* remove the A2DP SDP record, if no more audio stream is left */
+            if(!p_cb->reg_audio)
+            {
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+                bta_ar_dereg_avrc (UUID_SERVCLASS_AV_REMOTE_CONTROL, BTA_ID_AV);
+#endif
+                bta_av_del_sdp_rec(&p_cb->sdp_a2d_handle);
+                bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+            }
+        }
+        else
+        {
+            p_cb->reg_video  &= ~mask;
+            /* make sure that this channel is not connected */
+            p_cb->conn_video &= ~mask;
+            /* remove the VDP SDP record, (only one video stream at most) */
+            bta_av_del_sdp_rec(&p_cb->sdp_vdp_handle);
+            bta_sys_remove_uuid(UUID_SERVCLASS_VIDEO_SOURCE);
+        }
+
+        /* make sure that the timer is not active */
+        bta_sys_stop_timer(&p_scb->timer);
+        utl_freebuf((void **)&p_cb->p_scb[p_scb->hdi]);
+    }
+
+    APPL_TRACE_DEBUG3("audio 0x%x, video: 0x%x, disable:%d",
+        p_cb->reg_audio, p_cb->reg_video, p_cb->disabling);
+    /* if no stream control block is active */
+    if((p_cb->reg_audio + p_cb->reg_video) == 0)
+    {
+#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+        /* deregister from AVDT */
+        bta_ar_dereg_avdt(BTA_ID_AV);
+
+        /* deregister from AVCT */
+        bta_ar_dereg_avrc (UUID_SERVCLASS_AV_REM_CTRL_TARGET, BTA_ID_AV);
+        bta_ar_dereg_avct(BTA_ID_AV);
+#endif
+
+        if(p_cb->disabling)
+        {
+            p_cb->disabling     = FALSE;
+            bta_av_cb.features  = 0;
+        }
+
+        /* Clear the Capturing service class bit */
+        cod.service = BTM_COD_SERVICE_CAPTURING;
+        utl_set_device_class(&cod, BTA_UTL_CLR_COD_SERVICE_CLASS);
+    }
+}
+#endif /* BTA_AV_INCLUDED */
diff --git a/bta/av/bta_av_api.c b/bta/av/bta_av_api.c
new file mode 100644
index 0000000..a58e4a6
--- /dev/null
+++ b/bta/av/bta_av_api.c
@@ -0,0 +1,581 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2011-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the implementation of the API for the advanced audio/video (AV)
+ *  subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ *  phones.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE)
+
+#include "bta_api.h"
+#include "bd.h"
+#include "bta_sys.h"
+#include "bta_av_api.h"
+#include "bta_av_int.h"
+#include "gki.h"
+#include <string.h>
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_av_reg =
+{
+    bta_av_hdl_event,
+    BTA_AvDisable
+};
+
+/*******************************************************************************
+**
+** Function         BTA_AvEnable
+**
+** Description      Enable the advanced audio/video service. When the enable
+**                  operation is complete the callback function will be
+**                  called with a BTA_AV_ENABLE_EVT. This function must
+**                  be called before other function in the AV API are
+**                  called.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features, tBTA_AV_CBACK *p_cback)
+{
+    tBTA_AV_API_ENABLE  *p_buf;
+
+    /* register with BTA system manager */
+    GKI_sched_lock();
+    bta_sys_register(BTA_ID_AV, &bta_av_reg);
+    GKI_sched_unlock();
+
+    if ((p_buf = (tBTA_AV_API_ENABLE *) GKI_getbuf(sizeof(tBTA_AV_API_ENABLE))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_API_ENABLE_EVT;
+        p_buf->p_cback  = p_cback;
+        p_buf->features = features;
+        p_buf->sec_mask = sec_mask;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvDisable
+**
+** Description      Disable the advanced audio/video service.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvDisable(void)
+{
+    BT_HDR  *p_buf;
+
+    bta_sys_deregister(BTA_ID_AV);
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AV_API_DISABLE_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvRegister
+**
+** Description      Register the audio or video service to stack. When the
+**                  operation is complete the callback function will be
+**                  called with a BTA_AV_REGISTER_EVT. This function must
+**                  be called before AVDT stream is open.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id)
+{
+    tBTA_AV_API_REG  *p_buf;
+
+
+    if ((p_buf = (tBTA_AV_API_REG *) GKI_getbuf(sizeof(tBTA_AV_API_REG))) != NULL)
+    {
+        p_buf->hdr.layer_specific   = chnl;
+        p_buf->hdr.event = BTA_AV_API_REGISTER_EVT;
+        if(p_service_name)
+        {
+            BCM_STRNCPY_S(p_buf->p_service_name, sizeof(p_buf->p_service_name), p_service_name, BTA_SERVICE_NAME_LEN);
+            p_buf->p_service_name[BTA_SERVICE_NAME_LEN-1] = 0;
+        }
+        else
+        {
+            p_buf->p_service_name[0] = 0;
+        }
+        p_buf->app_id = app_id;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvDeregister
+**
+** Description      Deregister the audio or video service
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvDeregister(tBTA_AV_HNDL hndl)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->layer_specific   = hndl;
+        p_buf->event = BTA_AV_API_DEREGISTER_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvOpen
+**
+** Description      Opens an advanced audio/video connection to a peer device.
+**                  When connection is open callback function is called
+**                  with a BTA_AV_OPEN_EVT.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, BOOLEAN use_rc, tBTA_SEC sec_mask)
+{
+    tBTA_AV_API_OPEN  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_API_OPEN_EVT;
+        p_buf->hdr.layer_specific   = handle;
+        bdcpy(p_buf->bd_addr, bd_addr);
+        p_buf->use_rc = use_rc;
+        p_buf->sec_mask = sec_mask;
+        p_buf->switch_res = BTA_AV_RS_NONE;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvClose
+**
+** Description      Close the current streams.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvClose(tBTA_AV_HNDL handle)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AV_API_CLOSE_EVT;
+        p_buf->layer_specific   = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvDisconnect
+**
+** Description      Close the connection to the address.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvDisconnect(BD_ADDR bd_addr)
+{
+    tBTA_AV_API_DISCNT  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_DISCNT *) GKI_getbuf(sizeof(tBTA_AV_API_DISCNT))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_API_DISCONNECT_EVT;
+        bdcpy(p_buf->bd_addr, bd_addr);
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvStart
+**
+** Description      Start audio/video stream data transfer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvStart(void)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->event = BTA_AV_API_START_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvStop
+**
+** Description      Stop audio/video stream data transfer.
+**                  If suspend is TRUE, this function sends AVDT suspend signal
+**                  to the connected peer(s).
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvStop(BOOLEAN suspend)
+{
+    tBTA_AV_API_STOP  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_STOP *) GKI_getbuf(sizeof(tBTA_AV_API_STOP))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_API_STOP_EVT;
+        p_buf->flush   = TRUE;
+        p_buf->suspend = suspend;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvReconfig
+**
+** Description      Reconfigure the audio/video stream.
+**                  If suspend is TRUE, this function tries the suspend/reconfigure
+**                  procedure first.
+**                  If suspend is FALSE or when suspend/reconfigure fails,
+**                  this function closes and re-opens the AVDT connection.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvReconfig(tBTA_AV_HNDL hndl, BOOLEAN suspend, UINT8 sep_info_idx,
+                    UINT8 *p_codec_info, UINT8 num_protect, UINT8 *p_protect_info)
+{
+    tBTA_AV_API_RCFG  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_RCFG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_RCFG) + num_protect))) != NULL)
+    {
+        p_buf->hdr.layer_specific   = hndl;
+        p_buf->hdr.event    = BTA_AV_API_RECONFIG_EVT;
+        p_buf->num_protect  = num_protect;
+        p_buf->suspend      = suspend;
+        p_buf->sep_info_idx = sep_info_idx;
+        p_buf->p_protect_info = (UINT8 *)(p_buf + 1);
+        memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE);
+        memcpy(p_buf->p_protect_info, p_protect_info, num_protect);
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvProtectReq
+**
+** Description      Send a content protection request.  This function can only
+**                  be used if AV is enabled with feature BTA_AV_FEAT_PROTECT.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvProtectReq(tBTA_AV_HNDL hndl, UINT8 *p_data, UINT16 len)
+{
+    tBTA_AV_API_PROTECT_REQ  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_PROTECT_REQ *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_PROTECT_REQ) + len))) != NULL)
+    {
+        p_buf->hdr.layer_specific   = hndl;
+        p_buf->hdr.event = BTA_AV_API_PROTECT_REQ_EVT;
+        p_buf->len       = len;
+        if (p_data == NULL)
+        {
+            p_buf->p_data = NULL;
+        }
+        else
+        {
+            p_buf->p_data = (UINT8 *) (p_buf + 1);
+            memcpy(p_buf->p_data, p_data, len);
+        }
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvProtectRsp
+**
+** Description      Send a content protection response.  This function must
+**                  be called if a BTA_AV_PROTECT_REQ_EVT is received.
+**                  This function can only be used if AV is enabled with
+**                  feature BTA_AV_FEAT_PROTECT.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, UINT8 error_code, UINT8 *p_data, UINT16 len)
+{
+    tBTA_AV_API_PROTECT_RSP  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_PROTECT_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_PROTECT_RSP) + len))) != NULL)
+    {
+        p_buf->hdr.layer_specific   = hndl;
+        p_buf->hdr.event    = BTA_AV_API_PROTECT_RSP_EVT;
+        p_buf->len          = len;
+        p_buf->error_code   = error_code;
+        if (p_data == NULL)
+        {
+            p_buf->p_data = NULL;
+        }
+        else
+        {
+            p_buf->p_data = (UINT8 *) (p_buf + 1);
+            memcpy(p_buf->p_data, p_data, len);
+        }
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvRemoteCmd
+**
+** Description      Send a remote control command.  This function can only
+**                  be used if AV is enabled with feature BTA_AV_FEAT_RCCT.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvRemoteCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_RC rc_id, tBTA_AV_STATE key_state)
+{
+    tBTA_AV_API_REMOTE_CMD  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_REMOTE_CMD *) GKI_getbuf(sizeof(tBTA_AV_API_REMOTE_CMD))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_API_REMOTE_CMD_EVT;
+        p_buf->hdr.layer_specific   = rc_handle;
+        p_buf->msg.op_id = rc_id;
+        p_buf->msg.state = key_state;
+        p_buf->msg.p_pass_data = NULL;
+        p_buf->msg.pass_len = 0;
+        p_buf->label = label;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvVendorCmd
+**
+** Description      Send a vendor dependent remote control command.  This
+**                  function can only be used if AV is enabled with feature
+**                  BTA_AV_FEAT_VENDOR.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvVendorCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE cmd_code, UINT8 *p_data, UINT16 len)
+{
+    tBTA_AV_API_VENDOR  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_VENDOR *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_VENDOR) + len))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_API_VENDOR_CMD_EVT;
+        p_buf->hdr.layer_specific   = rc_handle;
+        p_buf->msg.hdr.ctype = cmd_code;
+        p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL;
+        p_buf->msg.hdr.subunit_id = 0;
+        p_buf->msg.company_id = p_bta_av_cfg->company_id;
+        p_buf->label = label;
+        p_buf->msg.vendor_len = len;
+        if (p_data == NULL)
+        {
+            p_buf->msg.p_vendor_data = NULL;
+        }
+        else
+        {
+            p_buf->msg.p_vendor_data = (UINT8 *) (p_buf + 1);
+            memcpy(p_buf->msg.p_vendor_data, p_data, len);
+        }
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvVendorRsp
+**
+** Description      Send a vendor dependent remote control response.
+**                  This function must be called if a BTA_AV_VENDOR_CMD_EVT
+**                  is received. This function can only be used if AV is
+**                  enabled with feature BTA_AV_FEAT_VENDOR.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvVendorRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code, UINT8 *p_data, UINT16 len, UINT32 company_id)
+{
+    tBTA_AV_API_VENDOR  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_VENDOR *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_VENDOR) + len))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_API_VENDOR_RSP_EVT;
+        p_buf->hdr.layer_specific   = rc_handle;
+        p_buf->msg.hdr.ctype = rsp_code;
+        p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL;
+        p_buf->msg.hdr.subunit_id = 0;
+        if(company_id)
+            p_buf->msg.company_id = company_id;
+        else
+            p_buf->msg.company_id = p_bta_av_cfg->company_id;
+        p_buf->label = label;
+        p_buf->msg.vendor_len = len;
+        if (p_data == NULL)
+        {
+            p_buf->msg.p_vendor_data = NULL;
+        }
+        else
+        {
+            p_buf->msg.p_vendor_data = (UINT8 *) (p_buf + 1);
+            memcpy(p_buf->msg.p_vendor_data, p_data, len);
+        }
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvOpenRc
+**
+** Description      Open an AVRCP connection toward the device with the
+**                  specified handle
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvOpenRc(tBTA_AV_HNDL handle)
+{
+    tBTA_AV_API_OPEN_RC  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_OPEN_RC *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN_RC))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_API_RC_OPEN_EVT;
+        p_buf->hdr.layer_specific   = handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvCloseRc
+**
+** Description      Close an AVRCP connection
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvCloseRc(UINT8 rc_handle)
+{
+    tBTA_AV_API_CLOSE_RC  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_CLOSE_RC *) GKI_getbuf(sizeof(tBTA_AV_API_CLOSE_RC))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_API_RC_CLOSE_EVT;
+        p_buf->hdr.layer_specific   = rc_handle;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvMetaRsp
+**
+** Description      Send a Metadata/Advanced Control response. The message contained
+**                  in p_pkt can be composed with AVRC utility functions.
+**                  This function can only be used if AV is enabled with feature
+**                  BTA_AV_FEAT_METADATA.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvMetaRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code,
+                               BT_HDR *p_pkt)
+{
+    tBTA_AV_API_META_RSP  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_META_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_META_RSP)))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_API_META_RSP_EVT;
+        p_buf->hdr.layer_specific   = rc_handle;
+        p_buf->rsp_code = rsp_code;
+        p_buf->p_pkt = p_pkt;
+        p_buf->is_rsp = TRUE;
+        p_buf->label = label;
+
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTA_AvMetaCmd
+**
+** Description      Send a Metadata/Advanced Control command. The message contained
+**                  in p_pkt can be composed with AVRC utility functions.
+**                  This function can only be used if AV is enabled with feature
+**                  BTA_AV_FEAT_METADATA.
+**                  This message is sent only when the peer supports the TG role.
+*8                  The only command makes sense right now is the absolute volume command.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_AvMetaCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CMD cmd_code, BT_HDR *p_pkt)
+{
+    tBTA_AV_API_META_RSP  *p_buf;
+
+    if ((p_buf = (tBTA_AV_API_META_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_META_RSP)))) != NULL)
+    {
+        p_buf->hdr.event = BTA_AV_API_META_RSP_EVT;
+        p_buf->hdr.layer_specific   = rc_handle;
+        p_buf->p_pkt = p_pkt;
+        p_buf->rsp_code = cmd_code;
+        p_buf->is_rsp = FALSE;
+        p_buf->label = label;
+
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+#endif /* BTA_AV_INCLUDED */
diff --git a/bta/av/bta_av_cfg.c b/bta/av/bta_av_cfg.c
new file mode 100644
index 0000000..793c772
--- /dev/null
+++ b/bta/av/bta_av_cfg.c
@@ -0,0 +1,231 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This file contains compile-time configurable constants for advanced
+ *  audio/video
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "gki.h"
+#include "bta_api.h"
+#include "bta_av_int.h"
+
+
+
+#ifndef BTA_AV_RC_PASS_RSP_CODE
+#define BTA_AV_RC_PASS_RSP_CODE     BTA_AV_RSP_NOT_IMPL
+#endif
+
+
+const UINT32  bta_av_meta_caps_co_ids[] = {
+    AVRC_CO_METADATA,
+    AVRC_CO_BROADCOM
+};
+
+/* AVRCP cupported categories */
+#define BTA_AV_RC_SUPF_CT       (AVRC_SUPF_CT_CAT2)
+
+
+/* Added to modify
+**	1. flush timeout
+**	2. Remove Group navigation support in SupportedFeatures
+**	3. GetCapabilities supported event_ids list
+**	4. GetCapabilities supported event_ids count
+*/
+#ifdef ANDROID_APP_INCLUDED
+/* Flushing partial avdtp packets can cause some headsets to disconnect the link
+   if receiving partial a2dp frames */
+const UINT16  bta_av_audio_flush_to[] = {
+     0, /* 1 stream */
+     0, /* 2 streams */
+     0, /* 3 streams */
+     0, /* 4 streams */
+     0  /* 5 streams */
+};     /* AVDTP audio transport channel flush timeout */
+
+/* Note: Android doesnt support AVRC_SUPF_TG_GROUP_NAVI  */
+#define BTA_AV_RC_SUPF_TG       (AVRC_SUPF_TG_CAT1)
+
+
+/*
+ * If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS   also needs to be changed.
+ */
+const UINT8  bta_av_meta_caps_evt_ids[] = {
+    AVRC_EVT_PLAY_STATUS_CHANGE,
+    AVRC_EVT_TRACK_CHANGE,
+    AVRC_EVT_PLAY_POS_CHANGED,
+    AVRC_EVT_APP_SETTING_CHANGE,
+};
+#ifndef BTA_AV_NUM_RC_EVT_IDS
+#define BTA_AV_NUM_RC_EVT_IDS   (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0]))
+#endif /* BTA_AV_NUM_RC_EVT_IDS */
+
+
+#else /* !ANDROID_APP_INCLUDED */
+
+/* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be TRUE */
+#define BTA_AV_RC_SUPF_TG       (AVRC_SUPF_TG_CAT1)
+
+const UINT16  bta_av_audio_flush_to[] = {
+    120, /* 1 stream  */
+    100, /* 2 streams */
+     80, /* 3 streams */
+     60, /* 4 streams */
+     40  /* 5 streams */
+};     /* AVDTP audio transport channel flush timeout */
+
+
+/*
+ * If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS   also needs to be changed.
+ */
+const UINT8  bta_av_meta_caps_evt_ids[] = {
+    AVRC_EVT_PLAY_STATUS_CHANGE,
+    AVRC_EVT_TRACK_CHANGE,
+    AVRC_EVT_TRACK_REACHED_END,
+    AVRC_EVT_TRACK_REACHED_START,
+    AVRC_EVT_PLAY_POS_CHANGED,
+    AVRC_EVT_BATTERY_STATUS_CHANGE,
+    AVRC_EVT_SYSTEM_STATUS_CHANGE,
+    AVRC_EVT_APP_SETTING_CHANGE,
+};
+
+#ifndef BTA_AV_NUM_RC_EVT_IDS
+#define BTA_AV_NUM_RC_EVT_IDS   8
+#endif
+
+#endif /* ANDROID_APP_INCLUDED */
+
+/* the MTU for the AVRCP browsing channel */
+#ifndef BTA_AV_MAX_RC_BR_MTU
+#define BTA_AV_MAX_RC_BR_MTU      1008
+#endif
+
+const tBTA_AV_CFG bta_av_cfg =
+{
+    AVRC_CO_BROADCOM,       /* AVRCP Company ID */
+    48,                     /* AVRCP MTU at L2CAP for control channel */
+    BTA_AV_MAX_RC_BR_MTU,   /* AVRCP MTU at L2CAP for browsing channel */
+    BTA_AV_RC_SUPF_CT,      /* AVRCP controller categories */
+    BTA_AV_RC_SUPF_TG,      /* AVRCP target categories */
+    672,                    /* AVDTP signaling channel MTU at L2CAP */
+    BTA_AV_MAX_A2DP_MTU,    /* AVDTP audio transport channel MTU at L2CAP */
+    bta_av_audio_flush_to,  /* AVDTP audio transport channel flush timeout */
+    6,                      /* AVDTP audio channel max data queue size */
+    BTA_AV_MAX_VDP_MTU,     /* AVDTP video transport channel MTU at L2CAP */
+    600,                    /* AVDTP video transport channel flush timeout */
+    TRUE,                   /* TRUE, to accept AVRC 1.3 group nevigation command */
+    2,                      /* company id count in p_meta_co_ids */
+    BTA_AV_NUM_RC_EVT_IDS, /* event id count in p_meta_evt_ids */
+    BTA_AV_RC_PASS_RSP_CODE,/* the default response code for pass through commands */
+    bta_av_meta_caps_co_ids,/* the metadata Get Capabilities response for company id */
+    bta_av_meta_caps_evt_ids,/* the the metadata Get Capabilities response for event id */
+};
+
+tBTA_AV_CFG *p_bta_av_cfg = (tBTA_AV_CFG *) &bta_av_cfg;
+
+const UINT16 bta_av_rc_id[] =
+{
+    0x021F, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
+                         4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP,
+                         8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU,
+                         12=FAV_MENU, 13=EXIT */
+
+    0,      /* not used */
+
+    0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3,
+                         4=4, 5=5, 6=6, 7=7,
+                         8=8, 9=9, 10=DOT, 11=ENTER,
+                         12=CLEAR */
+
+    0x0003, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL,
+                         4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP,
+                         8=PAGE_DOWN */
+
+#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
+    /* btui_app provides an example of how to leave the decision of rejecting a command or not
+     * based on which media player is currently addressed (this is only applicable for AVRCP 1.4 or later)
+     * If the decision is per player for a particular rc_id, the related bit is clear (not set) */
+    0x0070, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
+                         4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
+                         8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+                         12=BACKWARD */
+#else
+#if (defined BTA_AVRCP_FF_RW_SUPPORT) && (BTA_AVRCP_FF_RW_SUPPORT == TRUE)
+    0x1b70, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
+                         4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
+                         8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+                         12=BACKWARD */
+#else
+    0x1870, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
+                         4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
+                         8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+                         12=BACKWARD */
+#endif
+#endif
+
+    0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */
+
+    0,      /* not used */
+
+    0x0000  /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3,
+                         4=F4, 5=F5 */
+};
+
+#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
+const UINT16 bta_av_rc_id_ac[] =
+{
+    0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
+                         4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP,
+                         8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU,
+                         12=FAV_MENU, 13=EXIT */
+
+    0,      /* not used */
+
+    0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3,
+                         4=4, 5=5, 6=6, 7=7,
+                         8=8, 9=9, 10=DOT, 11=ENTER,
+                         12=CLEAR */
+
+    0x0000, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL,
+                         4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP,
+                         8=PAGE_DOWN */
+
+    /* btui_app provides an example of how to leave the decision of rejecting a command or not
+     * based on which media player is currently addressed (this is only applicable for AVRCP 1.4 or later)
+     * If the decision is per player for a particular rc_id, the related bit is set */
+    0x1800, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
+                         4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
+                         8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+                         12=BACKWARD */
+
+    0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */
+
+    0,      /* not used */
+
+    0x0000  /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3,
+                         4=F4, 5=F5 */
+};
+UINT16 *p_bta_av_rc_id_ac = (UINT16 *) bta_av_rc_id_ac;
+#else
+UINT16 *p_bta_av_rc_id_ac = NULL;
+#endif
+
+UINT16 *p_bta_av_rc_id = (UINT16 *) bta_av_rc_id;
diff --git a/bta/av/bta_av_ci.c b/bta/av/bta_av_ci.c
new file mode 100644
index 0000000..a1c2ac0
--- /dev/null
+++ b/bta/av/bta_av_ci.c
@@ -0,0 +1,98 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the implementation file for advanced audio/video call-in
+ *  functions.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_av_int.h"
+#include "bta_av_ci.h"
+
+#include <string.h>
+
+/*******************************************************************************
+**
+** Function         bta_av_ci_src_data_ready
+**
+** Description      This function sends an event to the AV indicating that
+**                  the phone has audio stream data ready to send and AV
+**                  should call bta_av_co_audio_src_data_path() or
+**                  bta_av_co_video_src_data_path().
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl)
+{
+    BT_HDR  *p_buf;
+
+    if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+    {
+        p_buf->layer_specific   = chnl;
+        p_buf->event = BTA_AV_CI_SRC_DATA_READY_EVT;
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_av_ci_setconfig
+**
+** Description      This function must be called in response to function
+**                  bta_av_co_audio_setconfig() or bta_av_co_video_setconfig.
+**                  Parameter err_code is set to an AVDTP status value;
+**                  AVDT_SUCCESS if the codec configuration is ok,
+**                  otherwise error.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, UINT8 err_code, UINT8 category,
+                         UINT8 num_seid, UINT8 *p_seid, BOOLEAN recfg_needed)
+{
+    tBTA_AV_CI_SETCONFIG  *p_buf;
+
+    if ((p_buf = (tBTA_AV_CI_SETCONFIG *) GKI_getbuf(sizeof(tBTA_AV_CI_SETCONFIG))) != NULL)
+    {
+        p_buf->hdr.layer_specific   = hndl;
+        p_buf->hdr.event = (err_code == AVDT_SUCCESS) ?
+                           BTA_AV_CI_SETCONFIG_OK_EVT : BTA_AV_CI_SETCONFIG_FAIL_EVT;
+        p_buf->err_code = err_code;
+        p_buf->category = category;
+        p_buf->recfg_needed = recfg_needed;
+        p_buf->num_seid = num_seid;
+        if(p_seid && num_seid)
+        {
+            p_buf->p_seid   = (UINT8 *)(p_buf + 1);
+            memcpy(p_buf->p_seid, p_seid, num_seid);
+        }
+        else
+        {
+            p_buf->p_seid   = NULL;
+            p_buf->num_seid = 0;
+        }
+
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
diff --git a/bta/av/bta_av_int.h b/bta/av/bta_av_int.h
new file mode 100644
index 0000000..05eb114
--- /dev/null
+++ b/bta/av/bta_av_int.h
@@ -0,0 +1,719 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  This is the private interface file for the BTA advanced audio/video.
+ *
+ ******************************************************************************/
+#ifndef BTA_AV_INT_H
+#define BTA_AV_INT_H
+
+#include "bta_sys.h"
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "avdt_api.h"
+#include "bta_av_co.h"
+
+#define BTA_AV_DEBUG TRUE
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+enum
+{
+    /* these events are handled by the AV main state machine */
+    BTA_AV_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_AV),
+    BTA_AV_API_REMOTE_CMD_EVT,
+    BTA_AV_API_VENDOR_CMD_EVT,
+    BTA_AV_API_VENDOR_RSP_EVT,
+    BTA_AV_API_META_RSP_EVT,
+    BTA_AV_API_RC_CLOSE_EVT,
+    BTA_AV_AVRC_OPEN_EVT,
+    BTA_AV_AVRC_MSG_EVT,
+    BTA_AV_AVRC_NONE_EVT,
+
+    /* these events are handled by the AV stream state machine */
+    BTA_AV_API_OPEN_EVT,
+    BTA_AV_API_CLOSE_EVT,
+    BTA_AV_AP_START_EVT,        /* the following 2 events must be in the same order as the *API_*EVT */
+    BTA_AV_AP_STOP_EVT,
+    BTA_AV_API_RECONFIG_EVT,
+    BTA_AV_API_PROTECT_REQ_EVT,
+    BTA_AV_API_PROTECT_RSP_EVT,
+    BTA_AV_API_RC_OPEN_EVT,
+    BTA_AV_SRC_DATA_READY_EVT,
+    BTA_AV_CI_SETCONFIG_OK_EVT,
+    BTA_AV_CI_SETCONFIG_FAIL_EVT,
+    BTA_AV_SDP_DISC_OK_EVT,
+    BTA_AV_SDP_DISC_FAIL_EVT,
+    BTA_AV_STR_DISC_OK_EVT,
+    BTA_AV_STR_DISC_FAIL_EVT,
+    BTA_AV_STR_GETCAP_OK_EVT,
+    BTA_AV_STR_GETCAP_FAIL_EVT,
+    BTA_AV_STR_OPEN_OK_EVT,
+    BTA_AV_STR_OPEN_FAIL_EVT,
+    BTA_AV_STR_START_OK_EVT,
+    BTA_AV_STR_START_FAIL_EVT,
+    BTA_AV_STR_CLOSE_EVT,
+    BTA_AV_STR_CONFIG_IND_EVT,
+    BTA_AV_STR_SECURITY_IND_EVT,
+    BTA_AV_STR_SECURITY_CFM_EVT,
+    BTA_AV_STR_WRITE_CFM_EVT,
+    BTA_AV_STR_SUSPEND_CFM_EVT,
+    BTA_AV_STR_RECONFIG_CFM_EVT,
+    BTA_AV_AVRC_TIMER_EVT,
+    BTA_AV_AVDT_CONNECT_EVT,
+    BTA_AV_AVDT_DISCONNECT_EVT,
+    BTA_AV_ROLE_CHANGE_EVT,
+    BTA_AV_AVDT_DELAY_RPT_EVT,
+    BTA_AV_ACP_CONNECT_EVT,
+
+    /* these events are handled outside of the state machine */
+    BTA_AV_API_ENABLE_EVT,
+    BTA_AV_API_REGISTER_EVT,
+    BTA_AV_API_DEREGISTER_EVT,
+    BTA_AV_API_DISCONNECT_EVT,
+    BTA_AV_CI_SRC_DATA_READY_EVT,
+    BTA_AV_SIG_CHG_EVT,
+    BTA_AV_SIG_TIMER_EVT,
+    BTA_AV_SDP_AVRC_DISC_EVT,
+    BTA_AV_AVRC_CLOSE_EVT,
+    BTA_AV_CONN_CHG_EVT,
+    BTA_AV_DEREG_COMP_EVT,
+#if (AVDT_REPORTING == TRUE)
+    BTA_AV_AVDT_RPT_CONN_EVT,
+#endif
+    BTA_AV_API_START_EVT,       /* the following 2 events must be in the same order as the *AP_*EVT */
+    BTA_AV_API_STOP_EVT
+};
+
+/* events for AV control block state machine */
+#define BTA_AV_FIRST_SM_EVT     BTA_AV_API_DISABLE_EVT
+#define BTA_AV_LAST_SM_EVT      BTA_AV_AVRC_NONE_EVT
+
+/* events for AV stream control block state machine */
+#define BTA_AV_FIRST_SSM_EVT    BTA_AV_API_OPEN_EVT
+
+/* events that do not go through state machine */
+#define BTA_AV_FIRST_NSM_EVT    BTA_AV_API_ENABLE_EVT
+#define BTA_AV_LAST_NSM_EVT     BTA_AV_API_STOP_EVT
+
+/* API events passed to both SSMs (by bta_av_api_to_ssm) */
+#define BTA_AV_FIRST_A2S_API_EVT    BTA_AV_API_START_EVT
+#define BTA_AV_FIRST_A2S_SSM_EVT    BTA_AV_AP_START_EVT
+
+#define BTA_AV_LAST_EVT             BTA_AV_API_STOP_EVT
+
+/* maximum number of SEPS in stream discovery results */
+#define BTA_AV_NUM_SEPS         32
+
+/* initialization value for AVRC handle */
+#define BTA_AV_RC_HANDLE_NONE   0xFF
+
+/* size of database for service discovery */
+#define BTA_AV_DISC_BUF_SIZE        1000
+
+/* offset of media type in codec info byte array */
+#define BTA_AV_MEDIA_TYPE_IDX       1
+
+/* maximum length of AVDTP security data */
+#define BTA_AV_SECURITY_MAX_LEN     400
+
+/* check number of buffers queued at L2CAP when this amount of buffers are queued to L2CAP */
+#define BTA_AV_QUEUE_DATA_CHK_NUM   5
+
+/* the number of ACL links with AVDT */
+#define BTA_AV_NUM_LINKS            AVDT_NUM_LINKS
+
+#define BTA_AV_CO_ID_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); }
+#define BTA_AV_BE_STREAM_TO_CO_ID(u32, p) {u32 = (((UINT32)(*((p) + 2))) + (((UINT32)(*((p) + 1))) << 8) + (((UINT32)(*(p))) << 16)); (p) += 3;}
+
+/* these bits are defined for bta_av_cb.multi_av */
+#define BTA_AV_MULTI_AV_SUPPORTED   0x01
+#define BTA_AV_MULTI_AV_IN_USE      0x02
+
+
+/*****************************************************************************
+**  Data types
+*****************************************************************************/
+
+/* function types for call-out functions */
+typedef BOOLEAN (*tBTA_AV_CO_INIT) (UINT8 *p_codec_type, UINT8 *p_codec_info,
+                                   UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index);
+
+typedef void (*tBTA_AV_CO_DISC_RES) (tBTA_AV_HNDL hndl, UINT8 num_seps,
+                                     UINT8 num_snk, BD_ADDR addr);
+
+typedef UINT8 (*tBTA_AV_CO_GETCFG) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+                                     UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid,
+                                     UINT8 *p_num_protect, UINT8 *p_protect_info);
+typedef void (*tBTA_AV_CO_SETCFG) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+                                    UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr,
+                                    UINT8 num_protect, UINT8 *p_protect_info);
+typedef void (*tBTA_AV_CO_OPEN) (tBTA_AV_HNDL hndl,
+                                 tBTA_AV_CODEC codec_type, UINT8 *p_codec_info,
+                                   UINT16 mtu);
+typedef void (*tBTA_AV_CO_CLOSE) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT16 mtu);
+typedef void (*tBTA_AV_CO_START) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type);
+typedef void (*tBTA_AV_CO_STOP) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type);
+typedef void * (*tBTA_AV_CO_DATAPATH) (tBTA_AV_CODEC codec_type,
+                                       UINT32 *p_len, UINT32 *p_timestamp);
+typedef void (*tBTA_AV_CO_DELAY) (tBTA_AV_HNDL hndl, UINT16 delay);
+
+/* the call-out functions for one stream */
+typedef struct
+{
+    tBTA_AV_CO_INIT     init;
+    tBTA_AV_CO_DISC_RES disc_res;
+    tBTA_AV_CO_GETCFG   getcfg;
+    tBTA_AV_CO_SETCFG   setcfg;
+    tBTA_AV_CO_OPEN     open;
+    tBTA_AV_CO_CLOSE    close;
+    tBTA_AV_CO_START    start;
+    tBTA_AV_CO_STOP     stop;
+    tBTA_AV_CO_DATAPATH data;
+    tBTA_AV_CO_DELAY    delay;
+} tBTA_AV_CO_FUNCTS;
+
+/* data type for BTA_AV_API_ENABLE_EVT */
+typedef struct
+{
+    BT_HDR              hdr;
+    tBTA_AV_CBACK       *p_cback;
+    tBTA_AV_FEAT        features;
+    tBTA_SEC            sec_mask;
+} tBTA_AV_API_ENABLE;
+