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, NULL);
51 UIPC_Ioctl(*lea_uipc, UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
52 reinterpret_cast<void*>(LEA_DATA_READ_POLL_MS));
53 break;
54 case UIPC_CLOSE_EVT:
55 log::info("UIPC_CLOSE_EVT");
56 break;
57 default:
58 break;
59 }
60 }
61
lea_data_path_open()62 static void lea_data_path_open() {
63 UIPC_Open(*lea_uipc, UIPC_CH_ID_AV_AUDIO, lea_data_cb, LEA_HOST_DATA_PATH);
64 struct group* grp = getgrnam(LEA_HOST_DATA_GROUP);
65 chmod(LEA_HOST_DATA_PATH, 0770);
66 if (grp) {
67 int res = chown(LEA_HOST_DATA_PATH, -1, grp->gr_gid);
68 if (res == -1) {
69 log::error("failed: {}", strerror(errno));
70 }
71 }
72 }
73
74 } // namespace
75
76 namespace bluetooth {
77 namespace audio {
78
79 namespace le_audio {
80
81 // Invoked by audio server when it has audio data to stream.
HostStartRequest()82 bool HostStartRequest() {
83 if (!host::le_audio::LeAudioSinkTransport::instance) {
84 log::warn("instance is null");
85 return false;
86 }
87
88 host::le_audio::LeAudioSinkTransport::stream_started = btle_stream_started_status::IDLE;
89 host::le_audio::LeAudioSinkTransport::instance->ResetPresentationPosition();
90 return host::le_audio::LeAudioSinkTransport::instance->StartRequest();
91 }
92
HostStopRequest()93 void HostStopRequest() {
94 if (!host::le_audio::LeAudioSinkTransport::instance) {
95 log::warn("instance is null");
96 return;
97 }
98
99 host::le_audio::LeAudioSinkTransport::instance->StopRequest();
100 }
101
GetHostPcmConfig()102 btle_pcm_parameters GetHostPcmConfig() {
103 if (!host::le_audio::LeAudioSinkTransport::instance) {
104 log::warn("instance is null");
105 return {};
106 }
107
108 auto pcm_params =
109 host::le_audio::LeAudioSinkTransport::instance->LeAudioGetSelectedHalPcmConfig();
110
111 btle_pcm_parameters pcm_config = {
112 .data_interval_us = pcm_params.data_interval_us,
113 .sample_rate = pcm_params.sample_rate,
114 .bits_per_sample = pcm_params.bits_per_sample,
115 .channels_count = pcm_params.channels_count,
116 };
117
118 return pcm_config;
119 }
120
121 // Invoked by audio server to request audio data streamed from the peer.
PeerStartRequest()122 bool PeerStartRequest() {
123 if (!host::le_audio::LeAudioSourceTransport::instance) {
124 log::warn("instance is null");
125 return false;
126 }
127
128 host::le_audio::LeAudioSourceTransport::stream_started = btle_stream_started_status::IDLE;
129 host::le_audio::LeAudioSourceTransport::instance->ResetPresentationPosition();
130 return host::le_audio::LeAudioSourceTransport::instance->StartRequest();
131 }
132
PeerStopRequest()133 void PeerStopRequest() {
134 if (!host::le_audio::LeAudioSourceTransport::instance) {
135 log::warn("instance is null");
136 return;
137 }
138
139 host::le_audio::LeAudioSourceTransport::instance->StopRequest();
140 }
141
GetPeerPcmConfig()142 btle_pcm_parameters GetPeerPcmConfig() {
143 if (!host::le_audio::LeAudioSourceTransport::instance) {
144 log::warn("instance is null");
145 return {};
146 }
147
148 auto pcm_params =
149 host::le_audio::LeAudioSourceTransport::instance->LeAudioGetSelectedHalPcmConfig();
150
151 btle_pcm_parameters pcm_config = {
152 .data_interval_us = pcm_params.data_interval_us,
153 .sample_rate = pcm_params.sample_rate,
154 .bits_per_sample = pcm_params.bits_per_sample,
155 .channels_count = pcm_params.channels_count,
156 };
157
158 return pcm_config;
159 }
160
GetHostStreamStarted()161 btle_stream_started_status GetHostStreamStarted() {
162 return host::le_audio::LeAudioSinkTransport::stream_started;
163 }
164
GetPeerStreamStarted()165 btle_stream_started_status GetPeerStreamStarted() {
166 return host::le_audio::LeAudioSourceTransport::stream_started;
167 }
168
SourceMetadataChanged(const source_metadata_v7_t & metadata)169 void SourceMetadataChanged(const source_metadata_v7_t& metadata) {
170 if (host::le_audio::LeAudioSourceTransport::instance) {
171 host::le_audio::LeAudioSourceTransport::instance->SourceMetadataChanged(metadata);
172 }
173
174 if (host::le_audio::LeAudioSinkTransport::instance) {
175 host::le_audio::LeAudioSinkTransport::instance->SourceMetadataChanged(metadata);
176 }
177 }
178
SinkMetadataChanged(const sink_metadata_v7_t & metadata)179 void SinkMetadataChanged(const sink_metadata_v7_t& metadata) {
180 if (host::le_audio::LeAudioSourceTransport::instance) {
181 host::le_audio::LeAudioSourceTransport::instance->SinkMetadataChanged(metadata);
182 }
183
184 if (host::le_audio::LeAudioSinkTransport::instance) {
185 host::le_audio::LeAudioSinkTransport::instance->SinkMetadataChanged(metadata);
186 }
187 }
188
get_offload_capabilities()189 OffloadCapabilities get_offload_capabilities() {
190 return {std::vector<bluetooth::le_audio::set_configurations::AudioSetConfiguration>(0),
191 std::vector<bluetooth::le_audio::set_configurations::AudioSetConfiguration>(0)};
192 }
193
Cleanup()194 void LeAudioClientInterface::Sink::Cleanup() {
195 log::info("");
196
197 StopSession();
198
199 delete host::le_audio::LeAudioSinkTransport::instance;
200 host::le_audio::LeAudioSinkTransport::instance = nullptr;
201 }
202
SetPcmParameters(const PcmParameters & params)203 void LeAudioClientInterface::Sink::SetPcmParameters(const PcmParameters& params) {
204 if (!host::le_audio::LeAudioSinkTransport::instance) {
205 log::warn("instance is null");
206 return;
207 }
208
209 log::info(
210 "sample_rate={}, bits_per_sample={}, channels_count={}, "
211 "data_interval_us={}",
212 params.sample_rate, params.bits_per_sample, params.channels_count,
213 params.data_interval_us);
214
215 host::le_audio::LeAudioSinkTransport::instance->LeAudioSetSelectedHalPcmConfig(
216 params.sample_rate, params.bits_per_sample, params.channels_count,
217 params.data_interval_us);
218 }
219
SetRemoteDelay(uint16_t delay_report_ms)220 void LeAudioClientInterface::Sink::SetRemoteDelay(uint16_t delay_report_ms) {
221 if (!host::le_audio::LeAudioSinkTransport::instance) {
222 log::warn("instance is null");
223 return;
224 }
225
226 log::info("delay_report_ms={} msec", delay_report_ms);
227
228 host::le_audio::LeAudioSinkTransport::instance->SetRemoteDelay(delay_report_ms);
229 }
230
StartSession()231 void LeAudioClientInterface::Sink::StartSession() { log::info(""); }
232
StopSession()233 void LeAudioClientInterface::Sink::StopSession() {
234 log::info("");
235
236 if (host::le_audio::LeAudioSinkTransport::instance) {
237 host::le_audio::LeAudioSinkTransport::instance->ClearStartRequestState();
238 }
239
240 host::le_audio::LeAudioSinkTransport::stream_started = btle_stream_started_status::IDLE;
241 }
242
ConfirmStreamingRequest()243 void LeAudioClientInterface::Sink::ConfirmStreamingRequest() {
244 if (!host::le_audio::LeAudioSinkTransport::instance) {
245 log::warn("instance is null");
246 return;
247 }
248
249 log::info("");
250
251 auto instance = host::le_audio::LeAudioSinkTransport::instance;
252 auto start_request_state = instance->GetStartRequestState();
253
254 switch (start_request_state) {
255 case StartRequestState::IDLE:
256 log::warn(", no pending start stream request");
257 return;
258 case StartRequestState::PENDING_BEFORE_RESUME:
259 log::info("Response before sending PENDING to audio HAL");
260 instance->SetStartRequestState(StartRequestState::CONFIRMED);
261 lea_data_path_open();
262 return;
263 case StartRequestState::PENDING_AFTER_RESUME:
264 log::info("Response after sending PENDING to audio HAL");
265 instance->ClearStartRequestState();
266 lea_data_path_open();
267 host::le_audio::LeAudioSinkTransport::stream_started = btle_stream_started_status::STARTED;
268 return;
269 case StartRequestState::CONFIRMED:
270 case StartRequestState::CANCELED:
271 log::error("Invalid state, start stream already confirmed");
272 return;
273 }
274 }
275
CancelStreamingRequest()276 void LeAudioClientInterface::Sink::CancelStreamingRequest() {
277 if (!host::le_audio::LeAudioSinkTransport::instance) {
278 log::warn("instance is null");
279 return;
280 }
281
282 log::info("");
283
284 auto instance = host::le_audio::LeAudioSinkTransport::instance;
285 auto start_request_state = instance->GetStartRequestState();
286
287 switch (start_request_state) {
288 case StartRequestState::IDLE:
289 log::warn(", no pending start stream request");
290 return;
291 case StartRequestState::PENDING_BEFORE_RESUME:
292 log::info("Response before sending PENDING to audio HAL");
293 instance->SetStartRequestState(StartRequestState::CANCELED);
294 return;
295 case StartRequestState::PENDING_AFTER_RESUME:
296 log::info("Response after sending PENDING to audio HAL");
297 instance->ClearStartRequestState();
298 host::le_audio::LeAudioSinkTransport::stream_started = btle_stream_started_status::CANCELED;
299 return;
300 case StartRequestState::CONFIRMED:
301 case StartRequestState::CANCELED:
302 log::error("Invalid state, start stream already confirmed");
303 break;
304 }
305 }
306
UpdateAudioConfigToHal(const::le_audio::offload_config &)307 void LeAudioClientInterface::Sink::UpdateAudioConfigToHal(
308 const ::le_audio::offload_config& /*offload_config*/) {}
309
UpdateBroadcastAudioConfigToHal(::le_audio::broadcast_offload_config const &)310 void LeAudioClientInterface::Sink::UpdateBroadcastAudioConfigToHal(
311 ::le_audio::broadcast_offload_config const& /*config*/) {}
312
SuspendedForReconfiguration()313 void LeAudioClientInterface::Sink::SuspendedForReconfiguration() {
314 log::info("");
315 // TODO
316 }
317
ReconfigurationComplete()318 void LeAudioClientInterface::Sink::ReconfigurationComplete() { log::info(""); }
319
Read(uint8_t * p_buf,uint32_t len)320 size_t LeAudioClientInterface::Sink::Read(uint8_t* p_buf, uint32_t len) {
321 uint32_t bytes_read = 0;
322 bytes_read = UIPC_Read(*lea_uipc, UIPC_CH_ID_AV_AUDIO, p_buf, len);
323
324 // TODO(b/317682986): grab meaningful statistics for logs and metrics
325 log::verbose("Read {} bytes", bytes_read);
326
327 return bytes_read;
328 }
329
330 std::optional<::bluetooth::le_audio::set_configurations::AudioSetConfiguration>
GetUnicastConfig(const::bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements &) const331 LeAudioClientInterface::Sink::GetUnicastConfig(
332 const ::bluetooth::le_audio::CodecManager::
333 UnicastConfigurationRequirements& /*requirements*/) const {
334 return std::nullopt;
335 }
336
337 std::optional<::bluetooth::le_audio::broadcaster::BroadcastConfiguration>
GetBroadcastConfig(const std::vector<std::pair<::bluetooth::le_audio::types::LeAudioContextType,uint8_t>> &,const std::optional<std::vector<::bluetooth::le_audio::types::acs_ac_record>> &) const338 LeAudioClientInterface::Sink::GetBroadcastConfig(
339 const std::vector<std::pair<::bluetooth::le_audio::types::LeAudioContextType,
340 uint8_t>>& /*subgroup_quality*/,
341 const std::optional<std::vector<::bluetooth::le_audio::types::acs_ac_record>>& /*pacs*/)
342 const {
343 return std::nullopt;
344 }
345
Cleanup()346 void LeAudioClientInterface::Source::Cleanup() {
347 log::info("");
348
349 StopSession();
350
351 delete host::le_audio::LeAudioSourceTransport::instance;
352 host::le_audio::LeAudioSourceTransport::instance = nullptr;
353 }
354
SetPcmParameters(const PcmParameters & params)355 void LeAudioClientInterface::Source::SetPcmParameters(const PcmParameters& params) {
356 if (!host::le_audio::LeAudioSourceTransport::instance) {
357 log::warn("instance is null");
358 return;
359 }
360
361 log::info(
362 "sample_rate={}, bits_per_sample={}, channels_count={}, "
363 "data_interval_us={}",
364 params.sample_rate, params.bits_per_sample, params.channels_count,
365 params.data_interval_us);
366
367 host::le_audio::LeAudioSourceTransport::instance->LeAudioSetSelectedHalPcmConfig(
368 params.sample_rate, params.bits_per_sample, params.channels_count,
369 params.data_interval_us);
370 }
371
SetRemoteDelay(uint16_t delay_report_ms)372 void LeAudioClientInterface::Source::SetRemoteDelay(uint16_t delay_report_ms) {
373 if (!host::le_audio::LeAudioSourceTransport::instance) {
374 log::warn("instance is null");
375 return;
376 }
377
378 log::info("delay_report_ms={} msec", delay_report_ms);
379
380 host::le_audio::LeAudioSourceTransport::instance->SetRemoteDelay(delay_report_ms);
381 }
382
StartSession()383 void LeAudioClientInterface::Source::StartSession() { log::info(""); }
384
StopSession()385 void LeAudioClientInterface::Source::StopSession() {
386 log::info("");
387
388 if (host::le_audio::LeAudioSourceTransport::instance) {
389 host::le_audio::LeAudioSourceTransport::instance->ClearStartRequestState();
390 }
391
392 host::le_audio::LeAudioSourceTransport::stream_started = btle_stream_started_status::IDLE;
393 }
394
ConfirmStreamingRequest()395 void LeAudioClientInterface::Source::ConfirmStreamingRequest() {
396 if (!host::le_audio::LeAudioSourceTransport::instance) {
397 log::warn("instance is null");
398 return;
399 }
400
401 log::info("");
402
403 auto instance = host::le_audio::LeAudioSourceTransport::instance;
404 auto start_request_state = instance->GetStartRequestState();
405
406 switch (start_request_state) {
407 case StartRequestState::IDLE:
408 log::warn(", no pending start stream request");
409 return;
410 case StartRequestState::PENDING_BEFORE_RESUME:
411 log::info("Response before sending PENDING to audio HAL");
412 instance->SetStartRequestState(StartRequestState::CONFIRMED);
413 lea_data_path_open();
414 return;
415 case StartRequestState::PENDING_AFTER_RESUME:
416 log::info("Response after sending PENDING to audio HAL");
417 instance->ClearStartRequestState();
418 lea_data_path_open();
419 host::le_audio::LeAudioSourceTransport::stream_started = btle_stream_started_status::STARTED;
420 return;
421 case StartRequestState::CONFIRMED:
422 case StartRequestState::CANCELED:
423 log::error("Invalid state, start stream already confirmed");
424 return;
425 }
426 }
427
CancelStreamingRequest()428 void LeAudioClientInterface::Source::CancelStreamingRequest() {
429 if (!host::le_audio::LeAudioSourceTransport::instance) {
430 log::warn("instance is null");
431 return;
432 }
433
434 log::info("");
435
436 auto instance = host::le_audio::LeAudioSourceTransport::instance;
437 auto start_request_state = instance->GetStartRequestState();
438
439 switch (start_request_state) {
440 case StartRequestState::IDLE:
441 log::warn(", no pending start stream request");
442 return;
443 case StartRequestState::PENDING_BEFORE_RESUME:
444 log::info("Response before sending PENDING to audio HAL");
445 instance->SetStartRequestState(StartRequestState::CANCELED);
446 return;
447 case StartRequestState::PENDING_AFTER_RESUME:
448 log::info("Response after sending PENDING to audio HAL");
449 instance->ClearStartRequestState();
450 host::le_audio::LeAudioSourceTransport::stream_started = btle_stream_started_status::CANCELED;
451 return;
452 case StartRequestState::CANCELED:
453 case StartRequestState::CONFIRMED:
454 log::error("Invalid state, start stream already confirmed");
455 break;
456 }
457 }
458
UpdateAudioConfigToHal(const::le_audio::offload_config &)459 void LeAudioClientInterface::Source::UpdateAudioConfigToHal(
460 const ::le_audio::offload_config& /*offload_config*/) {}
461
SuspendedForReconfiguration()462 void LeAudioClientInterface::Source::SuspendedForReconfiguration() {
463 log::info("");
464 // TODO
465 }
466
ReconfigurationComplete()467 void LeAudioClientInterface::Source::ReconfigurationComplete() { log::info(""); }
468
Write(const uint8_t * p_buf,uint32_t len)469 size_t LeAudioClientInterface::Source::Write(const uint8_t* p_buf, uint32_t len) {
470 bool ok = UIPC_Send(*lea_uipc, UIPC_CH_ID_AV_AUDIO, 0, p_buf, len);
471 return ok ? len : 0;
472 }
473
GetSink(StreamCallbacks stream_cb,bluetooth::common::MessageLoopThread *,bool is_broadcasting_session_type)474 LeAudioClientInterface::Sink* LeAudioClientInterface::GetSink(
475 StreamCallbacks stream_cb, bluetooth::common::MessageLoopThread* /*message_loop*/,
476 bool is_broadcasting_session_type) {
477 if (is_broadcasting_session_type && !LeAudioHalVerifier::SupportsLeAudioBroadcast()) {
478 log::warn("No support for broadcasting Le Audio");
479 return nullptr;
480 }
481
482 Sink* sink = is_broadcasting_session_type ? broadcast_sink_ : unicast_sink_;
483 if (sink == nullptr) {
484 sink = new Sink(is_broadcasting_session_type);
485 (is_broadcasting_session_type ? broadcast_sink_ : unicast_sink_) = sink;
486 } else {
487 log::warn("Sink is already acquired");
488 return nullptr;
489 }
490
491 host::le_audio::LeAudioSinkTransport::instance =
492 new host::le_audio::LeAudioSinkTransport(std::move(stream_cb));
493
494 return sink;
495 }
496
IsUnicastSinkAcquired()497 bool LeAudioClientInterface::IsUnicastSinkAcquired() { return unicast_sink_ != nullptr; }
498
IsBroadcastSinkAcquired()499 bool LeAudioClientInterface::IsBroadcastSinkAcquired() { return broadcast_sink_ != nullptr; }
500
ReleaseSink(LeAudioClientInterface::Sink * sink)501 bool LeAudioClientInterface::ReleaseSink(LeAudioClientInterface::Sink* sink) {
502 if (sink != unicast_sink_ && sink != broadcast_sink_) {
503 log::warn("Can't release not acquired sink");
504 return false;
505 }
506
507 sink->Cleanup();
508
509 if (sink == unicast_sink_) {
510 delete (unicast_sink_);
511 unicast_sink_ = nullptr;
512 } else if (sink == broadcast_sink_) {
513 delete (broadcast_sink_);
514 broadcast_sink_ = nullptr;
515 }
516
517 return true;
518 }
519
GetSource(StreamCallbacks stream_cb,bluetooth::common::MessageLoopThread *)520 LeAudioClientInterface::Source* LeAudioClientInterface::GetSource(
521 StreamCallbacks stream_cb, bluetooth::common::MessageLoopThread* /*message_loop*/) {
522 if (source_ == nullptr) {
523 source_ = new Source();
524 } else {
525 log::warn("Source is already acquired");
526 return nullptr;
527 }
528
529 log::info("");
530
531 host::le_audio::LeAudioSourceTransport::instance =
532 new host::le_audio::LeAudioSourceTransport(std::move(stream_cb));
533
534 return source_;
535 }
536
IsSourceAcquired()537 bool LeAudioClientInterface::IsSourceAcquired() { return source_ != nullptr; }
538
ReleaseSource(LeAudioClientInterface::Source * source)539 bool LeAudioClientInterface::ReleaseSource(LeAudioClientInterface::Source* source) {
540 if (source != source_) {
541 log::warn("Can't release not acquired source");
542 return false;
543 }
544
545 log::info("");
546
547 if (host::le_audio::LeAudioSourceTransport::instance) {
548 source->Cleanup();
549 }
550
551 delete (source_);
552 source_ = nullptr;
553
554 return true;
555 }
556
557 LeAudioClientInterface* LeAudioClientInterface::interface = nullptr;
558
Get()559 LeAudioClientInterface* LeAudioClientInterface::Get() {
560 // TODO: check flag
561
562 if (LeAudioClientInterface::interface == nullptr) {
563 lea_uipc = UIPC_Init();
564
565 LeAudioClientInterface::interface = new LeAudioClientInterface();
566 }
567
568 return LeAudioClientInterface::interface;
569 }
570
SetAllowedDsaModes(DsaModes)571 void LeAudioClientInterface::SetAllowedDsaModes(DsaModes /*dsa_modes*/) { return; }
572
573 } // namespace le_audio
574 } // namespace audio
575 } // namespace bluetooth
576