Merge "test_vendor: Extract DeviceProperties"
diff --git a/btcore/src/device_class.cc b/btcore/src/device_class.cc
index 1538ef6..911eeee 100644
--- a/btcore/src/device_class.cc
+++ b/btcore/src/device_class.cc
@@ -21,7 +21,6 @@
#include <string.h>
#include "btcore/include/device_class.h"
-#include "osi/include/osi.h"
typedef struct _bt_device_class_t {
uint32_t unused : 2; // LSBs
@@ -35,7 +34,9 @@
// Ensure the internal device class implementation and public one
// have equal size.
-COMPILE_ASSERT(sizeof(_bt_device_class_t) == sizeof(bt_device_class_t));
+static_assert(sizeof(_bt_device_class_t) == sizeof(bt_device_class_t),
+ "Internal and external device class implementation should have "
+ "the same size");
// [Major Service Classes]
// (https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband)
diff --git a/btif/co/bta_av_co.cc b/btif/co/bta_av_co.cc
index 1f1d7da..2b86bea 100644
--- a/btif/co/bta_av_co.cc
+++ b/btif/co/bta_av_co.cc
@@ -1051,6 +1051,19 @@
return encoder_interface;
}
+const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void) {
+ /* Protect access to bta_av_co_cb.codec_config */
+ mutex_global_lock();
+
+ const tA2DP_DECODER_INTERFACE* decoder_interface =
+ A2DP_GetDecoderInterface(bta_av_co_cb.codec_config);
+
+ /* Protect access to bta_av_co_cb.codec_config */
+ mutex_global_unlock();
+
+ return decoder_interface;
+}
+
bool bta_av_co_set_codec_user_config(
const btav_a2dp_codec_config_t& codec_user_config) {
uint8_t result_codec_config[AVDT_CODEC_SIZE];
diff --git a/btif/include/btif_av_co.h b/btif/include/btif_av_co.h
index caa90e9..00fd5b9 100644
--- a/btif/include/btif_av_co.h
+++ b/btif/include/btif_av_co.h
@@ -37,6 +37,12 @@
// otherwise NULL.
const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void);
+// Gets the current A2DP decoder interface that can be used to decode received
+// A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// Returns the A2DP decoder interface if the current codec is setup, otherwise
+// NULL.
+const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void);
+
// Sets the user preferred codec configuration.
// |codec_user_config| contains the preferred codec configuration.
// Returns true on success, otherwise false.
diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc
index 6e0c577..0a64f43 100644
--- a/btif/src/btif_a2dp_sink.cc
+++ b/btif/src/btif_a2dp_sink.cc
@@ -19,7 +19,9 @@
#define LOG_TAG "bt_btif_a2dp_sink"
-#include <string.h>
+#include <atomic>
+#include <cstring>
+#include <mutex>
#include "bt_common.h"
#include "btif_a2dp.h"
@@ -33,8 +35,7 @@
#include "osi/include/osi.h"
#include "osi/include/thread.h"
-#include "oi_codec_sbc.h"
-#include "oi_status.h"
+using LockGuard = std::lock_guard<std::mutex>;
/**
* The receiving queue buffer size.
@@ -71,13 +72,6 @@
btif_a2dp_sink_focus_state_t focus_state;
} tBTIF_MEDIA_SINK_FOCUS_UPDATE;
-typedef struct {
- uint16_t num_frames_to_be_processed;
- uint16_t len;
- uint16_t offset;
- uint16_t layer_specific;
-} tBT_SBC_HDR;
-
/* BTIF A2DP Sink control block */
typedef struct {
thread_t* worker_thread;
@@ -85,22 +79,19 @@
fixed_queue_t* rx_audio_queue;
bool rx_flush; /* discards any incoming data when true */
alarm_t* decode_alarm;
- uint8_t frames_to_process;
tA2DP_SAMPLE_RATE sample_rate;
tA2DP_CHANNEL_COUNT channel_count;
btif_a2dp_sink_focus_state_t rx_focus_state; /* audio focus state */
void* audio_track;
+ const tA2DP_DECODER_INTERFACE* decoder_interface;
} tBTIF_A2DP_SINK_CB;
+// Mutex for below data structures.
+static std::mutex g_mutex;
+
static tBTIF_A2DP_SINK_CB btif_a2dp_sink_cb;
-static int btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
-
-static OI_CODEC_SBC_DECODER_CONTEXT btif_a2dp_sink_context;
-static uint32_t btif_a2dp_sink_context_data[CODEC_DATA_WORDS(
- 2, SBC_CODEC_FAST_FILTER_BUFFERS)];
-static int16_t
- btif_a2dp_sink_pcm_data[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
+static std::atomic<int> btif_a2dp_sink_state{BTIF_A2DP_SINK_STATE_OFF};
static void btif_a2dp_sink_startup_delayed(void* context);
static void btif_a2dp_sink_shutdown_delayed(void* context);
@@ -111,7 +102,7 @@
static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context);
static void btif_a2dp_sink_audio_rx_flush_req(void);
/* Handle incoming media packets A2DP SINK streaming */
-static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg);
+static void btif_a2dp_sink_handle_inc_media(BT_HDR* p_msg);
static void btif_a2dp_sink_decoder_update_event(
tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf);
static void btif_a2dp_sink_clear_track_event(void);
@@ -133,6 +124,8 @@
}
bool btif_a2dp_sink_startup(void) {
+ LockGuard lock(g_mutex);
+
if (btif_a2dp_sink_state != BTIF_A2DP_SINK_STATE_OFF) {
APPL_TRACE_ERROR("%s: A2DP Sink media task already running", __func__);
return false;
@@ -176,30 +169,41 @@
}
void btif_a2dp_sink_shutdown(void) {
- if ((btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) ||
- (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_SHUTTING_DOWN)) {
- return;
+ alarm_t* decode_alarm;
+ fixed_queue_t* cmd_msg_queue;
+ thread_t* worker_thread;
+ {
+ LockGuard lock(g_mutex);
+ if ((btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) ||
+ (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_SHUTTING_DOWN)) {
+ return;
+ }
+ /* Make sure no channels are restarted while shutting down */
+ btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_SHUTTING_DOWN;
+
+ APPL_TRACE_EVENT("## A2DP SINK STOP MEDIA THREAD ##");
+
+ decode_alarm = btif_a2dp_sink_cb.decode_alarm;
+ btif_a2dp_sink_cb.decode_alarm = NULL;
+
+ cmd_msg_queue = btif_a2dp_sink_cb.cmd_msg_queue;
+ btif_a2dp_sink_cb.cmd_msg_queue = NULL;
+
+ worker_thread = btif_a2dp_sink_cb.worker_thread;
+ btif_a2dp_sink_cb.worker_thread = NULL;
}
- /* Make sure no channels are restarted while shutting down */
- btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_SHUTTING_DOWN;
-
- APPL_TRACE_EVENT("## A2DP SINK STOP MEDIA THREAD ##");
-
// Stop the timer
- alarm_free(btif_a2dp_sink_cb.decode_alarm);
- btif_a2dp_sink_cb.decode_alarm = NULL;
+ alarm_free(decode_alarm);
// Exit the thread
- fixed_queue_free(btif_a2dp_sink_cb.cmd_msg_queue, NULL);
- btif_a2dp_sink_cb.cmd_msg_queue = NULL;
- thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_shutdown_delayed,
- NULL);
- thread_free(btif_a2dp_sink_cb.worker_thread);
- btif_a2dp_sink_cb.worker_thread = NULL;
+ fixed_queue_free(cmd_msg_queue, NULL);
+ thread_post(worker_thread, btif_a2dp_sink_shutdown_delayed, NULL);
+ thread_free(worker_thread);
}
static void btif_a2dp_sink_shutdown_delayed(UNUSED_ATTR void* context) {
+ LockGuard lock(g_mutex);
fixed_queue_free(btif_a2dp_sink_cb.rx_audio_queue, NULL);
btif_a2dp_sink_cb.rx_audio_queue = NULL;
@@ -207,10 +211,12 @@
}
tA2DP_SAMPLE_RATE btif_a2dp_sink_get_sample_rate(void) {
+ LockGuard lock(g_mutex);
return btif_a2dp_sink_cb.sample_rate;
}
tA2DP_CHANNEL_COUNT btif_a2dp_sink_get_channel_count(void) {
+ LockGuard lock(g_mutex);
return btif_a2dp_sink_cb.channel_count;
}
@@ -283,17 +289,31 @@
}
static void btif_a2dp_sink_audio_handle_stop_decoding(void) {
- btif_a2dp_sink_cb.rx_flush = true;
- btif_a2dp_sink_audio_rx_flush_req();
+ alarm_t* old_alarm;
+ {
+ LockGuard lock(g_mutex);
+ btif_a2dp_sink_cb.rx_flush = true;
+ btif_a2dp_sink_audio_rx_flush_req();
+ old_alarm = btif_a2dp_sink_cb.decode_alarm;
+ btif_a2dp_sink_cb.decode_alarm = NULL;
+ }
- alarm_free(btif_a2dp_sink_cb.decode_alarm);
- btif_a2dp_sink_cb.decode_alarm = NULL;
+ // Drop the lock here, btif_decode_alarm_cb may in the process of being called
+ // while we alarm free leading to deadlock.
+ //
+ // alarm_free waits for btif_decode_alarm_cb which is waiting for g_mutex.
+ alarm_free(old_alarm);
+
+ {
+ LockGuard lock(g_mutex);
#ifndef OS_GENERIC
- BtifAvrcpAudioTrackPause(btif_a2dp_sink_cb.audio_track);
+ BtifAvrcpAudioTrackPause(btif_a2dp_sink_cb.audio_track);
#endif
+ }
}
static void btif_decode_alarm_cb(UNUSED_ATTR void* context) {
+ LockGuard lock(g_mutex);
if (btif_a2dp_sink_cb.worker_thread != NULL) {
thread_post(btif_a2dp_sink_cb.worker_thread,
btif_a2dp_sink_avk_handle_timer, NULL);
@@ -301,6 +321,7 @@
}
static void btif_a2dp_sink_clear_track_event(void) {
+ LockGuard lock(g_mutex);
APPL_TRACE_DEBUG("%s", __func__);
#ifndef OS_GENERIC
@@ -310,6 +331,7 @@
btif_a2dp_sink_cb.audio_track = NULL;
}
+// Must be called while locked.
static void btif_a2dp_sink_audio_handle_start_decoding(void) {
if (btif_a2dp_sink_cb.decode_alarm != NULL)
return; // Already started decoding
@@ -327,54 +349,31 @@
btif_decode_alarm_cb, NULL);
}
-static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg) {
- uint8_t* sbc_start_frame = ((uint8_t*)(p_msg + 1) + p_msg->offset + 1);
- int count;
- uint32_t pcmBytes, availPcmBytes;
- int16_t* pcmDataPointer =
- btif_a2dp_sink_pcm_data; /* Will be overwritten on next packet receipt */
- OI_STATUS status;
- int num_sbc_frames = p_msg->num_frames_to_be_processed;
- uint32_t sbc_frame_len = p_msg->len - 1;
- availPcmBytes = sizeof(btif_a2dp_sink_pcm_data);
+static void btif_a2dp_sink_on_decode_complete(uint8_t* data, uint32_t len) {
+#ifndef OS_GENERIC
+ BtifAvrcpAudioTrackWriteData(btif_a2dp_sink_cb.audio_track,
+ reinterpret_cast<void*>(data), len);
+#endif
+}
+// Must be called while locked.
+static void btif_a2dp_sink_handle_inc_media(BT_HDR* p_msg) {
if ((btif_av_get_peer_sep() == AVDT_TSEP_SNK) ||
(btif_a2dp_sink_cb.rx_flush)) {
APPL_TRACE_DEBUG("State Changed happened in this tick");
return;
}
- APPL_TRACE_DEBUG("%s Number of SBC frames %d, frame_len %d", __func__,
- num_sbc_frames, sbc_frame_len);
-
- for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count++) {
- pcmBytes = availPcmBytes;
- status = OI_CODEC_SBC_DecodeFrame(
- &btif_a2dp_sink_context, (const OI_BYTE**)&sbc_start_frame,
- (uint32_t*)&sbc_frame_len, (int16_t*)pcmDataPointer,
- (uint32_t*)&pcmBytes);
- if (!OI_SUCCESS(status)) {
- APPL_TRACE_ERROR("%s: Decoding failure: %d", __func__, status);
- break;
- }
- availPcmBytes -= pcmBytes;
- pcmDataPointer += pcmBytes / 2;
- p_msg->offset += (p_msg->len - 1) - sbc_frame_len;
- p_msg->len = sbc_frame_len + 1;
+ CHECK(btif_a2dp_sink_cb.decoder_interface);
+ if (!btif_a2dp_sink_cb.decoder_interface->decode_packet(p_msg)) {
+ APPL_TRACE_ERROR("%s Decoding failed!", __func__);
}
-
-#ifndef OS_GENERIC
- BtifAvrcpAudioTrackWriteData(
- btif_a2dp_sink_cb.audio_track, (void*)btif_a2dp_sink_pcm_data,
- (sizeof(btif_a2dp_sink_pcm_data) - availPcmBytes));
-#endif
}
static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context) {
- tBT_SBC_HDR* p_msg;
- int num_sbc_frames;
- int num_frames_to_process;
+ LockGuard lock(g_mutex);
+ BT_HDR* p_msg;
if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
APPL_TRACE_DEBUG("%s: empty queue", __func__);
return;
@@ -392,42 +391,20 @@
return;
}
- num_frames_to_process = btif_a2dp_sink_cb.frames_to_process;
APPL_TRACE_DEBUG(" Process Frames + ");
- do {
- p_msg = (tBT_SBC_HDR*)fixed_queue_try_peek_first(
- btif_a2dp_sink_cb.rx_audio_queue);
- if (p_msg == NULL) return;
- /* Number of frames in queue packets */
- num_sbc_frames = p_msg->num_frames_to_be_processed;
- APPL_TRACE_DEBUG("Frames left in topmost packet %d", num_sbc_frames);
- APPL_TRACE_DEBUG("Remaining frames to process in tick %d",
- num_frames_to_process);
+ while (true) {
+ p_msg = (BT_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
+ if (p_msg == NULL) {
+ break;
+ }
APPL_TRACE_DEBUG("Number of packets in queue %d",
fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue));
- if (num_sbc_frames > num_frames_to_process) {
- /* Queue packet has more frames */
- p_msg->num_frames_to_be_processed = num_frames_to_process;
- btif_a2dp_sink_handle_inc_media(p_msg);
- p_msg->num_frames_to_be_processed =
- num_sbc_frames - num_frames_to_process;
- num_frames_to_process = 0;
- break;
- }
/* Queue packet has less frames */
btif_a2dp_sink_handle_inc_media(p_msg);
- p_msg =
- (tBT_SBC_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
- if (p_msg == NULL) {
- APPL_TRACE_ERROR("Insufficient data in queue");
- break;
- }
- num_frames_to_process =
- num_frames_to_process - p_msg->num_frames_to_be_processed;
osi_free(p_msg);
- } while (num_frames_to_process > 0);
+ }
APPL_TRACE_DEBUG("Process Frames - ");
}
@@ -435,11 +412,14 @@
/* when true media task discards any rx frames */
void btif_a2dp_sink_set_rx_flush(bool enable) {
APPL_TRACE_EVENT("## DROP RX %d ##", enable);
+ LockGuard lock(g_mutex);
+
btif_a2dp_sink_cb.rx_flush = enable;
}
static void btif_a2dp_sink_audio_rx_flush_event(void) {
- /* Flush all received SBC buffers (encoded) */
+ LockGuard lock(g_mutex);
+ /* Flush all received encoded audio buffers */
APPL_TRACE_DEBUG("%s", __func__);
fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
@@ -447,8 +427,7 @@
static void btif_a2dp_sink_decoder_update_event(
tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) {
- OI_STATUS status;
-
+ 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],
p_buf->codec_info[3], p_buf->codec_info[4],
@@ -474,15 +453,21 @@
btif_a2dp_sink_cb.rx_flush = false;
APPL_TRACE_DEBUG("%s: Reset to Sink role", __func__);
- status = OI_CODEC_SBC_DecoderReset(
- &btif_a2dp_sink_context, btif_a2dp_sink_context_data,
- sizeof(btif_a2dp_sink_context_data), 2, 2, false);
- if (!OI_SUCCESS(status)) {
- APPL_TRACE_ERROR("%s: OI_CODEC_SBC_DecoderReset failed with error code %d",
- __func__, status);
+
+ btif_a2dp_sink_cb.decoder_interface = bta_av_co_get_decoder_interface();
+ if (btif_a2dp_sink_cb.decoder_interface == NULL) {
+ APPL_TRACE_ERROR("%s: Cannot stream audio: no source decoder interface",
+ __func__);
+ return;
}
- APPL_TRACE_DEBUG("%s: A2dpSink: SBC create track", __func__);
+ if (!btif_a2dp_sink_cb.decoder_interface->decoder_init(
+ btif_a2dp_sink_on_decode_complete)) {
+ APPL_TRACE_ERROR("%s: A2dpSink: Failed to initialize decoder", __func__);
+ return;
+ }
+
+ APPL_TRACE_DEBUG("%s: A2dpSink: create audio track", __func__);
btif_a2dp_sink_cb.audio_track =
#ifndef OS_GENERIC
BtifAvrcpAudioTrackCreate(sample_rate, channel_type);
@@ -493,18 +478,10 @@
APPL_TRACE_ERROR("%s: A2dpSink: Track creation failed", __func__);
return;
}
-
- btif_a2dp_sink_cb.frames_to_process = A2DP_GetSinkFramesCountToProcess(
- BTIF_SINK_MEDIA_TIME_TICK_MS, p_buf->codec_info);
- APPL_TRACE_DEBUG("%s: Frames to be processed in 20 ms %d", __func__,
- btif_a2dp_sink_cb.frames_to_process);
- if (btif_a2dp_sink_cb.frames_to_process == 0) {
- APPL_TRACE_ERROR("%s: Cannot compute the number of frames to process",
- __func__);
- }
}
uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) {
+ LockGuard lock(g_mutex);
if (btif_a2dp_sink_cb.rx_flush) /* Flush enabled, do not enqueue */
return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue);
@@ -517,17 +494,11 @@
BTIF_TRACE_VERBOSE("%s +", __func__);
/* Allocate and queue this buffer */
- tBT_SBC_HDR* p_msg = reinterpret_cast<tBT_SBC_HDR*>(
- osi_malloc(sizeof(tBT_SBC_HDR) + p_pkt->offset + p_pkt->len));
- memcpy((uint8_t*)(p_msg + 1), (uint8_t*)(p_pkt + 1) + p_pkt->offset,
- p_pkt->len);
- p_msg->num_frames_to_be_processed =
- (*((uint8_t*)(p_pkt + 1) + p_pkt->offset)) & 0x0f;
- p_msg->len = p_pkt->len;
+ BT_HDR* p_msg =
+ reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(*p_msg) + p_pkt->len));
+ memcpy(p_msg, p_pkt, sizeof(*p_msg));
p_msg->offset = 0;
- p_msg->layer_specific = p_pkt->layer_specific;
- BTIF_TRACE_VERBOSE("%s: frames to process %d, len %d", __func__,
- p_msg->num_frames_to_be_processed, p_msg->len);
+ memcpy(p_msg->data, p_pkt->data + p_pkt->offset, p_pkt->len);
fixed_queue_enqueue(btif_a2dp_sink_cb.rx_audio_queue, p_msg);
if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) ==
MAX_A2DP_DELAYED_START_FRAME_COUNT) {
@@ -567,6 +538,7 @@
static void btif_a2dp_sink_set_focus_state_event(
btif_a2dp_sink_focus_state_t state) {
+ LockGuard lock(g_mutex);
if (!btif_av_is_connected()) return;
APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state);
btif_a2dp_sink_cb.rx_focus_state = state;
@@ -580,6 +552,7 @@
void btif_a2dp_sink_set_audio_track_gain(float gain) {
APPL_TRACE_DEBUG("%s set gain to %f", __func__, gain);
+ LockGuard lock(g_mutex);
#ifndef OS_GENERIC
BtifAvrcpSetAudioTrackGain(btif_a2dp_sink_cb.audio_track, gain);
#endif
diff --git a/build/Android.bp b/build/Android.bp
index 79fbccc..53d461d 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -46,7 +46,6 @@
fluoride_defaults {
name: "fluoride_defaults",
defaults: ["fluoride_types_defaults"],
- compile_multilib: "first",
header_libs: ["libbluetooth_headers"],
static_libs: [
"libbluetooth-types",
diff --git a/hci/src/btsnoop.cc b/hci/src/btsnoop.cc
index f44713e..9812b61 100644
--- a/hci/src/btsnoop.cc
+++ b/hci/src/btsnoop.cc
@@ -200,7 +200,7 @@
get_btsnoop_log_path(log_path);
get_btsnoop_last_log_path(last_log_path, log_path);
- if (!rename(log_path, last_log_path) && errno != ENOENT)
+ if (rename(log_path, last_log_path) != 0 && errno != ENOENT)
LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__,
log_path, last_log_path, strerror(errno));
diff --git a/include/hardware/bt_av.h b/include/hardware/bt_av.h
index fac1aa4..7326c10 100644
--- a/include/hardware/bt_av.h
+++ b/include/hardware/bt_av.h
@@ -61,6 +61,7 @@
// Add an entry for each sink codec here
BTAV_A2DP_CODEC_INDEX_SINK_SBC = BTAV_A2DP_CODEC_INDEX_SINK_MIN,
+ BTAV_A2DP_CODEC_INDEX_SINK_AAC,
BTAV_A2DP_CODEC_INDEX_SINK_MAX,
diff --git a/osi/include/osi.h b/osi/include/osi.h
index 3c5b5fb..a39d56c 100644
--- a/osi/include/osi.h
+++ b/osi/include/osi.h
@@ -35,15 +35,6 @@
#define DUMMY_COUNTER(c) CONCAT(__osi_dummy_, c)
#define DUMMY_PTR DUMMY_COUNTER(__COUNTER__)
-// base/macros.h defines a COMPILE_ASSERT macro to the C++11 keyword
-// "static_assert" (it undef's COMPILE_ASSERT before redefining it).
-// C++ code that includes base and osi/include/osi.h can thus easily default to
-// the definition from libbase but we should check here to avoid compile errors.
-#ifndef COMPILE_ASSERT
-#define COMPILE_ASSERT(COND) \
- typedef int failed_compile_assert[(COND) ? 1 : -1] __attribute__((unused))
-#endif // COMPILE_ASSERT
-
// Macros for safe integer to pointer conversion. In the C language, data is
// commonly cast to opaque pointer containers and back for generic parameter
// passing in callbacks. These macros should be used sparingly in new code
diff --git a/stack/Android.bp b/stack/Android.bp
index 11b2e19..213da1c 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -24,6 +24,7 @@
],
include_dirs: [
"external/aac/libAACenc/include",
+ "external/aac/libAACdec/include",
"external/aac/libSYS/include",
"external/libldac/inc",
"external/libldac/abr/inc",
@@ -41,10 +42,12 @@
],
srcs: [
"a2dp/a2dp_aac.cc",
+ "a2dp/a2dp_aac_decoder.cc",
"a2dp/a2dp_aac_encoder.cc",
"a2dp/a2dp_api.cc",
"a2dp/a2dp_codec_config.cc",
"a2dp/a2dp_sbc.cc",
+ "a2dp/a2dp_sbc_decoder.cc",
"a2dp/a2dp_sbc_encoder.cc",
"a2dp/a2dp_sbc_up_sample.cc",
"a2dp/a2dp_vendor.cc",
@@ -201,6 +204,7 @@
],
static_libs: [
"libbt-stack",
+ "libbt-sbc-decoder",
"libbt-sbc-encoder",
"libFraunhoferAAC",
"libosi",
diff --git a/stack/BUILD.gn b/stack/BUILD.gn
index 68ae811..6f3c55a 100644
--- a/stack/BUILD.gn
+++ b/stack/BUILD.gn
@@ -17,10 +17,12 @@
static_library("stack") {
sources = [
"a2dp/a2dp_aac.cc",
+ "a2dp/a2dp_aac_decoder.cc",
"a2dp/a2dp_aac_encoder.cc",
"a2dp/a2dp_api.cc",
"a2dp/a2dp_codec_config.cc",
"a2dp/a2dp_sbc.cc",
+ "a2dp/a2dp_sbc_decoder.cc",
"a2dp/a2dp_sbc_encoder.cc",
"a2dp/a2dp_sbc_up_sample.cc",
"a2dp/a2dp_vendor.cc",
diff --git a/stack/a2dp/a2dp_aac.cc b/stack/a2dp/a2dp_aac.cc
index 65badeb..9bb67ea 100644
--- a/stack/a2dp/a2dp_aac.cc
+++ b/stack/a2dp/a2dp_aac.cc
@@ -30,6 +30,7 @@
#include <string.h>
#include <base/logging.h>
+#include "a2dp_aac_decoder.h"
#include "a2dp_aac_encoder.h"
#include "bt_utils.h"
#include "osi/include/log.h"
@@ -65,6 +66,21 @@
// bits_per_sample
BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16};
+/* AAC Sink codec capabilities */
+static const tA2DP_AAC_CIE a2dp_aac_sink_caps = {
+ // objectType
+ A2DP_AAC_OBJECT_TYPE_MPEG2_LC,
+ // sampleRate
+ A2DP_AAC_SAMPLING_FREQ_44100 | A2DP_AAC_SAMPLING_FREQ_48000,
+ // channelMode
+ A2DP_AAC_CHANNEL_MODE_MONO | A2DP_AAC_CHANNEL_MODE_STEREO,
+ // variableBitRateSupport
+ A2DP_AAC_VARIABLE_BIT_RATE_ENABLED,
+ // bitRate
+ A2DP_AAC_DEFAULT_BITRATE,
+ // bits_per_sample
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16};
+
/* Default AAC codec configuration */
static const tA2DP_AAC_CIE a2dp_aac_default_config = {
A2DP_AAC_OBJECT_TYPE_MPEG2_LC, // objectType
@@ -85,9 +101,14 @@
nullptr // set_transmit_queue_length
};
+static const tA2DP_DECODER_INTERFACE a2dp_decoder_interface_aac = {
+ a2dp_aac_decoder_init, a2dp_aac_decoder_cleanup,
+ a2dp_aac_decoder_decode_packet,
+};
+
UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAac(
const tA2DP_AAC_CIE* p_cap, const uint8_t* p_codec_info,
- bool is_peer_codec_info);
+ bool is_capability);
// Builds the AAC Media Codec Capabilities byte sequence beginning from the
// LOSC octet. |media_type| is the media type |AVDT_MEDIA_TYPE_*|.
@@ -191,11 +212,19 @@
}
bool A2DP_IsSinkCodecValidAac(UNUSED_ATTR const uint8_t* p_codec_info) {
- return false;
+ tA2DP_AAC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
}
bool A2DP_IsPeerSourceCodecValidAac(UNUSED_ATTR const uint8_t* p_codec_info) {
- return false;
+ tA2DP_AAC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
}
bool A2DP_IsPeerSinkCodecValidAac(const uint8_t* p_codec_info) {
@@ -206,13 +235,14 @@
(A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
}
-bool A2DP_IsSinkCodecSupportedAac(UNUSED_ATTR const uint8_t* p_codec_info) {
- return false;
+bool A2DP_IsSinkCodecSupportedAac(const uint8_t* p_codec_info) {
+ return A2DP_CodecInfoMatchesCapabilityAac(&a2dp_aac_sink_caps, p_codec_info,
+ false) == A2DP_SUCCESS;
}
-bool A2DP_IsPeerSourceCodecSupportedAac(
- UNUSED_ATTR const uint8_t* p_codec_info) {
- return false;
+bool A2DP_IsPeerSourceCodecSupportedAac(const uint8_t* p_codec_info) {
+ return A2DP_CodecInfoMatchesCapabilityAac(&a2dp_aac_sink_caps, p_codec_info,
+ true) == A2DP_SUCCESS;
}
tA2DP_STATUS A2DP_BuildSrc2SinkConfigAac(UNUSED_ATTR const uint8_t* p_src_cap,
@@ -222,11 +252,8 @@
// Checks whether A2DP AAC codec configuration matches with a device's codec
// capabilities. |p_cap| is the AAC codec configuration. |p_codec_info| is
-// the device's codec capabilities.
-// If |is_capability| is true, the byte sequence is codec capabilities,
-// otherwise is codec configuration.
-// |p_codec_info| contains the codec capabilities for a peer device that
-// is acting as an A2DP source.
+// the device's codec capabilities. |is_capability| is true if
+// |p_codec_info| contains A2DP codec capability.
// Returns A2DP_SUCCESS if the codec configuration matches with capabilities,
// otherwise the corresponding A2DP error status code.
static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAac(
@@ -390,13 +417,24 @@
return -1;
}
-int A2DP_GetSinkTrackChannelTypeAac(UNUSED_ATTR const uint8_t* p_codec_info) {
- return -1;
-}
+int A2DP_GetSinkTrackChannelTypeAac(const uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE aac_cie;
-int A2DP_GetSinkFramesCountToProcessAac(
- UNUSED_ATTR uint64_t time_interval_ms,
- UNUSED_ATTR const uint8_t* p_codec_info) {
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (aac_cie.channelMode) {
+ case A2DP_AAC_CHANNEL_MODE_MONO:
+ return 1;
+ case A2DP_AAC_CHANNEL_MODE_STEREO:
+ return 3;
+ }
+
return -1;
}
@@ -616,6 +654,13 @@
return &a2dp_encoder_interface_aac;
}
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceAac(
+ const uint8_t* p_codec_info) {
+ if (!A2DP_IsSinkCodecValidAac(p_codec_info)) return NULL;
+
+ return &a2dp_decoder_interface_aac;
+}
+
bool A2DP_AdjustCodecAac(uint8_t* p_codec_info) {
tA2DP_AAC_CIE cfg_cie;
@@ -633,6 +678,8 @@
const char* A2DP_CodecIndexStrAac(void) { return "AAC"; }
+const char* A2DP_CodecIndexStrAacSink(void) { return "AAC SINK"; }
+
bool A2DP_InitCodecConfigAac(tAVDT_CFG* p_cfg) {
if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_caps,
p_cfg->codec_info) != A2DP_SUCCESS) {
@@ -650,6 +697,11 @@
return true;
}
+bool A2DP_InitCodecConfigAacSink(tAVDT_CFG* p_cfg) {
+ return A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_sink_caps,
+ p_cfg->codec_info) == A2DP_SUCCESS;
+}
+
UNUSED_ATTR static void build_codec_config(const tA2DP_AAC_CIE& config_cie,
btav_a2dp_codec_config_t* result) {
if (config_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100)
@@ -672,7 +724,8 @@
A2dpCodecConfigAac::A2dpCodecConfigAac(
btav_a2dp_codec_priority_t codec_priority)
- : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, "AAC", codec_priority) {
+ : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, A2DP_CodecIndexStrAac(),
+ codec_priority) {
// Compute the local capability
if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
@@ -1263,3 +1316,48 @@
sizeof(ota_codec_peer_config_));
return false;
}
+
+A2dpCodecConfigAacSink::A2dpCodecConfigAacSink(
+ btav_a2dp_codec_priority_t codec_priority)
+ : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SINK_AAC,
+ A2DP_CodecIndexStrAacSink(), codec_priority) {}
+
+A2dpCodecConfigAacSink::~A2dpCodecConfigAacSink() {}
+
+bool A2dpCodecConfigAacSink::init() {
+ if (!isValid()) return false;
+
+ // Load the decoder
+ if (!A2DP_LoadDecoderAac()) {
+ LOG_ERROR(LOG_TAG, "%s: cannot load the decoder", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+period_ms_t A2dpCodecConfigAacSink::encoderIntervalMs() const {
+ // TODO: This method applies only to Source codecs
+ return 0;
+}
+
+bool A2dpCodecConfigAacSink::setCodecConfig(
+ UNUSED_ATTR const uint8_t* p_peer_codec_info,
+ UNUSED_ATTR bool is_capability,
+ UNUSED_ATTR uint8_t* p_result_codec_config) {
+ // TODO: This method applies only to Source codecs
+ return false;
+}
+
+bool A2dpCodecConfigAacSink::useRtpHeaderMarkerBit() const {
+ // TODO: This method applies only to Source codecs
+ return false;
+}
+
+bool A2dpCodecConfigAacSink::updateEncoderUserConfig(
+ UNUSED_ATTR const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ UNUSED_ATTR bool* p_restart_input, UNUSED_ATTR bool* p_restart_output,
+ UNUSED_ATTR bool* p_config_updated) {
+ // TODO: This method applies only to Source codecs
+ return false;
+}
diff --git a/stack/a2dp/a2dp_aac_decoder.cc b/stack/a2dp/a2dp_aac_decoder.cc
new file mode 100644
index 0000000..d9cd85d
--- /dev/null
+++ b/stack/a2dp/a2dp_aac_decoder.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "a2dp_aac_decoder"
+
+#include "a2dp_aac_decoder.h"
+
+#include <aacdecoder_lib.h>
+#include <base/logging.h>
+
+#include "a2dp_aac.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+#define DECODE_BUF_LEN (8 * 2 * 1024)
+
+typedef struct {
+ HANDLE_AACDECODER aac_handle;
+ bool has_aac_handle; // True if aac_handle is valid
+ INT_PCM* decode_buf;
+ decoded_data_callback_t decode_callback;
+} tA2DP_AAC_DECODER_CB;
+
+static tA2DP_AAC_DECODER_CB a2dp_aac_decoder_cb;
+
+bool A2DP_LoadDecoderAac(void) {
+ // Nothing to do - the library is statically linked
+ return true;
+}
+
+void A2DP_UnloadDecoderAac(void) { a2dp_aac_decoder_cleanup(); }
+
+bool a2dp_aac_decoder_init(decoded_data_callback_t decode_callback) {
+ a2dp_aac_decoder_cleanup();
+
+ a2dp_aac_decoder_cb.aac_handle =
+ aacDecoder_Open(TT_MP4_LATM_MCP1, 1 /* nrOfLayers */);
+ a2dp_aac_decoder_cb.has_aac_handle = true;
+ a2dp_aac_decoder_cb.decode_buf = static_cast<INT_PCM*>(
+ osi_malloc(sizeof(a2dp_aac_decoder_cb.decode_buf[0]) * DECODE_BUF_LEN));
+ a2dp_aac_decoder_cb.decode_callback = decode_callback;
+ return true;
+}
+
+void a2dp_aac_decoder_cleanup(void) {
+ if (a2dp_aac_decoder_cb.has_aac_handle)
+ aacDecoder_Close(a2dp_aac_decoder_cb.aac_handle);
+ free(a2dp_aac_decoder_cb.decode_buf);
+ memset(&a2dp_aac_decoder_cb, 0, sizeof(a2dp_aac_decoder_cb));
+}
+
+bool a2dp_aac_decoder_decode_packet(BT_HDR* p_buf) {
+ auto* pBuffer = reinterpret_cast<UCHAR*>(p_buf->data + p_buf->offset);
+ UINT bufferSize = p_buf->len;
+ UINT bytesValid = p_buf->len;
+ while (bytesValid > 0) {
+ AAC_DECODER_ERROR err = aacDecoder_Fill(a2dp_aac_decoder_cb.aac_handle,
+ &pBuffer, &bufferSize, &bytesValid);
+ if (err != AAC_DEC_OK) {
+ LOG_ERROR(LOG_TAG, "%s: aacDecoder_Fill failed: 0x%x", __func__,
+ static_cast<unsigned>(err));
+ return false;
+ }
+
+ while (true) {
+ err = aacDecoder_DecodeFrame(a2dp_aac_decoder_cb.aac_handle,
+ a2dp_aac_decoder_cb.decode_buf,
+ DECODE_BUF_LEN, 0 /* flags */);
+ if (err == AAC_DEC_NOT_ENOUGH_BITS) {
+ break;
+ }
+ if (err != AAC_DEC_OK) {
+ LOG_ERROR(LOG_TAG, "%s: aacDecoder_DecodeFrame failed: 0x%x", __func__,
+ static_cast<int>(err));
+ break;
+ }
+
+ CStreamInfo* info =
+ aacDecoder_GetStreamInfo(a2dp_aac_decoder_cb.aac_handle);
+ if (!info || info->sampleRate <= 0) {
+ LOG_ERROR(LOG_TAG, "%s: Invalid stream info", __func__);
+ break;
+ }
+
+ size_t frame_len = info->frameSize * info->numChannels *
+ sizeof(a2dp_aac_decoder_cb.decode_buf[0]);
+ a2dp_aac_decoder_cb.decode_callback(
+ reinterpret_cast<uint8_t*>(a2dp_aac_decoder_cb.decode_buf),
+ frame_len);
+ }
+ }
+
+ return true;
+}
diff --git a/stack/a2dp/a2dp_codec_config.cc b/stack/a2dp/a2dp_codec_config.cc
index 60dd7e0..b01c623 100644
--- a/stack/a2dp/a2dp_codec_config.cc
+++ b/stack/a2dp/a2dp_codec_config.cc
@@ -111,6 +111,9 @@
case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
codec_config = new A2dpCodecConfigAac(codec_priority);
break;
+ case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+ codec_config = new A2dpCodecConfigAacSink(codec_priority);
+ break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
codec_config = new A2dpCodecConfigAptx(codec_priority);
break;
@@ -1093,30 +1096,6 @@
return -1;
}
-int A2DP_GetSinkFramesCountToProcess(uint64_t time_interval_ms,
- const uint8_t* p_codec_info) {
- tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
-
- LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
-
- switch (codec_type) {
- case A2DP_MEDIA_CT_SBC:
- return A2DP_GetSinkFramesCountToProcessSbc(time_interval_ms,
- p_codec_info);
- case A2DP_MEDIA_CT_AAC:
- return A2DP_GetSinkFramesCountToProcessAac(time_interval_ms,
- p_codec_info);
- case A2DP_MEDIA_CT_NON_A2DP:
- return A2DP_VendorGetSinkFramesCountToProcess(time_interval_ms,
- p_codec_info);
- default:
- break;
- }
-
- LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
- return -1;
-}
-
bool A2DP_GetPacketTimestamp(const uint8_t* p_codec_info, const uint8_t* p_data,
uint32_t* p_timestamp) {
tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
@@ -1177,6 +1156,27 @@
return NULL;
}
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterface(
+ const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_GetDecoderInterfaceSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_GetDecoderInterfaceAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorGetDecoderInterface(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return NULL;
+}
+
bool A2DP_AdjustCodec(uint8_t* p_codec_info) {
tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
@@ -1223,6 +1223,8 @@
return A2DP_CodecIndexStrSbcSink();
case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
return A2DP_CodecIndexStrAac();
+ case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+ return A2DP_CodecIndexStrAacSink();
default:
break;
}
@@ -1249,6 +1251,8 @@
return A2DP_InitCodecConfigSbcSink(p_cfg);
case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
return A2DP_InitCodecConfigAac(p_cfg);
+ case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+ return A2DP_InitCodecConfigAacSink(p_cfg);
default:
break;
}
diff --git a/stack/a2dp/a2dp_sbc.cc b/stack/a2dp/a2dp_sbc.cc
index 18760c7..38e1b3b 100644
--- a/stack/a2dp/a2dp_sbc.cc
+++ b/stack/a2dp/a2dp_sbc.cc
@@ -32,6 +32,7 @@
#include <string.h>
#include <base/logging.h>
+#include "a2dp_sbc_decoder.h"
#include "a2dp_sbc_encoder.h"
#include "bt_utils.h"
#include "embdrv/sbc/encoder/include/sbc_encoder.h"
@@ -101,6 +102,11 @@
nullptr // set_transmit_queue_length
};
+static const tA2DP_DECODER_INTERFACE a2dp_decoder_interface_sbc = {
+ a2dp_sbc_decoder_init, a2dp_sbc_decoder_cleanup,
+ a2dp_sbc_decoder_decode_packet,
+};
+
static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilitySbc(
const tA2DP_SBC_CIE* p_cap, const uint8_t* p_codec_info,
bool is_capability);
@@ -716,138 +722,6 @@
return -1;
}
-int A2DP_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms,
- const uint8_t* p_codec_info) {
- tA2DP_SBC_CIE sbc_cie;
- uint32_t freq_multiple;
- uint32_t num_blocks;
- uint32_t num_subbands;
- int frames_to_process;
-
- tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
- if (a2dp_status != A2DP_SUCCESS) {
- LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
- a2dp_status);
- return -1;
- }
-
- // Check the sample frequency
- switch (sbc_cie.samp_freq) {
- case A2DP_SBC_IE_SAMP_FREQ_16:
- LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (16000)", __func__,
- sbc_cie.samp_freq);
- freq_multiple = 16 * time_interval_ms;
- break;
- case A2DP_SBC_IE_SAMP_FREQ_32:
- LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (32000)", __func__,
- sbc_cie.samp_freq);
- freq_multiple = 32 * time_interval_ms;
- break;
- case A2DP_SBC_IE_SAMP_FREQ_44:
- LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (44100)", __func__,
- sbc_cie.samp_freq);
- freq_multiple = (441 * time_interval_ms) / 10;
- break;
- case A2DP_SBC_IE_SAMP_FREQ_48:
- LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (48000)", __func__,
- sbc_cie.samp_freq);
- freq_multiple = 48 * time_interval_ms;
- break;
- default:
- LOG_ERROR(LOG_TAG, "%s: unknown frequency: %d", __func__,
- sbc_cie.samp_freq);
- return -1;
- }
-
- // Check the channel mode
- switch (sbc_cie.ch_mode) {
- case A2DP_SBC_IE_CH_MD_MONO:
- LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (Mono)", __func__, sbc_cie.ch_mode);
- break;
- case A2DP_SBC_IE_CH_MD_DUAL:
- LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (DUAL)", __func__, sbc_cie.ch_mode);
- break;
- case A2DP_SBC_IE_CH_MD_STEREO:
- LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (STEREO)", __func__,
- sbc_cie.ch_mode);
- break;
- case A2DP_SBC_IE_CH_MD_JOINT:
- LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (JOINT)", __func__, sbc_cie.ch_mode);
- break;
- default:
- LOG_ERROR(LOG_TAG, "%s: unknown channel mode: %d", __func__,
- sbc_cie.ch_mode);
- return -1;
- }
-
- // Check the block length
- switch (sbc_cie.block_len) {
- case A2DP_SBC_IE_BLOCKS_4:
- LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (4)", __func__, sbc_cie.block_len);
- num_blocks = 4;
- break;
- case A2DP_SBC_IE_BLOCKS_8:
- LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (8)", __func__, sbc_cie.block_len);
- num_blocks = 8;
- break;
- case A2DP_SBC_IE_BLOCKS_12:
- LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (12)", __func__,
- sbc_cie.block_len);
- num_blocks = 12;
- break;
- case A2DP_SBC_IE_BLOCKS_16:
- LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (16)", __func__,
- sbc_cie.block_len);
- num_blocks = 16;
- break;
- default:
- LOG_ERROR(LOG_TAG, "%s: unknown block length: %d", __func__,
- sbc_cie.block_len);
- return -1;
- }
-
- // Check the number of sub-bands
- switch (sbc_cie.num_subbands) {
- case A2DP_SBC_IE_SUBBAND_4:
- LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (4)", __func__,
- sbc_cie.num_subbands);
- num_subbands = 4;
- break;
- case A2DP_SBC_IE_SUBBAND_8:
- LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (8)", __func__,
- sbc_cie.num_subbands);
- num_subbands = 8;
- break;
- default:
- LOG_ERROR(LOG_TAG, "%s: unknown number of subbands: %d", __func__,
- sbc_cie.num_subbands);
- return -1;
- }
-
- // Check the allocation method
- switch (sbc_cie.alloc_method) {
- case A2DP_SBC_IE_ALLOC_MD_S:
- LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (SNR)", __func__,
- sbc_cie.alloc_method);
- break;
- case A2DP_SBC_IE_ALLOC_MD_L:
- LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (Loudness)", __func__,
- sbc_cie.alloc_method);
- break;
- default:
- LOG_ERROR(LOG_TAG, "%s: unknown allocation method: %d", __func__,
- sbc_cie.alloc_method);
- return -1;
- }
-
- LOG_VERBOSE(LOG_TAG, "%s: Bit pool Min:%d Max:%d", __func__,
- sbc_cie.min_bitpool, sbc_cie.max_bitpool);
-
- frames_to_process = ((freq_multiple) / (num_blocks * num_subbands)) + 1;
-
- return frames_to_process;
-}
-
bool A2DP_GetPacketTimestampSbc(UNUSED_ATTR const uint8_t* p_codec_info,
const uint8_t* p_data, uint32_t* p_timestamp) {
*p_timestamp = *(const uint32_t*)p_data;
@@ -950,6 +824,13 @@
return &a2dp_encoder_interface_sbc;
}
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceSbc(
+ const uint8_t* p_codec_info) {
+ if (!A2DP_IsSinkCodecValidSbc(p_codec_info)) return NULL;
+
+ return &a2dp_decoder_interface_sbc;
+}
+
bool A2DP_AdjustCodecSbc(uint8_t* p_codec_info) {
tA2DP_SBC_CIE cfg_cie;
@@ -1622,6 +1503,12 @@
bool A2dpCodecConfigSbcSink::init() {
if (!isValid()) return false;
+ // Load the decoder
+ if (!A2DP_LoadDecoderSbc()) {
+ LOG_ERROR(LOG_TAG, "%s: cannot load the decoder", __func__);
+ return false;
+ }
+
return true;
}
diff --git a/stack/a2dp/a2dp_sbc_decoder.cc b/stack/a2dp/a2dp_sbc_decoder.cc
new file mode 100644
index 0000000..bc64513
--- /dev/null
+++ b/stack/a2dp/a2dp_sbc_decoder.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "a2dp_sbc_decoder"
+
+#include "a2dp_sbc_decoder.h"
+
+#include <base/logging.h>
+
+#include "embdrv/sbc/decoder/include/oi_codec_sbc.h"
+#include "embdrv/sbc/decoder/include/oi_status.h"
+#include "osi/include/log.h"
+
+typedef struct {
+ OI_CODEC_SBC_DECODER_CONTEXT decoder_context;
+ uint32_t context_data[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
+ int16_t decode_buf[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
+ decoded_data_callback_t decode_callback;
+} tA2DP_SBC_DECODER_CB;
+
+static tA2DP_SBC_DECODER_CB a2dp_sbc_decoder_cb;
+
+bool A2DP_LoadDecoderSbc(void) {
+ // Nothing to do - the library is statically linked
+ return true;
+}
+
+void A2DP_UnloadDecoderSbc(void) { a2dp_sbc_decoder_cleanup(); }
+
+bool a2dp_sbc_decoder_init(decoded_data_callback_t decode_callback) {
+ OI_STATUS status = OI_CODEC_SBC_DecoderReset(
+ &a2dp_sbc_decoder_cb.decoder_context, a2dp_sbc_decoder_cb.context_data,
+ sizeof(a2dp_sbc_decoder_cb.context_data), 2, 2, false);
+ if (!OI_SUCCESS(status)) {
+ LOG_ERROR(LOG_TAG,
+ "%s: OI_CODEC_SBC_DecoderReset failed with error code %d",
+ __func__, status);
+ return false;
+ }
+
+ a2dp_sbc_decoder_cb.decode_callback = decode_callback;
+ return true;
+}
+
+void a2dp_sbc_decoder_cleanup(void) {
+ // Do nothing.
+}
+
+bool a2dp_sbc_decoder_decode_packet(BT_HDR* p_buf) {
+ uint8_t* data = p_buf->data + p_buf->offset;
+ size_t data_size = p_buf->len;
+
+ if (data_size == 0) {
+ LOG_ERROR(LOG_TAG, "%s: Empty packet", __func__);
+ return false;
+ }
+ size_t num_frames = data[0] & 0xf;
+ data += 1;
+ data_size -= 1;
+
+ const OI_BYTE* oi_data = data;
+ uint32_t oi_size = data_size;
+ size_t out_avail = sizeof(a2dp_sbc_decoder_cb.decode_buf);
+ int16_t* out_ptr = a2dp_sbc_decoder_cb.decode_buf;
+
+ for (size_t i = 0; i < num_frames; ++i) {
+ uint32_t out_size = out_avail;
+ OI_STATUS status =
+ OI_CODEC_SBC_DecodeFrame(&a2dp_sbc_decoder_cb.decoder_context, &oi_data,
+ &oi_size, out_ptr, &out_size);
+ if (!OI_SUCCESS(status)) {
+ LOG_ERROR(LOG_TAG, "%s: Decoding failure: %d", __func__, status);
+ return false;
+ }
+ out_avail -= out_size;
+ out_ptr += out_size / sizeof(*out_ptr);
+ }
+
+ size_t out_used =
+ (out_ptr - a2dp_sbc_decoder_cb.decode_buf) * sizeof(*out_ptr);
+ a2dp_sbc_decoder_cb.decode_callback(
+ reinterpret_cast<uint8_t*>(a2dp_sbc_decoder_cb.decode_buf), out_used);
+ return true;
+}
diff --git a/stack/a2dp/a2dp_vendor.cc b/stack/a2dp/a2dp_vendor.cc
index 724bf51..2b874e3 100644
--- a/stack/a2dp/a2dp_vendor.cc
+++ b/stack/a2dp/a2dp_vendor.cc
@@ -350,18 +350,6 @@
return -1;
}
-int A2DP_VendorGetSinkFramesCountToProcess(
- UNUSED_ATTR uint64_t time_interval_ms,
- UNUSED_ATTR const uint8_t* p_codec_info) {
- // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
- // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
-
- // Add checks based on <vendor_id, codec_id>
- // NOTE: Should be done only for local Sink codecs.
-
- return -1;
-}
-
bool A2DP_VendorGetPacketTimestamp(const uint8_t* p_codec_info,
const uint8_t* p_data,
uint32_t* p_timestamp) {
@@ -448,6 +436,12 @@
return NULL;
}
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterface(
+ const uint8_t* p_codec_info) {
+ // We do not support vendor codecs for decoding right now.
+ return NULL;
+}
+
bool A2DP_VendorAdjustCodec(uint8_t* p_codec_info) {
uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
@@ -507,6 +501,7 @@
case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
break; // These are not vendor-specific codecs
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
return A2DP_VendorCodecIndexStrAptx();
@@ -529,6 +524,7 @@
case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
break; // These are not vendor-specific codecs
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
return A2DP_VendorInitCodecConfigAptx(p_cfg);
diff --git a/stack/avrc/avrc_sdp.cc b/stack/avrc/avrc_sdp.cc
index 9ce38f5..eba96cc 100644
--- a/stack/avrc/avrc_sdp.cc
+++ b/stack/avrc/avrc_sdp.cc
@@ -209,7 +209,17 @@
}
result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list);
- /* add protocol descriptor list */
+ uint16_t protocol_reported_version;
+ /* AVRCP versions 1.3 to 1.5 report (version - 1) in the protocol
+ descriptor list. Oh, and 1.6 and 1.6.1 report version 1.4.
+ /because-we-smart */
+ if (profile_version < AVRC_REV_1_6) {
+ protocol_reported_version = profile_version - 1;
+ } else {
+ protocol_reported_version = AVCT_REV_1_4;
+ }
+
+ /* add protocol descriptor list */
tSDP_PROTOCOL_ELEM avrc_proto_desc_list[AVRC_NUM_PROTO_ELEMS];
avrc_proto_desc_list[0].num_params = 1;
avrc_proto_desc_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
@@ -218,13 +228,13 @@
for (index = 1; index < AVRC_NUM_PROTO_ELEMS; index++) {
avrc_proto_desc_list[index].num_params = 1;
avrc_proto_desc_list[index].protocol_uuid = UUID_PROTOCOL_AVCTP;
- avrc_proto_desc_list[index].params[0] = AVCT_REV_1_4;
+ avrc_proto_desc_list[index].params[0] = protocol_reported_version;
avrc_proto_desc_list[index].params[1] = 0;
}
result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS,
&avrc_proto_desc_list[0]);
- /* additional protocal descriptor, required only for version > 1.3 */
+ /* additional protocal descriptor, required only for version > 1.3 */
if ((profile_version > AVRC_REV_1_3) && (browse_supported)) {
tSDP_PROTO_LIST_ELEM avrc_add_proto_desc_list;
avrc_add_proto_desc_list.num_elems = 2;
@@ -234,7 +244,7 @@
avrc_add_proto_desc_list.list_elem[0].params[1] = 0;
avrc_add_proto_desc_list.list_elem[1].num_params = 1;
avrc_add_proto_desc_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_AVCTP;
- avrc_add_proto_desc_list.list_elem[1].params[0] = AVCT_REV_1_4;
+ avrc_add_proto_desc_list.list_elem[1].params[0] = protocol_reported_version;
avrc_add_proto_desc_list.list_elem[1].params[1] = 0;
result &=
diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc
index a3d9caa..d63187b 100644
--- a/stack/btm/btm_ble_gap.cc
+++ b/stack/btm/btm_ble_gap.cc
@@ -1841,10 +1841,10 @@
}
}
-void btm_ble_process_adv_addr(RawAddress& bda, uint8_t addr_type) {
+void btm_ble_process_adv_addr(RawAddress& bda, uint8_t* addr_type) {
#if (BLE_PRIVACY_SPT == TRUE)
/* map address to security record */
- bool match = btm_identity_addr_to_random_pseudo(&bda, &addr_type, false);
+ bool match = btm_identity_addr_to_random_pseudo(&bda, addr_type, false);
VLOG(1) << __func__ << ": bda=" << bda;
/* always do RRA resolution on host */
@@ -1915,7 +1915,7 @@
pkt_data_len, rssi);
}
- btm_ble_process_adv_addr(bda, addr_type);
+ btm_ble_process_adv_addr(bda, &addr_type);
btm_ble_process_adv_pkt_cont(event_type, addr_type, bda, primary_phy,
secondary_phy, advertising_sid, tx_power, rssi,
periodic_adv_int, pkt_data_len, pkt_data);
@@ -1962,7 +1962,7 @@
pkt_data_len, rssi);
}
- btm_ble_process_adv_addr(bda, addr_type);
+ btm_ble_process_adv_addr(bda, &addr_type);
uint16_t event_type;
if (legacy_evt_type == 0x00) { // ADV_IND;
diff --git a/stack/include/a2dp_aac.h b/stack/include/a2dp_aac.h
index ac85975..f2d2553 100644
--- a/stack/include/a2dp_aac.h
+++ b/stack/include/a2dp_aac.h
@@ -44,6 +44,24 @@
void debug_codec_dump(int fd) override;
};
+class A2dpCodecConfigAacSink : public A2dpCodecConfig {
+ public:
+ A2dpCodecConfigAacSink(btav_a2dp_codec_priority_t codec_priority);
+ virtual ~A2dpCodecConfigAacSink();
+
+ bool init() override;
+ period_ms_t encoderIntervalMs() const override;
+ bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+ uint8_t* p_result_codec_config) override;
+
+ private:
+ bool useRtpHeaderMarkerBit() const override;
+ bool updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ bool* p_restart_input, bool* p_restart_output,
+ bool* p_config_updated) override;
+};
+
// Checks whether the codec capabilities contain a valid A2DP AAC Source
// codec.
// NOTE: only codecs that are implemented are considered valid.
@@ -135,14 +153,6 @@
// contains invalid codec information.
int A2DP_GetSinkTrackChannelTypeAac(const uint8_t* p_codec_info);
-// Computes the number of frames to process in a time window for the A2DP
-// AAC sink codec. |time_interval_ms| is the time interval (in milliseconds).
-// |p_codec_info| is a pointer to the codec_info to decode.
-// Returns the number of frames to process on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_GetSinkFramesCountToProcessAac(uint64_t time_interval_ms,
- const uint8_t* p_codec_info);
-
// Gets the object type code for the A2DP AAC codec.
// The actual value is codec-specific - see |A2DP_AAC_OBJECT_TYPE_*|.
// |p_codec_info| is a pointer to the AAC codec_info to decode.
@@ -208,6 +218,14 @@
const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceAac(
const uint8_t* p_codec_info);
+// Gets the current A2DP AAC decoder interface that can be used to decode
+// received A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP AAC decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceAac(
+ const uint8_t* p_codec_info);
+
// Adjusts the A2DP AAC codec, based on local support and Bluetooth
// specification.
// |p_codec_info| contains the codec information to adjust.
@@ -222,8 +240,15 @@
// Gets the A2DP AAC Source codec name.
const char* A2DP_CodecIndexStrAac(void);
+// Gets the A2DP AAC Sink codec name.
+const char* A2DP_CodecIndexStrAacSink(void);
+
// Initializes A2DP AAC Source codec information into |tAVDT_CFG|
// configuration entry pointed by |p_cfg|.
bool A2DP_InitCodecConfigAac(tAVDT_CFG* p_cfg);
+// Initializes A2DP AAC Sink codec information into |tAVDT_CFG|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_InitCodecConfigAacSink(tAVDT_CFG* p_cfg);
+
#endif // A2DP_AAC_H
diff --git a/stack/include/a2dp_aac_decoder.h b/stack/include/a2dp_aac_decoder.h
new file mode 100644
index 0000000..53ffc52
--- /dev/null
+++ b/stack/include/a2dp_aac_decoder.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Interface to the A2DP AAC Decoder
+//
+
+#ifndef A2DP_AAC_DECODER_H
+#define A2DP_AAC_DECODER_H
+
+#include "a2dp_codec_api.h"
+
+// Loads the A2DP AAC decoder.
+// Return true on success, otherwise false.
+bool A2DP_LoadDecoderAac(void);
+
+// Unloads the A2DP AAC decoder.
+void A2DP_UnloadDecoderAac(void);
+
+// Initialize the A2DP AAC decoder.
+bool a2dp_aac_decoder_init(decoded_data_callback_t decode_callback);
+
+// Cleanup the A2DP AAC decoder.
+void a2dp_aac_decoder_cleanup(void);
+
+// Decodes |p_buf|. Calls |decode_callback| passed into |a2dp_aac_decoder_init|
+// if decoded frames are available.
+bool a2dp_aac_decoder_decode_packet(BT_HDR* p_buf);
+
+#endif // A2DP_AAC_DECODER_H
diff --git a/stack/include/a2dp_codec_api.h b/stack/include/a2dp_codec_api.h
index c10264a..ba62fbe 100644
--- a/stack/include/a2dp_codec_api.h
+++ b/stack/include/a2dp_codec_api.h
@@ -490,6 +490,27 @@
void (*set_transmit_queue_length)(size_t transmit_queue_length);
} tA2DP_ENCODER_INTERFACE;
+// Prototype for a callback to receive decoded audio data from a
+// tA2DP_DECODER_INTERFACE|.
+// |buf| is a pointer to the data.
+// |len| is the number of octets pointed to by |buf|.
+typedef void (*decoded_data_callback_t)(uint8_t* buf, uint32_t len);
+
+//
+// A2DP decoder callbacks interface.
+//
+typedef struct {
+ // Initialize the decoder. Can be called multiple times, will reinitalize.
+ bool (*decoder_init)(decoded_data_callback_t decode_callback);
+
+ // Cleanup the A2DP decoder.
+ void (*decoder_cleanup)();
+
+ // Decodes |p_buf| and calls |decode_callback| passed into init for the
+ // decoded data.
+ bool (*decode_packet)(BT_HDR* p_buf);
+} tA2DP_DECODER_INTERFACE;
+
// Gets the A2DP codec type.
// |p_codec_info| contains information about the codec capabilities.
tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info);
@@ -592,14 +613,6 @@
// contains invalid codec information.
int A2DP_GetSinkTrackChannelType(const uint8_t* p_codec_info);
-// Computes the number of frames to process in a time window for the A2DP
-// Sink codec. |time_interval_ms| is the time interval (in milliseconds).
-// |p_codec_info| is a pointer to the codec_info to decode.
-// Returns the number of frames to process on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_GetSinkFramesCountToProcess(uint64_t time_interval_ms,
- const uint8_t* p_codec_info);
-
// Gets the A2DP audio data timestamp from an audio packet.
// |p_codec_info| contains the codec information.
// |p_data| contains the audio data.
@@ -624,6 +637,14 @@
const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterface(
const uint8_t* p_codec_info);
+// Gets the A2DP decoder interface that can be used to decode received A2DP
+// packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterface(
+ const uint8_t* p_codec_info);
+
// Adjusts the A2DP codec, based on local support and Bluetooth specification.
// |p_codec_info| contains the codec information to adjust.
// Returns true if |p_codec_info| is valid and supported, otherwise false.
diff --git a/stack/include/a2dp_sbc.h b/stack/include/a2dp_sbc.h
index ee10858..51632ad 100644
--- a/stack/include/a2dp_sbc.h
+++ b/stack/include/a2dp_sbc.h
@@ -196,14 +196,6 @@
// contains invalid codec information.
int A2DP_GetSinkTrackChannelTypeSbc(const uint8_t* p_codec_info);
-// Computes the number of frames to process in a time window for the A2DP
-// SBC sink codec. |time_interval_ms| is the time interval (in milliseconds).
-// |p_codec_info| is a pointer to the codec_info to decode.
-// Returns the number of frames to process on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms,
- const uint8_t* p_codec_info);
-
// Gets the A2DP SBC audio data timestamp from an audio packet.
// |p_codec_info| contains the codec information.
// |p_data| contains the audio data.
@@ -233,6 +225,14 @@
const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceSbc(
const uint8_t* p_codec_info);
+// Gets the A2DP SBC decoder interface that can be used to decode received A2DP
+// packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP SBC decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_GetDecoderInterfaceSbc(
+ const uint8_t* p_codec_info);
+
// Adjusts the A2DP SBC codec, based on local support and Bluetooth
// specification.
// |p_codec_info| contains the codec information to adjust.
diff --git a/stack/include/a2dp_sbc_decoder.h b/stack/include/a2dp_sbc_decoder.h
new file mode 100644
index 0000000..f5ac99a
--- /dev/null
+++ b/stack/include/a2dp_sbc_decoder.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Interface to the A2DP SBC Decoder
+//
+
+#ifndef A2DP_SBC_DECODER_H
+#define A2DP_SBC_DECODER_H
+
+#include "a2dp_codec_api.h"
+
+// Loads the A2DP SBC decoder.
+// Return true on success, otherwise false.
+bool A2DP_LoadDecoderSbc(void);
+
+// Unloads the A2DP SBC decoder.
+void A2DP_UnloadDecoderSbc(void);
+
+// Initialize the A2DP SBC decoder.
+bool a2dp_sbc_decoder_init(decoded_data_callback_t decode_callback);
+
+// Cleanup the A2DP SBC decoder.
+void a2dp_sbc_decoder_cleanup(void);
+
+// Decodes |p_buf|. Calls |decode_callback| passed into |a2dp_sbc_decoder_init|
+// if decoded frames are available.
+bool a2dp_sbc_decoder_decode_packet(BT_HDR* p_buf);
+
+#endif // A2DP_SBC_DECODER_H
diff --git a/stack/include/a2dp_vendor.h b/stack/include/a2dp_vendor.h
index 97663fd..0547d46 100644
--- a/stack/include/a2dp_vendor.h
+++ b/stack/include/a2dp_vendor.h
@@ -139,15 +139,6 @@
// contains invalid codec information.
int A2DP_VendorGetSinkTrackChannelType(const uint8_t* p_codec_info);
-// Computes the number of frames to process in a time window for the A2DP
-// vendor-specific Sink codec. |time_interval_ms| is the time interval
-// (in milliseconds).
-// |p_codec_info| is a pointer to the codec_info to decode.
-// Returns the number of frames to process on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_VendorGetSinkFramesCountToProcess(uint64_t time_interval_ms,
- const uint8_t* p_codec_info);
-
// Gets the A2DP codec-specific audio data timestamp from an audio packet.
// |p_codec_info| contains the codec information.
// |p_data| contains the audio data.
@@ -173,6 +164,14 @@
const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterface(
const uint8_t* p_codec_info);
+// Gets the current A2DP vendor decoder interface that can be used to decode
+// received A2DP packets - see |tA2DP_DECODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP vendor decoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterface(
+ const uint8_t* p_codec_info);
+
// Adjusts the A2DP vendor-specific codec, based on local support and Bluetooth
// specification.
// |p_codec_info| contains the codec information to adjust.
diff --git a/stack/test/stack_a2dp_test.cc b/stack/test/stack_a2dp_test.cc
index b6a33b3..91c1c83 100644
--- a/stack/test/stack_a2dp_test.cc
+++ b/stack/test/stack_a2dp_test.cc
@@ -220,6 +220,9 @@
case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
supported = true;
break;
+ case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+ supported = true;
+ break;
case BTAV_A2DP_CODEC_INDEX_MAX:
// Needed to avoid using "default:" case so we can capture when
// a new codec is added, and it can be included here.
@@ -310,10 +313,10 @@
TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_aac) {
EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac));
EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac_capability));
- EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac));
- EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac_capability));
+ EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_aac));
+ EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_aac_capability));
- EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_aac_sink_capability));
+ EXPECT_TRUE(A2DP_IsSinkCodecValid(codec_info_aac_sink_capability));
EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_aac_sink_capability));
// Test with invalid AAC codecs
@@ -349,8 +352,11 @@
EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_sbc_capability));
EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_sbc_sink_capability));
- EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac));
- EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac_capability));
+ EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_aac));
+ // NOTE: The test below should be EXPECT_FALSE.
+ // However, codec_info_aac_capability is practically same as codec_info_aac,
+ // therefore we cannot differentiate it as a capability.
+ EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_aac_capability));
EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac_sink_capability));
EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_non_a2dp));
@@ -361,9 +367,9 @@
EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc_capability));
EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc_sink_capability));
- EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac));
- EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_capability));
- EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_sink_capability));
+ EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac));
+ EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_capability));
+ EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_sink_capability));
EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_non_a2dp));
}
@@ -607,16 +613,10 @@
TEST_F(StackA2dpTest, test_a2dp_get_sink_track_channel_type) {
EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_sbc), 3);
- EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_aac), -1);
+ EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_aac), 3);
EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_non_a2dp), -1);
}
-TEST_F(StackA2dpTest, test_a2dp_get_sink_frames_count_to_process) {
- EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_sbc), 7);
- EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_aac), -1);
- EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_non_a2dp), -1);
-}
-
TEST_F(StackA2dpTest, test_a2dp_get_object_type_code_aac) {
EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_sbc), -1);
EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_aac), 0x80);
diff --git a/test/run_host_unit_tests.py b/test/run_host_unit_tests.py
index 536ad21..e5e392c 100755
--- a/test/run_host_unit_tests.py
+++ b/test/run_host_unit_tests.py
@@ -77,7 +77,7 @@
current_path = parent_path
if not value:
print 'Cannot determine ANDROID_BUILD_TOP'
- sys.exit(0)
+ sys.exit(1)
check_dir_exists(value, '$ANDROID_BUILD_TOP')
return value
@@ -93,7 +93,7 @@
'HOST_OUT'))
if not value:
print 'Cannot determine ANDROID_HOST_OUT'
- sys.exit(0)
+ sys.exit(1)
check_dir_exists(value, '$ANDROID_HOST_OUT')
return value
@@ -108,7 +108,7 @@
if not os.path.isdir(value):
if os.path.exists(value):
print '%s is not a directory!' % (value)
- sys.exit(0)
+ sys.exit(1)
os.makedirs(value)
return value
@@ -121,7 +121,7 @@
if not os.path.isdir(test_root):
print 'Neither nativetest64 nor nativetest directory exist,' \
' please compile first'
- sys.exit(0)
+ sys.exit(1)
return test_root
@@ -129,7 +129,7 @@
test_path = os.path.join(os.path.join(test_root, test_name), test_name)
if not os.path.isfile(test_path):
print 'Cannot find: ' + test_path
- return None
+ sys.exit(1)
cmd = [test_path]
if enable_xml:
dist_dir = get_android_dist_dir_or_die()
@@ -149,9 +149,10 @@
build_cmd.append('-j' + str(num_tasks))
build_cmd.append(target)
p = subprocess.Popen(build_cmd, cwd=ANDROID_BUILD_TOP, env=os.environ.copy())
- if p.wait() != 0:
- print 'BUILD FAILED'
- sys.exit(0)
+ return_code = p.wait()
+ if return_code != 0:
+ print 'BUILD FAILED, return code: {0}'.format(str(return_code))
+ sys.exit(1)
return
@@ -187,9 +188,6 @@
test_results = []
for test in HOST_TESTS:
test_cmd = get_test_cmd_or_die(TEST_ROOT, test, args.enable_xml, args.rest)
- if not test_cmd:
- test_results.append(False)
- continue
if subprocess.call(test_cmd) != 0:
test_results.append(False)
else:
diff --git a/test/run_unit_tests.sh b/test/run_unit_tests.sh
index 4c390bf..8fe47f8 100755
--- a/test/run_unit_tests.sh
+++ b/test/run_unit_tests.sh
@@ -102,18 +102,11 @@
adb+=( "-s" "${device}" )
fi
-source ${ANDROID_BUILD_TOP}/build/envsetup.sh
-target_arch=$(gettargetarch)
-
failed_tests=()
for spec in "${tests[@]}"
do
name="${spec%%.*}"
- if [[ $target_arch == *"64"* ]]; then
- binary="/data/nativetest64/${name}/${name}"
- else
- binary="/data/nativetest/${name}/${name}"
- fi
+ binary="/data/nativetest/${name}/${name}"
push_command=( "${adb[@]}" push {"${ANDROID_PRODUCT_OUT}",}"${binary}" )
test_command=( "${adb[@]}" shell "${binary}" )
diff --git a/types/Android.bp b/types/Android.bp
index ed5c613..5867d63 100644
--- a/types/Android.bp
+++ b/types/Android.bp
@@ -6,11 +6,10 @@
host_supported: true,
}
-cc_library {
+cc_library_static {
name: "libbluetooth-types",
vendor_available: true,
defaults: ["fluoride_types_defaults"],
- compile_multilib: "both",
cflags: [
/* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/
"-fvisibility=default",