1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cstdint>
18
19 #define LOG_TAG "BTAudioClientHfpStub"
20
21 #include <bluetooth/log.h>
22
23 #include "aidl/client_interface_aidl.h"
24 #include "aidl/hfp_client_interface_aidl.h"
25 #include "hal_version_manager.h"
26 #include "hfp_client_interface.h"
27 #include "osi/include/properties.h"
28
29 using ::bluetooth::audio::aidl::hfp::HfpDecodingTransport;
30 using ::bluetooth::audio::aidl::hfp::HfpEncodingTransport;
31 using AudioConfiguration = ::aidl::android::hardware::bluetooth::audio::AudioConfiguration;
32 using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
33 using ::aidl::android::hardware::bluetooth::audio::CodecId;
34 using ::aidl::android::hardware::bluetooth::audio::HfpConfiguration;
35 using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
36
37 namespace bluetooth {
38 namespace audio {
39 namespace hfp {
40
get_decode_client_interface()41 static aidl::BluetoothAudioSourceClientInterface* get_decode_client_interface() {
42 return HfpDecodingTransport::active_hal_interface;
43 }
44
get_encode_client_interface()45 static aidl::BluetoothAudioSinkClientInterface* get_encode_client_interface() {
46 return HfpEncodingTransport::active_hal_interface;
47 }
48
get_decode_transport_instance()49 static HfpDecodingTransport* get_decode_transport_instance() {
50 return HfpDecodingTransport::instance_;
51 }
52
get_encode_transport_instance()53 static HfpDecodingTransport* get_encode_transport_instance() {
54 return HfpDecodingTransport::instance_;
55 }
56
get_default_pcm_configuration()57 static PcmConfiguration get_default_pcm_configuration() {
58 PcmConfiguration pcm_config{
59 .sampleRateHz = 8000,
60 .channelMode = ChannelMode::MONO,
61 .bitsPerSample = 16,
62 .dataIntervalUs = 7500,
63 };
64 return pcm_config;
65 }
66
get_default_hfp_configuration()67 static HfpConfiguration get_default_hfp_configuration() {
68 HfpConfiguration hfp_config{
69 .codecId = CodecId::Core::CVSD,
70 .connectionHandle = 6,
71 .nrec = false,
72 .controllerCodec = true,
73 };
74 return hfp_config;
75 }
76
sco_codec_to_hal_codec(tBTA_AG_UUID_CODEC sco_codec)77 static CodecId sco_codec_to_hal_codec(tBTA_AG_UUID_CODEC sco_codec) {
78 switch (sco_codec) {
79 case tBTA_AG_UUID_CODEC::UUID_CODEC_LC3:
80 return CodecId::Core::LC3;
81 case tBTA_AG_UUID_CODEC::UUID_CODEC_MSBC:
82 return CodecId::Core::MSBC;
83 case tBTA_AG_UUID_CODEC::UUID_CODEC_CVSD:
84 return CodecId::Core::CVSD;
85 default:
86 log::warn("Unknown sco_codec {}, defaulting to vendor codec",
87 bta_ag_uuid_codec_text(sco_codec));
88 return CodecId::Vendor();
89 }
90 }
91
offload_config_to_hal_audio_config(const::hfp::offload_config & offload_config)92 static AudioConfiguration offload_config_to_hal_audio_config(
93 const ::hfp::offload_config& offload_config) {
94 HfpConfiguration hfp_config{
95 .codecId = sco_codec_to_hal_codec(offload_config.sco_codec),
96 .connectionHandle = offload_config.connection_handle,
97 .nrec = offload_config.is_nrec,
98 .controllerCodec = offload_config.is_controller_codec,
99 };
100 return AudioConfiguration(hfp_config);
101 }
102
pcm_config_to_hal_audio_config(const::hfp::pcm_config & pcm_config)103 static AudioConfiguration pcm_config_to_hal_audio_config(const ::hfp::pcm_config& pcm_config) {
104 PcmConfiguration config = get_default_pcm_configuration();
105 config.sampleRateHz = pcm_config.sample_rate_hz;
106 return AudioConfiguration(config);
107 }
108
is_aidl_support_hfp()109 static bool is_aidl_support_hfp() {
110 return HalVersionManager::GetHalTransport() == BluetoothAudioHalTransport::AIDL &&
111 HalVersionManager::GetHalVersion() >= BluetoothAudioHalVersion::VERSION_AIDL_V4;
112 }
113
114 // Parent client implementation
115 HfpClientInterface* HfpClientInterface::interface = nullptr;
Get()116 HfpClientInterface* HfpClientInterface::Get() {
117 if (!is_aidl_support_hfp()) {
118 log::warn("Unsupported HIDL or AIDL version");
119 return nullptr;
120 }
121 if (HfpClientInterface::interface == nullptr) {
122 HfpClientInterface::interface = new HfpClientInterface();
123 }
124 return HfpClientInterface::interface;
125 }
126
127 // Decode client implementation
Cleanup()128 void HfpClientInterface::Decode::Cleanup() {
129 log::info("decode");
130 StopSession();
131 if (HfpDecodingTransport::instance_) {
132 delete HfpDecodingTransport::software_hal_interface;
133 HfpDecodingTransport::software_hal_interface = nullptr;
134 delete HfpDecodingTransport::instance_;
135 HfpDecodingTransport::instance_ = nullptr;
136 }
137 }
138
StartSession()139 void HfpClientInterface::Decode::StartSession() {
140 if (!is_aidl_support_hfp()) {
141 log::warn("Unsupported HIDL or AIDL version");
142 return;
143 }
144 log::info("decode");
145 AudioConfiguration audio_config;
146 audio_config.set<AudioConfiguration::pcmConfig>(get_default_pcm_configuration());
147 if (!get_decode_client_interface()->UpdateAudioConfig(audio_config)) {
148 log::error("cannot update audio config to HAL");
149 return;
150 }
151 auto instance = aidl::hfp::HfpEncodingTransport::instance_;
152 instance->ResetPendingCmd();
153 get_decode_client_interface()->StartSession();
154 }
155
StopSession()156 void HfpClientInterface::Decode::StopSession() {
157 if (!is_aidl_support_hfp()) {
158 log::warn("Unsupported HIDL or AIDL version");
159 return;
160 }
161 log::info("decode");
162 get_decode_client_interface()->EndSession();
163 if (get_decode_transport_instance()) {
164 get_decode_transport_instance()->ResetPendingCmd();
165 get_decode_transport_instance()->ResetPresentationPosition();
166 }
167 }
168
UpdateAudioConfigToHal(const::hfp::offload_config &)169 void HfpClientInterface::Decode::UpdateAudioConfigToHal(
170 const ::hfp::offload_config& /*offload_config*/) {
171 log::warn(
172 "'UpdateAudioConfigToHal(offload_config)' should not be called on "
173 "HfpClientInterface::Decode");
174 }
175
UpdateAudioConfigToHal(const::hfp::pcm_config & pcm_config)176 void HfpClientInterface::Decode::UpdateAudioConfigToHal(const ::hfp::pcm_config& pcm_config) {
177 if (!is_aidl_support_hfp()) {
178 log::warn("Unsupported HIDL or AIDL version");
179 return;
180 }
181
182 log::info("decode");
183 if (!get_decode_client_interface()->UpdateAudioConfig(
184 pcm_config_to_hal_audio_config(pcm_config))) {
185 log::error("cannot update audio config to HAL");
186 return;
187 }
188 }
189
Write(const uint8_t * p_buf,uint32_t len)190 size_t HfpClientInterface::Decode::Write(const uint8_t* p_buf, uint32_t len) {
191 if (!is_aidl_support_hfp()) {
192 log::warn("Unsupported HIDL or AIDL version");
193 return 0;
194 }
195 log::verbose("decode");
196
197 auto instance = aidl::hfp::HfpDecodingTransport::instance_;
198 if (instance->IsStreamActive()) {
199 return get_decode_client_interface()->WriteAudioData(p_buf, len);
200 }
201
202 return len;
203 }
204
ConfirmStreamingRequest()205 void HfpClientInterface::Decode::ConfirmStreamingRequest() {
206 auto instance = aidl::hfp::HfpDecodingTransport::instance_;
207 auto pending_cmd = instance->GetPendingCmd();
208 switch (pending_cmd) {
209 case aidl::hfp::HFP_CTRL_CMD_NONE:
210 log::warn("no pending start stream request");
211 FALLTHROUGH_INTENDED;
212 case aidl::hfp::HFP_CTRL_CMD_START:
213 aidl::hfp::HfpDecodingTransport::software_hal_interface->StreamStarted(
214 aidl::BluetoothAudioCtrlAck::SUCCESS_FINISHED);
215 instance->ResetPendingCmd();
216 return;
217 default:
218 log::warn("Invalid state, {}", pending_cmd);
219 }
220 }
221
CancelStreamingRequest()222 void HfpClientInterface::Decode::CancelStreamingRequest() {
223 auto instance = aidl::hfp::HfpDecodingTransport::instance_;
224 auto pending_cmd = instance->GetPendingCmd();
225 switch (pending_cmd) {
226 case aidl::hfp::HFP_CTRL_CMD_START:
227 aidl::hfp::HfpDecodingTransport::software_hal_interface->StreamStarted(
228 aidl::BluetoothAudioCtrlAck::FAILURE);
229 instance->ResetPendingCmd();
230 return;
231 case aidl::hfp::HFP_CTRL_CMD_NONE:
232 log::warn("no pending start stream request");
233 FALLTHROUGH_INTENDED;
234 case aidl::hfp::HFP_CTRL_CMD_SUSPEND:
235 log::info("suspends");
236 aidl::hfp::HfpDecodingTransport::software_hal_interface->StreamSuspended(
237 aidl::BluetoothAudioCtrlAck::SUCCESS_FINISHED);
238 instance->ResetPendingCmd();
239 return;
240 default:
241 log::warn("Invalid state, {}", pending_cmd);
242 }
243 }
244
GetDecode(bluetooth::common::MessageLoopThread *)245 HfpClientInterface::Decode* HfpClientInterface::GetDecode(
246 bluetooth::common::MessageLoopThread* /*message_loop*/) {
247 if (!is_aidl_support_hfp()) {
248 log::warn("Unsupported HIDL or AIDL version");
249 return nullptr;
250 }
251
252 if (decode_ == nullptr) {
253 decode_ = new Decode();
254 } else {
255 log::warn("Decode is already acquired");
256 return nullptr;
257 }
258
259 log::info("decode");
260
261 HfpDecodingTransport::instance_ =
262 new HfpDecodingTransport(aidl::SessionType::HFP_SOFTWARE_DECODING_DATAPATH);
263 HfpDecodingTransport::software_hal_interface =
264 new aidl::BluetoothAudioSourceClientInterface(HfpDecodingTransport::instance_);
265 if (!HfpDecodingTransport::software_hal_interface->IsValid()) {
266 log::warn("BluetoothAudio HAL for HFP is invalid");
267 delete HfpDecodingTransport::software_hal_interface;
268 HfpDecodingTransport::software_hal_interface = nullptr;
269 delete HfpDecodingTransport::instance_;
270 HfpDecodingTransport::instance_ = nullptr;
271 return nullptr;
272 }
273
274 HfpDecodingTransport::active_hal_interface = HfpDecodingTransport::software_hal_interface;
275
276 return decode_;
277 }
278
ReleaseDecode(HfpClientInterface::Decode * decode)279 bool HfpClientInterface::ReleaseDecode(HfpClientInterface::Decode* decode) {
280 if (decode != decode_) {
281 log::warn("can't release not acquired decode");
282 return false;
283 }
284
285 log::info("decode");
286 if (get_decode_client_interface()) {
287 decode->Cleanup();
288 }
289
290 delete decode_;
291 decode_ = nullptr;
292
293 return true;
294 }
295
296 // Encoding client implementation
Cleanup()297 void HfpClientInterface::Encode::Cleanup() {
298 log::info("encode");
299 StopSession();
300 if (HfpEncodingTransport::instance_) {
301 delete HfpEncodingTransport::software_hal_interface;
302 HfpEncodingTransport::software_hal_interface = nullptr;
303 delete HfpEncodingTransport::instance_;
304 HfpEncodingTransport::instance_ = nullptr;
305 }
306 }
307
StartSession()308 void HfpClientInterface::Encode::StartSession() {
309 if (!is_aidl_support_hfp()) {
310 log::warn("Unsupported HIDL or AIDL version");
311 return;
312 }
313 log::info("encode");
314 AudioConfiguration audio_config;
315 audio_config.set<AudioConfiguration::pcmConfig>(get_default_pcm_configuration());
316 if (!get_encode_client_interface()->UpdateAudioConfig(audio_config)) {
317 log::error("cannot update audio config to HAL");
318 return;
319 }
320 get_encode_client_interface()->StartSession();
321 }
322
StopSession()323 void HfpClientInterface::Encode::StopSession() {
324 if (!is_aidl_support_hfp()) {
325 log::warn("Unsupported HIDL or AIDL version");
326 return;
327 }
328 log::info("encode");
329 get_encode_client_interface()->EndSession();
330 if (get_encode_transport_instance()) {
331 get_encode_transport_instance()->ResetPendingCmd();
332 get_encode_transport_instance()->ResetPresentationPosition();
333 }
334 }
335
UpdateAudioConfigToHal(const::hfp::offload_config &)336 void HfpClientInterface::Encode::UpdateAudioConfigToHal(
337 const ::hfp::offload_config& /*offload_config*/) {
338 log::warn(
339 "'UpdateAudioConfigToHal(offload_config)' should not be called on "
340 "HfpClientInterface::Encode");
341 }
342
UpdateAudioConfigToHal(const::hfp::pcm_config & pcm_config)343 void HfpClientInterface::Encode::UpdateAudioConfigToHal(const ::hfp::pcm_config& pcm_config) {
344 if (!is_aidl_support_hfp()) {
345 log::warn("Unsupported HIDL or AIDL version");
346 return;
347 }
348
349 log::info("encode");
350 if (!get_encode_client_interface()->UpdateAudioConfig(
351 pcm_config_to_hal_audio_config(pcm_config))) {
352 log::error("cannot update audio config to HAL");
353 return;
354 }
355 }
356
Read(uint8_t * p_buf,uint32_t len)357 size_t HfpClientInterface::Encode::Read(uint8_t* p_buf, uint32_t len) {
358 if (!is_aidl_support_hfp()) {
359 log::warn("Unsupported HIDL or AIDL version");
360 return 0;
361 }
362 log::verbose("encode");
363
364 auto instance = aidl::hfp::HfpEncodingTransport::instance_;
365 if (instance->IsStreamActive()) {
366 return get_encode_client_interface()->ReadAudioData(p_buf, len);
367 }
368
369 memset(p_buf, 0x00, len);
370
371 return len;
372 }
373
ConfirmStreamingRequest()374 void HfpClientInterface::Encode::ConfirmStreamingRequest() {
375 auto instance = aidl::hfp::HfpEncodingTransport::instance_;
376 auto pending_cmd = instance->GetPendingCmd();
377 switch (pending_cmd) {
378 case aidl::hfp::HFP_CTRL_CMD_NONE:
379 log::warn("no pending start stream request");
380 FALLTHROUGH_INTENDED;
381 case aidl::hfp::HFP_CTRL_CMD_START:
382 aidl::hfp::HfpEncodingTransport::software_hal_interface->StreamStarted(
383 aidl::BluetoothAudioCtrlAck::SUCCESS_FINISHED);
384 instance->ResetPendingCmd();
385 return;
386 default:
387 log::warn("Invalid state, {}", pending_cmd);
388 }
389 }
390
CancelStreamingRequest()391 void HfpClientInterface::Encode::CancelStreamingRequest() {
392 auto instance = aidl::hfp::HfpEncodingTransport::instance_;
393 auto pending_cmd = instance->GetPendingCmd();
394 switch (pending_cmd) {
395 case aidl::hfp::HFP_CTRL_CMD_START:
396 aidl::hfp::HfpEncodingTransport::software_hal_interface->StreamStarted(
397 aidl::BluetoothAudioCtrlAck::FAILURE);
398 instance->ResetPendingCmd();
399 return;
400 case aidl::hfp::HFP_CTRL_CMD_NONE:
401 log::warn("no pending start stream request");
402 FALLTHROUGH_INTENDED;
403 case aidl::hfp::HFP_CTRL_CMD_SUSPEND:
404 log::info("suspends");
405 aidl::hfp::HfpEncodingTransport::software_hal_interface->StreamSuspended(
406 aidl::BluetoothAudioCtrlAck::SUCCESS_FINISHED);
407 instance->ResetPendingCmd();
408 return;
409 default:
410 log::warn("Invalid state, {}", pending_cmd);
411 }
412 }
413
GetEncode(bluetooth::common::MessageLoopThread *)414 HfpClientInterface::Encode* HfpClientInterface::GetEncode(
415 bluetooth::common::MessageLoopThread* /*message_loop*/) {
416 if (!is_aidl_support_hfp()) {
417 log::warn("Unsupported HIDL or AIDL version");
418 return nullptr;
419 }
420
421 if (encode_ == nullptr) {
422 encode_ = new Encode();
423 } else {
424 log::warn("Encoding is already acquired");
425 return nullptr;
426 }
427
428 log::info("encode");
429
430 HfpEncodingTransport::instance_ =
431 new HfpEncodingTransport(aidl::SessionType::HFP_SOFTWARE_ENCODING_DATAPATH);
432 HfpEncodingTransport::software_hal_interface =
433 new aidl::BluetoothAudioSinkClientInterface(HfpEncodingTransport::instance_);
434 if (!HfpEncodingTransport::software_hal_interface->IsValid()) {
435 log::warn("BluetoothAudio HAL for HFP is invalid");
436 delete HfpEncodingTransport::software_hal_interface;
437 HfpEncodingTransport::software_hal_interface = nullptr;
438 delete HfpEncodingTransport::instance_;
439 HfpEncodingTransport::instance_ = nullptr;
440 return nullptr;
441 }
442
443 HfpEncodingTransport::active_hal_interface = HfpEncodingTransport::software_hal_interface;
444
445 return encode_;
446 }
447
ReleaseEncode(HfpClientInterface::Encode * encode)448 bool HfpClientInterface::ReleaseEncode(HfpClientInterface::Encode* encode) {
449 if (encode != encode_) {
450 log::warn("can't release not acquired encode");
451 return false;
452 }
453
454 if (get_encode_client_interface()) {
455 encode->Cleanup();
456 }
457
458 delete encode_;
459 encode_ = nullptr;
460
461 return true;
462 }
463
464 // Offload client implementation
465 // Based on HfpEncodingTransport
Cleanup()466 void HfpClientInterface::Offload::Cleanup() {
467 log::info("offload");
468 StopSession();
469 if (HfpEncodingTransport::instance_) {
470 delete HfpEncodingTransport::offloading_hal_interface;
471 HfpEncodingTransport::offloading_hal_interface = nullptr;
472 delete HfpEncodingTransport::instance_;
473 HfpEncodingTransport::instance_ = nullptr;
474 }
475 }
476
StartSession()477 void HfpClientInterface::Offload::StartSession() {
478 if (!is_aidl_support_hfp()) {
479 log::warn("Unsupported HIDL or AIDL version");
480 return;
481 }
482 log::info("offload");
483 AudioConfiguration audio_config;
484 audio_config.set<AudioConfiguration::hfpConfig>(get_default_hfp_configuration());
485 if (!get_encode_client_interface()->UpdateAudioConfig(audio_config)) {
486 log::error("cannot update audio config to HAL");
487 return;
488 }
489 if (get_encode_client_interface()->StartSession() == 0) {
490 log::info("session started");
491 } else {
492 log::warn("session not started");
493 }
494 }
495
StopSession()496 void HfpClientInterface::Offload::StopSession() {
497 if (!is_aidl_support_hfp()) {
498 log::warn("Unsupported HIDL or AIDL version");
499 return;
500 }
501 log::info("offload");
502 get_encode_client_interface()->EndSession();
503 if (get_encode_transport_instance()) {
504 get_encode_transport_instance()->ResetPendingCmd();
505 get_encode_transport_instance()->ResetPresentationPosition();
506 }
507 }
508
UpdateAudioConfigToHal(const::hfp::offload_config & offload_config)509 void HfpClientInterface::Offload::UpdateAudioConfigToHal(
510 const ::hfp::offload_config& offload_config) {
511 if (!is_aidl_support_hfp()) {
512 log::warn("Unsupported HIDL or AIDL version");
513 return;
514 }
515
516 log::info("offload");
517 get_encode_client_interface()->UpdateAudioConfig(
518 offload_config_to_hal_audio_config(offload_config));
519 }
520
UpdateAudioConfigToHal(const::hfp::pcm_config &)521 void HfpClientInterface::Offload::UpdateAudioConfigToHal(const ::hfp::pcm_config& /*pcm_config*/) {
522 log::warn(
523 "'UpdateAudioConfigToHal(pcm_config)' should not be called on "
524 "HfpClientInterface::Offload");
525 }
526
ConfirmStreamingRequest()527 void HfpClientInterface::Offload::ConfirmStreamingRequest() {
528 auto instance = aidl::hfp::HfpEncodingTransport::instance_;
529 auto pending_cmd = instance->GetPendingCmd();
530 switch (pending_cmd) {
531 case aidl::hfp::HFP_CTRL_CMD_START:
532 aidl::hfp::HfpEncodingTransport::offloading_hal_interface->StreamStarted(
533 aidl::BluetoothAudioCtrlAck::SUCCESS_FINISHED);
534 instance->ResetPendingCmd();
535 return;
536 case aidl::hfp::HFP_CTRL_CMD_NONE:
537 log::warn("no pending start stream request");
538 return;
539 default:
540 log::warn("Invalid state, {}", pending_cmd);
541 }
542 }
543
CancelStreamingRequest()544 void HfpClientInterface::Offload::CancelStreamingRequest() {
545 auto instance = aidl::hfp::HfpEncodingTransport::instance_;
546 auto pending_cmd = instance->GetPendingCmd();
547 switch (pending_cmd) {
548 case aidl::hfp::HFP_CTRL_CMD_START:
549 aidl::hfp::HfpEncodingTransport::offloading_hal_interface->StreamStarted(
550 aidl::BluetoothAudioCtrlAck::FAILURE);
551 instance->ResetPendingCmd();
552 return;
553 case aidl::hfp::HFP_CTRL_CMD_NONE:
554 log::info("no pending start stream request");
555 [[fallthrough]];
556 case aidl::hfp::HFP_CTRL_CMD_SUSPEND:
557 log::info("suspends");
558 aidl::hfp::HfpEncodingTransport::offloading_hal_interface->StreamSuspended(
559 aidl::BluetoothAudioCtrlAck::SUCCESS_FINISHED);
560 instance->ResetPendingCmd();
561 return;
562 default:
563 log::warn("Invalid state, {}", pending_cmd);
564 }
565 }
566
567 std::unordered_map<tBTA_AG_UUID_CODEC, ::hfp::sco_config>
GetHfpScoConfig()568 HfpClientInterface::Offload::GetHfpScoConfig() {
569 return aidl::hfp::HfpTransport::GetHfpScoConfig(aidl::SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH);
570 }
571
GetOffload(bluetooth::common::MessageLoopThread *)572 HfpClientInterface::Offload* HfpClientInterface::GetOffload(
573 bluetooth::common::MessageLoopThread* /*message_loop*/) {
574 if (!is_aidl_support_hfp()) {
575 log::warn("Unsupported HIDL or AIDL version");
576 return nullptr;
577 }
578
579 if (offload_ == nullptr) {
580 offload_ = new Offload();
581 } else {
582 log::warn("Offload is already acquired");
583 return nullptr;
584 }
585
586 log::info("offload");
587
588 // Prepare offload hal interface.
589 if (bta_ag_get_sco_offload_enabled()) {
590 HfpEncodingTransport::instance_ =
591 new HfpEncodingTransport(aidl::SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH);
592 HfpEncodingTransport::offloading_hal_interface =
593 new aidl::BluetoothAudioSinkClientInterface(HfpEncodingTransport::instance_);
594 if (!HfpEncodingTransport::offloading_hal_interface->IsValid()) {
595 log::fatal("BluetoothAudio HAL for HFP offloading is invalid");
596 delete HfpEncodingTransport::offloading_hal_interface;
597 HfpEncodingTransport::offloading_hal_interface = nullptr;
598 delete HfpEncodingTransport::instance_;
599 HfpEncodingTransport::instance_ = static_cast<HfpEncodingTransport*>(
600 HfpEncodingTransport::software_hal_interface->GetTransportInstance());
601 delete HfpEncodingTransport::software_hal_interface;
602 HfpEncodingTransport::software_hal_interface = nullptr;
603 delete HfpEncodingTransport::instance_;
604 return nullptr;
605 }
606 }
607
608 HfpEncodingTransport::active_hal_interface = HfpEncodingTransport::offloading_hal_interface;
609
610 return offload_;
611 }
612
ReleaseOffload(HfpClientInterface::Offload * offload)613 bool HfpClientInterface::ReleaseOffload(HfpClientInterface::Offload* offload) {
614 if (offload != offload_) {
615 log::warn("can't release not acquired offload");
616 return false;
617 }
618
619 if (get_encode_client_interface()) {
620 offload->Cleanup();
621 }
622
623 delete offload_;
624 offload_ = nullptr;
625
626 return true;
627 }
628
629 } // namespace hfp
630 } // namespace audio
631 } // namespace bluetooth
632