* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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.
*/
#include <map>
#include <hdf_log.h>
#include <atomic>
#include "audio_internal.h"
#include "i_bluetooth_a2dp_src.h"
#include "i_bluetooth_host.h"
#include "bluetooth_host_proxy.h"
#include "bluetooth_a2dp_src_observer.h"
#include "bluetooth_def.h"
#include "iservice_registry.h"
#include "system_ability_definition.h"
#include "audio_bluetooth_manager.h"
#ifdef A2DP_HDI_SERVICE
#include "bluetooth_audio_device.h"
#endif
#define HDF_LOG_TAG BTAudioBluetoothManager
namespace OHOS {
namespace Bluetooth {
using namespace OHOS::bluetooth;
#ifdef A2DP_HDI_SERVICE
using namespace OHOS::bluetooth::audio;
static const char *g_bluetoothAudioDeviceSoPath = HDF_LIBRARY_FULL_PATH("libbluetooth_audio_session");
static void *g_ptrAudioDeviceHandle = NULL;
std::atomic_bool g_allowAudioStart = true;
SetUpFunc setUpFunc;
TearDownFunc tearDownFunc;
GetStateFunc getStateFunc;
StartPlayingFunc startPlayingFunc;
SuspendPlayingFunc suspendPlayingFunc;
StopPlayingFunc stopPlayingFunc;
WriteFrameFunc writeFrameFunc;
GetLatencyFunc getLatencyFunc;
SetUpFunc fastSetUpFunc;
TearDownFunc fastTearDownFunc;
GetStateFunc fastGetStateFunc;
StartPlayingFunc fastStartPlayingFunc;
SuspendPlayingFunc fastSuspendPlayingFunc;
StopPlayingFunc fastStopPlayingFunc;
ReqMmapBufferFunc fastReqMmapBufferFunc;
ReadMmapPositionFunc fastReadMmapPositionFunc;
GetLatencyFunc fastGetLatencyFunc;
GetRealStateFunc getRealStateFunc;
GetRenderMixerStateFunc getRenderMixerStateFunc;
SetUpFunc setUpCaptureFunc;
TearDownFunc tearDownCaptureFunc;
GetStateFunc getCaptureStateFunc;
StartCaptureFunc startCaptureFunc;
SuspendPlayingFunc suspendCaptureFunc;
StopPlayingFunc stopCaptureFunc;
ReadFrameFunc readFrameFunc;
SetUpFunc setUpHearingAidFunc;
TearDownFunc tearDownHearingAidFunc;
GetStateFunc getHearingAidStateFunc;
StartHearingAidFunc startHearingAidFunc;
SuspendPlayingFunc suspendHearingAidFunc;
StopPlayingFunc stopHearingAidFunc;
WriteFrameFunc writeFrameHearingAidFunc;
#endif
sptr<IBluetoothA2dpSrc> g_proxy_ = nullptr;
static sptr<BluetoothA2dpSrcObserver> g_btA2dpSrcObserverCallbacks = nullptr;
int g_playState = A2DP_NOT_PLAYING;
std::map<int, std::string> g_playdevices {};
std::mutex g_playStateMutex;
static void AudioOnConnectionStateChanged(const RawAddress &device, int state, int cause)
{
HDF_LOGI("%{public}s, state:%{public}d", __func__, state);
(void) state;
(void) cause;
}
static void AudioOnPlayingStatusChanged(const RawAddress &device, int playingState, int error)
{
HDF_LOGI("%{public}s, playingState:%{public}d", __func__, playingState);
std::lock_guard<std::mutex> lock(g_playStateMutex);
std::string addr = device.GetAddress();
if (playingState) {
for (const auto &it : g_playdevices) {
if (strcmp(it.second.c_str(), device.GetAddress().c_str()) == 0) {
return;
}
}
g_playdevices.insert(std::make_pair(playingState, addr));
g_playState = playingState;
} else {
std::map<int, std::string>::iterator it;
for (it = g_playdevices.begin(); it != g_playdevices.end(); it++) {
if (strcmp(it->second.c_str(), device.GetAddress().c_str()) == 0) {
g_playdevices.erase(it);
break;
}
}
if (g_playdevices.empty()) {
g_playState = playingState;
}
}
(void) error;
}
static void AudioOnConfigurationChanged(const RawAddress &device, const BluetoothA2dpCodecInfo &info, int error)
{
(void) device;
(void) info;
(void) error;
}
static void AudioOnMediaStackChanged(const RawAddress &device, int action)
{
(void) device;
(void) action;
}
static BtA2dpAudioCallback g_hdiCallbacks = {
.OnConnectionStateChanged = AudioOnConnectionStateChanged,
.OnPlayingStatusChanged = AudioOnPlayingStatusChanged,
.OnConfigurationChanged = AudioOnConfigurationChanged,
.OnMediaStackChanged = AudioOnMediaStackChanged,
};
int GetPlayingState()
{
HDF_LOGI("%{public}s: state:%{public}d", __func__, g_playState);
return g_playState;
}
void GetProxy()
{
HDF_LOGI("%{public}s start", __func__);
sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (!samgr) {
HDF_LOGE("%{public}s: error: no samgr", __func__);
return;
}
sptr<IRemoteObject> hostRemote = samgr->GetSystemAbility(BLUETOOTH_HOST_SYS_ABILITY_ID);
if (!hostRemote) {
HDF_LOGE("%{public}s: failed: no hostRemote", __func__);
return;
}
sptr<IBluetoothHost> hostProxy = new BluetoothHostProxy(hostRemote);
if (!hostProxy) {
HDF_LOGE("%{public}s: error: host no proxy", __func__);
return;
}
sptr<IRemoteObject> remote = hostProxy->GetProfile("A2dpSrcServer");
if (!remote) {
HDF_LOGE("%{public}s: error: no remote", __func__);
return;
}
g_proxy_ = iface_cast<IBluetoothA2dpSrc>(remote);
if (!g_proxy_) {
HDF_LOGE("%{public}s: error: no proxy", __func__);
return;
}
}
void RegisterObserver()
{
HDF_LOGI("%{public}s", __func__);
g_btA2dpSrcObserverCallbacks = new (std::nothrow) BluetoothA2dpSrcObserver(&g_hdiCallbacks);
if (!g_btA2dpSrcObserverCallbacks) {
HDF_LOGE("%{public}s: g_btA2dpSrcObserverCallbacks is null", __func__);
return;
}
if (!g_proxy_) {
HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
return;
}
g_proxy_->RegisterObserver(g_btA2dpSrcObserverCallbacks);
}
void DeRegisterObserver()
{
HDF_LOGI("%{public}s", __func__);
if (!g_proxy_) {
HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
return;
}
g_proxy_->DeregisterObserver(g_btA2dpSrcObserverCallbacks);
}
#ifdef A2DP_HDI_SERVICE
#define GET_SYM_ERRPR_RET(handle, funcType, funcPtr, funcStr) \
do { \
funcPtr = (funcType)dlsym(handle, funcStr); \
if (funcPtr == nullptr) { \
HDF_LOGE("%{public}s: lib so func not found", funcStr); \
return false; \
} \
} while (0)
static bool InitHearingAidDevice()
{
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SetUpFunc, setUpHearingAidFunc, "SetUpHearingAid");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, TearDownFunc, tearDownHearingAidFunc, "TearDownHearingAid");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetStateFunc, getHearingAidStateFunc, "GetHearingAidState");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StartHearingAidFunc, startHearingAidFunc, "StartHearingAid");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SuspendPlayingFunc, suspendHearingAidFunc, "SuspendHearingAid");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StopPlayingFunc, stopHearingAidFunc, "StopHearingAid");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, WriteFrameFunc, writeFrameHearingAidFunc, "WriteFrameHearingAid");
return true;
}
static bool InitAudioDeviceSoHandle(const char *path)
{
if (path == NULL) {
HDF_LOGE("%{public}s: path is NULL", __func__);
return false;
}
char pathBuf[PATH_MAX] = {'\0'};
if (realpath(path, pathBuf) == NULL) {
return false;
}
if (g_ptrAudioDeviceHandle == NULL) {
g_ptrAudioDeviceHandle = dlopen(pathBuf, RTLD_LAZY);
if (g_ptrAudioDeviceHandle == NULL) {
HDF_LOGE("%{public}s: open lib so fail, reason:%{public}s ", __func__, dlerror());
return false;
}
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SetUpFunc, setUpFunc, "SetUp");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, TearDownFunc, tearDownFunc, "TearDown");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetStateFunc, getStateFunc, "GetState");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StartPlayingFunc, startPlayingFunc, "StartPlaying");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SuspendPlayingFunc, suspendPlayingFunc, "SuspendPlaying");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StopPlayingFunc, stopPlayingFunc, "StopPlaying");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, WriteFrameFunc, writeFrameFunc, "WriteFrame");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetLatencyFunc, getLatencyFunc, "GetLatency");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SetUpFunc, fastSetUpFunc, "FastSetUp");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, TearDownFunc, fastTearDownFunc, "FastTearDown");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetStateFunc, fastGetStateFunc, "FastGetState");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StartPlayingFunc, fastStartPlayingFunc, "FastStartPlaying");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SuspendPlayingFunc, fastSuspendPlayingFunc, "FastSuspendPlaying");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StopPlayingFunc, fastStopPlayingFunc, "FastStopPlaying");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, ReqMmapBufferFunc, fastReqMmapBufferFunc, "FastReqMmapBuffer");
GET_SYM_ERRPR_RET(
g_ptrAudioDeviceHandle, ReadMmapPositionFunc, fastReadMmapPositionFunc, "FastReadMmapPosition");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetLatencyFunc, fastGetLatencyFunc, "FastGetLatency");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetRealStateFunc, getRealStateFunc, "GetRealState");
GET_SYM_ERRPR_RET(
g_ptrAudioDeviceHandle, GetRenderMixerStateFunc, getRenderMixerStateFunc, "GetRenderMixerState");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SetUpFunc, setUpCaptureFunc, "SetUpCapture");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, TearDownFunc, tearDownCaptureFunc, "TearDownCapture");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetStateFunc, getCaptureStateFunc, "GetCaptureState");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StartCaptureFunc, startCaptureFunc, "StartCapture");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SuspendPlayingFunc, suspendCaptureFunc, "SuspendCapture");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StopPlayingFunc, stopCaptureFunc, "StopCapture");
GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, ReadFrameFunc, readFrameFunc, "ReadFrame");
if (!InitHearingAidDevice()) {
return false;
}
}
return true;
}
bool SetUp()
{
bool ret = false;
ret = InitAudioDeviceSoHandle(g_bluetoothAudioDeviceSoPath);
if (ret == true) {
ret = setUpFunc();
}
if (ret == false) {
HDF_LOGE("%{public}s failed!", __func__);
}
return ret;
}
bool SetUpCapture()
{
bool ret = InitAudioDeviceSoHandle(g_bluetoothAudioDeviceSoPath);
if (ret) {
ret = setUpCaptureFunc();
}
if (!ret) {
HDF_LOGE("%{public}s failed!", __func__);
}
return ret;
}
bool SetUpHearingAid()
{
bool ret = InitAudioDeviceSoHandle(g_bluetoothAudioDeviceSoPath);
if (ret) {
ret = setUpHearingAidFunc();
}
if (!ret) {
HDF_LOGE("%{public}s failed!", __func__);
}
return ret;
}
void TearDown()
{
tearDownFunc();
}
void TearDownCapture()
{
tearDownCaptureFunc();
}
void TearDownHearingAid()
{
tearDownHearingAidFunc();
}
bool FastSetUp()
{
bool ret = InitAudioDeviceSoHandle(g_bluetoothAudioDeviceSoPath);
if (ret) {
ret = fastSetUpFunc();
}
if (!ret) {
HDF_LOGE("%{public}s failed", __func__);
}
return ret;
}
void FastTearDown()
{
fastTearDownFunc();
}
int FastStartPlaying(uint32_t sampleRate, uint32_t channelCount, uint32_t format)
{
BTAudioStreamState state = fastGetStateFunc();
if (!g_allowAudioStart.load()) {
HDF_LOGE("not allow to start fast render, state=%{public}hhu", state);
return HDF_FAILURE;
} else if (state != BTAudioStreamState::STARTED) {
HDF_LOGI("%{public}s, state=%{public}hhu", __func__, state);
if (!fastStartPlayingFunc(sampleRate, channelCount, format)) {
HDF_LOGE("%{public}s, fail to startPlaying", __func__);
return HDF_FAILURE;
}
}
return HDF_SUCCESS;
}
int FastSuspendPlayingFromParam()
{
int ret = 0;
RenderMixerState renderState = getRenderMixerStateFunc();
if (!g_allowAudioStart.load()) {
if (renderState == RenderMixerState::INITED || renderState == RenderMixerState::NORMAL_ON_MIX_STOP) {
HDF_LOGE("fast render is already stopping or stopped");
return ret;
}
}
BTAudioStreamState state = fastGetStateFunc();
BTAudioStreamState realState = getRealStateFunc();
g_allowAudioStart = false;
if (state == BTAudioStreamState::STARTED) {
HDF_LOGI("%{public}s", __func__);
ret = (fastSuspendPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
} else if (realState == BTAudioStreamState::STARTING && renderState == RenderMixerState::FAST_STARTED) {
HDF_LOGI("%{public}s fast render starting, so stopPlaying", __func__);
ret = (fastStopPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
} else {
HDF_LOGE("%{public}s, state=%{public}hhu is bad state, realState=%{public}hhu, renderState=%{public}hhu",
__func__, state, realState, renderState);
}
return ret;
}
int FastSuspendPlaying()
{
int ret = 0;
BTAudioStreamState state = fastGetStateFunc();
if (state == BTAudioStreamState::STARTED) {
ret = (fastSuspendPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
} else {
HDF_LOGE("%{public}s, state=%{public}hhu is bad state", __func__, state);
}
return ret;
}
int FastStopPlaying()
{
BTAudioStreamState state = fastGetStateFunc();
HDF_LOGI("%{public}s, state=%{public}hhu", __func__, state);
if (state != BTAudioStreamState::INVALID) {
fastStopPlayingFunc();
}
return HDF_SUCCESS;
}
int FastReqMmapBuffer(int32_t ashmemLength)
{
return fastReqMmapBufferFunc(ashmemLength);
}
void FastReadMmapPosition(int64_t &sec, int64_t &nSec, uint64_t &frames)
{
fastReadMmapPositionFunc(sec, nSec, frames);
}
int FastGetLatency(uint32_t &latency)
{
return (fastGetLatencyFunc(latency) ? HDF_SUCCESS : HDF_FAILURE);
}
int SuspendPlayingFromParam()
{
int retVal = 0;
RenderMixerState renderState = getRenderMixerStateFunc();
if (!g_allowAudioStart.load()) {
if (renderState == RenderMixerState::INITED || renderState == RenderMixerState::FAST_ON_MIX_STOP) {
HDF_LOGE("normal render is already stopping or stopped");
return retVal;
}
}
BTAudioStreamState state = getStateFunc();
BTAudioStreamState realState = getRealStateFunc();
g_allowAudioStart = false;
if (state == BTAudioStreamState::STARTED) {
HDF_LOGI("%{public}s", __func__);
retVal = (suspendPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
} else if (realState == BTAudioStreamState::STARTING && renderState == RenderMixerState::INITED) {
HDF_LOGI("%{public}s normal render starting, so stopPlaying", __func__);
retVal = (stopPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
} else {
HDF_LOGE("%{public}s, state=%{public}hhu is bad state, realState=%{public}hhu, renderState=%{public}hhu",
__func__, state, realState, renderState);
}
return retVal;
}
void UnBlockStart()
{
g_allowAudioStart = true;
}
int StartCapture()
{
BTAudioStreamState state = getCaptureStateFunc();
if (state != BTAudioStreamState::STARTED) {
HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
if (!startCaptureFunc()) {
HDF_LOGE("%{public}s: fail to startPlaying", __func__);
return HDF_FAILURE;
}
}
return HDF_SUCCESS;
}
int SuspendCapture()
{
int ret = 0;
BTAudioStreamState state = getCaptureStateFunc();
if (state == BTAudioStreamState::STARTED) {
ret = suspendCaptureFunc() ? HDF_SUCCESS : HDF_FAILURE;
} else {
HDF_LOGE("%{public}s: state=%{public}hhu is bad state", __func__, state);
}
return ret;
}
int StopCapture()
{
BTAudioStreamState state = getCaptureStateFunc();
HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
if (state != BTAudioStreamState::INVALID) {
stopCaptureFunc();
}
return HDF_SUCCESS;
}
int ReadFrame(uint8_t *data, uint64_t size)
{
HDF_LOGD("%{public}s", __func__);
return readFrameFunc(data, size);
}
int StartHearingAid()
{
BTAudioStreamState state = getHearingAidStateFunc();
if (state != BTAudioStreamState::STARTED) {
HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
if (!startHearingAidFunc()) {
HDF_LOGE("%{public}s: fail to startPlaying", __func__);
return HDF_FAILURE;
}
}
return HDF_SUCCESS;
}
int SuspendHearingAid()
{
int ret = 0;
BTAudioStreamState state = getHearingAidStateFunc();
if (state == BTAudioStreamState::STARTED) {
ret = suspendHearingAidFunc() ? HDF_SUCCESS : HDF_FAILURE;
} else {
HDF_LOGE("%{public}s: state=%{public}hhu is bad state", __func__, state);
}
return ret;
}
int StopHearingAid()
{
BTAudioStreamState state = getHearingAidStateFunc();
HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
if (state != BTAudioStreamState::INVALID) {
stopHearingAidFunc();
}
return HDF_SUCCESS;
}
#endif
int WriteFrameHearingAid(const uint8_t *data, uint32_t size, const HDI::Audio_Bluetooth::AudioSampleAttributes *attrs)
{
HDF_LOGD("%{public}s", __func__);
#ifdef A2DP_HDI_SERVICE
BTAudioStreamState state = getHearingAidStateFunc();
if (state != BTAudioStreamState::STARTED) {
HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
if (!startHearingAidFunc()) {
HDF_LOGE("%{public}s: fail to startHearingAid", __func__);
return HDF_FAILURE;
}
}
return writeFrameHearingAidFunc(data, size);
#else
return HDF_ERR_NOT_SUPPORT;
#endif
}
int WriteFrame(const uint8_t *data, uint32_t size, const HDI::Audio_Bluetooth::AudioSampleAttributes *attrs)
{
HDF_LOGD("%{public}s", __func__);
#ifdef A2DP_HDI_SERVICE
BTAudioStreamState state = getStateFunc();
if (!g_allowAudioStart.load()) {
HDF_LOGE("not allow to start normal render, state=%{public}hhu", state);
return HDF_FAILURE;
} else if (state != BTAudioStreamState::STARTED) {
HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
if (!startPlayingFunc(attrs->sampleRate, attrs->channelCount, static_cast<uint32_t>(attrs->format))) {
HDF_LOGE("%{public}s: fail to startPlaying", __func__);
return HDF_FAILURE;
}
}
return writeFrameFunc(data, size);
#else
if (!g_proxy_) {
HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
return RET_BAD_STATUS;
}
if (g_playState == A2DP_NOT_PLAYING) {
HDF_LOGE("%{public}s: playState is not Streaming", __func__);
return RET_BAD_STATUS;
}
return g_proxy_->WriteFrame(data, size);
#endif
}
int StartPlaying()
{
HDF_LOGI("%{public}s", __func__);
#ifdef A2DP_HDI_SERVICE
return HDF_SUCCESS;
#else
if (!g_proxy_) {
HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
return RET_BAD_STATUS;
}
return g_proxy_->StartPlaying(g_proxy_->GetActiveSinkDevice());
#endif
}
int SuspendPlaying()
{
#ifdef A2DP_HDI_SERVICE
int retval = 0;
BTAudioStreamState state = getStateFunc();
HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
if (state == BTAudioStreamState::STARTED) {
retval = (suspendPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
} else {
HDF_LOGE("%{public}s: state=%{public}hhu is bad state", __func__, state);
}
return retval;
#else
HDF_LOGI("%{public}s", __func__);
if (!g_proxy_) {
HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
return RET_BAD_STATUS;
}
return g_proxy_->SuspendPlaying(g_proxy_->GetActiveSinkDevice());
#endif
}
int StopPlaying()
{
HDF_LOGI("%{public}s", __func__);
#ifdef A2DP_HDI_SERVICE
BTAudioStreamState state = getStateFunc();
HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
if (state != BTAudioStreamState::INVALID) {
stopPlayingFunc();
}
return HDF_SUCCESS;
#else
if (!g_proxy_) {
HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
return RET_BAD_STATUS;
}
return g_proxy_->StopPlaying(g_proxy_->GetActiveSinkDevice());
#endif
}
int GetLatency(uint32_t &latency)
{
HDF_LOGD("%{public}s", __func__);
#ifdef A2DP_HDI_SERVICE
return (getLatencyFunc(latency) ? HDF_SUCCESS : HDF_FAILURE);
#else
return HDF_ERR_NOT_SUPPORT;
#endif
}
}
}