1 /*
2 * Copyright 2021 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
3 * www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "audio_hal_interface/le_audio_software_host.h"
19
20 #include <bluetooth/log.h>
21 #include <errno.h>
22 #include <grp.h>
23 #include <sys/stat.h>
24
25 #include "audio_hal_interface/le_audio_software.h"
26 #include "audio_hal_interface/le_audio_software_host_transport.h"
27 #include "bta/include/bta_le_audio_api.h"
28 #include "bta/le_audio/codec_manager.h"
29 #include "udrv/include/uipc.h"
30
31 #define LEA_DATA_READ_POLL_MS 10
32 #define LEA_HOST_DATA_PATH "/var/run/bluetooth/audio/.lea_data"
33 // TODO(b/198260375): Make LEA data owner group configurable.
34 #define LEA_HOST_DATA_GROUP "bluetooth-audio"
35
36 using namespace bluetooth;
37
38 namespace {
39
40 std::unique_ptr<tUIPC_STATE> lea_uipc = nullptr;
41
lea_data_cb(tUIPC_CH_ID,tUIPC_EVENT event)42 void lea_data_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
43 switch (event) {
44 case UIPC_OPEN_EVT:
45 log::info("UIPC_OPEN_EVT");
46 /*
47 * Read directly from media task from here on (keep callback for
48 * connection events.
49 */
50 UIPC_Ioctl(*lea_uipc, UIPC_CH_ID_AV_AUDIO, UIPC_REG_REMOVE_ACTIVE_READSET,
51 NULL);
52 UIPC_Ioctl(*lea_uipc, UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
53 reinterpret_cast<void*>(LEA_DATA_READ_POLL_MS));
54 break;
55 case UIPC_CLOSE_EVT:
56 log::info("UIPC_CLOSE_EVT");
57 break;
58 default:
59 break;
60 }
61 }
62
lea_data_path_open()63 static void lea_data_path_open() {
64 UIPC_Open(*lea_uipc, UIPC_CH_ID_AV_AUDIO, lea_data_cb, LEA_HOST_DATA_PATH);
65 struct group* grp = getgrnam(LEA_HOST_DATA_GROUP);
66 chmod(LEA_HOST_DATA_PATH, 0770);
67 if (grp) {
68 int res = chown(LEA_HOST_DATA_PATH, -1, grp->gr_gid);
69 if (res == -1) {
70 log::error("failed: {}", strerror(errno));
71 }
72 }
73 }
74
75 } // namespace
76
77 namespace bluetooth {
78 namespace audio {
79
80 namespace le_audio {
81
82 // Invoked by audio server when it has audio data to stream.
HostStartRequest()83 bool HostStartRequest() {
84 if (!host::le_audio::LeAudioSinkTransport::instance) {
85 log::warn("instance is null");
86 return false;
87 }
88
89 host::le_audio::LeAudioSinkTransport::stream_started =
90 btle_stream_started_status::IDLE;
91 host::le_audio::LeAudioSinkTransport::instance->ResetPresentationPosition();
92 return host::le_audio::LeAudioSinkTransport::instance->StartRequest();
93 }
94
HostStopRequest()95 void HostStopRequest() {
96 if (!host::le_audio::LeAudioSinkTransport::instance) {
97 log::warn("instance is null");
98 return;
99 }
100
101 host::le_audio::LeAudioSinkTransport::instance->StopRequest();
102 }
103
GetHostPcmConfig()104 btle_pcm_parameters GetHostPcmConfig() {
105 if (!host::le_audio::LeAudioSinkTransport::instance) {
106 log::warn("instance is null");
107 return {};
108 }
109
110 auto pcm_params = host::le_audio::LeAudioSinkTransport::instance
111 ->LeAudioGetSelectedHalPcmConfig();
112
113 btle_pcm_parameters pcm_config = {
114 .data_interval_us = pcm_params.data_interval_us,
115 .sample_rate = pcm_params.sample_rate,
116 .bits_per_sample = pcm_params.bits_per_sample,
117 .channels_count = pcm_params.channels_count,
118 };
119
120 return pcm_config;
121 }
122
123 // Invoked by audio server to request audio data streamed from the peer.
PeerStartRequest()124 bool PeerStartRequest() {
125 if (!host::le_audio::LeAudioSourceTransport::instance) {
126 log::warn("instance is null");
127 return false;
128 }
129
130 host::le_audio::LeAudioSourceTransport::stream_started =
131 btle_stream_started_status::IDLE;
132 host::le_audio::LeAudioSourceTransport::instance->ResetPresentationPosition();
133 return host::le_audio::LeAudioSourceTransport::instance->StartRequest();
134 }
135
PeerStopRequest()136 void PeerStopRequest() {
137 if (!host::le_audio::LeAudioSourceTransport::instance) {
138 log::warn("instance is null");
139 return;
140 }
141
142 host::le_audio::LeAudioSourceTransport::instance->StopRequest();
143 }
144
GetPeerPcmConfig()145 btle_pcm_parameters GetPeerPcmConfig() {
146 if (!host::le_audio::LeAudioSourceTransport::instance) {
147 log::warn("instance is null");
148 return {};
149 }
150
151 auto pcm_params = host::le_audio::LeAudioSourceTransport::instance
152 ->LeAudioGetSelectedHalPcmConfig();
153
154 btle_pcm_parameters pcm_config = {
155 .data_interval_us = pcm_params.data_interval_us,
156 .sample_rate = pcm_params.sample_rate,
157 .bits_per_sample = pcm_params.bits_per_sample,
158 .channels_count = pcm_params.channels_count,
159 };
160
161 return pcm_config;
162 }
163
GetHostStreamStarted()164 btle_stream_started_status GetHostStreamStarted() {
165 return host::le_audio::LeAudioSinkTransport::stream_started;
166 }
167
GetPeerStreamStarted()168 btle_stream_started_status GetPeerStreamStarted() {
169 return host::le_audio::LeAudioSourceTransport::stream_started;
170 }
171
SourceMetadataChanged(const source_metadata_v7_t & metadata)172 void SourceMetadataChanged(const source_metadata_v7_t& metadata) {
173 if (host::le_audio::LeAudioSourceTransport::instance) {
174 host::le_audio::LeAudioSourceTransport::instance->SourceMetadataChanged(
175 metadata);
176 }
177
178 if (host::le_audio::LeAudioSinkTransport::instance) {
179 host::le_audio::LeAudioSinkTransport::instance->SourceMetadataChanged(
180 metadata);
181 }
182 }
183
SinkMetadataChanged(const sink_metadata_v7_t & metadata)184 void SinkMetadataChanged(const sink_metadata_v7_t& metadata) {
185 if (host::le_audio::LeAudioSourceTransport::instance) {
186 host::le_audio::LeAudioSourceTransport::instance->SinkMetadataChanged(
187 metadata);
188 }
189
190 if (host::le_audio::LeAudioSinkTransport::instance) {
191 host::le_audio::LeAudioSinkTransport::instance->SinkMetadataChanged(
192 metadata);
193 }
194 }
195
get_offload_capabilities()196 OffloadCapabilities get_offload_capabilities() {
197 return {
198 std::vector<
199 bluetooth::le_audio::set_configurations::AudioSetConfiguration>(0),
200 std::vector<
201 bluetooth::le_audio::set_configurations::AudioSetConfiguration>(0)};
202 }
203
GetAidlInterfaceVersion()204 int GetAidlInterfaceVersion() { return 0; }
205
Cleanup()206 void LeAudioClientInterface::Sink::Cleanup() {
207 log::info("");
208
209 StopSession();
210
211 delete host::le_audio::LeAudioSinkTransport::instance;
212 host::le_audio::LeAudioSinkTransport::instance = nullptr;
213 }
214
SetPcmParameters(const PcmParameters & params)215 void LeAudioClientInterface::Sink::SetPcmParameters(
216 const PcmParameters& params) {
217 if (!host::le_audio::LeAudioSinkTransport::instance) {
218 log::warn("instance is null");
219 return;
220 }
221
222 log::info(
223 "sample_rate={}, bits_per_sample={}, channels_count={}, "
224 "data_interval_us={}",
225 params.sample_rate, params.bits_per_sample, params.channels_count,
226 params.data_interval_us);
227
228 host::le_audio::LeAudioSinkTransport::instance
229 ->LeAudioSetSelectedHalPcmConfig(
230 params.sample_rate, params.bits_per_sample, params.channels_count,
231 params.data_interval_us);
232 }
233
SetRemoteDelay(uint16_t delay_report_ms)234 void LeAudioClientInterface::Sink::SetRemoteDelay(uint16_t delay_report_ms) {
235 if (!host::le_audio::LeAudioSinkTransport::instance) {
236 log::warn("instance is null");
237 return;
238 }
239
240 log::info("delay_report_ms={} msec", delay_report_ms);
241
242 host::le_audio::LeAudioSinkTransport::instance->SetRemoteDelay(
243 delay_report_ms);
244 }
245
StartSession()246 void LeAudioClientInterface::Sink::StartSession() { log::info(""); }
247
StopSession()248 void LeAudioClientInterface::Sink::StopSession() {
249 log::info("");
250
251 if (host::le_audio::LeAudioSinkTransport::instance) {
252 host::le_audio::LeAudioSinkTransport::instance->ClearStartRequestState();
253 }
254
255 host::le_audio::LeAudioSinkTransport::stream_started =
256 btle_stream_started_status::IDLE;
257 }
258
ConfirmStreamingRequest()259 void LeAudioClientInterface::Sink::ConfirmStreamingRequest() {
260 if (!host::le_audio::LeAudioSinkTransport::instance) {
261 log::warn("instance is null");
262 return;
263 }
264
265 log::info("");
266
267 auto instance = host::le_audio::LeAudioSinkTransport::instance;
268 auto start_request_state = instance->GetStartRequestState();
269
270 switch (start_request_state) {
271 case StartRequestState::IDLE:
272 log::warn(", no pending start stream request");
273 return;
274 case StartRequestState::PENDING_BEFORE_RESUME:
275 log::info("Response before sending PENDING to audio HAL");
276 instance->SetStartRequestState(StartRequestState::CONFIRMED);
277 lea_data_path_open();
278 return;
279 case StartRequestState::PENDING_AFTER_RESUME:
280 log::info("Response after sending PENDING to audio HAL");
281 instance->ClearStartRequestState();
282 lea_data_path_open();
283 host::le_audio::LeAudioSinkTransport::stream_started =
284 btle_stream_started_status::STARTED;
285 return;
286 case StartRequestState::CONFIRMED:
287 case StartRequestState::CANCELED:
288 log::error("Invalid state, start stream already confirmed");
289 return;
290 }
291 }
292
ConfirmStreamingRequestV2()293 void LeAudioClientInterface::Sink::ConfirmStreamingRequestV2() {
294 ConfirmStreamingRequest();
295 }
296
CancelStreamingRequest()297 void LeAudioClientInterface::Sink::CancelStreamingRequest() {
298 if (!host::le_audio::LeAudioSinkTransport::instance) {
299 log::warn("instance is null");
300 return;
301 }
302
303 log::info("");
304
305 auto instance = host::le_audio::LeAudioSinkTransport::instance;
306 auto start_request_state = instance->GetStartRequestState();
307
308 switch (start_request_state) {
309 case StartRequestState::IDLE:
310 log::warn(", no pending start stream request");
311 return;
312 case StartRequestState::PENDING_BEFORE_RESUME:
313 log::info("Response before sending PENDING to audio HAL");
314 instance->SetStartRequestState(StartRequestState::CANCELED);
315 return;
316 case StartRequestState::PENDING_AFTER_RESUME:
317 log::info("Response after sending PENDING to audio HAL");
318 instance->ClearStartRequestState();
319 host::le_audio::LeAudioSinkTransport::stream_started =
320 btle_stream_started_status::CANCELED;
321 return;
322 case StartRequestState::CONFIRMED:
323 case StartRequestState::CANCELED:
324 log::error("Invalid state, start stream already confirmed");
325 break;
326 }
327 }
328
CancelStreamingRequestV2()329 void LeAudioClientInterface::Sink::CancelStreamingRequestV2() {
330 CancelStreamingRequest();
331 }
332
UpdateAudioConfigToHal(const::le_audio::offload_config & offload_config)333 void LeAudioClientInterface::Sink::UpdateAudioConfigToHal(
334 const ::le_audio::offload_config& offload_config) {}
335
UpdateBroadcastAudioConfigToHal(::le_audio::broadcast_offload_config const & config)336 void LeAudioClientInterface::Sink::UpdateBroadcastAudioConfigToHal(
337 ::le_audio::broadcast_offload_config const& config) {}
338
SuspendedForReconfiguration()339 void LeAudioClientInterface::Sink::SuspendedForReconfiguration() {
340 log::info("");
341 // TODO
342 }
343
ReconfigurationComplete()344 void LeAudioClientInterface::Sink::ReconfigurationComplete() { log::info(""); }
345
Read(uint8_t * p_buf,uint32_t len)346 size_t LeAudioClientInterface::Sink::Read(uint8_t* p_buf, uint32_t len) {
347 uint32_t bytes_read = 0;
348 bytes_read = UIPC_Read(*lea_uipc, UIPC_CH_ID_AV_AUDIO, p_buf, len);
349
350 // TODO(b/317682986): grab meaningful statistics for logs and metrics
351 log::verbose("Read {} bytes", bytes_read);
352
353 return bytes_read;
354 }
355
356 std::optional<::bluetooth::le_audio::set_configurations::AudioSetConfiguration>
GetUnicastConfig(const::bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements & requirements) const357 LeAudioClientInterface::Sink::GetUnicastConfig(
358 const ::bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements&
359 requirements) const {
360 return std::nullopt;
361 }
362
363 std::optional<::bluetooth::le_audio::broadcaster::BroadcastConfiguration>
GetBroadcastConfig(const std::vector<std::pair<::bluetooth::le_audio::types::LeAudioContextType,uint8_t>> & subgroup_quality,const std::optional<std::vector<::bluetooth::le_audio::types::acs_ac_record>> & pacs) const364 LeAudioClientInterface::Sink::GetBroadcastConfig(
365 const std::vector<
366 std::pair<::bluetooth::le_audio::types::LeAudioContextType, uint8_t>>&
367 subgroup_quality,
368 const std::optional<
369 std::vector<::bluetooth::le_audio::types::acs_ac_record>>& pacs) const {
370 return std::nullopt;
371 }
372
Cleanup()373 void LeAudioClientInterface::Source::Cleanup() {
374 log::info("");
375
376 StopSession();
377
378 delete host::le_audio::LeAudioSourceTransport::instance;
379 host::le_audio::LeAudioSourceTransport::instance = nullptr;
380 }
381
SetPcmParameters(const PcmParameters & params)382 void LeAudioClientInterface::Source::SetPcmParameters(
383 const PcmParameters& params) {
384 if (!host::le_audio::LeAudioSourceTransport::instance) {
385 log::warn("instance is null");
386 return;
387 }
388
389 log::info(
390 "sample_rate={}, bits_per_sample={}, channels_count={}, "
391 "data_interval_us={}",
392 params.sample_rate, params.bits_per_sample, params.channels_count,
393 params.data_interval_us);
394
395 host::le_audio::LeAudioSourceTransport::instance
396 ->LeAudioSetSelectedHalPcmConfig(
397 params.sample_rate, params.bits_per_sample, params.channels_count,
398 params.data_interval_us);
399 }
400
SetRemoteDelay(uint16_t delay_report_ms)401 void LeAudioClientInterface::Source::SetRemoteDelay(uint16_t delay_report_ms) {
402 if (!host::le_audio::LeAudioSourceTransport::instance) {
403 log::warn("instance is null");
404 return;
405 }
406
407 log::info("delay_report_ms={} msec", delay_report_ms);
408
409 host::le_audio::LeAudioSourceTransport::instance->SetRemoteDelay(
410 delay_report_ms);
411 }
412
StartSession()413 void LeAudioClientInterface::Source::StartSession() { log::info(""); }
414
StopSession()415 void LeAudioClientInterface::Source::StopSession() {
416 log::info("");
417
418 if (host::le_audio::LeAudioSourceTransport::instance) {
419 host::le_audio::LeAudioSourceTransport::instance->ClearStartRequestState();
420 }
421
422 host::le_audio::LeAudioSourceTransport::stream_started =
423 btle_stream_started_status::IDLE;
424 }
425
ConfirmStreamingRequest()426 void LeAudioClientInterface::Source::ConfirmStreamingRequest() {
427 if (!host::le_audio::LeAudioSourceTransport::instance) {
428 log::warn("instance is null");
429 return;
430 }
431
432 log::info("");
433
434 auto instance = host::le_audio::LeAudioSourceTransport::instance;
435 auto start_request_state = instance->GetStartRequestState();
436
437 switch (start_request_state) {
438 case StartRequestState::IDLE:
439 log::warn(", no pending start stream request");
440 return;
441 case StartRequestState::PENDING_BEFORE_RESUME:
442 log::info("Response before sending PENDING to audio HAL");
443 instance->SetStartRequestState(StartRequestState::CONFIRMED);
444 lea_data_path_open();
445 return;
446 case StartRequestState::PENDING_AFTER_RESUME:
447 log::info("Response after sending PENDING to audio HAL");
448 instance->ClearStartRequestState();
449 lea_data_path_open();
450 host::le_audio::LeAudioSourceTransport::stream_started =
451 btle_stream_started_status::STARTED;
452 return;
453 case StartRequestState::CONFIRMED:
454 case StartRequestState::CANCELED:
455 log::error("Invalid state, start stream already confirmed");
456 return;
457 }
458 }
459
ConfirmStreamingRequestV2()460 void LeAudioClientInterface::Source::ConfirmStreamingRequestV2() {
461 ConfirmStreamingRequest();
462 }
463
CancelStreamingRequest()464 void LeAudioClientInterface::Source::CancelStreamingRequest() {
465 if (!host::le_audio::LeAudioSourceTransport::instance) {
466 log::warn("instance is null");
467 return;
468 }
469
470 log::info("");
471
472 auto instance = host::le_audio::LeAudioSourceTransport::instance;
473 auto start_request_state = instance->GetStartRequestState();
474
475 switch (start_request_state) {
476 case StartRequestState::IDLE:
477 log::warn(", no pending start stream request");
478 return;
479 case StartRequestState::PENDING_BEFORE_RESUME:
480 log::info("Response before sending PENDING to audio HAL");
481 instance->SetStartRequestState(StartRequestState::CANCELED);
482 return;
483 case StartRequestState::PENDING_AFTER_RESUME:
484 log::info("Response after sending PENDING to audio HAL");
485 instance->ClearStartRequestState();
486 host::le_audio::LeAudioSourceTransport::stream_started =
487 btle_stream_started_status::CANCELED;
488 return;
489 case StartRequestState::CANCELED:
490 case StartRequestState::CONFIRMED:
491 log::error("Invalid state, start stream already confirmed");
492 break;
493 }
494 }
495
CancelStreamingRequestV2()496 void LeAudioClientInterface::Source::CancelStreamingRequestV2() {
497 CancelStreamingRequest();
498 }
499
UpdateAudioConfigToHal(const::le_audio::offload_config & offload_config)500 void LeAudioClientInterface::Source::UpdateAudioConfigToHal(
501 const ::le_audio::offload_config& offload_config) {}
502
SuspendedForReconfiguration()503 void LeAudioClientInterface::Source::SuspendedForReconfiguration() {
504 log::info("");
505 // TODO
506 }
507
ReconfigurationComplete()508 void LeAudioClientInterface::Source::ReconfigurationComplete() {
509 log::info("");
510 }
511
Write(const uint8_t * p_buf,uint32_t len)512 size_t LeAudioClientInterface::Source::Write(const uint8_t* p_buf,
513 uint32_t len) {
514 bool ok = UIPC_Send(*lea_uipc, UIPC_CH_ID_AV_AUDIO, 0, p_buf, len);
515 return ok ? len : 0;
516 }
517
GetSink(StreamCallbacks stream_cb,bluetooth::common::MessageLoopThread * message_loop,bool is_broadcasting_session_type)518 LeAudioClientInterface::Sink* LeAudioClientInterface::GetSink(
519 StreamCallbacks stream_cb,
520 bluetooth::common::MessageLoopThread* message_loop,
521 bool is_broadcasting_session_type) {
522 if (is_broadcasting_session_type &&
523 !LeAudioHalVerifier::SupportsLeAudioBroadcast()) {
524 log::warn("No support for broadcasting Le Audio");
525 return nullptr;
526 }
527
528 Sink* sink = is_broadcasting_session_type ? broadcast_sink_ : unicast_sink_;
529 if (sink == nullptr) {
530 sink = new Sink(is_broadcasting_session_type);
531 (is_broadcasting_session_type ? broadcast_sink_ : unicast_sink_) = sink;
532 } else {
533 log::warn("Sink is already acquired");
534 return nullptr;
535 }
536
537 host::le_audio::LeAudioSinkTransport::instance =
538 new host::le_audio::LeAudioSinkTransport(std::move(stream_cb));
539
540 return sink;
541 }
542
IsUnicastSinkAcquired()543 bool LeAudioClientInterface::IsUnicastSinkAcquired() {
544 return unicast_sink_ != nullptr;
545 }
546
IsBroadcastSinkAcquired()547 bool LeAudioClientInterface::IsBroadcastSinkAcquired() {
548 return broadcast_sink_ != nullptr;
549 }
550
ReleaseSink(LeAudioClientInterface::Sink * sink)551 bool LeAudioClientInterface::ReleaseSink(LeAudioClientInterface::Sink* sink) {
552 if (sink != unicast_sink_ && sink != broadcast_sink_) {
553 log::warn("Can't release not acquired sink");
554 return false;
555 }
556
557 sink->Cleanup();
558
559 if (sink == unicast_sink_) {
560 delete (unicast_sink_);
561 unicast_sink_ = nullptr;
562 } else if (sink == broadcast_sink_) {
563 delete (broadcast_sink_);
564 broadcast_sink_ = nullptr;
565 }
566
567 return true;
568 }
569
GetSource(StreamCallbacks stream_cb,bluetooth::common::MessageLoopThread * message_loop)570 LeAudioClientInterface::Source* LeAudioClientInterface::GetSource(
571 StreamCallbacks stream_cb,
572 bluetooth::common::MessageLoopThread* message_loop) {
573 if (source_ == nullptr) {
574 source_ = new Source();
575 } else {
576 log::warn("Source is already acquired");
577 return nullptr;
578 }
579
580 log::info("");
581
582 host::le_audio::LeAudioSourceTransport::instance =
583 new host::le_audio::LeAudioSourceTransport(std::move(stream_cb));
584
585 return source_;
586 }
587
IsSourceAcquired()588 bool LeAudioClientInterface::IsSourceAcquired() { return source_ != nullptr; }
589
ReleaseSource(LeAudioClientInterface::Source * source)590 bool LeAudioClientInterface::ReleaseSource(
591 LeAudioClientInterface::Source* source) {
592 if (source != source_) {
593 log::warn("Can't release not acquired source");
594 return false;
595 }
596
597 log::info("");
598
599 if (host::le_audio::LeAudioSourceTransport::instance) source->Cleanup();
600
601 delete (source_);
602 source_ = nullptr;
603
604 return true;
605 }
606
607 LeAudioClientInterface* LeAudioClientInterface::interface = nullptr;
608
Get()609 LeAudioClientInterface* LeAudioClientInterface::Get() {
610 // TODO: check flag
611
612 if (LeAudioClientInterface::interface == nullptr) {
613 lea_uipc = UIPC_Init();
614
615 LeAudioClientInterface::interface = new LeAudioClientInterface();
616 }
617
618 return LeAudioClientInterface::interface;
619 }
620
SetAllowedDsaModes(DsaModes dsa_modes)621 void LeAudioClientInterface::SetAllowedDsaModes(DsaModes dsa_modes) { return; }
622
623 } // namespace le_audio
624 } // namespace audio
625 } // namespace bluetooth
626