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