+++ /dev/null
-/******************************************************************************
- *
- * 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 <inttypes.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"
-#include "bt_utils.h"
-
-#define LOG_TAG "bt_a2dp_hw"
-#include "osi/include/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() LOG_VERBOSE("%s", __FUNCTION__);
-#define DEBUG(fmt, ...) LOG_VERBOSE("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
-#define INFO(fmt, ...) LOG_INFO("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
-#define ERROR(fmt, ...) LOG_ERROR("%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_in;
-struct a2dp_stream_out;
-
-struct a2dp_audio_device {
- struct audio_hw_device device;
- struct a2dp_stream_in *input;
- 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_common {
- pthread_mutex_t lock;
- int ctrl_fd;
- int audio_fd;
- size_t buffer_sz;
- struct a2dp_config cfg;
- a2dp_state_t state;
-};
-
-struct a2dp_stream_out {
- struct audio_stream_out stream;
- struct a2dp_stream_common common;
- uint64_t frames_presented; // frames written, never reset
- uint64_t frames_rendered; // frames written, reset on standby
-};
-
-struct a2dp_stream_in {
- struct audio_stream_in stream;
- struct a2dp_stream_common common;
-};
-
-/*****************************************************************************
-** 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;
- UNUSED(tag);
- UNUSED(val);
-
- 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(char *path, size_t buffer_sz)
-{
- int ret;
- int skt_fd;
- struct sockaddr_un remote;
- int len;
-
- INFO("connect to %s (sz %zu)", path, 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 = 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));
- }
-
- ret = setsockopt(skt_fd, SOL_SOCKET, SO_RCVBUF, (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_read(int fd, void *p, size_t len)
-{
- int read;
- struct pollfd pfd;
- struct timespec ts;
-
- FNLOG();
-
- ts_log("skt_read recv", len, NULL);
-
- if ((read = recv(fd, p, len, MSG_NOSIGNAL)) == -1) {
- ERROR("write failed with errno=%d\n", errno);
- return -1;
- }
-
- return read;
-}
-
-static int skt_write(int fd, const void *p, size_t len)
-{
- int sent;
- 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_ctrl_receive(struct a2dp_stream_common *common, void *buffer, int length)
-{
- int ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL);
- if (ret < 0) {
- ERROR("ack failed (%s)", strerror(errno));
- if (errno == EINTR) {
- /* retry again */
- ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL);
- if (ret < 0) {
- ERROR("ack failed (%s)", strerror(errno));
- skt_disconnect(common->ctrl_fd);
- common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
- return -1;
- }
- } else {
- skt_disconnect(common->ctrl_fd);
- common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
- return -1;
-
- }
- }
- return ret;
-}
-
-static int a2dp_command(struct a2dp_stream_common *common, char cmd)
-{
- char ack;
-
- DEBUG("A2DP COMMAND %s", dump_a2dp_ctrl_event(cmd));
-
- /* send command */
- if (send(common->ctrl_fd, &cmd, 1, MSG_NOSIGNAL) == -1) {
- ERROR("cmd failed (%s)", strerror(errno));
- skt_disconnect(common->ctrl_fd);
- common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
- return -1;
- }
-
- /* wait for ack byte */
- if (a2dp_ctrl_receive(common, &ack, 1) < 0) {
- return -1;
- }
-
- DEBUG("A2DP COMMAND %s DONE STATUS %d", dump_a2dp_ctrl_event(cmd), ack);
-
- if (ack == A2DP_CTRL_ACK_INCALL_FAILURE) {
- return ack;
- }
- if (ack != A2DP_CTRL_ACK_SUCCESS) {
- return -1;
- }
-
- return 0;
-}
-
-static int check_a2dp_ready(struct a2dp_stream_common *common)
-{
- if (a2dp_command(common, A2DP_CTRL_CMD_CHECK_READY) < 0) {
- ERROR("check a2dp ready failed");
- return -1;
- }
- return 0;
-}
-
-static int a2dp_read_audio_config(struct a2dp_stream_common *common)
-{
- char cmd = A2DP_CTRL_GET_AUDIO_CONFIG;
- uint32_t sample_rate;
- uint8_t channel_count;
-
- if (a2dp_command(common, A2DP_CTRL_GET_AUDIO_CONFIG) < 0) {
- ERROR("check a2dp ready failed");
- return -1;
- }
-
- if (a2dp_ctrl_receive(common, &sample_rate, 4) < 0) {
- return -1;
- }
- if (a2dp_ctrl_receive(common, &channel_count, 1) < 0) {
- return -1;
- }
-
- common->cfg.channel_flags = (channel_count == 1 ? AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO);
- common->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
- common->cfg.rate = sample_rate;
-
- INFO("got config %d %d", common->cfg.format, common->cfg.rate);
-
- return 0;
-}
-
-static void a2dp_open_ctrl_path(struct a2dp_stream_common *common)
-{
- int i;
-
- /* retry logic to catch any timing variations on control channel */
- for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++) {
- /* connect control channel if not already connected */
- if ((common->ctrl_fd = skt_connect(A2DP_CTRL_PATH, common->buffer_sz)) > 0) {
- /* success, now check if stack is ready */
- if (check_a2dp_ready(common) == 0) {
- break;
- }
-
- ERROR("error : a2dp not ready, wait 250 ms and retry");
- usleep(250000);
- skt_disconnect(common->ctrl_fd);
- common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
- }
-
- /* ctrl channel not ready, wait a bit */
- usleep(250000);
- }
-}
-
-/*****************************************************************************
-**
-** AUDIO DATA PATH
-**
-*****************************************************************************/
-
-static void a2dp_stream_common_init(struct a2dp_stream_common *common)
-{
- pthread_mutexattr_t lock_attr;
-
- FNLOG();
-
- pthread_mutexattr_init(&lock_attr);
- pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&common->lock, &lock_attr);
-
- common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
- common->audio_fd = AUDIO_SKT_DISCONNECTED;
- common->state = AUDIO_A2DP_STATE_STOPPED;
-
- /* manages max capacity of socket pipe */
- common->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
-}
-
-static int start_audio_datapath(struct a2dp_stream_common *common)
-{
- INFO("state %d", common->state);
-
- if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
- INFO("%s AUDIO_SKT_DISCONNECTED", __func__);
- return -1;
- }
-
- int oldstate = common->state;
- common->state = AUDIO_A2DP_STATE_STARTING;
-
- int a2dp_status = a2dp_command(common, A2DP_CTRL_CMD_START);
- if (a2dp_status < 0) {
- ERROR("%s Audiopath start failed (status %d)", __func__, a2dp_status);
-
- common->state = oldstate;
- return -1;
- } else if (a2dp_status == A2DP_CTRL_ACK_INCALL_FAILURE) {
- ERROR("%s Audiopath start failed - in call, move to suspended", __func__);
- common->state = oldstate;
- return -1;
- }
-
- /* connect socket if not yet connected */
- if (common->audio_fd == AUDIO_SKT_DISCONNECTED) {
- common->audio_fd = skt_connect(A2DP_DATA_PATH, common->buffer_sz);
- if (common->audio_fd < 0) {
- common->state = oldstate;
- return -1;
- }
-
- common->state = AUDIO_A2DP_STATE_STARTED;
- }
-
- return 0;
-}
-
-static int stop_audio_datapath(struct a2dp_stream_common *common)
-{
- int oldstate = common->state;
-
- INFO("state %d", common->state);
-
- if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
- return -1;
- }
-
- /* prevent any stray output writes from autostarting the stream
- while stopping audiopath */
- common->state = AUDIO_A2DP_STATE_STOPPING;
-
- if (a2dp_command(common, A2DP_CTRL_CMD_STOP) < 0) {
- ERROR("audiopath stop failed");
- common->state = oldstate;
- return -1;
- }
-
- common->state = AUDIO_A2DP_STATE_STOPPED;
-
- /* disconnect audio path */
- skt_disconnect(common->audio_fd);
- common->audio_fd = AUDIO_SKT_DISCONNECTED;
-
- return 0;
-}
-
-static int suspend_audio_datapath(struct a2dp_stream_common *common, bool standby)
-{
- INFO("state %d", common->state);
-
- if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
- return -1;
- }
-
- if (common->state == AUDIO_A2DP_STATE_STOPPING) {
- return -1;
- }
-
- if (a2dp_command(common, A2DP_CTRL_CMD_SUSPEND) < 0) {
- return -1;
- }
-
- if (standby) {
- common->state = AUDIO_A2DP_STATE_STANDBY;
- } else {
- common->state = AUDIO_A2DP_STATE_SUSPENDED;
- }
-
- /* disconnect audio path */
- skt_disconnect(common->audio_fd);
-
- common->audio_fd = AUDIO_SKT_DISCONNECTED;
-
- 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 %zu bytes (fd %d)", bytes, out->common.audio_fd);
-
- pthread_mutex_lock(&out->common.lock);
-
- if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED) {
- DEBUG("stream suspended");
- pthread_mutex_unlock(&out->common.lock);
- return -1;
- }
-
- /* only allow autostarting if we are in stopped or standby */
- if ((out->common.state == AUDIO_A2DP_STATE_STOPPED) ||
- (out->common.state == AUDIO_A2DP_STATE_STANDBY)) {
- if (start_audio_datapath(&out->common) < 0) {
- /* emulate time this write represents to avoid very fast write
- failures during transition periods or remote suspend */
-
- int us_delay = calc_audiotime(out->common.cfg, bytes);
-
- DEBUG("emulate a2dp write delay (%d us)", us_delay);
-
- usleep(us_delay);
- pthread_mutex_unlock(&out->common.lock);
- return -1;
- }
- } else if (out->common.state != AUDIO_A2DP_STATE_STARTED) {
- ERROR("stream not in stopped or standby");
- pthread_mutex_unlock(&out->common.lock);
- return -1;
- }
-
- pthread_mutex_unlock(&out->common.lock);
- sent = skt_write(out->common.audio_fd, buffer, bytes);
-
- if (sent == -1) {
- skt_disconnect(out->common.audio_fd);
- out->common.audio_fd = AUDIO_SKT_DISCONNECTED;
- if (out->common.state != AUDIO_A2DP_STATE_SUSPENDED) {
- out->common.state = AUDIO_A2DP_STATE_STOPPED;
- } else {
- ERROR("write failed : stream suspended, avoid resetting state");
- }
- } else {
- const size_t frames = bytes / audio_stream_out_frame_size(stream);
- out->frames_rendered += frames;
- out->frames_presented += frames;
- }
-
- DEBUG("wrote %d bytes out of %zu 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 %" PRIu32, out->common.cfg.rate);
-
- return out->common.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 : %" PRIu32, rate);
-
- if (rate != AUDIO_STREAM_DEFAULT_RATE) {
- ERROR("only rate %d supported", AUDIO_STREAM_DEFAULT_RATE);
- return -1;
- }
-
- out->common.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 : %zu", out->common.buffer_sz);
-
- return out->common.buffer_sz;
-}
-
-static uint32_t out_get_channels(const struct audio_stream *stream)
-{
- struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
-
- DEBUG("channels 0x%" PRIx32, out->common.cfg.channel_flags);
-
- return out->common.cfg.channel_flags;
-}
-
-static audio_format_t out_get_format(const struct audio_stream *stream)
-{
- struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
- DEBUG("format 0x%x", out->common.cfg.format);
- return out->common.cfg.format;
-}
-
-static int out_set_format(struct audio_stream *stream, audio_format_t format)
-{
- UNUSED(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;
-
- FNLOG();
-
- pthread_mutex_lock(&out->common.lock);
- // Do nothing in SUSPENDED state.
- if (out->common.state != AUDIO_A2DP_STATE_SUSPENDED) {
- retVal = suspend_audio_datapath(&out->common, true);
- }
- out->frames_rendered = 0; // rendered is reset, presented is not
- pthread_mutex_unlock (&out->common.lock);
-
- return retVal;
-}
-
-static int out_dump(const struct audio_stream *stream, int fd)
-{
- UNUSED(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;
- int status = 0;
-
- INFO("state %d", out->common.state);
-
- 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");
- pthread_mutex_lock(&out->common.lock);
- out->common.state = AUDIO_A2DP_STATE_STOPPING;
- pthread_mutex_unlock(&out->common.lock);
- }
- }
-
- retval = str_parms_get_str(parms, "A2dpSuspended", keyval, sizeof(keyval));
-
- if (retval >= 0) {
- pthread_mutex_lock(&out->common.lock);
- if (strcmp(keyval, "true") == 0) {
- if (out->common.state == AUDIO_A2DP_STATE_STARTED) {
- status = suspend_audio_datapath(&out->common, false);
- }
- } else {
- /* Do not start the streaming automatically. If the phone was streaming
- * prior to being suspended, the next out_write shall trigger the
- * AVDTP start procedure */
- if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED) {
- out->common.state = AUDIO_A2DP_STATE_STANDBY;
- }
- /* Irrespective of the state, return 0 */
- }
- pthread_mutex_unlock(&out->common.lock);
- }
-
- str_parms_destroy(parms);
-
- return status;
-}
-
-static char *out_get_parameters(const struct audio_stream *stream, const char *keys)
-{
- UNUSED(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->common.buffer_sz * 1000 ) /
- audio_stream_out_frame_size(&out->stream) /
- out->common.cfg.rate) * 1000;
-
-
- return (latency_us / 1000) + 200;
-}
-
-static int out_set_volume(struct audio_stream_out *stream, float left,
- float right)
-{
- UNUSED(stream);
- UNUSED(left);
- UNUSED(right);
-
- FNLOG();
-
- /* volume controlled in audioflinger mixer (digital) */
-
- return -ENOSYS;
-}
-
-static int out_get_presentation_position(const struct audio_stream_out *stream,
- uint64_t *frames, struct timespec *timestamp)
-{
- struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
-
- FNLOG();
- if (stream == NULL || frames == NULL || timestamp == NULL) {
- return -EINVAL;
- }
-
- int ret = -EWOULDBLOCK;
- pthread_mutex_lock(&out->common.lock);
- uint64_t latency_frames = (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
- if (out->frames_presented >= latency_frames) {
- *frames = out->frames_presented - latency_frames;
- clock_gettime(CLOCK_MONOTONIC, timestamp); // could also be associated with out_write().
- ret = 0;
- }
- pthread_mutex_unlock(&out->common.lock);
- return ret;
-}
-
-static int out_get_render_position(const struct audio_stream_out *stream,
- uint32_t *dsp_frames)
-{
- struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
-
- FNLOG();
- if (stream == NULL || dsp_frames == NULL) {
- return -EINVAL;
- }
-
- pthread_mutex_lock(&out->common.lock);
- uint64_t latency_frames = (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
- if (out->frames_rendered >= latency_frames) {
- *dsp_frames = (uint32_t)(out->frames_rendered - latency_frames);
- } else {
- *dsp_frames = 0;
- }
- pthread_mutex_unlock(&out->common.lock);
- return 0;
-}
-
-static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
-{
- UNUSED(stream);
- UNUSED(effect);
-
- FNLOG();
- return 0;
-}
-
-static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
-{
- UNUSED(stream);
- UNUSED(effect);
-
- FNLOG();
- return 0;
-}
-
-/*
- * AUDIO INPUT STREAM
- */
-
-static uint32_t in_get_sample_rate(const struct audio_stream *stream)
-{
- struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream;
-
- FNLOG();
- return in->common.cfg.rate;
-}
-
-static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
-{
- struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream;
-
- FNLOG();
-
- if (in->common.cfg.rate > 0 && in->common.cfg.rate == rate) {
- return 0;
- } else {
- return -1;
- }
-}
-
-static size_t in_get_buffer_size(const struct audio_stream *stream)
-{
- UNUSED(stream);
-
- FNLOG();
- return 320;
-}
-
-static uint32_t in_get_channels(const struct audio_stream *stream)
-{
- struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream;
-
- FNLOG();
- return in->common.cfg.channel_flags;
-}
-
-static audio_format_t in_get_format(const struct audio_stream *stream)
-{
- UNUSED(stream);
-
- FNLOG();
- return AUDIO_FORMAT_PCM_16_BIT;
-}
-
-static int in_set_format(struct audio_stream *stream, audio_format_t format)
-{
- UNUSED(stream);
- UNUSED(format);
-
- FNLOG();
- if (format == AUDIO_FORMAT_PCM_16_BIT) {
- return 0;
- } else {
- return -1;
- }
-}
-
-static int in_standby(struct audio_stream *stream)
-{
- UNUSED(stream);
-
- FNLOG();
- return 0;
-}
-
-static int in_dump(const struct audio_stream *stream, int fd)
-{
- UNUSED(stream);
- UNUSED(fd);
-
- FNLOG();
- return 0;
-}
-
-static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
-{
- UNUSED(stream);
- UNUSED(kvpairs);
-
- FNLOG();
- return 0;
-}
-
-static char *in_get_parameters(const struct audio_stream *stream,
- const char *keys)
-{
- UNUSED(stream);
- UNUSED(keys);
-
- FNLOG();
- return strdup("");
-}
-
-static int in_set_gain(struct audio_stream_in *stream, float gain)
-{
- UNUSED(stream);
- UNUSED(gain);
-
- FNLOG();
- return 0;
-}
-
-static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
- size_t bytes)
-{
- struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream;
- int read;
-
- DEBUG("read %zu bytes, state: %d", bytes, in->common.state);
-
- if (in->common.state == AUDIO_A2DP_STATE_SUSPENDED) {
- DEBUG("stream suspended");
- return -1;
- }
-
- /* only allow autostarting if we are in stopped or standby */
- if ((in->common.state == AUDIO_A2DP_STATE_STOPPED) ||
- (in->common.state == AUDIO_A2DP_STATE_STANDBY)) {
- pthread_mutex_lock(&in->common.lock);
-
- if (start_audio_datapath(&in->common) < 0) {
- /* emulate time this write represents to avoid very fast write
- failures during transition periods or remote suspend */
-
- int us_delay = calc_audiotime(in->common.cfg, bytes);
-
- DEBUG("emulate a2dp read delay (%d us)", us_delay);
-
- usleep(us_delay);
- pthread_mutex_unlock(&in->common.lock);
- return -1;
- }
-
- pthread_mutex_unlock(&in->common.lock);
- } else if (in->common.state != AUDIO_A2DP_STATE_STARTED) {
- ERROR("stream not in stopped or standby");
- return -1;
- }
-
- read = skt_read(in->common.audio_fd, buffer, bytes);
-
- if (read == -1) {
- skt_disconnect(in->common.audio_fd);
- in->common.audio_fd = AUDIO_SKT_DISCONNECTED;
- in->common.state = AUDIO_A2DP_STATE_STOPPED;
- } else if (read == 0) {
- DEBUG("read time out - return zeros");
- memset(buffer, 0, bytes);
- read = bytes;
- }
-
- DEBUG("read %d bytes out of %zu bytes", read, bytes);
- return read;
-}
-
-static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
-{
- UNUSED(stream);
-
- FNLOG();
- return 0;
-}
-
-static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
-{
- UNUSED(stream);
- UNUSED(effect);
-
- FNLOG();
- return 0;
-}
-
-static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
-{
- UNUSED(stream);
- UNUSED(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,
- const char *address)
-
-{
- struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
- struct a2dp_stream_out *out;
- int ret = 0;
- int i;
- UNUSED(address);
- UNUSED(handle);
- UNUSED(devices);
- UNUSED(flags);
-
- 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;
- out->stream.get_presentation_position = out_get_presentation_position;
-
-
- /* initialize a2dp specifics */
- a2dp_stream_common_init(&out->common);
-
- out->common.cfg.channel_flags = AUDIO_STREAM_DEFAULT_CHANNEL_FLAG;
- out->common.cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
- out->common.cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
-
- /* set output config values */
- if (config) {
- 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;
-
- a2dp_open_ctrl_path(&out->common);
- if (out->common.ctrl_fd == AUDIO_SKT_DISCONNECTED) {
- ERROR("ctrl socket failed to connect (%s)", strerror(errno));
- ret = -1;
- goto err_open;
- }
-
- DEBUG("success");
- /* Delay to ensure Headset is in proper state when START is initiated
- from DUT immediately after the connection due to ongoing music playback. */
- usleep(250000);
- return 0;
-
-err_open:
- free(out);
- *stream_out = NULL;
- a2dp_dev->output = 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->common.state);
-
- pthread_mutex_lock(&out->common.lock);
- if ((out->common.state == AUDIO_A2DP_STATE_STARTED) || (out->common.state == AUDIO_A2DP_STATE_STOPPING)) {
- stop_audio_datapath(&out->common);
- }
-
- skt_disconnect(out->common.ctrl_fd);
- free(stream);
- a2dp_dev->output = NULL;
- pthread_mutex_unlock(&out->common.lock);
-
- 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->common.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;
- UNUSED(dev);
-
- 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)
-{
- UNUSED(dev);
- UNUSED(volume);
-
- FNLOG();
-
- return -ENOSYS;
-}
-
-static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
-{
- UNUSED(dev);
- UNUSED(volume);
-
- FNLOG();
-
- return -ENOSYS;
-}
-
-static int adev_set_mode(struct audio_hw_device *dev, int mode)
-{
- UNUSED(dev);
- UNUSED(mode);
-
- FNLOG();
-
- return 0;
-}
-
-static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
-{
- UNUSED(dev);
- UNUSED(state);
-
- FNLOG();
-
- return -ENOSYS;
-}
-
-static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
-{
- UNUSED(dev);
- UNUSED(state);
-
- FNLOG();
-
- return -ENOSYS;
-}
-
-static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
- const struct audio_config *config)
-{
- UNUSED(dev);
- UNUSED(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,
- audio_input_flags_t flags,
- const char *address,
- audio_source_t source)
-{
- struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
- struct a2dp_stream_in *in;
- int ret;
- UNUSED(address);
- UNUSED(config);
- UNUSED(devices);
- UNUSED(flags);
- UNUSED(handle);
- UNUSED(source);
-
- 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;
-
- /* initialize a2dp specifics */
- a2dp_stream_common_init(&in->common);
-
- *stream_in = &in->stream;
- a2dp_dev->input = in;
-
- a2dp_open_ctrl_path(&in->common);
- if (in->common.ctrl_fd == AUDIO_SKT_DISCONNECTED) {
- ERROR("ctrl socket failed to connect (%s)", strerror(errno));
- ret = -1;
- goto err_open;
- }
-
- if (a2dp_read_audio_config(&in->common) < 0) {
- ERROR("a2dp_read_audio_config failed (%s)", strerror(errno));
- ret = -1;
- goto err_open;
- }
-
- DEBUG("success");
- return 0;
-
-err_open:
- free(in);
- *stream_in = NULL;
- a2dp_dev->input = NULL;
- ERROR("failed");
- return ret;
-}
-
-static void adev_close_input_stream(struct audio_hw_device *dev,
- struct audio_stream_in *stream)
-{
- struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
- struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream;
- a2dp_state_t state = in->common.state;
-
- INFO("closing input (state %d)", state);
-
- if ((state == AUDIO_A2DP_STATE_STARTED) || (state == AUDIO_A2DP_STATE_STOPPING)) {
- stop_audio_datapath(&in->common);
- }
-
- skt_disconnect(in->common.ctrl_fd);
- free(stream);
- a2dp_dev->input = NULL;
-
- DEBUG("done");
-}
-
-static int adev_dump(const audio_hw_device_t *device, int fd)
-{
- UNUSED(device);
- UNUSED(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_2_0;
- 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,
- },
-};
#define LOG_TAG "bt_btif_media"
-// #include <assert.h>
#include "bt_trace.h"
#include <string.h>
#include <stdio.h>
-// #include <sys/types.h>
-// #include <sys/stat.h>
-// #include <fcntl.h>
-// #include <unistd.h>
-// #include <pthread.h>
#include <stdint.h>
-// #include <sys/time.h>
-// #include <errno.h>
#include "bt_target.h"
#include "fixed_queue.h"
#include "btif_media.h"
#include "alarm.h"
-// #include "ois/include/log.h"
#include "bt_trace.h"
#include "thread.h"
#include "sbc_encoder.h"
#endif
-// #include <hardware/bluetooth.h>
#include "bt_defs.h"
#include "audio_a2dp_hw.h"
#include "btif_av.h"
#include "oi_status.h"
#endif
#include "stdio.h"
-// #include <dlfcn.h>
+
#include "btif_media.h"
#include "allocator.h"
#include "bt_utils.h"
long long ts_prev_us;
} t_stat;
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-static UINT64 last_frame_us = 0;
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
-
static void btif_a2dp_data_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-static void btif_a2dp_encoder_update(void);
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
#if (BTA_AV_SINK_INCLUDED == TRUE)
extern OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
#endif
#if (BTA_AV_INCLUDED == TRUE)
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-static void btif_media_send_aa_frame(void);
-static void btif_media_task_feeding_state_reset(void);
-static void btif_media_task_aa_start_tx(void);
-static void btif_media_task_aa_stop_tx(void);
-static void btif_media_task_enc_init(BT_HDR *p_msg);
-static void btif_media_task_enc_update(BT_HDR *p_msg);
-static void btif_media_task_audio_feeding_init(BT_HDR *p_msg);
-static void btif_media_task_aa_tx_flush(BT_HDR *p_msg);
-static void btif_media_aa_prep_2_send(UINT8 nb_frame);
-#endif /* (BTIF_AV_SRC_INCLUDED == TRUE) */
#if (BTA_AV_SINK_INCLUDED == TRUE)
static void btif_media_task_aa_handle_decoder_reset(BT_HDR *p_msg);
static void btif_media_task_aa_handle_clear_track(void);
#endif
BOOLEAN btif_media_task_clear_track(void);
static void btif_media_task_handler(void *arg);
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-static void btif_media_task_aa_handle_timer(UNUSED_ATTR void *context);
-#endif
+
static void btif_media_task_avk_handle_timer(UNUSED_ATTR void *context);
static void btif_media_thread_init(UNUSED_ATTR void *context);
static void btif_media_thread_cleanup(UNUSED_ATTR void *context);
** Misc helper functions
*****************************************************************************/
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-static UINT64 time_now_us()
-{
- // TODO: implement this function
- return 0;
-}
-
-static void log_tstamps_us(char *comment)
-{
- static UINT64 prev_us = 0;
- const UINT64 now_us = time_now_us();
- APPL_TRACE_DEBUG("[%s] ts %08llu, diff : %08llu, queue sz %d\n", comment, now_us, now_us - prev_us,
- GKI_queue_length(&btif_media_cb.TxAaQ));
- prev_us = now_us;
-}
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
-
UNUSED_ATTR static const char *dump_media_event(UINT16 event)
{
switch (event) {
UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
(void *)A2DP_DATA_READ_POLL_MS);
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
- if (btif_media_cb.peer_sep == AVDT_TSEP_SNK) {
- /* Start the media task to encode SBC */
- btif_media_task_start_aa_req();
-
- /* make sure we update any changed sbc encoder params */
- btif_a2dp_encoder_update();
- }
-#endif /* BTIF_AV_SRC_INCLUDED == TRUE */
btif_media_cb.data_channel_open = TRUE;
/* ack back when media task is fully started */
/*****************************************************************************
** BTIF ADAPTATION
*****************************************************************************/
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-static UINT16 btif_media_task_get_sbc_rate(void)
-{
- UINT16 rate = DEFAULT_SBC_BITRATE;
-
- /* restrict bitrate if a2dp link is non-edr */
- if (!btif_av_is_peer_edr()) {
- rate = BTIF_A2DP_NON_EDR_MAX_RATE;
- APPL_TRACE_DEBUG("non-edr a2dp sink detected, restrict rate to %d\n", rate);
- }
-
- return rate;
-}
-
-static void btif_a2dp_encoder_init(void)
-{
- UINT16 minmtu;
- tBTIF_MEDIA_INIT_AUDIO msg;
- tA2D_SBC_CIE sbc_config;
-
- /* lookup table for converting channel mode */
- UINT16 codec_mode_tbl[5] = { SBC_JOINT_STEREO, SBC_STEREO, SBC_DUAL, 0, SBC_MONO };
-
- /* lookup table for converting number of blocks */
- UINT16 codec_block_tbl[5] = { 16, 12, 8, 0, 4 };
-
- /* lookup table to convert freq */
- UINT16 freq_block_tbl[5] = { SBC_sf48000, SBC_sf44100, SBC_sf32000, 0, SBC_sf16000 };
-
- APPL_TRACE_DEBUG("btif_a2dp_encoder_init");
-
- /* Retrieve the current SBC configuration (default if currently not used) */
- bta_av_co_audio_get_sbc_config(&sbc_config, &minmtu);
- msg.NumOfSubBands = (sbc_config.num_subbands == A2D_SBC_IE_SUBBAND_4) ? 4 : 8;
- msg.NumOfBlocks = codec_block_tbl[sbc_config.block_len >> 5];
- msg.AllocationMethod = (sbc_config.alloc_mthd == A2D_SBC_IE_ALLOC_MD_L) ? SBC_LOUDNESS : SBC_SNR;
- msg.ChannelMode = codec_mode_tbl[sbc_config.ch_mode >> 1];
- msg.SamplingFreq = freq_block_tbl[sbc_config.samp_freq >> 5];
- msg.MtuSize = minmtu;
-
- APPL_TRACE_EVENT("msg.ChannelMode %x\n", msg.ChannelMode);
-
- /* Init the media task to encode SBC properly */
- btif_media_task_enc_init_req(&msg);
-}
-
-static void btif_a2dp_encoder_update(void)
-{
- UINT16 minmtu;
- tA2D_SBC_CIE sbc_config;
- tBTIF_MEDIA_UPDATE_AUDIO msg;
- UINT8 pref_min;
- UINT8 pref_max;
-
- APPL_TRACE_DEBUG("btif_a2dp_encoder_update");
-
- /* Retrieve the current SBC configuration (default if currently not used) */
- bta_av_co_audio_get_sbc_config(&sbc_config, &minmtu);
-
- APPL_TRACE_DEBUG("btif_a2dp_encoder_update: Common min_bitpool:%d(0x%x) max_bitpool:%d(0x%x)\n",
- sbc_config.min_bitpool, sbc_config.min_bitpool,
- sbc_config.max_bitpool, sbc_config.max_bitpool);
-
- if (sbc_config.min_bitpool > sbc_config.max_bitpool) {
- APPL_TRACE_ERROR("btif_a2dp_encoder_update: ERROR btif_a2dp_encoder_update min_bitpool > max_bitpool");
- }
-
- /* check if remote sink has a preferred bitpool range */
- if (bta_av_co_get_remote_bitpool_pref(&pref_min, &pref_max) == TRUE) {
- /* adjust our preferred bitpool with the remote preference if within
- our capable range */
-
- if (pref_min < sbc_config.min_bitpool) {
- pref_min = sbc_config.min_bitpool;
- }
-
- if (pref_max > sbc_config.max_bitpool) {
- pref_max = sbc_config.max_bitpool;
- }
-
- msg.MinBitPool = pref_min;
- msg.MaxBitPool = pref_max;
-
- if ((pref_min != sbc_config.min_bitpool) || (pref_max != sbc_config.max_bitpool)) {
- APPL_TRACE_EVENT("## adjusted our bitpool range to peer pref [%d:%d] ##\n",
- pref_min, pref_max);
- }
- } else {
- msg.MinBitPool = sbc_config.min_bitpool;
- msg.MaxBitPool = sbc_config.max_bitpool;
- }
-
- msg.MinMtuSize = minmtu;
-
- /* Update the media task to encode SBC properly */
- btif_media_task_enc_update_req(&msg);
-}
-
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
static void btif_media_task_post(uint32_t sig)
{
case SIG_MEDIA_TASK_AVK_ALARM_TO:
btif_media_task_avk_handle_timer(NULL);
break;
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
- case SIG_MEDIA_TASK_AA_ALARM_TO:
- btif_media_task_aa_handle_timer(NULL);
-#endif
- break;
case SIG_MEDIA_TASK_CMD_READY:
fixed_queue_process(btif_media_cmd_msg_queue);
break;
media_feeding.format = BTIF_AV_CODEC_PCM;
if (bta_av_co_audio_set_codec(&media_feeding, &status)) {
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-
- tBTIF_MEDIA_INIT_AUDIO_FEEDING mfeed;
-
- /* Init the encoding task */
- btif_a2dp_encoder_init();
-
- /* Build the media task configuration */
- mfeed.feeding = media_feeding;
- mfeed.feeding_mode = BTIF_AV_FEEDING_ASYNCHRONOUS;
- /* Send message to Media task to configure transcoding */
- btif_media_task_audio_feeding_init_req(&mfeed);
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
}
GKI_enable();
void btif_a2dp_on_idle(void)
{
APPL_TRACE_EVENT("## ON A2DP IDLE ##\n");
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
- if (btif_media_cb.peer_sep == AVDT_TSEP_SNK) {
- /* Make sure media task is stopped */
- btif_media_task_stop_aa_req();
- }
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
bta_av_co_init();
#if (BTA_AV_SINK_INCLUDED == TRUE)
}
}
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
- /* ensure tx frames are immediately suspended */
- btif_media_cb.tx_flush = 1;
-
- /* request to stop media task */
- btif_media_task_aa_tx_flush_req();
- btif_media_task_stop_aa_req();
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
/* once stream is fully stopped we will ack back */
}
}
/* once stream is fully stopped we will ack back */
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
- /* ensure tx frames are immediately flushed */
- btif_media_cb.tx_flush = 1;
-
- /* stop timer tick */
- btif_media_task_stop_aa_req();
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
}
/* when true media task discards any rx frames */
btif_media_cb.rx_flush = enable;
}
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-/* when true media task discards any tx frames */
-void btif_a2dp_set_tx_flush(BOOLEAN enable)
-{
- APPL_TRACE_EVENT("## DROP TX %d ##\n", enable);
- btif_media_cb.tx_flush = enable;
-}
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
#if (BTA_AV_SINK_INCLUDED == TRUE)
static void btif_media_task_avk_handle_timer(UNUSED_ATTR void *context)
{
static void btif_media_task_avk_handle_timer(UNUSED_ATTR void *context) {}
#endif
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-static void btif_media_task_aa_handle_timer(UNUSED_ATTR void *context)
-{
- log_tstamps_us("media task tx timer");
-
-#if (BTA_AV_INCLUDED == TRUE)
- if (btif_media_cb.is_tx_timer == TRUE) {
- btif_media_send_aa_frame();
- } else {
- APPL_TRACE_ERROR("ERROR Media task Scheduled after Suspend");
- }
-#endif
-}
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
-
-#if (BTA_AV_INCLUDED == TRUE)
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-static void btif_media_task_aa_handle_uipc_rx_rdy(void)
-{
- /* process all the UIPC data */
- btif_media_aa_prep_2_send(0xFF);
-
- /* send it */
- LOG_VERBOSE("btif_media_task_aa_handle_uipc_rx_rdy calls bta_av_ci_src_data_ready");
- bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
-}
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
-#endif
-
static void btif_media_thread_init(UNUSED_ATTR void *context)
{
memset(&btif_media_cb, 0, sizeof(btif_media_cb));
switch (p_msg->event) {
#if (BTA_AV_INCLUDED == TRUE)
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
- case BTIF_MEDIA_START_AA_TX:
- btif_media_task_aa_start_tx();
- break;
- case BTIF_MEDIA_STOP_AA_TX:
- btif_media_task_aa_stop_tx();
- break;
- case BTIF_MEDIA_SBC_ENC_INIT:
- btif_media_task_enc_init(p_msg);
- break;
- case BTIF_MEDIA_SBC_ENC_UPDATE:
- btif_media_task_enc_update(p_msg);
- break;
- case BTIF_MEDIA_AUDIO_FEEDING_INIT:
- btif_media_task_audio_feeding_init(p_msg);
- break;
- case BTIF_MEDIA_FLUSH_AA_TX:
- btif_media_task_aa_tx_flush(p_msg);
- break;
- case BTIF_MEDIA_UIPC_RX_RDY:
- btif_media_task_aa_handle_uipc_rx_rdy();
- break;
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
case BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE:
#if (BTA_AV_SINK_INCLUDED == TRUE)
LOG_ERROR("SINK_CFG_UPDATE: xx\n");
#endif
#if (BTA_AV_INCLUDED == TRUE)
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-/*******************************************************************************
- **
- ** Function btif_media_task_enc_init_req
- **
- ** Description
- **
- ** Returns TRUE is success
- **
- *******************************************************************************/
-BOOLEAN btif_media_task_enc_init_req(tBTIF_MEDIA_INIT_AUDIO *p_msg)
-{
- tBTIF_MEDIA_INIT_AUDIO *p_buf;
- if (NULL == (p_buf = GKI_getbuf(sizeof(tBTIF_MEDIA_INIT_AUDIO)))) {
- return FALSE;
- }
-
- memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_INIT_AUDIO));
- p_buf->hdr.event = BTIF_MEDIA_SBC_ENC_INIT;
-
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
- btif_media_task_post(SIG_MEDIA_TASK_CMD_READY);
- return TRUE;
-}
-
-/*******************************************************************************
- **
- ** Function btif_media_task_enc_update_req
- **
- ** Description
- **
- ** Returns TRUE is success
- **
- *******************************************************************************/
-BOOLEAN btif_media_task_enc_update_req(tBTIF_MEDIA_UPDATE_AUDIO *p_msg)
-{
- tBTIF_MEDIA_UPDATE_AUDIO *p_buf;
- if (NULL == (p_buf = GKI_getbuf(sizeof(tBTIF_MEDIA_UPDATE_AUDIO)))) {
- return FALSE;
- }
-
- memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_UPDATE_AUDIO));
- p_buf->hdr.event = BTIF_MEDIA_SBC_ENC_UPDATE;
-
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
- btif_media_task_post(SIG_MEDIA_TASK_CMD_READY);
- return TRUE;
-}
-
-/*******************************************************************************
- **
- ** Function btif_media_task_audio_feeding_init_req
- **
- ** Description
- **
- ** Returns TRUE is success
- **
- *******************************************************************************/
-BOOLEAN btif_media_task_audio_feeding_init_req(tBTIF_MEDIA_INIT_AUDIO_FEEDING *p_msg)
-{
- tBTIF_MEDIA_INIT_AUDIO_FEEDING *p_buf;
- if (NULL == (p_buf = GKI_getbuf(sizeof(tBTIF_MEDIA_INIT_AUDIO_FEEDING)))) {
- return FALSE;
- }
-
- memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_INIT_AUDIO_FEEDING));
- p_buf->hdr.event = BTIF_MEDIA_AUDIO_FEEDING_INIT;
-
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
- btif_media_task_post(SIG_MEDIA_TASK_CMD_READY);
- return TRUE;
-}
-
-/*******************************************************************************
- **
- ** Function btif_media_task_start_aa_req
- **
- ** Description
- **
- ** Returns TRUE is success
- **
- *******************************************************************************/
-BOOLEAN btif_media_task_start_aa_req(void)
-{
- BT_HDR *p_buf;
- if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) {
- APPL_TRACE_EVENT("GKI failed");
- return FALSE;
- }
-
- p_buf->event = BTIF_MEDIA_START_AA_TX;
-
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
- btif_media_task_post(SIG_MEDIA_TASK_CMD_READY);
- return TRUE;
-}
-/*******************************************************************************
- **
- ** Function btif_media_task_stop_aa_req
- **
- ** Description
- **
- ** Returns TRUE is success
- **
- *******************************************************************************/
-BOOLEAN btif_media_task_stop_aa_req(void)
-{
- BT_HDR *p_buf;
- if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) {
- return FALSE;
- }
-
- p_buf->event = BTIF_MEDIA_STOP_AA_TX;
-
- /*
- * Explicitly check whether the btif_media_cmd_msg_queue is not NULL to
- * avoid a race condition during shutdown of the Bluetooth stack.
- * This race condition is triggered when A2DP audio is streaming on
- * shutdown:
- * "btif_a2dp_on_stopped() -> btif_media_task_stop_aa_req()" is called
- * to stop the particular audio stream, and this happens right after
- * the "cleanup() -> btif_a2dp_stop_media_task()" processing during
- * the shutdown of the Bluetooth stack.
- */
- if (btif_media_cmd_msg_queue != NULL) {
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
- btif_media_task_post(SIG_MEDIA_TASK_CMD_READY);
- }
-
- return TRUE;
-}
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
/*******************************************************************************
**
** Function btif_media_task_aa_rx_flush_req
return TRUE;
}
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-/*******************************************************************************
- **
- ** Function btif_media_task_aa_tx_flush_req
- **
- ** Description
- **
- ** Returns TRUE is success
- **
- *******************************************************************************/
-BOOLEAN btif_media_task_aa_tx_flush_req(void)
-{
- BT_HDR *p_buf = GKI_getbuf(sizeof(BT_HDR));
-
- if (p_buf == NULL) {
- return FALSE;
- }
-
- p_buf->event = BTIF_MEDIA_FLUSH_AA_TX;
-
- /*
- * Explicitly check whether the btif_media_cmd_msg_queue is not NULL to
- * avoid a race condition during shutdown of the Bluetooth stack.
- * This race condition is triggered when A2DP audio is streaming on
- * shutdown:
- * "btif_a2dp_on_stopped() -> btif_media_task_aa_tx_flush_req()" is called
- * to stop the particular audio stream, and this happens right after
- * the "cleanup() -> btif_a2dp_stop_media_task()" processing during
- * the shutdown of the Bluetooth stack.
- */
- if (btif_media_cmd_msg_queue != NULL) {
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
- btif_media_task_post(SIG_MEDIA_TASK_CMD_READY);
- }
-
- return TRUE;
-}
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
-
/*******************************************************************************
**
** Function btif_media_task_aa_rx_flush
btif_media_flush_q(&(btif_media_cb.RxSbcQ));
}
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-/*******************************************************************************
- **
- ** Function btif_media_task_aa_tx_flush
- **
- ** Description
- **
- ** Returns void
- **
- *******************************************************************************/
-static void btif_media_task_aa_tx_flush(BT_HDR *p_msg)
-{
- UNUSED(p_msg);
-
- /* Flush all enqueued GKI music buffers (encoded) */
- APPL_TRACE_DEBUG("btif_media_task_aa_tx_flush");
-
- btif_media_cb.media_feeding_state.pcm.counter = 0;
- btif_media_cb.media_feeding_state.pcm.aa_feed_residue = 0;
-
- btif_media_flush_q(&(btif_media_cb.TxAaQ));
-
- UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REQ_RX_FLUSH, NULL);
-}
-
-/*******************************************************************************
- **
- ** Function btif_media_task_enc_init
- **
- ** Description Initialize encoding task
- **
- ** Returns void
- **
- *******************************************************************************/
-static void btif_media_task_enc_init(BT_HDR *p_msg)
-{
- tBTIF_MEDIA_INIT_AUDIO *pInitAudio = (tBTIF_MEDIA_INIT_AUDIO *) p_msg;
-
- APPL_TRACE_DEBUG("btif_media_task_enc_init");
-
- btif_media_cb.timestamp = 0;
-
- /* SBC encoder config (enforced even if not used) */
- btif_media_cb.encoder.s16ChannelMode = pInitAudio->ChannelMode;
- btif_media_cb.encoder.s16NumOfSubBands = pInitAudio->NumOfSubBands;
- btif_media_cb.encoder.s16NumOfBlocks = pInitAudio->NumOfBlocks;
- btif_media_cb.encoder.s16AllocationMethod = pInitAudio->AllocationMethod;
- btif_media_cb.encoder.s16SamplingFreq = pInitAudio->SamplingFreq;
-
- btif_media_cb.encoder.u16BitRate = btif_media_task_get_sbc_rate();
-
- /* Default transcoding is PCM to SBC, modified by feeding configuration */
- btif_media_cb.TxTranscoding = BTIF_MEDIA_TRSCD_PCM_2_SBC;
- btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR))
- < pInitAudio->MtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_SBC_OFFSET
- - sizeof(BT_HDR)) : pInitAudio->MtuSize;
-
- APPL_TRACE_EVENT("btif_media_task_enc_init busy %d, mtu %d, peer mtu %d\n",
- btif_media_cb.busy_level, btif_media_cb.TxAaMtuSize, pInitAudio->MtuSize);
- APPL_TRACE_EVENT(" ch mode %d, subnd %d, nb blk %d, alloc %d, rate %d, freq %d\n",
- btif_media_cb.encoder.s16ChannelMode, btif_media_cb.encoder.s16NumOfSubBands,
- btif_media_cb.encoder.s16NumOfBlocks,
- btif_media_cb.encoder.s16AllocationMethod, btif_media_cb.encoder.u16BitRate,
- btif_media_cb.encoder.s16SamplingFreq);
-
- /* Reset entirely the SBC encoder */
- SBC_Encoder_Init(&(btif_media_cb.encoder));
- APPL_TRACE_DEBUG("btif_media_task_enc_init bit pool %d\n", btif_media_cb.encoder.s16BitPool);
-}
-
-/*******************************************************************************
- **
- ** Function btif_media_task_enc_update
- **
- ** Description Update encoding task
- **
- ** Returns void
- **
- *******************************************************************************/
-static void btif_media_task_enc_update(BT_HDR *p_msg)
-{
- tBTIF_MEDIA_UPDATE_AUDIO *pUpdateAudio = (tBTIF_MEDIA_UPDATE_AUDIO *) p_msg;
- SBC_ENC_PARAMS *pstrEncParams = &btif_media_cb.encoder;
- UINT16 s16SamplingFreq;
- SINT16 s16BitPool = 0;
- SINT16 s16BitRate;
- SINT16 s16FrameLen;
- UINT8 protect = 0;
-
- APPL_TRACE_DEBUG("btif_media_task_enc_update : minmtu %d, maxbp %d minbp %d\n",
- pUpdateAudio->MinMtuSize, pUpdateAudio->MaxBitPool, pUpdateAudio->MinBitPool);
-
- /* Only update the bitrate and MTU size while timer is running to make sure it has been initialized */
- //if (btif_media_cb.is_tx_timer)
- {
- btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE -
- BTIF_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR))
- < pUpdateAudio->MinMtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_SBC_OFFSET
- - sizeof(BT_HDR)) : pUpdateAudio->MinMtuSize;
-
- /* Set the initial target bit rate */
- pstrEncParams->u16BitRate = btif_media_task_get_sbc_rate();
-
- if (pstrEncParams->s16SamplingFreq == SBC_sf16000) {
- s16SamplingFreq = 16000;
- } else if (pstrEncParams->s16SamplingFreq == SBC_sf32000) {
- s16SamplingFreq = 32000;
- } else if (pstrEncParams->s16SamplingFreq == SBC_sf44100) {
- s16SamplingFreq = 44100;
- } else {
- s16SamplingFreq = 48000;
- }
-
- do {
- if (pstrEncParams->s16NumOfBlocks == 0 || pstrEncParams->s16NumOfSubBands == 0
- || pstrEncParams->s16NumOfChannels == 0) {
- APPL_TRACE_ERROR("btif_media_task_enc_update() - Avoiding division by zero...");
- APPL_TRACE_ERROR("btif_media_task_enc_update() - block=%d, subBands=%d, channels=%d\n",
- pstrEncParams->s16NumOfBlocks, pstrEncParams->s16NumOfSubBands,
- pstrEncParams->s16NumOfChannels);
- break;
- }
-
- if ((pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) ||
- (pstrEncParams->s16ChannelMode == SBC_STEREO) ) {
- s16BitPool = (SINT16)( (pstrEncParams->u16BitRate *
- pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq)
- - ( (32 + (4 * pstrEncParams->s16NumOfSubBands *
- pstrEncParams->s16NumOfChannels)
- + ( (pstrEncParams->s16ChannelMode - 2) *
- pstrEncParams->s16NumOfSubBands ) )
- / pstrEncParams->s16NumOfBlocks) );
-
- s16FrameLen = 4 + (4 * pstrEncParams->s16NumOfSubBands *
- pstrEncParams->s16NumOfChannels) / 8
- + ( ((pstrEncParams->s16ChannelMode - 2) *
- pstrEncParams->s16NumOfSubBands)
- + (pstrEncParams->s16NumOfBlocks * s16BitPool) ) / 8;
-
- s16BitRate = (8 * s16FrameLen * s16SamplingFreq)
- / (pstrEncParams->s16NumOfSubBands *
- pstrEncParams->s16NumOfBlocks * 1000);
-
- if (s16BitRate > pstrEncParams->u16BitRate) {
- s16BitPool--;
- }
-
- if (pstrEncParams->s16NumOfSubBands == 8) {
- s16BitPool = (s16BitPool > 255) ? 255 : s16BitPool;
- } else {
- s16BitPool = (s16BitPool > 128) ? 128 : s16BitPool;
- }
- } else {
- s16BitPool = (SINT16)( ((pstrEncParams->s16NumOfSubBands *
- pstrEncParams->u16BitRate * 1000)
- / (s16SamplingFreq * pstrEncParams->s16NumOfChannels))
- - ( ( (32 / pstrEncParams->s16NumOfChannels) +
- (4 * pstrEncParams->s16NumOfSubBands) )
- / pstrEncParams->s16NumOfBlocks ) );
-
- pstrEncParams->s16BitPool = (s16BitPool >
- (16 * pstrEncParams->s16NumOfSubBands))
- ? (16 * pstrEncParams->s16NumOfSubBands) : s16BitPool;
- }
-
- if (s16BitPool < 0) {
- s16BitPool = 0;
- }
-
- APPL_TRACE_EVENT("bitpool candidate : %d (%d kbps)\n",
- s16BitPool, pstrEncParams->u16BitRate);
-
- if (s16BitPool > pUpdateAudio->MaxBitPool) {
- APPL_TRACE_DEBUG("btif_media_task_enc_update computed bitpool too large (%d)\n",
- s16BitPool);
- /* Decrease bitrate */
- btif_media_cb.encoder.u16BitRate -= BTIF_MEDIA_BITRATE_STEP;
- /* Record that we have decreased the bitrate */
- protect |= 1;
- } else if (s16BitPool < pUpdateAudio->MinBitPool) {
- APPL_TRACE_WARNING("btif_media_task_enc_update computed bitpool too small (%d)\n", s16BitPool);
-
- /* Increase bitrate */
- UINT16 previous_u16BitRate = btif_media_cb.encoder.u16BitRate;
- btif_media_cb.encoder.u16BitRate += BTIF_MEDIA_BITRATE_STEP;
- /* Record that we have increased the bitrate */
- protect |= 2;
- /* Check over-flow */
- if (btif_media_cb.encoder.u16BitRate < previous_u16BitRate) {
- protect |= 3;
- }
- } else {
- break;
- }
- /* In case we have already increased and decreased the bitrate, just stop */
- if (protect == 3) {
- APPL_TRACE_ERROR("btif_media_task_enc_update could not find bitpool in range");
- break;
- }
- } while (1);
-
- /* Finally update the bitpool in the encoder structure */
- pstrEncParams->s16BitPool = s16BitPool;
-
- APPL_TRACE_DEBUG("btif_media_task_enc_update final bit rate %d, final bit pool %d\n",
- btif_media_cb.encoder.u16BitRate, btif_media_cb.encoder.s16BitPool);
-
- /* make sure we reinitialize encoder with new settings */
- SBC_Encoder_Init(&(btif_media_cb.encoder));
- }
-}
-
-/*******************************************************************************
- **
- ** Function btif_media_task_pcm2sbc_init
- **
- ** Description Init encoding task for PCM to SBC according to feeding
- **
- ** Returns void
- **
- *******************************************************************************/
-static void btif_media_task_pcm2sbc_init(tBTIF_MEDIA_INIT_AUDIO_FEEDING *p_feeding)
-{
- BOOLEAN reconfig_needed = FALSE;
-
- APPL_TRACE_DEBUG("PCM feeding:");
- APPL_TRACE_DEBUG("sampling_freq:%d\n", p_feeding->feeding.cfg.pcm.sampling_freq);
- APPL_TRACE_DEBUG("num_channel:%d\n", p_feeding->feeding.cfg.pcm.num_channel);
- APPL_TRACE_DEBUG("bit_per_sample:%d\n", p_feeding->feeding.cfg.pcm.bit_per_sample);
-
- /* Check the PCM feeding sampling_freq */
- switch (p_feeding->feeding.cfg.pcm.sampling_freq) {
- case 8000:
- case 12000:
- case 16000:
- case 24000:
- case 32000:
- case 48000:
- /* For these sampling_freq the AV connection must be 48000 */
- if (btif_media_cb.encoder.s16SamplingFreq != SBC_sf48000) {
- /* Reconfiguration needed at 48000 */
- APPL_TRACE_DEBUG("SBC Reconfiguration needed at 48000");
- btif_media_cb.encoder.s16SamplingFreq = SBC_sf48000;
- reconfig_needed = TRUE;
- }
- break;
-
- case 11025:
- case 22050:
- case 44100:
- /* For these sampling_freq the AV connection must be 44100 */
- if (btif_media_cb.encoder.s16SamplingFreq != SBC_sf44100) {
- /* Reconfiguration needed at 44100 */
- APPL_TRACE_DEBUG("SBC Reconfiguration needed at 44100");
- btif_media_cb.encoder.s16SamplingFreq = SBC_sf44100;
- reconfig_needed = TRUE;
- }
- break;
- default:
- APPL_TRACE_DEBUG("Feeding PCM sampling_freq unsupported");
- break;
- }
-
- /* Some AV Headsets do not support Mono => always ask for Stereo */
- if (btif_media_cb.encoder.s16ChannelMode == SBC_MONO) {
- APPL_TRACE_DEBUG("SBC Reconfiguration needed in Stereo");
- btif_media_cb.encoder.s16ChannelMode = SBC_JOINT_STEREO;
- reconfig_needed = TRUE;
- }
-
- if (reconfig_needed != FALSE) {
- APPL_TRACE_DEBUG("btif_media_task_pcm2sbc_init :: mtu %d\n", btif_media_cb.TxAaMtuSize);
- APPL_TRACE_DEBUG("ch mode %d, nbsubd %d, nb %d, alloc %d, rate %d, freq %d\n",
- btif_media_cb.encoder.s16ChannelMode,
- btif_media_cb.encoder.s16NumOfSubBands, btif_media_cb.encoder.s16NumOfBlocks,
- btif_media_cb.encoder.s16AllocationMethod, btif_media_cb.encoder.u16BitRate,
- btif_media_cb.encoder.s16SamplingFreq);
- SBC_Encoder_Init(&(btif_media_cb.encoder));
- } else {
- APPL_TRACE_DEBUG("btif_media_task_pcm2sbc_init no SBC reconfig needed");
- }
-}
-
-/*******************************************************************************
- **
- ** Function btif_media_task_audio_feeding_init
- **
- ** Description Initialize the audio path according to the feeding format
- **
- ** Returns void
- **
- *******************************************************************************/
-static void btif_media_task_audio_feeding_init(BT_HDR *p_msg)
-{
- tBTIF_MEDIA_INIT_AUDIO_FEEDING *p_feeding = (tBTIF_MEDIA_INIT_AUDIO_FEEDING *) p_msg;
-
- APPL_TRACE_DEBUG("btif_media_task_audio_feeding_init format:%d\n", p_feeding->feeding.format);
-
- /* Save Media Feeding information */
- btif_media_cb.feeding_mode = p_feeding->feeding_mode;
- btif_media_cb.media_feeding = p_feeding->feeding;
-
- /* Handle different feeding formats */
- switch (p_feeding->feeding.format) {
- case BTIF_AV_CODEC_PCM:
- btif_media_cb.TxTranscoding = BTIF_MEDIA_TRSCD_PCM_2_SBC;
- btif_media_task_pcm2sbc_init(p_feeding);
- break;
-
- default :
- APPL_TRACE_ERROR("unknown feeding format %d\n", p_feeding->feeding.format);
- break;
- }
-}
-
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
int btif_a2dp_get_track_frequency(UINT8 frequency)
{
int freq = 48000;
}
#endif
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-/*******************************************************************************
- **
- ** Function btif_media_task_feeding_state_reset
- **
- ** Description Reset the media feeding state
- **
- ** Returns void
- **
- *******************************************************************************/
-static void btif_media_task_feeding_state_reset(void)
-{
- /* By default, just clear the entire state */
- memset(&btif_media_cb.media_feeding_state, 0, sizeof(btif_media_cb.media_feeding_state));
-
- if (btif_media_cb.TxTranscoding == BTIF_MEDIA_TRSCD_PCM_2_SBC) {
- btif_media_cb.media_feeding_state.pcm.bytes_per_tick =
- (btif_media_cb.media_feeding.cfg.pcm.sampling_freq *
- btif_media_cb.media_feeding.cfg.pcm.bit_per_sample / 8 *
- btif_media_cb.media_feeding.cfg.pcm.num_channel *
- BTIF_MEDIA_TIME_TICK) / 1000;
-
- APPL_TRACE_WARNING("pcm bytes per tick %d\n",
- (int)btif_media_cb.media_feeding_state.pcm.bytes_per_tick);
- }
-}
-
-static void btif_media_task_alarm_cb(UNUSED_ATTR void *context)
-{
- btif_media_task_post(SIG_MEDIA_TASK_AA_ALARM_TO);
-}
-
-/*******************************************************************************
- **
- ** Function btif_media_task_aa_start_tx
- **
- ** Description Start media task encoding
- **
- ** Returns void
- **
- *******************************************************************************/
-static void btif_media_task_aa_start_tx(void)
-{
- APPL_TRACE_DEBUG("btif_media_task_aa_start_tx is timer %d, feeding mode %d\n",
- btif_media_cb.is_tx_timer, btif_media_cb.feeding_mode);
-
- /* Use a timer to poll the UIPC, get rid of the UIPC call back */
- // UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REG_CBACK, NULL);
-
- btif_media_cb.is_tx_timer = TRUE;
- last_frame_us = 0;
-
- /* Reset the media feeding state */
- btif_media_task_feeding_state_reset();
-
- APPL_TRACE_EVENT("starting timer %dms\n", BTIF_MEDIA_TIME_TICK);
-
- assert(btif_media_cb.media_alarm == NULL);
-
- btif_media_cb.media_alarm = osi_alarm_new("media_alarm\n", btif_media_task_alarm_cb, NULL, BTIF_MEDIA_TIME_TICK, true);
- if (!btif_media_cb.media_alarm) {
- APPL_TRACE_ERROR("%s unable to allocate media alarm.\n", __func__);
- return;
- }
-
- // alarm_set_periodic(btif_media_cb.media_alarm, BTIF_MEDIA_TIME_TICK, btif_media_task_alarm_cb, NULL);
- osi_alarm_set(btif_media_cb.media_alarm, BTIF_MEDIA_TIME_TICK);
-}
-
-/*******************************************************************************
- **
- ** Function btif_media_task_aa_stop_tx
- **
- ** Description Stop media task encoding
- **
- ** Returns void
- **
- *******************************************************************************/
-static void btif_media_task_aa_stop_tx(void)
-{
- APPL_TRACE_DEBUG("%s is_tx_timer: %d\n", __func__, btif_media_cb.is_tx_timer);
-
- const bool send_ack = (btif_media_cb.is_tx_timer != FALSE);
-
- /* Stop the timer first */
- osi_alarm_free(btif_media_cb.media_alarm);
- btif_media_cb.media_alarm = NULL;
- btif_media_cb.is_tx_timer = FALSE;
-
- UIPC_Close(UIPC_CH_ID_AV_AUDIO);
-
- /* Try to send acknowldegment once the media stream is
- stopped. This will make sure that the A2DP HAL layer is
- un-blocked on wait for acknowledgment for the sent command.
- This resolves a corner cases AVDTP SUSPEND collision
- when the DUT and the remote device issue SUSPEND simultaneously
- and due to the processing of the SUSPEND request from the remote,
- the media path is torn down. If the A2DP HAL happens to wait
- for ACK for the initiated SUSPEND, it would never receive it casuing
- a block/wait. Due to this acknowledgement, the A2DP HAL is guranteed
- to get the ACK for any pending command in such cases. */
-
- if (send_ack) {
- a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
- }
-
- /* audio engine stopped, reset tx suspended flag */
- btif_media_cb.tx_flush = 0;
- last_frame_us = 0;
-
- /* Reset the media feeding state */
- btif_media_task_feeding_state_reset();
-}
-
-/*******************************************************************************
- **
- ** Function btif_get_num_aa_frame
- **
- ** Description
- **
- ** Returns The number of media frames in this time slice
- **
- *******************************************************************************/
-static UINT8 btif_get_num_aa_frame(void)
-{
- UINT8 result = 0;
-
- switch (btif_media_cb.TxTranscoding) {
- case BTIF_MEDIA_TRSCD_PCM_2_SBC: {
- UINT32 pcm_bytes_per_frame = btif_media_cb.encoder.s16NumOfSubBands *
- btif_media_cb.encoder.s16NumOfBlocks *
- btif_media_cb.media_feeding.cfg.pcm.num_channel *
- btif_media_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
-
- UINT32 us_this_tick = BTIF_MEDIA_TIME_TICK * 1000;
- UINT64 now_us = time_now_us();
- if (last_frame_us != 0) {
- us_this_tick = (now_us - last_frame_us);
- }
- last_frame_us = now_us;
-
- btif_media_cb.media_feeding_state.pcm.counter +=
- btif_media_cb.media_feeding_state.pcm.bytes_per_tick *
- us_this_tick / (BTIF_MEDIA_TIME_TICK * 1000);
-
- /* calculate nbr of frames pending for this media tick */
- result = btif_media_cb.media_feeding_state.pcm.counter / pcm_bytes_per_frame;
- if (result > MAX_PCM_FRAME_NUM_PER_TICK) {
- APPL_TRACE_WARNING("%s() - Limiting frames to be sent from %d to %d"
- , __FUNCTION__, result, MAX_PCM_FRAME_NUM_PER_TICK);
- result = MAX_PCM_FRAME_NUM_PER_TICK;
- }
- btif_media_cb.media_feeding_state.pcm.counter -= result * pcm_bytes_per_frame;
-
- LOG_VERBOSE("WRITE %d FRAMES\n", result);
- }
- break;
-
- default:
- APPL_TRACE_ERROR("ERROR btif_get_num_aa_frame Unsupported transcoding format 0x%x\n",
- btif_media_cb.TxTranscoding);
- result = 0;
- break;
- }
-
- return (UINT8)result;
-}
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
-
/*******************************************************************************
**
** Function btif_media_sink_enque_buf
**
** Returns void
*******************************************************************************/
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-BT_HDR *btif_media_aa_readbuf(void)
-{
- return GKI_dequeue(&(btif_media_cb.TxAaQ));
-}
-#else
BT_HDR *btif_media_aa_readbuf(void)
{
return NULL;
}
-#endif /* BTIF_AV_SRC_INCLUDED */
-
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-/*******************************************************************************
- **
- ** Function btif_media_aa_read_feeding
- **
- ** Description
- **
- ** Returns void
- **
- *******************************************************************************/
-BOOLEAN btif_media_aa_read_feeding(tUIPC_CH_ID channel_id)
-{
- UINT16 event;
- UINT16 blocm_x_subband = btif_media_cb.encoder.s16NumOfSubBands * \
- btif_media_cb.encoder.s16NumOfBlocks;
- UINT32 read_size;
- UINT16 sbc_sampling = 48000;
- UINT32 src_samples;
- UINT16 bytes_needed = blocm_x_subband * btif_media_cb.encoder.s16NumOfChannels * \
- btif_media_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
- static UINT16 up_sampled_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS
- * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * 2];
- static UINT16 read_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS
- * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS];
- UINT32 src_size_used;
- UINT32 dst_size_used;
- BOOLEAN fract_needed;
- INT32 fract_max;
- INT32 fract_threshold;
- UINT32 nb_byte_read;
-
- /* Get the SBC sampling rate */
- switch (btif_media_cb.encoder.s16SamplingFreq) {
- case SBC_sf48000:
- sbc_sampling = 48000;
- break;
- case SBC_sf44100:
- sbc_sampling = 44100;
- break;
- case SBC_sf32000:
- sbc_sampling = 32000;
- break;
- case SBC_sf16000:
- sbc_sampling = 16000;
- break;
- }
-
- if (sbc_sampling == btif_media_cb.media_feeding.cfg.pcm.sampling_freq) {
- read_size = bytes_needed - btif_media_cb.media_feeding_state.pcm.aa_feed_residue;
- nb_byte_read = UIPC_Read(channel_id, &event,
- ((UINT8 *)btif_media_cb.encoder.as16PcmBuffer) +
- btif_media_cb.media_feeding_state.pcm.aa_feed_residue,
- read_size);
- if (nb_byte_read == read_size) {
- btif_media_cb.media_feeding_state.pcm.aa_feed_residue = 0;
- return TRUE;
- } else {
- APPL_TRACE_WARNING("### UNDERFLOW :: ONLY READ %d BYTES OUT OF %d ###\n",
- nb_byte_read, read_size);
- btif_media_cb.media_feeding_state.pcm.aa_feed_residue += nb_byte_read;
- return FALSE;
- }
- }
-
- /* Some Feeding PCM frequencies require to split the number of sample */
- /* to read. */
- /* E.g 128/6=21.3333 => read 22 and 21 and 21 => max = 2; threshold = 0*/
- fract_needed = FALSE; /* Default */
- switch (btif_media_cb.media_feeding.cfg.pcm.sampling_freq) {
- case 32000:
- case 8000:
- fract_needed = TRUE;
- fract_max = 2; /* 0, 1 and 2 */
- fract_threshold = 0; /* Add one for the first */
- break;
- case 16000:
- fract_needed = TRUE;
- fract_max = 2; /* 0, 1 and 2 */
- fract_threshold = 1; /* Add one for the first two frames*/
- break;
- }
-
- /* Compute number of sample to read from source */
- src_samples = blocm_x_subband;
- src_samples *= btif_media_cb.media_feeding.cfg.pcm.sampling_freq;
- src_samples /= sbc_sampling;
-
- /* The previous division may have a remainder not null */
- if (fract_needed) {
- if (btif_media_cb.media_feeding_state.pcm.aa_feed_counter <= fract_threshold) {
- src_samples++; /* for every read before threshold add one sample */
- }
-
- /* do nothing if counter >= threshold */
- btif_media_cb.media_feeding_state.pcm.aa_feed_counter++; /* one more read */
- if (btif_media_cb.media_feeding_state.pcm.aa_feed_counter > fract_max) {
- btif_media_cb.media_feeding_state.pcm.aa_feed_counter = 0;
- }
- }
-
- /* Compute number of bytes to read from source */
- read_size = src_samples;
- read_size *= btif_media_cb.media_feeding.cfg.pcm.num_channel;
- read_size *= (btif_media_cb.media_feeding.cfg.pcm.bit_per_sample / 8);
-
- /* Read Data from UIPC channel */
- nb_byte_read = UIPC_Read(channel_id, &event, (UINT8 *)read_buffer, read_size);
-
- //tput_mon(TRUE, nb_byte_read, FALSE);
-
- if (nb_byte_read < read_size) {
- APPL_TRACE_WARNING("### UNDERRUN :: ONLY READ %d BYTES OUT OF %d ###\n",
- nb_byte_read, read_size);
-
- if (nb_byte_read == 0) {
- return FALSE;
- }
-
- if (btif_media_cb.feeding_mode == BTIF_AV_FEEDING_ASYNCHRONOUS) {
- /* Fill the unfilled part of the read buffer with silence (0) */
- memset(((UINT8 *)read_buffer) + nb_byte_read, 0, read_size - nb_byte_read);
- nb_byte_read = read_size;
- }
- }
-
- /* Initialize PCM up-sampling engine */
- bta_av_sbc_init_up_sample(btif_media_cb.media_feeding.cfg.pcm.sampling_freq,
- sbc_sampling, btif_media_cb.media_feeding.cfg.pcm.bit_per_sample,
- btif_media_cb.media_feeding.cfg.pcm.num_channel);
-
- /* re-sample read buffer */
- /* The output PCM buffer will be stereo, 16 bit per sample */
- dst_size_used = bta_av_sbc_up_sample((UINT8 *)read_buffer,
- (UINT8 *)up_sampled_buffer + btif_media_cb.media_feeding_state.pcm.aa_feed_residue,
- nb_byte_read,
- sizeof(up_sampled_buffer) - btif_media_cb.media_feeding_state.pcm.aa_feed_residue,
- &src_size_used);
-
- /* update the residue */
- btif_media_cb.media_feeding_state.pcm.aa_feed_residue += dst_size_used;
-
- /* only copy the pcm sample when we have up-sampled enough PCM */
- if (btif_media_cb.media_feeding_state.pcm.aa_feed_residue >= bytes_needed) {
- /* Copy the output pcm samples in SBC encoding buffer */
- memcpy((UINT8 *)btif_media_cb.encoder.as16PcmBuffer,
- (UINT8 *)up_sampled_buffer,
- bytes_needed);
- /* update the residue */
- btif_media_cb.media_feeding_state.pcm.aa_feed_residue -= bytes_needed;
-
- if (btif_media_cb.media_feeding_state.pcm.aa_feed_residue != 0) {
- memcpy((UINT8 *)up_sampled_buffer,
- (UINT8 *)up_sampled_buffer + bytes_needed,
- btif_media_cb.media_feeding_state.pcm.aa_feed_residue);
- }
- return TRUE;
- }
-
- return FALSE;
-}
-
-/*******************************************************************************
- **
- ** Function btif_media_aa_prep_sbc_2_send
- **
- ** Description
- **
- ** Returns void
- **
- *******************************************************************************/
-static void btif_media_aa_prep_sbc_2_send(UINT8 nb_frame)
-{
- BT_HDR *p_buf;
- UINT16 blocm_x_subband = btif_media_cb.encoder.s16NumOfSubBands *
- btif_media_cb.encoder.s16NumOfBlocks;
-
- while (nb_frame) {
- if (NULL == (p_buf = GKI_getpoolbuf(BTIF_MEDIA_AA_POOL_ID))) {
- APPL_TRACE_ERROR ("ERROR btif_media_aa_prep_sbc_2_send no buffer TxCnt %d \n",
- GKI_queue_length(&btif_media_cb.TxAaQ));
- return;
- }
-
- /* Init buffer */
- p_buf->offset = BTIF_MEDIA_AA_SBC_OFFSET;
- p_buf->len = 0;
- p_buf->layer_specific = 0;
-
- do {
- /* Write @ of allocated buffer in encoder.pu8Packet */
- btif_media_cb.encoder.pu8Packet = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len;
- /* Fill allocated buffer with 0 */
- memset(btif_media_cb.encoder.as16PcmBuffer, 0, blocm_x_subband
- * btif_media_cb.encoder.s16NumOfChannels);
-
- /* Read PCM data and upsample them if needed */
- if (btif_media_aa_read_feeding(UIPC_CH_ID_AV_AUDIO)) {
- /* SBC encode and descramble frame */
- SBC_Encoder(&(btif_media_cb.encoder));
- A2D_SbcChkFrInit(btif_media_cb.encoder.pu8Packet);
- A2D_SbcDescramble(btif_media_cb.encoder.pu8Packet, btif_media_cb.encoder.u16PacketLength);
- /* Update SBC frame length */
- p_buf->len += btif_media_cb.encoder.u16PacketLength;
- nb_frame--;
- p_buf->layer_specific++;
- } else {
- APPL_TRACE_WARNING("btif_media_aa_prep_sbc_2_send underflow %d, %d\n",
- nb_frame, btif_media_cb.media_feeding_state.pcm.aa_feed_residue);
- btif_media_cb.media_feeding_state.pcm.counter += nb_frame *
- btif_media_cb.encoder.s16NumOfSubBands *
- btif_media_cb.encoder.s16NumOfBlocks *
- btif_media_cb.media_feeding.cfg.pcm.num_channel *
- btif_media_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
- /* no more pcm to read */
- nb_frame = 0;
-
- /* break read loop if timer was stopped (media task stopped) */
- if ( btif_media_cb.is_tx_timer == FALSE ) {
- GKI_freebuf(p_buf);
- return;
- }
- }
-
- } while (((p_buf->len + btif_media_cb.encoder.u16PacketLength) < btif_media_cb.TxAaMtuSize)
- && (p_buf->layer_specific < 0x0F) && nb_frame);
-
- if (p_buf->len) {
- /* timestamp of the media packet header represent the TS of the first SBC frame
- i.e the timestamp before including this frame */
- *((UINT32 *) (p_buf + 1)) = btif_media_cb.timestamp;
-
- btif_media_cb.timestamp += p_buf->layer_specific * blocm_x_subband;
-
- if (btif_media_cb.tx_flush) {
- APPL_TRACE_DEBUG("### tx suspended, discarded frame ###\n");
-
- if (GKI_queue_length(&btif_media_cb.TxAaQ) > 0) {
- btif_media_flush_q(&(btif_media_cb.TxAaQ));
- }
-
- GKI_freebuf(p_buf);
- return;
- }
-
- /* Enqueue the encoded SBC frame in AA Tx Queue */
- GKI_enqueue(&(btif_media_cb.TxAaQ), p_buf);
- } else {
- GKI_freebuf(p_buf);
- }
- }
-}
-
-/*******************************************************************************
- **
- ** Function btif_media_aa_prep_2_send
- **
- ** Description
- **
- ** Returns void
- **
- *******************************************************************************/
-
-static void btif_media_aa_prep_2_send(UINT8 nb_frame)
-{
- // Check for TX queue overflow
-
- if (nb_frame > MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ) {
- nb_frame = MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ;
- }
-
- if (GKI_queue_length(&btif_media_cb.TxAaQ) > (MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ - nb_frame)) {
- APPL_TRACE_WARNING("%s() - TX queue buffer count %d/%d\n", __func__,
- GKI_queue_length(&btif_media_cb.TxAaQ), MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ - nb_frame);
- }
-
- while (GKI_queue_length(&btif_media_cb.TxAaQ) > (MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ - nb_frame)) {
- GKI_freebuf(GKI_dequeue(&(btif_media_cb.TxAaQ)));
- }
-
- // Transcode frame
-
- switch (btif_media_cb.TxTranscoding) {
- case BTIF_MEDIA_TRSCD_PCM_2_SBC:
- btif_media_aa_prep_sbc_2_send(nb_frame);
- break;
-
- default:
- APPL_TRACE_ERROR("%s unsupported transcoding format 0x%x\n", __func__, btif_media_cb.TxTranscoding);
- break;
- }
-}
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
-
-#if (BTIF_AV_SRC_INCLUDED == TRUE)
-/*******************************************************************************
- **
- ** Function btif_media_send_aa_frame
- **
- ** Description
- **
- ** Returns void
- **
- *******************************************************************************/
-static void btif_media_send_aa_frame(void)
-{
- UINT8 nb_frame_2_send;
-
- /* get the number of frame to send */
- nb_frame_2_send = btif_get_num_aa_frame();
-
- if (nb_frame_2_send != 0) {
- /* format and Q buffer to send */
- btif_media_aa_prep_2_send(nb_frame_2_send);
- }
-
- /* send it */
- LOG_VERBOSE("btif_media_send_aa_frame : send %d frames\n", nb_frame_2_send);
- bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
-}
#endif /* BTA_AV_INCLUDED == TRUE */
-#endif /* #if (BTIF_AV_SRC_INCLUDED == TRUE) */
/*******************************************************************************
**
** Function dump_codec_info