1 /*
2  * Copyright (C) 2024 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 "gd/rust/topshim/le_audio/le_audio_shim.h"
18 
19 #include <bluetooth/log.h>
20 #include <hardware/bluetooth.h>
21 
22 #include <vector>
23 
24 #include "bta/le_audio/le_audio_types.h"
25 #include "os/log.h"
26 #include "src/profiles/le_audio.rs.h"
27 #include "types/raw_address.h"
28 
29 namespace rusty = ::bluetooth::topshim::rust;
30 
31 namespace bluetooth {
32 namespace topshim {
33 namespace rust {
34 namespace internal {
35 
36 static LeAudioClientIntf* g_lea_client_if;
37 
from_rust_btle_audio_direction(BtLeAudioDirection direction)38 static uint8_t from_rust_btle_audio_direction(BtLeAudioDirection direction) {
39   switch (direction) {
40     case BtLeAudioDirection::Sink:
41       return le_audio::types::kLeAudioDirectionSink;
42     case BtLeAudioDirection::Source:
43       return le_audio::types::kLeAudioDirectionSource;
44     case BtLeAudioDirection::Both:
45       return le_audio::types::kLeAudioDirectionBoth;
46     default:
47       log::assert_that(false, "Unhandled enum value from C++");
48   }
49   return 0;
50 }
51 
from_rust_btle_audio_codec_config(BtLeAudioCodecConfig codec_config)52 static le_audio::btle_audio_codec_config_t from_rust_btle_audio_codec_config(
53     BtLeAudioCodecConfig codec_config) {
54   switch (codec_config.codec_type) {
55     case static_cast<int>(BtLeAudioCodecIndex::SrcLc3):
56       return le_audio::btle_audio_codec_config_t{
57           .codec_type = le_audio::btle_audio_codec_index_t::LE_AUDIO_CODEC_INDEX_SOURCE_LC3};
58     default:
59       log::assert_that(false, "Unhandled enum value from C++");
60   }
61   return le_audio::btle_audio_codec_config_t{};
62 }
63 
to_rust_btle_audio_codec_config(le_audio::btle_audio_codec_config_t codec_config)64 static BtLeAudioCodecConfig to_rust_btle_audio_codec_config(
65     le_audio::btle_audio_codec_config_t codec_config) {
66   switch (codec_config.codec_type) {
67     case le_audio::btle_audio_codec_index_t::LE_AUDIO_CODEC_INDEX_SOURCE_LC3:
68       return BtLeAudioCodecConfig{.codec_type = static_cast<int>(BtLeAudioCodecIndex::SrcLc3)};
69     default:
70       log::assert_that(false, "Unhandled enum value from C++");
71   }
72   return BtLeAudioCodecConfig{};
73 }
74 
to_rust_btle_audio_codec_config_vec(std::vector<le_audio::btle_audio_codec_config_t> codec_configs)75 static ::rust::vec<BtLeAudioCodecConfig> to_rust_btle_audio_codec_config_vec(
76     std::vector<le_audio::btle_audio_codec_config_t> codec_configs) {
77   ::rust::vec<BtLeAudioCodecConfig> rconfigs;
78   for (auto c : codec_configs) {
79     rconfigs.push_back(to_rust_btle_audio_codec_config(c));
80   }
81   return rconfigs;
82 }
83 
to_rust_btle_audio_connection_state(le_audio::ConnectionState state)84 static BtLeAudioConnectionState to_rust_btle_audio_connection_state(
85     le_audio::ConnectionState state) {
86   switch (state) {
87     case le_audio::ConnectionState::DISCONNECTED:
88       return BtLeAudioConnectionState::Disconnected;
89     case le_audio::ConnectionState::CONNECTING:
90       return BtLeAudioConnectionState::Connecting;
91     case le_audio::ConnectionState::CONNECTED:
92       return BtLeAudioConnectionState::Connected;
93     case le_audio::ConnectionState::DISCONNECTING:
94       return BtLeAudioConnectionState::Disconnecting;
95     default:
96       log::assert_that(false, "Unhandled enum value from C++");
97   }
98   return BtLeAudioConnectionState{};
99 }
100 
to_rust_btle_audio_group_status(le_audio::GroupStatus status)101 static BtLeAudioGroupStatus to_rust_btle_audio_group_status(le_audio::GroupStatus status) {
102   switch (status) {
103     case le_audio::GroupStatus::INACTIVE:
104       return BtLeAudioGroupStatus::Inactive;
105     case le_audio::GroupStatus::ACTIVE:
106       return BtLeAudioGroupStatus::Active;
107     case le_audio::GroupStatus::TURNED_IDLE_DURING_CALL:
108       return BtLeAudioGroupStatus::TurnedIdleDuringCall;
109     default:
110       log::assert_that(false, "Unhandled enum value from C++");
111   }
112   return BtLeAudioGroupStatus{};
113 }
114 
to_rust_btle_audio_group_node_status(le_audio::GroupNodeStatus status)115 static BtLeAudioGroupNodeStatus to_rust_btle_audio_group_node_status(
116     le_audio::GroupNodeStatus status) {
117   switch (status) {
118     case le_audio::GroupNodeStatus::ADDED:
119       return BtLeAudioGroupNodeStatus::Added;
120     case le_audio::GroupNodeStatus::REMOVED:
121       return BtLeAudioGroupNodeStatus::Removed;
122     default:
123       log::assert_that(false, "Unhandled enum value from C++");
124   }
125   return BtLeAudioGroupNodeStatus{};
126 }
127 
to_rust_btle_audio_unicast_monitor_mode_status(le_audio::UnicastMonitorModeStatus status)128 static BtLeAudioUnicastMonitorModeStatus to_rust_btle_audio_unicast_monitor_mode_status(
129     le_audio::UnicastMonitorModeStatus status) {
130   switch (status) {
131     case le_audio::UnicastMonitorModeStatus::STREAMING_REQUESTED:
132       return BtLeAudioUnicastMonitorModeStatus::StreamingRequested;
133     case le_audio::UnicastMonitorModeStatus::STREAMING:
134       return BtLeAudioUnicastMonitorModeStatus::Streaming;
135     case le_audio::UnicastMonitorModeStatus::STREAMING_SUSPENDED:
136       return BtLeAudioUnicastMonitorModeStatus::StreamingSuspended;
137     default:
138       log::assert_that(false, "Unhandled enum value from C++");
139   }
140   return BtLeAudioUnicastMonitorModeStatus{};
141 }
142 
to_rust_btle_audio_direction(uint8_t direction)143 static BtLeAudioDirection to_rust_btle_audio_direction(uint8_t direction) {
144   switch (direction) {
145     case le_audio::types::kLeAudioDirectionSink:
146       return BtLeAudioDirection::Sink;
147     case le_audio::types::kLeAudioDirectionSource:
148       return BtLeAudioDirection::Source;
149     case le_audio::types::kLeAudioDirectionBoth:
150       return BtLeAudioDirection::Both;
151     default:
152       log::assert_that(false, "Unhandled enum value from C++");
153   }
154   return BtLeAudioDirection{};
155 }
156 
to_rust_btle_audio_group_stream_status(le_audio::GroupStreamStatus status)157 static BtLeAudioGroupStreamStatus to_rust_btle_audio_group_stream_status(
158     le_audio::GroupStreamStatus status) {
159   switch (status) {
160     case le_audio::GroupStreamStatus::IDLE:
161       return BtLeAudioGroupStreamStatus::Idle;
162     case le_audio::GroupStreamStatus::STREAMING:
163       return BtLeAudioGroupStreamStatus::Streaming;
164     case le_audio::GroupStreamStatus::RELEASING:
165       return BtLeAudioGroupStreamStatus::Releasing;
166     case le_audio::GroupStreamStatus::SUSPENDING:
167       return BtLeAudioGroupStreamStatus::Suspending;
168     case le_audio::GroupStreamStatus::SUSPENDED:
169       return BtLeAudioGroupStreamStatus::Suspended;
170     case le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS:
171       return BtLeAudioGroupStreamStatus::ConfiguredAutonomous;
172     case le_audio::GroupStreamStatus::CONFIGURED_BY_USER:
173       return BtLeAudioGroupStreamStatus::ConfiguredByUser;
174     case le_audio::GroupStreamStatus::DESTROYED:
175       return BtLeAudioGroupStreamStatus::Destroyed;
176     default:
177       log::assert_that(false, "Unhandled enum value from C++");
178   }
179   return BtLeAudioGroupStreamStatus{};
180 }
181 
initialized_cb()182 static void initialized_cb() {
183   le_audio_initialized_callback();
184 }
185 
connection_state_cb(le_audio::ConnectionState state,const RawAddress & address)186 static void connection_state_cb(le_audio::ConnectionState state, const RawAddress& address) {
187   le_audio_connection_state_callback(to_rust_btle_audio_connection_state(state), address);
188 }
189 
group_status_cb(int group_id,le_audio::GroupStatus group_status)190 static void group_status_cb(int group_id, le_audio::GroupStatus group_status) {
191   le_audio_group_status_callback(group_id, to_rust_btle_audio_group_status(group_status));
192 }
193 
group_node_status_cb(const RawAddress & bd_addr,int group_id,le_audio::GroupNodeStatus node_status)194 static void group_node_status_cb(
195     const RawAddress& bd_addr, int group_id, le_audio::GroupNodeStatus node_status) {
196   le_audio_group_node_status_callback(
197       bd_addr, group_id, to_rust_btle_audio_group_node_status(node_status));
198 }
199 
unicast_monitor_mode_status_cb(uint8_t direction,le_audio::UnicastMonitorModeStatus status)200 static void unicast_monitor_mode_status_cb(
201     uint8_t direction, le_audio::UnicastMonitorModeStatus status) {
202   le_audio_unicast_monitor_mode_status_callback(
203       to_rust_btle_audio_direction(direction),
204       to_rust_btle_audio_unicast_monitor_mode_status(status));
205 }
206 
group_stream_status_cb(int group_id,le_audio::GroupStreamStatus status)207 static void group_stream_status_cb(int group_id, le_audio::GroupStreamStatus status) {
208   le_audio_group_stream_status_callback(group_id, to_rust_btle_audio_group_stream_status(status));
209 }
210 
audio_conf_cb(uint8_t direction,int group_id,uint32_t snk_audio_location,uint32_t src_audio_location,uint16_t avail_cont)211 static void audio_conf_cb(
212     uint8_t direction,
213     int group_id,
214     uint32_t snk_audio_location,
215     uint32_t src_audio_location,
216     uint16_t avail_cont) {
217   le_audio_audio_conf_callback(
218       direction, group_id, snk_audio_location, src_audio_location, avail_cont);
219 }
220 
sink_audio_location_available_cb(const RawAddress & address,uint32_t snk_audio_locations)221 static void sink_audio_location_available_cb(
222     const RawAddress& address, uint32_t snk_audio_locations) {
223   le_audio_sink_audio_location_available_callback(address, snk_audio_locations);
224 }
225 
audio_local_codec_capabilities_cb(std::vector<le_audio::btle_audio_codec_config_t> local_input_capa_codec_conf,std::vector<le_audio::btle_audio_codec_config_t> local_output_capa_codec_conf)226 static void audio_local_codec_capabilities_cb(
227     std::vector<le_audio::btle_audio_codec_config_t> local_input_capa_codec_conf,
228     std::vector<le_audio::btle_audio_codec_config_t> local_output_capa_codec_conf) {
229   le_audio_audio_local_codec_capabilities_callback(
230       to_rust_btle_audio_codec_config_vec(local_input_capa_codec_conf),
231       to_rust_btle_audio_codec_config_vec(local_output_capa_codec_conf));
232 }
233 
audio_group_codec_conf_cb(int group_id,le_audio::btle_audio_codec_config_t input_codec_conf,le_audio::btle_audio_codec_config_t output_codec_conf,std::vector<le_audio::btle_audio_codec_config_t> input_selectable_codec_conf,std::vector<le_audio::btle_audio_codec_config_t> output_selectable_codec_conf)234 static void audio_group_codec_conf_cb(
235     int group_id,
236     le_audio::btle_audio_codec_config_t input_codec_conf,
237     le_audio::btle_audio_codec_config_t output_codec_conf,
238     std::vector<le_audio::btle_audio_codec_config_t> input_selectable_codec_conf,
239     std::vector<le_audio::btle_audio_codec_config_t> output_selectable_codec_conf) {
240   le_audio_audio_group_codec_conf_callback(
241       group_id,
242       to_rust_btle_audio_codec_config(input_codec_conf),
243       to_rust_btle_audio_codec_config(output_codec_conf),
244       to_rust_btle_audio_codec_config_vec(input_selectable_codec_conf),
245       to_rust_btle_audio_codec_config_vec(output_selectable_codec_conf));
246 }
247 }  // namespace internal
248 
249 class DBusLeAudioClientCallbacks : public le_audio::LeAudioClientCallbacks {
250  public:
GetInstance()251   static le_audio::LeAudioClientCallbacks* GetInstance() {
252     static auto instance = new DBusLeAudioClientCallbacks();
253     return instance;
254   }
255 
DBusLeAudioClientCallbacks()256   DBusLeAudioClientCallbacks(){};
257 
OnInitialized()258   void OnInitialized() override {
259     log::info("");
260     topshim::rust::internal::initialized_cb();
261   }
262 
OnConnectionState(le_audio::ConnectionState state,const RawAddress & address)263   void OnConnectionState(le_audio::ConnectionState state, const RawAddress& address) override {
264     log::info("state={}, address={}", static_cast<int>(state), ADDRESS_TO_LOGGABLE_CSTR(address));
265     topshim::rust::internal::connection_state_cb(state, address);
266   }
267 
OnGroupStatus(int group_id,le_audio::GroupStatus group_status)268   void OnGroupStatus(int group_id, le_audio::GroupStatus group_status) override {
269     log::info("group_id={}, group_status={}", group_id, static_cast<int>(group_status));
270     topshim::rust::internal::group_status_cb(group_id, group_status);
271   }
272 
OnGroupNodeStatus(const RawAddress & bd_addr,int group_id,le_audio::GroupNodeStatus node_status)273   void OnGroupNodeStatus(
274       const RawAddress& bd_addr, int group_id, le_audio::GroupNodeStatus node_status) {
275     log::info(
276         "bd_addr={}, group_id={}, node_status={}",
277         ADDRESS_TO_LOGGABLE_CSTR(bd_addr),
278         group_id,
279         static_cast<int>(node_status));
280     topshim::rust::internal::group_node_status_cb(bd_addr, group_id, node_status);
281   }
282 
OnAudioConf(uint8_t direction,int group_id,uint32_t snk_audio_location,uint32_t src_audio_location,uint16_t avail_cont)283   void OnAudioConf(
284       uint8_t direction,
285       int group_id,
286       uint32_t snk_audio_location,
287       uint32_t src_audio_location,
288       uint16_t avail_cont) {
289     log::info(
290         "direction={}, group_id={}, snk_audio_location={}, src_audio_location={}, avail_cont={}",
291         direction,
292         group_id,
293         snk_audio_location,
294         src_audio_location,
295         avail_cont);
296     topshim::rust::internal::audio_conf_cb(
297         direction, group_id, snk_audio_location, src_audio_location, avail_cont);
298   }
299 
OnSinkAudioLocationAvailable(const RawAddress & address,uint32_t snk_audio_locations)300   void OnSinkAudioLocationAvailable(const RawAddress& address, uint32_t snk_audio_locations) {
301     log::info(
302         "address={}, snk_audio_locations={}",
303         ADDRESS_TO_LOGGABLE_CSTR(address),
304         snk_audio_locations);
305     topshim::rust::internal::sink_audio_location_available_cb(address, snk_audio_locations);
306   }
307 
OnAudioLocalCodecCapabilities(std::vector<le_audio::btle_audio_codec_config_t> local_input_capa_codec_conf,std::vector<le_audio::btle_audio_codec_config_t> local_output_capa_codec_conf)308   void OnAudioLocalCodecCapabilities(
309       std::vector<le_audio::btle_audio_codec_config_t> local_input_capa_codec_conf,
310       std::vector<le_audio::btle_audio_codec_config_t> local_output_capa_codec_conf) {
311     log::info("");
312     topshim::rust::internal::audio_local_codec_capabilities_cb(
313         local_input_capa_codec_conf, local_output_capa_codec_conf);
314   }
315 
OnAudioGroupCodecConf(int group_id,le_audio::btle_audio_codec_config_t input_codec_conf,le_audio::btle_audio_codec_config_t output_codec_conf,std::vector<le_audio::btle_audio_codec_config_t> input_selectable_codec_conf,std::vector<le_audio::btle_audio_codec_config_t> output_selectable_codec_conf)316   void OnAudioGroupCodecConf(
317       int group_id,
318       le_audio::btle_audio_codec_config_t input_codec_conf,
319       le_audio::btle_audio_codec_config_t output_codec_conf,
320       std::vector<le_audio::btle_audio_codec_config_t> input_selectable_codec_conf,
321       std::vector<le_audio::btle_audio_codec_config_t> output_selectable_codec_conf) {
322     log::info("group_id={}", group_id);
323     topshim::rust::internal::audio_group_codec_conf_cb(
324         group_id,
325         input_codec_conf,
326         output_codec_conf,
327         input_selectable_codec_conf,
328         output_selectable_codec_conf);
329   }
330 
OnAudioGroupCurrentCodecConf(int group_id,le_audio::btle_audio_codec_config_t input_codec_conf,le_audio::btle_audio_codec_config_t output_codec_conf)331   void OnAudioGroupCurrentCodecConf(
332       int group_id,
333       le_audio::btle_audio_codec_config_t input_codec_conf,
334       le_audio::btle_audio_codec_config_t output_codec_conf) {
335     log::info(
336         "group_id={}, input_codec_conf={}, output_codec_conf={}",
337         group_id,
338         input_codec_conf.ToString(),
339         output_codec_conf.ToString());
340   }
341 
OnAudioGroupSelectableCodecConf(int group_id,std::vector<le_audio::btle_audio_codec_config_t> input_selectable_codec_conf,std::vector<le_audio::btle_audio_codec_config_t> output_selectable_codec_conf)342   void OnAudioGroupSelectableCodecConf(
343       int group_id,
344       std::vector<le_audio::btle_audio_codec_config_t> input_selectable_codec_conf,
345       std::vector<le_audio::btle_audio_codec_config_t> output_selectable_codec_conf) {
346     log::info(
347         "group_id={}, input_selectable_codec_conf.size={}, output_selectable_codec_conf.size={}",
348         group_id,
349         input_selectable_codec_conf.size(),
350         output_selectable_codec_conf.size());
351   }
352 
OnHealthBasedRecommendationAction(const RawAddress & address,le_audio::LeAudioHealthBasedAction action)353   void OnHealthBasedRecommendationAction(
354       const RawAddress& address, le_audio::LeAudioHealthBasedAction action) {
355     log::info("address={}, action={}", ADDRESS_TO_LOGGABLE_CSTR(address), static_cast<int>(action));
356   }
357 
OnHealthBasedGroupRecommendationAction(int group_id,le_audio::LeAudioHealthBasedAction action)358   void OnHealthBasedGroupRecommendationAction(
359       int group_id, le_audio::LeAudioHealthBasedAction action) {
360     log::info("group_id={}, action={}", group_id, static_cast<int>(action));
361   }
362 
OnUnicastMonitorModeStatus(uint8_t direction,le_audio::UnicastMonitorModeStatus status)363   void OnUnicastMonitorModeStatus(uint8_t direction, le_audio::UnicastMonitorModeStatus status) {
364     log::info("direction={}, status={}", direction, static_cast<int>(status));
365     topshim::rust::internal::unicast_monitor_mode_status_cb(direction, status);
366   }
367 
OnGroupStreamStatus(int group_id,le_audio::GroupStreamStatus status)368   void OnGroupStreamStatus(int group_id, le_audio::GroupStreamStatus status) {
369     log::info("group_id={}, status={}", group_id, static_cast<int>(status));
370     topshim::rust::internal::group_stream_status_cb(group_id, status);
371   }
372 };
373 
init()374 void LeAudioClientIntf::init(/*
375      LeAudioClientCallbacks* callbacks,
376      const std::vector<le_audio::btle_audio_codec_config_t>& offloading_preference */) {
377   return intf_->Initialize(DBusLeAudioClientCallbacks::GetInstance(), {});
378 }
379 
connect(RawAddress addr)380 void LeAudioClientIntf::connect(RawAddress addr) {
381   return intf_->Connect(addr);
382 }
383 
disconnect(RawAddress addr)384 void LeAudioClientIntf::disconnect(RawAddress addr) {
385   return intf_->Disconnect(addr);
386 }
387 
set_enable_state(RawAddress addr,bool enabled)388 void LeAudioClientIntf::set_enable_state(RawAddress addr, bool enabled) {
389   return intf_->SetEnableState(addr, enabled);
390 }
391 
cleanup()392 void LeAudioClientIntf::cleanup() {
393   return intf_->Cleanup();
394 }
395 
remove_device(RawAddress addr)396 void LeAudioClientIntf::remove_device(RawAddress addr) {
397   return intf_->RemoveDevice(addr);
398 }
399 
group_add_node(int group_id,RawAddress addr)400 void LeAudioClientIntf::group_add_node(int group_id, RawAddress addr) {
401   return intf_->GroupAddNode(group_id, addr);
402 }
403 
group_remove_node(int group_id,RawAddress addr)404 void LeAudioClientIntf::group_remove_node(int group_id, RawAddress addr) {
405   return intf_->GroupRemoveNode(group_id, addr);
406 }
407 
group_set_active(int group_id)408 void LeAudioClientIntf::group_set_active(int group_id) {
409   return intf_->GroupSetActive(group_id);
410 }
411 
set_codec_config_preference(int group_id,BtLeAudioCodecConfig input_codec_config,BtLeAudioCodecConfig output_codec_config)412 void LeAudioClientIntf::set_codec_config_preference(
413     int group_id,
414     BtLeAudioCodecConfig input_codec_config,
415     BtLeAudioCodecConfig output_codec_config) {
416   return intf_->SetCodecConfigPreference(
417       group_id,
418       internal::from_rust_btle_audio_codec_config(input_codec_config),
419       internal::from_rust_btle_audio_codec_config(output_codec_config));
420 }
421 
set_ccid_information(int ccid,int context_type)422 void LeAudioClientIntf::set_ccid_information(int ccid, int context_type) {
423   return intf_->SetCcidInformation(ccid, context_type);
424 }
425 
set_in_call(bool in_call)426 void LeAudioClientIntf::set_in_call(bool in_call) {
427   return intf_->SetInCall(in_call);
428 }
429 
send_audio_profile_preferences(int group_id,bool is_output_preference_le_audio,bool is_duplex_preference_le_audio)430 void LeAudioClientIntf::send_audio_profile_preferences(
431     int group_id, bool is_output_preference_le_audio, bool is_duplex_preference_le_audio) {
432   return intf_->SendAudioProfilePreferences(
433       group_id, is_output_preference_le_audio, is_duplex_preference_le_audio);
434 }
435 
set_unicast_monitor_mode(BtLeAudioDirection direction,bool enable)436 void LeAudioClientIntf::set_unicast_monitor_mode(BtLeAudioDirection direction, bool enable) {
437   return intf_->SetUnicastMonitorMode(internal::from_rust_btle_audio_direction(direction), enable);
438 }
439 
GetLeAudioClientProfile(const unsigned char * btif)440 std::unique_ptr<LeAudioClientIntf> GetLeAudioClientProfile(const unsigned char* btif) {
441   if (internal::g_lea_client_if) std::abort();
442 
443   const bt_interface_t* btif_ = reinterpret_cast<const bt_interface_t*>(btif);
444 
445   auto lea_client_if =
446       std::make_unique<LeAudioClientIntf>(const_cast<le_audio::LeAudioClientInterface*>(
447           reinterpret_cast<const le_audio::LeAudioClientInterface*>(
448               btif_->get_profile_interface("le_audio"))));
449 
450   internal::g_lea_client_if = lea_client_if.get();
451 
452   return lea_client_if;
453 }
454 
host_start_audio_request()455 bool LeAudioClientIntf::host_start_audio_request() {
456   return ::bluetooth::audio::le_audio::HostStartRequest();
457 }
458 
host_stop_audio_request()459 void LeAudioClientIntf::host_stop_audio_request() {
460   ::bluetooth::audio::le_audio::HostStopRequest();
461 }
462 
peer_start_audio_request()463 bool LeAudioClientIntf::peer_start_audio_request() {
464   return ::bluetooth::audio::le_audio::PeerStartRequest();
465 }
466 
peer_stop_audio_request()467 void LeAudioClientIntf::peer_stop_audio_request() {
468   ::bluetooth::audio::le_audio::PeerStopRequest();
469 }
470 
to_rust_btle_pcm_params(audio::le_audio::btle_pcm_parameters pcm_params)471 static BtLePcmConfig to_rust_btle_pcm_params(audio::le_audio::btle_pcm_parameters pcm_params) {
472   return BtLePcmConfig{
473       .data_interval_us = pcm_params.data_interval_us,
474       .sample_rate = pcm_params.sample_rate,
475       .bits_per_sample = pcm_params.bits_per_sample,
476       .channels_count = pcm_params.channels_count,
477   };
478 }
479 
get_host_pcm_config()480 BtLePcmConfig LeAudioClientIntf::get_host_pcm_config() {
481   return to_rust_btle_pcm_params(::bluetooth::audio::le_audio::GetHostPcmConfig());
482 }
483 
get_peer_pcm_config()484 BtLePcmConfig LeAudioClientIntf::get_peer_pcm_config() {
485   return to_rust_btle_pcm_params(::bluetooth::audio::le_audio::GetPeerPcmConfig());
486 }
487 
to_rust_btle_stream_started_status(audio::le_audio::btle_stream_started_status status)488 static BtLeStreamStartedStatus to_rust_btle_stream_started_status(
489     audio::le_audio::btle_stream_started_status status) {
490   switch (status) {
491     case audio::le_audio::btle_stream_started_status::CANCELED:
492       return BtLeStreamStartedStatus::Canceled;
493     case audio::le_audio::btle_stream_started_status::IDLE:
494       return BtLeStreamStartedStatus::Idle;
495     case audio::le_audio::btle_stream_started_status::STARTED:
496       return BtLeStreamStartedStatus::Started;
497     default:
498       log::assert_that(false, "Unhandled enum value from C++");
499   }
500   return BtLeStreamStartedStatus{};
501 }
502 
get_host_stream_started()503 BtLeStreamStartedStatus LeAudioClientIntf::get_host_stream_started() {
504   return to_rust_btle_stream_started_status(::bluetooth::audio::le_audio::GetHostStreamStarted());
505 }
506 
get_peer_stream_started()507 BtLeStreamStartedStatus LeAudioClientIntf::get_peer_stream_started() {
508   return to_rust_btle_stream_started_status(::bluetooth::audio::le_audio::GetPeerStreamStarted());
509 }
510 
source_metadata_changed(::rust::Vec<SourceMetadata> metadata)511 void LeAudioClientIntf::source_metadata_changed(::rust::Vec<SourceMetadata> metadata) {
512   if (metadata.empty()) {
513     log::warn("Received empty metadata.");
514     return;
515   }
516 
517   // This will be referenced across threads.
518   static std::vector<playback_track_metadata_v7> tracks;
519   tracks.clear();
520   tracks.reserve(metadata.size());
521   for (auto m : metadata) {
522     struct playback_track_metadata_v7 track = {
523         .base =
524             {
525                 .usage = static_cast<audio_usage_t>(m.usage),
526                 .content_type = static_cast<audio_content_type_t>(m.content_type),
527                 .gain = static_cast<float>(m.gain),
528             },
529         .channel_mask = AUDIO_CHANNEL_NONE,  // unused
530         .tags = "",
531     };
532 
533     tracks.push_back(track);
534   }
535 
536   source_metadata_v7_t data = {
537       .track_count = tracks.size(),
538       .tracks = tracks.data(),
539   };
540 
541   ::bluetooth::audio::le_audio::SourceMetadataChanged(data);
542 }
543 
sink_metadata_changed(::rust::Vec<SinkMetadata> metadata)544 void LeAudioClientIntf::sink_metadata_changed(::rust::Vec<SinkMetadata> metadata) {
545   if (metadata.empty()) {
546     log::warn("Received empty metadata.");
547     return;
548   }
549 
550   // This will be referenced across threads.
551   static std::vector<record_track_metadata_v7> tracks;
552   tracks.clear();
553   tracks.reserve(metadata.size());
554   for (auto m : metadata) {
555     struct record_track_metadata_v7 track = {
556         .base =
557             {
558                 .source = static_cast<audio_source_t>(m.source),
559                 .gain = static_cast<float>(m.gain),
560                 .dest_device = AUDIO_DEVICE_IN_DEFAULT,
561                 .dest_device_address = "",  // unused
562             },
563         .channel_mask = AUDIO_CHANNEL_NONE,  // unused
564         .tags = "",
565     };
566 
567     tracks.push_back(track);
568   }
569 
570   const sink_metadata_v7_t data = {
571       .track_count = tracks.size(),
572       .tracks = tracks.data(),
573   };
574 
575   ::bluetooth::audio::le_audio::SinkMetadataChanged(data);
576 }
577 }  // namespace rust
578 }  // namespace topshim
579 }  // namespace bluetooth
580