blob: 53b11c5a06c0994aa5568fbf0a62a3b0eb0d96a0 [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2017 Google, Inc.
*
* 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 "btif_a2dp_audio_interface"
#include "btif_a2dp_audio_interface.h"
#include <a2dp_vendor.h>
#include <a2dp_vendor_ldac_constants.h>
#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioHost.h>
#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
#include <android/hardware/bluetooth/a2dp/1.0/types.h>
#include <base/logging.h>
#include <hwbinder/ProcessState.h>
#include <utils/RefBase.h>
#include "a2dp_sbc.h"
#include "bt_common.h"
#include "bta/av/bta_av_int.h"
#include "btif_a2dp.h"
#include "btif_a2dp_control.h"
#include "btif_a2dp_sink.h"
#include "btif_a2dp_source.h"
#include "btif_av.h"
#include "btif_av_co.h"
#include "btif_hf.h"
#include "osi/include/osi.h"
using android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload;
using android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost;
using android::hardware::bluetooth::a2dp::V1_0::Status;
using android::hardware::bluetooth::a2dp::V1_0::CodecConfiguration;
using android::hardware::bluetooth::a2dp::V1_0::CodecType;
using android::hardware::bluetooth::a2dp::V1_0::SampleRate;
using android::hardware::bluetooth::a2dp::V1_0::BitsPerSample;
using android::hardware::bluetooth::a2dp::V1_0::ChannelMode;
using android::hardware::ProcessState;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::sp;
android::sp<IBluetoothAudioOffload> btAudio;
#define CASE_RETURN_STR(const) \
case const: \
return #const;
static uint8_t a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
static Status mapToStatus(uint8_t resp);
uint8_t btif_a2dp_audio_process_request(uint8_t cmd);
static void btif_a2dp_audio_send_start_req();
static void btif_a2dp_audio_send_suspend_req();
// Delay reporting
// static void btif_a2dp_audio_send_sink_latency();
class BluetoothAudioHost : public IBluetoothAudioHost {
public:
Return<void> startStream() {
btif_a2dp_audio_send_start_req();
return Void();
}
Return<void> suspendStream() {
btif_a2dp_audio_send_suspend_req();
return Void();
}
Return<void> stopStream() {
btif_a2dp_audio_process_request(A2DP_CTRL_CMD_STOP);
return Void();
}
// TODO : Delay reporting
/* Return<void> a2dp_get_sink_latency() {
LOG_INFO(LOG_TAG,"%s:start ", __func__);
btif_a2dp_audio_send_sink_latency();
return Void();
}*/
};
static Status mapToStatus(uint8_t resp) {
switch (resp) {
case A2DP_CTRL_ACK_SUCCESS:
return Status::SUCCESS;
break;
case A2DP_CTRL_ACK_PENDING:
return Status::PENDING;
break;
case A2DP_CTRL_ACK_FAILURE:
case A2DP_CTRL_ACK_INCALL_FAILURE:
case A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS:
return Status::FAILURE;
default:
APPL_TRACE_WARNING("%s: unknown status recevied :%d", __func__, resp);
return Status::FAILURE;
break;
}
}
static void btif_a2dp_get_codec_configuration(
CodecConfiguration* p_codec_info) {
LOG_INFO(LOG_TAG, "%s", __func__);
tBT_A2DP_OFFLOAD a2dp_offload;
tA2DP_ENCODER_INIT_PEER_PARAMS peer_param;
A2dpCodecConfig* CodecConfig = bta_av_get_a2dp_current_codec();
CodecConfig->getCodecSpecificConfig(&a2dp_offload);
btav_a2dp_codec_config_t codec_config;
codec_config = CodecConfig->getCodecConfig();
RawAddress peer_addr = btif_av_source_active_peer();
bta_av_co_get_peer_params(peer_addr, &peer_param);
switch (codec_config.codec_type) {
case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
p_codec_info->codecType =
(::android::hardware::bluetooth::a2dp::V1_0::CodecType)
BTA_AV_CODEC_TYPE_SBC;
p_codec_info->codecSpecific.sbcData.codecParameters =
a2dp_offload.codec_info[0];
LOG_INFO(LOG_TAG, " %s: codec parameters =%d", __func__,
a2dp_offload.codec_info[0]);
p_codec_info->codecSpecific.sbcData.minBitpool =
a2dp_offload.codec_info[1];
p_codec_info->codecSpecific.sbcData.maxBitpool =
a2dp_offload.codec_info[2];
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
p_codec_info->codecType =
(::android::hardware::bluetooth::a2dp::V1_0::CodecType)
BTA_AV_CODEC_TYPE_AAC;
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
p_codec_info->codecType =
(::android::hardware::bluetooth::a2dp::V1_0::CodecType)
BTA_AV_CODEC_TYPE_APTX;
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
p_codec_info->codecType =
(::android::hardware::bluetooth::a2dp::V1_0::CodecType)
BTA_AV_CODEC_TYPE_APTXHD;
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
p_codec_info->codecType =
(::android::hardware::bluetooth::a2dp::V1_0::CodecType)
BTA_AV_CODEC_TYPE_LDAC;
p_codec_info->codecSpecific.ldacData.bitrateIndex =
a2dp_offload.codec_info[6];
break;
default:
APPL_TRACE_ERROR("%s: Unknown Codec type :%d ", __func__,
codec_config.codec_type);
}
p_codec_info->peerMtu = peer_param.peer_mtu;
p_codec_info->sampleRate =
(::android::hardware::bluetooth::a2dp::V1_0::SampleRate)
codec_config.sample_rate;
p_codec_info->bitsPerSample =
(::android::hardware::bluetooth::a2dp::V1_0::BitsPerSample)
codec_config.bits_per_sample;
p_codec_info->channelMode =
(::android::hardware::bluetooth::a2dp::V1_0::ChannelMode)
codec_config.channel_mode;
p_codec_info->encodedAudioBitrate = CodecConfig->getTrackBitRate();
}
void btif_a2dp_audio_interface_init() {
LOG_INFO(LOG_TAG, "%s", __func__);
btAudio = IBluetoothAudioOffload::getService();
CHECK(btAudio != nullptr);
LOG_DEBUG(
LOG_TAG, "%s: IBluetoothAudioOffload::getService() returned %p (%s)",
__func__, btAudio.get(), (btAudio->isRemote() ? "remote" : "local"));
LOG_INFO(LOG_TAG, "%s:Init returned", __func__);
}
void btif_a2dp_audio_interface_deinit() {
LOG_INFO(LOG_TAG, "%s: start", __func__);
btAudio = nullptr;
LOG_INFO(LOG_TAG, "%s: exit", __func__);
}
void btif_a2dp_audio_interface_start_session() {
LOG_INFO(LOG_TAG, "%s", __func__);
CHECK(btAudio != nullptr);
CodecConfiguration codec_info;
btif_a2dp_get_codec_configuration(&codec_info);
android::sp<IBluetoothAudioHost> host_if = new BluetoothAudioHost();
btAudio->startSession(host_if, codec_info);
}
void btif_a2dp_audio_interface_end_session() {
LOG_INFO(LOG_TAG, "%s", __func__);
CHECK(btAudio != nullptr);
auto ret = btAudio->endSession();
if (!ret.isOk()) {
LOG_ERROR(LOG_TAG, "HAL server is dead");
}
}
void btif_a2dp_audio_on_started(tBTA_AV_STATUS status) {
LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
if (btAudio != nullptr) {
if (a2dp_cmd_pending == A2DP_CTRL_CMD_START) {
LOG_INFO(LOG_TAG, "%s: calling method onStarted", __func__);
btAudio->streamStarted(mapToStatus(status));
}
}
}
void btif_a2dp_audio_on_suspended(tBTA_AV_STATUS status) {
LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
if (btAudio != nullptr) {
if (a2dp_cmd_pending == A2DP_CTRL_CMD_SUSPEND) {
LOG_INFO(LOG_TAG, "calling method onSuspended");
btAudio->streamSuspended(mapToStatus(status));
}
}
}
void btif_a2dp_audio_on_stopped(tBTA_AV_STATUS status) {
LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
if (btAudio != nullptr && a2dp_cmd_pending == A2DP_CTRL_CMD_START) {
LOG_INFO(LOG_TAG, "%s: Remote disconnected when start under progress",
__func__);
btAudio->streamStarted(mapToStatus(A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS));
}
}
void btif_a2dp_audio_send_start_req() {
LOG_INFO(LOG_TAG, "%s", __func__);
uint8_t resp;
resp = btif_a2dp_audio_process_request(A2DP_CTRL_CMD_START);
if (btAudio != nullptr) {
auto ret = btAudio->streamStarted(mapToStatus(resp));
if (!ret.isOk()) LOG_ERROR(LOG_TAG, "HAL server died");
}
}
void btif_a2dp_audio_send_suspend_req() {
uint8_t resp;
resp = btif_a2dp_audio_process_request(A2DP_CTRL_CMD_SUSPEND);
if (btAudio != nullptr) {
auto ret = btAudio->streamSuspended(mapToStatus(resp));
if (!ret.isOk()) LOG_ERROR(LOG_TAG, "HAL server died");
}
}
/*void btif_a2dp_audio_send_sink_latency()
{
LOG_INFO(LOG_TAG, "%s", __func__);
uint16_t sink_latency = btif_av_get_sink_latency();
if (btAudio != nullptr) {
auto ret = btAudio->a2dp_on_get_sink_latency(sink_latency);
if (!ret.isOk()) LOG_ERROR(LOG_TAG, "server died");
}
}*/
uint8_t btif_a2dp_audio_process_request(uint8_t cmd) {
APPL_TRACE_DEBUG(LOG_TAG, "%s: cmd: %s", __func__,
audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
a2dp_cmd_pending = cmd;
uint8_t status;
switch (cmd) {
case A2DP_CTRL_CMD_START:
/*
* Don't send START request to stack while we are in a call.
* Some headsets such as "Sony MW600", don't allow AVDTP START
* while in a call, and respond with BAD_STATE.
*/
if (!bluetooth::headset::IsCallIdle()) {
status = A2DP_CTRL_ACK_INCALL_FAILURE;
break;
}
if (btif_av_stream_started_ready()) {
/*
* Already started, setup audio data channel listener and ACK
* back immediately.
*/
status = A2DP_CTRL_ACK_SUCCESS;
break;
}
if (btif_av_stream_ready()) {
/*
* Post start event and wait for audio path to open.
* If we are the source, the ACK will be sent after the start
* procedure is completed, othewise send it now.
*/
btif_av_stream_start();
if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
status = A2DP_CTRL_ACK_SUCCESS;
break;
}
/*Return pending and ack when start stream cfm received from remote*/
status = A2DP_CTRL_ACK_PENDING;
break;
}
APPL_TRACE_WARNING("%s: A2DP command %s while AV stream is not ready",
__func__,
audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
return A2DP_CTRL_ACK_FAILURE;
break;
case A2DP_CTRL_CMD_STOP:
if (btif_av_get_peer_sep() == AVDT_TSEP_SNK &&
!btif_a2dp_source_is_streaming()) {
/* We are already stopped, just ack back */
status = A2DP_CTRL_ACK_SUCCESS;
break;
}
btif_av_stream_stop();
return A2DP_CTRL_ACK_SUCCESS;
break;
case A2DP_CTRL_CMD_SUSPEND:
/* Local suspend */
if (btif_av_stream_started_ready()) {
btif_av_stream_suspend();
status = A2DP_CTRL_ACK_PENDING;
break;
}
/* If we are not in started state, just ack back ok and let
* audioflinger close the channel. This can happen if we are
* remotely suspended, clear REMOTE SUSPEND flag.
*/
btif_av_clear_remote_suspend_flag();
status = A2DP_CTRL_ACK_SUCCESS;
break;
case A2DP_CTRL_CMD_OFFLOAD_START:
btif_av_stream_start_offload();
status = A2DP_CTRL_ACK_PENDING;
break;
default:
APPL_TRACE_ERROR("UNSUPPORTED CMD (%d)", cmd);
status = A2DP_CTRL_ACK_FAILURE;
break;
}
APPL_TRACE_DEBUG("a2dp-ctrl-cmd : %s DONE",
audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
return status;
}