#define LOG_TAG "bt_btif_a2dp_sink"
+#include <base/bind.h>
#include <atomic>
-#include <cstdio>
-#include <cstring>
#include <mutex>
#include <string>
-#include <base/bind.h>
+#include "bt_target.h" // Must be first to define build configuration
-#include "bt_common.h"
-#include "btif_a2dp.h"
-#include "btif_a2dp_sink.h"
-#include "btif_av.h"
-#include "btif_av_co.h"
-#include "btif_avrcp_audio_track.h"
-#include "btif_util.h"
+#include "btif/include/btif_a2dp_sink.h"
+#include "btif/include/btif_av.h"
+#include "btif/include/btif_av_co.h"
+#include "btif/include/btif_avrcp_audio_track.h"
+#include "btif/include/btif_util.h" // CASE_RETURN_STR
#include "common/message_loop_thread.h"
+#include "osi/include/alarm.h"
+#include "osi/include/allocator.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/log.h"
-#include "osi/include/osi.h"
+#include "osi/include/osi.h" // UNUSED_ATTR
+#include "stack/include/bt_types.h"
using bluetooth::common::MessageLoopThread;
using LockGuard = std::lock_guard<std::mutex>;
BTIF_MEDIA_SINK_DECODER_UPDATE = 1,
BTIF_MEDIA_SINK_CLEAR_TRACK,
BTIF_MEDIA_SINK_SET_FOCUS_STATE,
- BTIF_MEDIA_SINK_AUDIO_RX_FLUSH
+ BTIF_MEDIA_SINK_AUDIO_RX_FLUSH,
+ BTIF_MEDIA_SINK_START,
+ BTIF_MEDIA_SINK_SUSPEND
};
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
uint8_t codec_info[AVDT_CODEC_SIZE];
} tBTIF_MEDIA_SINK_DECODER_UPDATE;
typedef struct {
- BT_HDR hdr;
+ BT_HDR_RIGID hdr;
btif_a2dp_sink_focus_state_t focus_state;
} tBTIF_MEDIA_SINK_FOCUS_UPDATE;
static void btif_a2dp_sink_end_session_delayed();
static void btif_a2dp_sink_shutdown_delayed();
static void btif_a2dp_sink_cleanup_delayed();
-static void btif_a2dp_sink_command_ready(BT_HDR* p_msg);
+static void btif_a2dp_sink_command_ready(BT_HDR_RIGID* p_msg);
static void btif_a2dp_sink_audio_handle_stop_decoding();
static void btif_decode_alarm_cb(void* context);
static void btif_a2dp_sink_audio_handle_start_decoding();
btif_a2dp_sink_focus_state_t state);
static void btif_a2dp_sink_audio_rx_flush_event();
static void btif_a2dp_sink_clear_track_event_req();
+static void btif_a2dp_sink_on_start_event();
+static void btif_a2dp_sink_on_suspend_event();
UNUSED_ATTR static const char* dump_media_event(uint16_t event) {
switch (event) {
CASE_RETURN_STR(BTIF_MEDIA_SINK_CLEAR_TRACK)
CASE_RETURN_STR(BTIF_MEDIA_SINK_SET_FOCUS_STATE)
CASE_RETURN_STR(BTIF_MEDIA_SINK_AUDIO_RX_FLUSH)
+ CASE_RETURN_STR(BTIF_MEDIA_SINK_START)
+ CASE_RETURN_STR(BTIF_MEDIA_SINK_SUSPEND)
default:
break;
}
}
bool btif_a2dp_sink_init() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
LockGuard lock(g_mutex);
if (btif_a2dp_sink_state != BTIF_A2DP_SINK_STATE_OFF) {
- LOG_ERROR(LOG_TAG, "%s: A2DP Sink media task already running", __func__);
+ LOG_ERROR("%s: A2DP Sink media task already running", __func__);
return false;
}
/* Start A2DP Sink media task */
btif_a2dp_sink_cb.worker_thread.StartUp();
if (!btif_a2dp_sink_cb.worker_thread.IsRunning()) {
- LOG_ERROR(LOG_TAG, "%s: unable to start up media thread", __func__);
+ LOG_ERROR("%s: unable to start up media thread", __func__);
btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
return false;
}
}
static void btif_a2dp_sink_init_delayed() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_RUNNING;
}
bool btif_a2dp_sink_startup() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
btif_a2dp_sink_cb.worker_thread.DoInThread(
FROM_HERE, base::BindOnce(btif_a2dp_sink_startup_delayed));
return true;
}
static void btif_a2dp_sink_startup_delayed() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
LockGuard lock(g_mutex);
// Nothing to do
}
}
bool btif_a2dp_sink_end_session(const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
- peer_address.ToString().c_str());
+ LOG_INFO("%s: peer_address=%s", __func__, peer_address.ToString().c_str());
btif_a2dp_sink_cb.worker_thread.DoInThread(
FROM_HERE, base::BindOnce(btif_a2dp_sink_end_session_delayed));
return true;
}
static void btif_a2dp_sink_end_session_delayed() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
LockGuard lock(g_mutex);
// Nothing to do
}
void btif_a2dp_sink_shutdown() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
btif_a2dp_sink_cb.worker_thread.DoInThread(
FROM_HERE, base::BindOnce(btif_a2dp_sink_shutdown_delayed));
}
static void btif_a2dp_sink_shutdown_delayed() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
LockGuard lock(g_mutex);
// Nothing to do
}
void btif_a2dp_sink_cleanup() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
alarm_t* decode_alarm;
}
static void btif_a2dp_sink_cleanup_delayed() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
LockGuard lock(g_mutex);
fixed_queue_free(btif_a2dp_sink_cb.rx_audio_queue, nullptr);
return btif_a2dp_sink_cb.channel_count;
}
-static void btif_a2dp_sink_command_ready(BT_HDR* p_msg) {
- LOG_VERBOSE(LOG_TAG, "%s: event %d %s", __func__, p_msg->event,
+static void btif_a2dp_sink_command_ready(BT_HDR_RIGID* p_msg) {
+ LOG_VERBOSE("%s: event %d %s", __func__, p_msg->event,
dump_media_event(p_msg->event));
switch (p_msg->event) {
case BTIF_MEDIA_SINK_AUDIO_RX_FLUSH:
btif_a2dp_sink_audio_rx_flush_event();
break;
+ case BTIF_MEDIA_SINK_START:
+ btif_a2dp_sink_on_start_event();
+ break;
+ case BTIF_MEDIA_SINK_SUSPEND:
+ btif_a2dp_sink_on_suspend_event();
+ break;
default:
- LOG_ERROR(LOG_TAG, "%s: unknown event %d", __func__, p_msg->event);
+ LOG_ERROR("%s: unknown event %d", __func__, p_msg->event);
break;
}
osi_free(p_msg);
- LOG_VERBOSE(LOG_TAG, "%s: %s DONE", __func__, dump_media_event(p_msg->event));
+ LOG_VERBOSE("%s: %s DONE", __func__, dump_media_event(p_msg->event));
}
void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf =
reinterpret_cast<tBTIF_MEDIA_SINK_DECODER_UPDATE*>(
osi_malloc(sizeof(tBTIF_MEDIA_SINK_DECODER_UPDATE)));
p_buf->hdr.event = BTIF_MEDIA_SINK_DECODER_UPDATE;
btif_a2dp_sink_cb.worker_thread.DoInThread(
- FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR*)p_buf));
+ FROM_HERE,
+ base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR_RIGID*)p_buf));
}
void btif_a2dp_sink_on_idle() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
+ p_buf->event = BTIF_MEDIA_SINK_SUSPEND;
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
+
if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
btif_a2dp_sink_audio_handle_stop_decoding();
btif_a2dp_sink_clear_track_event_req();
}
void btif_a2dp_sink_on_stopped(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
+ p_buf->event = BTIF_MEDIA_SINK_SUSPEND;
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
+
if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
btif_a2dp_sink_audio_handle_stop_decoding();
}
void btif_a2dp_sink_on_suspended(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
+ p_buf->event = BTIF_MEDIA_SINK_SUSPEND;
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
+
if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
btif_a2dp_sink_audio_handle_stop_decoding();
}
+bool btif_a2dp_sink_on_start() {
+ LOG_INFO("%s", __func__);
+
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
+ p_buf->event = BTIF_MEDIA_SINK_START;
+ btif_a2dp_sink_cb.worker_thread.DoInThread(
+ FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
+
+ return true;
+}
+
static void btif_a2dp_sink_audio_handle_stop_decoding() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
alarm_t* old_alarm;
{
LockGuard lock(g_mutex);
}
static void btif_a2dp_sink_clear_track_event() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
LockGuard lock(g_mutex);
#ifndef OS_GENERIC
// Must be called while locked.
static void btif_a2dp_sink_audio_handle_start_decoding() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
if (btif_a2dp_sink_cb.decode_alarm != nullptr)
return; // Already started decoding
btif_a2dp_sink_cb.decode_alarm = alarm_new_periodic("btif.a2dp_sink_decode");
if (btif_a2dp_sink_cb.decode_alarm == nullptr) {
- LOG_ERROR(LOG_TAG, "%s: unable to allocate decode alarm", __func__);
+ LOG_ERROR("%s: unable to allocate decode alarm", __func__);
return;
}
alarm_set(btif_a2dp_sink_cb.decode_alarm, BTIF_SINK_MEDIA_TIME_TICK_MS,
CHECK(btif_a2dp_sink_cb.decoder_interface != nullptr);
if (!btif_a2dp_sink_cb.decoder_interface->decode_packet(p_msg)) {
- LOG_ERROR(LOG_TAG, "%s: decoding failed", __func__);
+ LOG_ERROR("%s: decoding failed", __func__);
}
}
/* when true media task discards any rx frames */
void btif_a2dp_sink_set_rx_flush(bool enable) {
- LOG_INFO(LOG_TAG, "%s: enable=%s", __func__, (enable) ? "true" : "false");
+ LOG_INFO("%s: enable=%s", __func__, (enable) ? "true" : "false");
LockGuard lock(g_mutex);
btif_a2dp_sink_cb.rx_flush = enable;
}
static void btif_a2dp_sink_audio_rx_flush_event() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
LockGuard lock(g_mutex);
// Flush all received encoded audio buffers
fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
static void btif_a2dp_sink_decoder_update_event(
tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
LockGuard lock(g_mutex);
APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
p_buf->codec_info[1], p_buf->codec_info[2],
int sample_rate = A2DP_GetTrackSampleRate(p_buf->codec_info);
if (sample_rate == -1) {
- LOG_ERROR(LOG_TAG, "%s: cannot get the track frequency", __func__);
+ LOG_ERROR("%s: cannot get the track frequency", __func__);
return;
}
int bits_per_sample = A2DP_GetTrackBitsPerSample(p_buf->codec_info);
if (bits_per_sample == -1) {
- LOG_ERROR(LOG_TAG, "%s: cannot get the bits per sample", __func__);
+ LOG_ERROR("%s: cannot get the bits per sample", __func__);
return;
}
int channel_count = A2DP_GetTrackChannelCount(p_buf->codec_info);
if (channel_count == -1) {
- LOG_ERROR(LOG_TAG, "%s: cannot get the channel count", __func__);
+ LOG_ERROR("%s: cannot get the channel count", __func__);
return;
}
int channel_type = A2DP_GetSinkTrackChannelType(p_buf->codec_info);
if (channel_type == -1) {
- LOG_ERROR(LOG_TAG, "%s: cannot get the Sink channel type", __func__);
+ LOG_ERROR("%s: cannot get the Sink channel type", __func__);
return;
}
btif_a2dp_sink_cb.sample_rate = sample_rate;
btif_a2dp_sink_cb.decoder_interface = bta_av_co_get_decoder_interface();
if (btif_a2dp_sink_cb.decoder_interface == nullptr) {
- LOG_ERROR(LOG_TAG, "%s: cannot stream audio: no source decoder interface",
- __func__);
+ LOG_ERROR("%s: cannot stream audio: no source decoder interface", __func__);
return;
}
if (!btif_a2dp_sink_cb.decoder_interface->decoder_init(
btif_a2dp_sink_on_decode_complete)) {
- LOG_ERROR(LOG_TAG, "%s: failed to initialize decoder", __func__);
+ LOG_ERROR("%s: failed to initialize decoder", __func__);
return;
}
+ if (btif_a2dp_sink_cb.decoder_interface->decoder_configure != nullptr) {
+ btif_a2dp_sink_cb.decoder_interface->decoder_configure(p_buf->codec_info);
+ }
+
APPL_TRACE_DEBUG("%s: create audio track", __func__);
btif_a2dp_sink_cb.audio_track =
#ifndef OS_GENERIC
- BtifAvrcpAudioTrackCreate(sample_rate, bits_per_sample, channel_type);
+ BtifAvrcpAudioTrackCreate(sample_rate, bits_per_sample, channel_count);
#else
NULL;
#endif
if (btif_a2dp_sink_cb.audio_track == nullptr) {
- LOG_ERROR(LOG_TAG, "%s: track creation failed", __func__);
+ LOG_ERROR("%s: track creation failed", __func__);
return;
}
}
}
void btif_a2dp_sink_audio_rx_flush_req() {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
/* Queue is already empty */
return;
}
- BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
p_buf->event = BTIF_MEDIA_SINK_AUDIO_RX_FLUSH;
btif_a2dp_sink_cb.worker_thread.DoInThread(
FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
}
void btif_a2dp_sink_set_focus_state_req(btif_a2dp_sink_focus_state_t state) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO("%s", __func__);
tBTIF_MEDIA_SINK_FOCUS_UPDATE* p_buf =
reinterpret_cast<tBTIF_MEDIA_SINK_FOCUS_UPDATE*>(
osi_malloc(sizeof(tBTIF_MEDIA_SINK_FOCUS_UPDATE)));
p_buf->focus_state = state;
p_buf->hdr.event = BTIF_MEDIA_SINK_SET_FOCUS_STATE;
btif_a2dp_sink_cb.worker_thread.DoInThread(
- FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR*)p_buf));
+ FROM_HERE,
+ base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR_RIGID*)p_buf));
}
static void btif_a2dp_sink_set_focus_state_event(
btif_a2dp_sink_focus_state_t state) {
- LOG_INFO(LOG_TAG, "%s: state=%d", __func__, state);
+ LOG_INFO("%s: state=%d", __func__, state);
LockGuard lock(g_mutex);
APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state);
}
void btif_a2dp_sink_set_audio_track_gain(float gain) {
- LOG_INFO(LOG_TAG, "%s: set gain to %f", __func__, gain);
+ LOG_INFO("%s: set gain to %f", __func__, gain);
LockGuard lock(g_mutex);
#ifndef OS_GENERIC
}
static void btif_a2dp_sink_clear_track_event_req() {
- LOG_INFO(LOG_TAG, "%s", __func__);
- BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+ LOG_INFO("%s", __func__);
+ BT_HDR_RIGID* p_buf =
+ reinterpret_cast<BT_HDR_RIGID*>(osi_malloc(sizeof(BT_HDR_RIGID)));
p_buf->event = BTIF_MEDIA_SINK_CLEAR_TRACK;
btif_a2dp_sink_cb.worker_thread.DoInThread(
FROM_HERE, base::BindOnce(btif_a2dp_sink_command_ready, p_buf));
}
+
+static void btif_a2dp_sink_on_start_event() {
+ LOG_INFO("%s", __func__);
+
+ if ((btif_a2dp_sink_cb.decoder_interface != nullptr) &&
+ (btif_a2dp_sink_cb.decoder_interface->decoder_start != nullptr)) {
+ btif_a2dp_sink_cb.decoder_interface->decoder_start();
+ }
+
+ return;
+}
+
+static void btif_a2dp_sink_on_suspend_event() {
+ LOG_INFO("%s", __func__);
+
+ if ((btif_a2dp_sink_cb.decoder_interface != nullptr) &&
+ (btif_a2dp_sink_cb.decoder_interface->decoder_suspend != nullptr)) {
+ btif_a2dp_sink_cb.decoder_interface->decoder_suspend();
+ }
+
+ return;
+}