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