1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <map>
17 #include <hdf_log.h>
18 #include <atomic>
19 #include "audio_internal.h"
20 #include "i_bluetooth_a2dp_src.h"
21 #include "i_bluetooth_host.h"
22 #include "bluetooth_a2dp_src_observer.h"
23 #include "bluetooth_def.h"
24 #include "iservice_registry.h"
25 #include "system_ability_definition.h"
26 #include "audio_bluetooth_manager.h"
27
28 #ifdef A2DP_HDI_SERVICE
29 #include "bluetooth_audio_device.h"
30 #endif
31
32 #define HDF_LOG_TAG BTAudioBluetoothManager
33
34 namespace OHOS {
35 namespace Bluetooth {
36 using namespace OHOS::bluetooth;
37
38 #ifdef A2DP_HDI_SERVICE
39 using namespace OHOS::bluetooth::audio;
40 static const char *g_bluetoothAudioDeviceSoPath = HDF_LIBRARY_FULL_PATH("libbluetooth_audio_session");
41 static void *g_ptrAudioDeviceHandle = NULL;
42 std::atomic_bool g_allowAudioStart = true;
43
44 SetUpFunc setUpFunc;
45 TearDownFunc tearDownFunc;
46 GetStateFunc getStateFunc;
47 StartPlayingFunc startPlayingFunc;
48 SuspendPlayingFunc suspendPlayingFunc;
49 StopPlayingFunc stopPlayingFunc;
50 WriteFrameFunc writeFrameFunc;
51 GetLatencyFunc getLatencyFunc;
52
53 SetUpFunc fastSetUpFunc;
54 TearDownFunc fastTearDownFunc;
55 GetStateFunc fastGetStateFunc;
56 StartPlayingFunc fastStartPlayingFunc;
57 SuspendPlayingFunc fastSuspendPlayingFunc;
58 StopPlayingFunc fastStopPlayingFunc;
59 ReqMmapBufferFunc fastReqMmapBufferFunc;
60 ReadMmapPositionFunc fastReadMmapPositionFunc;
61 GetLatencyFunc fastGetLatencyFunc;
62 GetRealStateFunc getRealStateFunc;
63 GetRenderMixerStateFunc getRenderMixerStateFunc;
64
65 SetUpFunc setUpCaptureFunc;
66 TearDownFunc tearDownCaptureFunc;
67 GetStateFunc getCaptureStateFunc;
68 StartCaptureFunc startCaptureFunc;
69 SuspendPlayingFunc suspendCaptureFunc;
70 StopPlayingFunc stopCaptureFunc;
71 ReadFrameFunc readFrameFunc;
72 #endif
73
74 sptr<IBluetoothA2dpSrc> g_proxy_ = nullptr;
75 static sptr<BluetoothA2dpSrcObserver> g_btA2dpSrcObserverCallbacks = nullptr;
76 int g_playState = A2DP_NOT_PLAYING;
77 std::map<int, std::string> g_playdevices {};
78 std::mutex g_playStateMutex;
79
AudioOnConnectionStateChanged(const RawAddress & device,int state,int cause)80 static void AudioOnConnectionStateChanged(const RawAddress &device, int state, int cause)
81 {
82 HDF_LOGI("%{public}s, state:%{public}d", __func__, state);
83 (void) state;
84 (void) cause;
85 }
86
AudioOnPlayingStatusChanged(const RawAddress & device,int playingState,int error)87 static void AudioOnPlayingStatusChanged(const RawAddress &device, int playingState, int error)
88 {
89 HDF_LOGI("%{public}s, playingState:%{public}d", __func__, playingState);
90 std::lock_guard<std::mutex> lock(g_playStateMutex);
91 std::string addr = device.GetAddress();
92 if (playingState) {
93 for (const auto &it : g_playdevices) {
94 if (strcmp(it.second.c_str(), device.GetAddress().c_str()) == 0) {
95 return;
96 }
97 }
98 g_playdevices.insert(std::make_pair(playingState, addr));
99 g_playState = playingState;
100 } else {
101 std::map<int, std::string>::iterator it;
102 for (it = g_playdevices.begin(); it != g_playdevices.end(); it++) {
103 if (strcmp(it->second.c_str(), device.GetAddress().c_str()) == 0) {
104 g_playdevices.erase(it);
105 break;
106 }
107 }
108 if (g_playdevices.empty()) {
109 g_playState = playingState;
110 }
111 }
112 (void) error;
113 }
114
AudioOnConfigurationChanged(const RawAddress & device,const BluetoothA2dpCodecInfo & info,int error)115 static void AudioOnConfigurationChanged(const RawAddress &device, const BluetoothA2dpCodecInfo &info, int error)
116 {
117 (void) device;
118 (void) info;
119 (void) error;
120 }
121
AudioOnMediaStackChanged(const RawAddress & device,int action)122 static void AudioOnMediaStackChanged(const RawAddress &device, int action)
123 {
124 (void) device;
125 (void) action;
126 }
127
128
129 static BtA2dpAudioCallback g_hdiCallbacks = {
130 .OnConnectionStateChanged = AudioOnConnectionStateChanged,
131 .OnPlayingStatusChanged = AudioOnPlayingStatusChanged,
132 .OnConfigurationChanged = AudioOnConfigurationChanged,
133 .OnMediaStackChanged = AudioOnMediaStackChanged,
134 };
135
GetPlayingState()136 int GetPlayingState()
137 {
138 HDF_LOGI("%{public}s: state:%{public}d", __func__, g_playState);
139 return g_playState;
140 }
141
GetProxy()142 void GetProxy()
143 {
144 HDF_LOGI("%{public}s start", __func__);
145 sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
146 if (!samgr) {
147 HDF_LOGE("%{public}s: error: no samgr", __func__);
148 return;
149 }
150
151 sptr<IRemoteObject> hostRemote = samgr->GetSystemAbility(BLUETOOTH_HOST_SYS_ABILITY_ID);
152 if (!hostRemote) {
153 HDF_LOGE("%{public}s: failed: no hostRemote", __func__);
154 return;
155 }
156
157 sptr<IBluetoothHost> hostProxy = iface_cast<IBluetoothHost>(hostRemote);
158 if (!hostProxy) {
159 HDF_LOGE("%{public}s: error: host no proxy", __func__);
160 return;
161 }
162
163 sptr<IRemoteObject> remote = hostProxy->GetProfile("A2dpSrcServer");
164 if (!remote) {
165 HDF_LOGE("%{public}s: error: no remote", __func__);
166 return;
167 }
168
169 g_proxy_ = iface_cast<IBluetoothA2dpSrc>(remote);
170 if (!g_proxy_) {
171 HDF_LOGE("%{public}s: error: no proxy", __func__);
172 return;
173 }
174 }
175
RegisterObserver()176 void RegisterObserver()
177 {
178 HDF_LOGI("%{public}s", __func__);
179 g_btA2dpSrcObserverCallbacks = new (std::nothrow) BluetoothA2dpSrcObserver(&g_hdiCallbacks);
180 if (!g_btA2dpSrcObserverCallbacks) {
181 HDF_LOGE("%{public}s: g_btA2dpSrcObserverCallbacks is null", __func__);
182 return;
183 }
184 if (!g_proxy_) {
185 HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
186 return;
187 }
188 g_proxy_->RegisterObserver(g_btA2dpSrcObserverCallbacks);
189 }
190
DeRegisterObserver()191 void DeRegisterObserver()
192 {
193 HDF_LOGI("%{public}s", __func__);
194 if (!g_proxy_) {
195 HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
196 return;
197 }
198 g_proxy_->DeregisterObserver(g_btA2dpSrcObserverCallbacks);
199 }
200
201 #ifdef A2DP_HDI_SERVICE
202 #define GET_SYM_ERRPR_RET(handle, funcType, funcPtr, funcStr) \
203 do { \
204 funcPtr = (funcType)dlsym(handle, funcStr); \
205 if (funcPtr == nullptr) { \
206 HDF_LOGE("%{public}s: lib so func not found", funcStr); \
207 return false; \
208 } \
209 } while (0)
210
InitAudioDeviceSoHandle(const char * path)211 static bool InitAudioDeviceSoHandle(const char *path)
212 {
213 if (path == NULL) {
214 HDF_LOGE("%{public}s: path is NULL", __func__);
215 return false;
216 }
217 char pathBuf[PATH_MAX] = {'\0'};
218 if (realpath(path, pathBuf) == NULL) {
219 return false;
220 }
221 if (g_ptrAudioDeviceHandle == NULL) {
222 g_ptrAudioDeviceHandle = dlopen(pathBuf, RTLD_LAZY);
223 if (g_ptrAudioDeviceHandle == NULL) {
224 HDF_LOGE("%{public}s: open lib so fail, reason:%{public}s ", __func__, dlerror());
225 return false;
226 }
227 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SetUpFunc, setUpFunc, "SetUp");
228 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, TearDownFunc, tearDownFunc, "TearDown");
229 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetStateFunc, getStateFunc, "GetState");
230 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StartPlayingFunc, startPlayingFunc, "StartPlaying");
231 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SuspendPlayingFunc, suspendPlayingFunc, "SuspendPlaying");
232 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StopPlayingFunc, stopPlayingFunc, "StopPlaying");
233 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, WriteFrameFunc, writeFrameFunc, "WriteFrame");
234 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetLatencyFunc, getLatencyFunc, "GetLatency");
235
236 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SetUpFunc, fastSetUpFunc, "FastSetUp");
237 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, TearDownFunc, fastTearDownFunc, "FastTearDown");
238 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetStateFunc, fastGetStateFunc, "FastGetState");
239 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StartPlayingFunc, fastStartPlayingFunc, "FastStartPlaying");
240 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SuspendPlayingFunc, fastSuspendPlayingFunc, "FastSuspendPlaying");
241 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StopPlayingFunc, fastStopPlayingFunc, "FastStopPlaying");
242 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, ReqMmapBufferFunc, fastReqMmapBufferFunc, "FastReqMmapBuffer");
243 GET_SYM_ERRPR_RET(
244 g_ptrAudioDeviceHandle, ReadMmapPositionFunc, fastReadMmapPositionFunc, "FastReadMmapPosition");
245 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetLatencyFunc, fastGetLatencyFunc, "FastGetLatency");
246 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetRealStateFunc, getRealStateFunc, "GetRealState");
247 GET_SYM_ERRPR_RET(
248 g_ptrAudioDeviceHandle, GetRenderMixerStateFunc, getRenderMixerStateFunc, "GetRenderMixerState");
249
250 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SetUpFunc, setUpCaptureFunc, "SetUpCapture");
251 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, TearDownFunc, tearDownCaptureFunc, "TearDownCapture");
252 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, GetStateFunc, getCaptureStateFunc, "GetCaptureState");
253 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StartCaptureFunc, startCaptureFunc, "StartCapture");
254 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, SuspendPlayingFunc, suspendCaptureFunc, "SuspendCapture");
255 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, StopPlayingFunc, stopCaptureFunc, "StopCapture");
256 GET_SYM_ERRPR_RET(g_ptrAudioDeviceHandle, ReadFrameFunc, readFrameFunc, "ReadFrame");
257 }
258 return true;
259 }
260
SetUp()261 bool SetUp()
262 {
263 bool ret = false;
264 ret = InitAudioDeviceSoHandle(g_bluetoothAudioDeviceSoPath);
265 if (ret == true) {
266 ret = setUpFunc();
267 }
268 if (ret == false) {
269 HDF_LOGE("%{public}s failed!", __func__);
270 }
271 return ret;
272 }
273
SetUpCapture()274 bool SetUpCapture()
275 {
276 bool ret = InitAudioDeviceSoHandle(g_bluetoothAudioDeviceSoPath);
277 if (ret) {
278 ret = setUpCaptureFunc();
279 }
280 if (!ret) {
281 HDF_LOGE("%{public}s failed!", __func__);
282 }
283 return ret;
284 }
285
TearDown()286 void TearDown()
287 {
288 tearDownFunc();
289 }
290
TearDownCapture()291 void TearDownCapture()
292 {
293 tearDownCaptureFunc();
294 }
295
FastSetUp()296 bool FastSetUp()
297 {
298 bool ret = InitAudioDeviceSoHandle(g_bluetoothAudioDeviceSoPath);
299 if (ret) {
300 ret = fastSetUpFunc();
301 }
302 if (!ret) {
303 HDF_LOGE("%{public}s failed", __func__);
304 }
305 return ret;
306 }
307
FastTearDown()308 void FastTearDown()
309 {
310 fastTearDownFunc();
311 }
312
FastStartPlaying(uint32_t sampleRate,uint32_t channelCount,uint32_t format)313 int FastStartPlaying(uint32_t sampleRate, uint32_t channelCount, uint32_t format)
314 {
315 BTAudioStreamState state = fastGetStateFunc();
316 if (!g_allowAudioStart.load()) {
317 HDF_LOGE("not allow to start fast render, state=%{public}hhu", state);
318 return HDF_FAILURE;
319 } else if (state != BTAudioStreamState::STARTED) {
320 HDF_LOGI("%{public}s, state=%{public}hhu", __func__, state);
321 if (!fastStartPlayingFunc(sampleRate, channelCount, format)) {
322 HDF_LOGE("%{public}s, fail to startPlaying", __func__);
323 return HDF_FAILURE;
324 }
325 }
326 return HDF_SUCCESS;
327 }
328
FastSuspendPlayingFromParam()329 int FastSuspendPlayingFromParam()
330 {
331 int ret = 0;
332 RenderMixerState renderState = getRenderMixerStateFunc();
333 if (!g_allowAudioStart.load()) {
334 if (renderState == RenderMixerState::INITED || renderState == RenderMixerState::NORMAL_ON_MIX_STOP) {
335 HDF_LOGE("fast render is already stopping or stopped");
336 return ret;
337 }
338 }
339
340 BTAudioStreamState state = fastGetStateFunc();
341 BTAudioStreamState realState = getRealStateFunc();
342 g_allowAudioStart = false;
343 if (state == BTAudioStreamState::STARTED) {
344 HDF_LOGI("%{public}s", __func__);
345 ret = (fastSuspendPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
346 } else if (realState == BTAudioStreamState::STARTING && renderState == RenderMixerState::FAST_STARTED) {
347 HDF_LOGI("%{public}s fast render starting, so stopPlaying", __func__);
348 ret = (fastStopPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
349 } else {
350 HDF_LOGE("%{public}s, state=%{public}hhu is bad state, realState=%{public}hhu, renderState=%{public}hhu",
351 __func__, state, realState, renderState);
352 }
353 return ret;
354 }
355
FastSuspendPlaying()356 int FastSuspendPlaying()
357 {
358 int ret = 0;
359 BTAudioStreamState state = fastGetStateFunc();
360 if (state == BTAudioStreamState::STARTED) {
361 ret = (fastSuspendPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
362 } else {
363 HDF_LOGE("%{public}s, state=%{public}hhu is bad state", __func__, state);
364 }
365 return ret;
366 }
367
FastStopPlaying()368 int FastStopPlaying()
369 {
370 BTAudioStreamState state = fastGetStateFunc();
371 HDF_LOGI("%{public}s, state=%{public}hhu", __func__, state);
372 if (state != BTAudioStreamState::INVALID) {
373 fastStopPlayingFunc();
374 }
375 return HDF_SUCCESS;
376 }
377
FastReqMmapBuffer(int32_t ashmemLength)378 int FastReqMmapBuffer(int32_t ashmemLength)
379 {
380 return fastReqMmapBufferFunc(ashmemLength);
381 }
382
FastReadMmapPosition(int64_t & sec,int64_t & nSec,uint64_t & frames)383 void FastReadMmapPosition(int64_t &sec, int64_t &nSec, uint64_t &frames)
384 {
385 fastReadMmapPositionFunc(sec, nSec, frames);
386 }
387
FastGetLatency(uint32_t & latency)388 int FastGetLatency(uint32_t &latency)
389 {
390 return (fastGetLatencyFunc(latency) ? HDF_SUCCESS : HDF_FAILURE);
391 }
392
SuspendPlayingFromParam()393 int SuspendPlayingFromParam()
394 {
395 int retVal = 0;
396 RenderMixerState renderState = getRenderMixerStateFunc();
397 if (!g_allowAudioStart.load()) {
398 if (renderState == RenderMixerState::INITED || renderState == RenderMixerState::FAST_ON_MIX_STOP) {
399 HDF_LOGE("normal render is already stopping or stopped");
400 return retVal;
401 }
402 }
403
404 BTAudioStreamState state = getStateFunc();
405 BTAudioStreamState realState = getRealStateFunc();
406 g_allowAudioStart = false;
407 if (state == BTAudioStreamState::STARTED) {
408 HDF_LOGI("%{public}s", __func__);
409 retVal = (suspendPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
410 } else if (realState == BTAudioStreamState::STARTING && renderState == RenderMixerState::INITED) {
411 HDF_LOGI("%{public}s normal render starting, so stopPlaying", __func__);
412 retVal = (stopPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
413 } else {
414 HDF_LOGE("%{public}s, state=%{public}hhu is bad state, realState=%{public}hhu, renderState=%{public}hhu",
415 __func__, state, realState, renderState);
416 }
417 return retVal;
418 }
419
UnBlockStart()420 void UnBlockStart()
421 {
422 g_allowAudioStart = true;
423 }
424
StartCapture()425 int StartCapture()
426 {
427 BTAudioStreamState state = getCaptureStateFunc();
428 if (state != BTAudioStreamState::STARTED) {
429 HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
430 if (!startCaptureFunc()) {
431 HDF_LOGE("%{public}s: fail to startPlaying", __func__);
432 return HDF_FAILURE;
433 }
434 }
435 return HDF_SUCCESS;
436 }
437
SuspendCapture()438 int SuspendCapture()
439 {
440 int ret = 0;
441 BTAudioStreamState state = getCaptureStateFunc();
442 if (state == BTAudioStreamState::STARTED) {
443 ret = suspendCaptureFunc() ? HDF_SUCCESS : HDF_FAILURE;
444 } else {
445 HDF_LOGE("%{public}s: state=%{public}hhu is bad state", __func__, state);
446 }
447 return ret;
448 }
449
StopCapture()450 int StopCapture()
451 {
452 BTAudioStreamState state = getCaptureStateFunc();
453 HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
454 if (state != BTAudioStreamState::INVALID) {
455 stopCaptureFunc();
456 }
457 return HDF_SUCCESS;
458 }
459
ReadFrame(uint8_t * data,uint64_t size)460 int ReadFrame(uint8_t *data, uint64_t size)
461 {
462 HDF_LOGD("%{public}s", __func__);
463 return readFrameFunc(data, size);
464 }
465
466 #endif
467
WriteFrame(const uint8_t * data,uint32_t size,const HDI::Audio_Bluetooth::AudioSampleAttributes * attrs)468 int WriteFrame(const uint8_t *data, uint32_t size, const HDI::Audio_Bluetooth::AudioSampleAttributes *attrs)
469 {
470 HDF_LOGD("%{public}s", __func__);
471 #ifdef A2DP_HDI_SERVICE
472 BTAudioStreamState state = getStateFunc();
473 if (!g_allowAudioStart.load()) {
474 HDF_LOGE("not allow to start normal render, state=%{public}hhu", state);
475 return HDF_FAILURE;
476 } else if (state != BTAudioStreamState::STARTED) {
477 HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
478 if (!startPlayingFunc(attrs->sampleRate, attrs->channelCount, static_cast<uint32_t>(attrs->format))) {
479 HDF_LOGE("%{public}s: fail to startPlaying", __func__);
480 return HDF_FAILURE;
481 }
482 }
483 return writeFrameFunc(data, size);
484 #else
485 if (!g_proxy_) {
486 HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
487 return RET_BAD_STATUS;
488 }
489 if (g_playState == A2DP_NOT_PLAYING) {
490 HDF_LOGE("%{public}s: playState is not Streaming", __func__);
491 return RET_BAD_STATUS;
492 }
493 return g_proxy_->WriteFrame(data, size);
494 #endif
495 }
496
StartPlaying()497 int StartPlaying()
498 {
499 HDF_LOGI("%{public}s", __func__);
500 #ifdef A2DP_HDI_SERVICE
501 return HDF_SUCCESS;
502 #else
503 if (!g_proxy_) {
504 HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
505 return RET_BAD_STATUS;
506 }
507 return g_proxy_->StartPlaying(g_proxy_->GetActiveSinkDevice());
508 #endif
509 }
510
SuspendPlaying()511 int SuspendPlaying()
512 {
513 #ifdef A2DP_HDI_SERVICE
514 int retval = 0;
515 BTAudioStreamState state = getStateFunc();
516 HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
517 if (state == BTAudioStreamState::STARTED) {
518 retval = (suspendPlayingFunc() ? HDF_SUCCESS : HDF_FAILURE);
519 } else {
520 HDF_LOGE("%{public}s: state=%{public}hhu is bad state", __func__, state);
521 }
522 return retval;
523 #else
524 HDF_LOGI("%{public}s", __func__);
525 if (!g_proxy_) {
526 HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
527 return RET_BAD_STATUS;
528 }
529 return g_proxy_->SuspendPlaying(g_proxy_->GetActiveSinkDevice());
530 #endif
531 }
532
StopPlaying()533 int StopPlaying()
534 {
535 HDF_LOGI("%{public}s", __func__);
536 #ifdef A2DP_HDI_SERVICE
537 BTAudioStreamState state = getStateFunc();
538 HDF_LOGE("%{public}s: state=%{public}hhu", __func__, state);
539 if (state != BTAudioStreamState::INVALID) {
540 stopPlayingFunc();
541 }
542 return HDF_SUCCESS;
543 #else
544 if (!g_proxy_) {
545 HDF_LOGE("%{public}s: g_proxy_ is null", __func__);
546 return RET_BAD_STATUS;
547 }
548 return g_proxy_->StopPlaying(g_proxy_->GetActiveSinkDevice());
549 #endif
550 }
551
GetLatency(uint32_t & latency)552 int GetLatency(uint32_t &latency)
553 {
554 HDF_LOGD("%{public}s", __func__);
555 #ifdef A2DP_HDI_SERVICE
556 return (getLatencyFunc(latency) ? HDF_SUCCESS : HDF_FAILURE);
557 #else
558 return HDF_ERR_NOT_SUPPORT;
559 #endif
560 }
561 }
562 }
563