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::SUSPENDING:
166       return BtLeAudioGroupStreamStatus::Suspending;
167     case le_audio::GroupStreamStatus::SUSPENDED:
168       return BtLeAudioGroupStreamStatus::Suspended;
169     case le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS:
170       return BtLeAudioGroupStreamStatus::ConfiguredAutonomous;
171     case le_audio::GroupStreamStatus::CONFIGURED_BY_USER:
172       return BtLeAudioGroupStreamStatus::ConfiguredByUser;
173     case le_audio::GroupStreamStatus::DESTROYED:
174       return BtLeAudioGroupStreamStatus::Destroyed;
175     default:
176       log::assert_that(false, "Unhandled enum value from C++");
177   }
178   return BtLeAudioGroupStreamStatus{};
179 }
180 
initialized_cb()181 static void initialized_cb() { le_audio_initialized_callback(); }
182 
connection_state_cb(le_audio::ConnectionState state,const RawAddress & address)183 static void connection_state_cb(le_audio::ConnectionState state, const RawAddress& address) {
184   le_audio_connection_state_callback(to_rust_btle_audio_connection_state(state), address);
185 }
186 
group_status_cb(int group_id,le_audio::GroupStatus group_status)187 static void group_status_cb(int group_id, le_audio::GroupStatus group_status) {
188   le_audio_group_status_callback(group_id, to_rust_btle_audio_group_status(group_status));
189 }
190 
group_node_status_cb(const RawAddress & bd_addr,int group_id,le_audio::GroupNodeStatus node_status)191 static void group_node_status_cb(const RawAddress& bd_addr, int group_id,
192                                  le_audio::GroupNodeStatus node_status) {
193   le_audio_group_node_status_callback(bd_addr, group_id,
194                                       to_rust_btle_audio_group_node_status(node_status));
195 }
196 
unicast_monitor_mode_status_cb(uint8_t direction,le_audio::UnicastMonitorModeStatus status)197 static void unicast_monitor_mode_status_cb(uint8_t direction,
198                                            le_audio::UnicastMonitorModeStatus status) {
199   le_audio_unicast_monitor_mode_status_callback(
200           to_rust_btle_audio_direction(direction),
201           to_rust_btle_audio_unicast_monitor_mode_status(status));
202 }
203 
group_stream_status_cb(int group_id,le_audio::GroupStreamStatus status)204 static void group_stream_status_cb(int group_id, le_audio::GroupStreamStatus status) {
205   le_audio_group_stream_status_callback(group_id, to_rust_btle_audio_group_stream_status(status));
206 }
207 
audio_conf_cb(uint8_t direction,int group_id,uint32_t snk_audio_location,uint32_t src_audio_location,uint16_t avail_cont)208 static void audio_conf_cb(uint8_t direction, int group_id, uint32_t snk_audio_location,
209                           uint32_t src_audio_location, uint16_t avail_cont) {
210   le_audio_audio_conf_callback(direction, group_id, snk_audio_location, src_audio_location,
211                                avail_cont);
212 }
213 
sink_audio_location_available_cb(const RawAddress & address,uint32_t snk_audio_locations)214 static void sink_audio_location_available_cb(const RawAddress& address,
215                                              uint32_t snk_audio_locations) {
216   le_audio_sink_audio_location_available_callback(address, snk_audio_locations);
217 }
218 
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)219 static void audio_local_codec_capabilities_cb(
220         std::vector<le_audio::btle_audio_codec_config_t> local_input_capa_codec_conf,
221         std::vector<le_audio::btle_audio_codec_config_t> local_output_capa_codec_conf) {
222   le_audio_audio_local_codec_capabilities_callback(
223           to_rust_btle_audio_codec_config_vec(local_input_capa_codec_conf),
224           to_rust_btle_audio_codec_config_vec(local_output_capa_codec_conf));
225 }
226 
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)227 static void audio_group_codec_conf_cb(
228         int group_id, le_audio::btle_audio_codec_config_t input_codec_conf,
229         le_audio::btle_audio_codec_config_t output_codec_conf,
230         std::vector<le_audio::btle_audio_codec_config_t> input_selectable_codec_conf,
231         std::vector<le_audio::btle_audio_codec_config_t> output_selectable_codec_conf) {
232   le_audio_audio_group_codec_conf_callback(
233           group_id, to_rust_btle_audio_codec_config(input_codec_conf),
234           to_rust_btle_audio_codec_config(output_codec_conf),
235           to_rust_btle_audio_codec_config_vec(input_selectable_codec_conf),
236           to_rust_btle_audio_codec_config_vec(output_selectable_codec_conf));
237 }
238 }  // namespace internal
239 
240 class DBusLeAudioClientCallbacks : public le_audio::LeAudioClientCallbacks {
241 public:
GetInstance()242   static le_audio::LeAudioClientCallbacks* GetInstance() {
243     static auto instance = new DBusLeAudioClientCallbacks();
244     return instance;
245   }
246 
DBusLeAudioClientCallbacks()247   DBusLeAudioClientCallbacks() {}
248 
OnInitialized()249   void OnInitialized() override {
250     log::info("");
251     topshim::rust::internal::initialized_cb();
252   }
253 
OnConnectionState(le_audio::ConnectionState state,const RawAddress & address)254   void OnConnectionState(le_audio::ConnectionState state, const RawAddress& address) override {
255     log::info("state={}, address={}", static_cast<int>(state), address);
256     topshim::rust::internal::connection_state_cb(state, address);
257   }
258 
OnGroupStatus(int group_id,le_audio::GroupStatus group_status)259   void OnGroupStatus(int group_id, le_audio::GroupStatus group_status) override {
260     log::info("group_id={}, group_status={}", group_id, static_cast<int>(group_status));
261     topshim::rust::internal::group_status_cb(group_id, group_status);
262   }
263 
OnGroupNodeStatus(const RawAddress & bd_addr,int group_id,le_audio::GroupNodeStatus node_status)264   void OnGroupNodeStatus(const RawAddress& bd_addr, int group_id,
265                          le_audio::GroupNodeStatus node_status) {
266     log::info("bd_addr={}, group_id={}, node_status={}", bd_addr, group_id,
267               static_cast<int>(node_status));
268     topshim::rust::internal::group_node_status_cb(bd_addr, group_id, node_status);
269   }
270 
OnAudioConf(uint8_t direction,int group_id,uint32_t snk_audio_location,uint32_t src_audio_location,uint16_t avail_cont)271   void OnAudioConf(uint8_t direction, int group_id, uint32_t snk_audio_location,
272                    uint32_t src_audio_location, uint16_t avail_cont) {
273     log::info(
274             "direction={}, group_id={}, snk_audio_location={}, src_audio_location={}, "
275             "avail_cont={}",
276             direction, group_id, snk_audio_location, src_audio_location, avail_cont);
277     topshim::rust::internal::audio_conf_cb(direction, group_id, snk_audio_location,
278                                            src_audio_location, avail_cont);
279   }
280 
OnSinkAudioLocationAvailable(const RawAddress & address,uint32_t snk_audio_locations)281   void OnSinkAudioLocationAvailable(const RawAddress& address, uint32_t snk_audio_locations) {
282     log::info("address={}, snk_audio_locations={}", address, snk_audio_locations);
283     topshim::rust::internal::sink_audio_location_available_cb(address, snk_audio_locations);
284   }
285 
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)286   void OnAudioLocalCodecCapabilities(
287           std::vector<le_audio::btle_audio_codec_config_t> local_input_capa_codec_conf,
288           std::vector<le_audio::btle_audio_codec_config_t> local_output_capa_codec_conf) {
289     log::info("");
290     topshim::rust::internal::audio_local_codec_capabilities_cb(local_input_capa_codec_conf,
291                                                                local_output_capa_codec_conf);
292   }
293 
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)294   void OnAudioGroupCodecConf(
295           int group_id, le_audio::btle_audio_codec_config_t input_codec_conf,
296           le_audio::btle_audio_codec_config_t output_codec_conf,
297           std::vector<le_audio::btle_audio_codec_config_t> input_selectable_codec_conf,
298           std::vector<le_audio::btle_audio_codec_config_t> output_selectable_codec_conf) {
299     log::info("group_id={}", group_id);
300     topshim::rust::internal::audio_group_codec_conf_cb(
301             group_id, input_codec_conf, output_codec_conf, input_selectable_codec_conf,
302             output_selectable_codec_conf);
303   }
304 
OnAudioGroupCurrentCodecConf(int group_id,le_audio::btle_audio_codec_config_t input_codec_conf,le_audio::btle_audio_codec_config_t output_codec_conf)305   void OnAudioGroupCurrentCodecConf(int group_id,
306                                     le_audio::btle_audio_codec_config_t input_codec_conf,
307                                     le_audio::btle_audio_codec_config_t output_codec_conf) {
308     log::info("group_id={}, input_codec_conf={}, output_codec_conf={}", group_id,
309               input_codec_conf.ToString(), output_codec_conf.ToString());
310   }
311 
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)312   void OnAudioGroupSelectableCodecConf(
313           int group_id,
314           std::vector<le_audio::btle_audio_codec_config_t> input_selectable_codec_conf,
315           std::vector<le_audio::btle_audio_codec_config_t> output_selectable_codec_conf) {
316     log::info(
317             "group_id={}, input_selectable_codec_conf.size={}, "
318             "output_selectable_codec_conf.size={}",
319             group_id, input_selectable_codec_conf.size(), output_selectable_codec_conf.size());
320   }
321 
OnHealthBasedRecommendationAction(const RawAddress & address,le_audio::LeAudioHealthBasedAction action)322   void OnHealthBasedRecommendationAction(const RawAddress& address,
323                                          le_audio::LeAudioHealthBasedAction action) {
324     log::info("address={}, action={}", address, static_cast<int>(action));
325   }
326 
OnHealthBasedGroupRecommendationAction(int group_id,le_audio::LeAudioHealthBasedAction action)327   void OnHealthBasedGroupRecommendationAction(int group_id,
328                                               le_audio::LeAudioHealthBasedAction action) {
329     log::info("group_id={}, action={}", group_id, static_cast<int>(action));
330   }
331 
OnUnicastMonitorModeStatus(uint8_t direction,le_audio::UnicastMonitorModeStatus status)332   void OnUnicastMonitorModeStatus(uint8_t direction, le_audio::UnicastMonitorModeStatus status) {
333     log::info("direction={}, status={}", direction, static_cast<int>(status));
334     topshim::rust::internal::unicast_monitor_mode_status_cb(direction, status);
335   }
336 
OnGroupStreamStatus(int group_id,le_audio::GroupStreamStatus status)337   void OnGroupStreamStatus(int group_id, le_audio::GroupStreamStatus status) {
338     log::info("group_id={}, status={}", group_id, static_cast<int>(status));
339     topshim::rust::internal::group_stream_status_cb(group_id, status);
340   }
341 };
342 
init()343 void LeAudioClientIntf::init(/*
344      LeAudioClientCallbacks* callbacks,
345      const std::vector<le_audio::btle_audio_codec_config_t>& offloading_preference */) {
346   return intf_->Initialize(DBusLeAudioClientCallbacks::GetInstance(), {});
347 }
348 
connect(RawAddress addr)349 void LeAudioClientIntf::connect(RawAddress addr) { return intf_->Connect(addr); }
350 
disconnect(RawAddress addr)351 void LeAudioClientIntf::disconnect(RawAddress addr) { return intf_->Disconnect(addr); }
352 
set_enable_state(RawAddress addr,bool enabled)353 void LeAudioClientIntf::set_enable_state(RawAddress addr, bool enabled) {
354   return intf_->SetEnableState(addr, enabled);
355 }
356 
cleanup()357 void LeAudioClientIntf::cleanup() { return intf_->Cleanup(); }
358 
remove_device(RawAddress addr)359 void LeAudioClientIntf::remove_device(RawAddress addr) { return intf_->RemoveDevice(addr); }
360 
group_add_node(int group_id,RawAddress addr)361 void LeAudioClientIntf::group_add_node(int group_id, RawAddress addr) {
362   return intf_->GroupAddNode(group_id, addr);
363 }
364 
group_remove_node(int group_id,RawAddress addr)365 void LeAudioClientIntf::group_remove_node(int group_id, RawAddress addr) {
366   return intf_->GroupRemoveNode(group_id, addr);
367 }
368 
group_set_active(int group_id)369 void LeAudioClientIntf::group_set_active(int group_id) { return intf_->GroupSetActive(group_id); }
370 
set_codec_config_preference(int group_id,BtLeAudioCodecConfig input_codec_config,BtLeAudioCodecConfig output_codec_config)371 void LeAudioClientIntf::set_codec_config_preference(int group_id,
372                                                     BtLeAudioCodecConfig input_codec_config,
373                                                     BtLeAudioCodecConfig output_codec_config) {
374   return intf_->SetCodecConfigPreference(
375           group_id, internal::from_rust_btle_audio_codec_config(input_codec_config),
376           internal::from_rust_btle_audio_codec_config(output_codec_config));
377 }
378 
set_ccid_information(int ccid,int context_type)379 void LeAudioClientIntf::set_ccid_information(int ccid, int context_type) {
380   return intf_->SetCcidInformation(ccid, context_type);
381 }
382 
set_in_call(bool in_call)383 void LeAudioClientIntf::set_in_call(bool in_call) { return intf_->SetInCall(in_call); }
384 
send_audio_profile_preferences(int group_id,bool is_output_preference_le_audio,bool is_duplex_preference_le_audio)385 void LeAudioClientIntf::send_audio_profile_preferences(int group_id,
386                                                        bool is_output_preference_le_audio,
387                                                        bool is_duplex_preference_le_audio) {
388   return intf_->SendAudioProfilePreferences(group_id, is_output_preference_le_audio,
389                                             is_duplex_preference_le_audio);
390 }
391 
set_unicast_monitor_mode(BtLeAudioDirection direction,bool enable)392 void LeAudioClientIntf::set_unicast_monitor_mode(BtLeAudioDirection direction, bool enable) {
393   return intf_->SetUnicastMonitorMode(internal::from_rust_btle_audio_direction(direction), enable);
394 }
395 
GetLeAudioClientProfile(const unsigned char * btif)396 std::unique_ptr<LeAudioClientIntf> GetLeAudioClientProfile(const unsigned char* btif) {
397   if (internal::g_lea_client_if) {
398     std::abort();
399   }
400 
401   const bt_interface_t* btif_ = reinterpret_cast<const bt_interface_t*>(btif);
402 
403   auto lea_client_if =
404           std::make_unique<LeAudioClientIntf>(const_cast<le_audio::LeAudioClientInterface*>(
405                   reinterpret_cast<const le_audio::LeAudioClientInterface*>(
406                           btif_->get_profile_interface("le_audio"))));
407 
408   internal::g_lea_client_if = lea_client_if.get();
409 
410   return lea_client_if;
411 }
412 
host_start_audio_request()413 bool LeAudioClientIntf::host_start_audio_request() {
414   return ::bluetooth::audio::le_audio::HostStartRequest();
415 }
416 
host_stop_audio_request()417 void LeAudioClientIntf::host_stop_audio_request() {
418   ::bluetooth::audio::le_audio::HostStopRequest();
419 }
420 
peer_start_audio_request()421 bool LeAudioClientIntf::peer_start_audio_request() {
422   return ::bluetooth::audio::le_audio::PeerStartRequest();
423 }
424 
peer_stop_audio_request()425 void LeAudioClientIntf::peer_stop_audio_request() {
426   ::bluetooth::audio::le_audio::PeerStopRequest();
427 }
428 
to_rust_btle_pcm_params(audio::le_audio::btle_pcm_parameters pcm_params)429 static BtLePcmConfig to_rust_btle_pcm_params(audio::le_audio::btle_pcm_parameters pcm_params) {
430   return BtLePcmConfig{
431           .data_interval_us = pcm_params.data_interval_us,
432           .sample_rate = pcm_params.sample_rate,
433           .bits_per_sample = pcm_params.bits_per_sample,
434           .channels_count = pcm_params.channels_count,
435   };
436 }
437 
get_host_pcm_config()438 BtLePcmConfig LeAudioClientIntf::get_host_pcm_config() {
439   return to_rust_btle_pcm_params(::bluetooth::audio::le_audio::GetHostPcmConfig());
440 }
441 
get_peer_pcm_config()442 BtLePcmConfig LeAudioClientIntf::get_peer_pcm_config() {
443   return to_rust_btle_pcm_params(::bluetooth::audio::le_audio::GetPeerPcmConfig());
444 }
445 
to_rust_btle_stream_started_status(audio::le_audio::btle_stream_started_status status)446 static BtLeStreamStartedStatus to_rust_btle_stream_started_status(
447         audio::le_audio::btle_stream_started_status status) {
448   switch (status) {
449     case audio::le_audio::btle_stream_started_status::CANCELED:
450       return BtLeStreamStartedStatus::Canceled;
451     case audio::le_audio::btle_stream_started_status::IDLE:
452       return BtLeStreamStartedStatus::Idle;
453     case audio::le_audio::btle_stream_started_status::STARTED:
454       return BtLeStreamStartedStatus::Started;
455     default:
456       log::assert_that(false, "Unhandled enum value from C++");
457   }
458   return BtLeStreamStartedStatus{};
459 }
460 
get_host_stream_started()461 BtLeStreamStartedStatus LeAudioClientIntf::get_host_stream_started() {
462   return to_rust_btle_stream_started_status(::bluetooth::audio::le_audio::GetHostStreamStarted());
463 }
464 
get_peer_stream_started()465 BtLeStreamStartedStatus LeAudioClientIntf::get_peer_stream_started() {
466   return to_rust_btle_stream_started_status(::bluetooth::audio::le_audio::GetPeerStreamStarted());
467 }
468 
source_metadata_changed(::rust::Vec<SourceMetadata> metadata)469 void LeAudioClientIntf::source_metadata_changed(::rust::Vec<SourceMetadata> metadata) {
470   if (metadata.empty()) {
471     log::warn("Received empty metadata.");
472     return;
473   }
474 
475   // This will be referenced across threads.
476   static std::vector<playback_track_metadata_v7> tracks;
477   tracks.clear();
478   tracks.reserve(metadata.size());
479   for (auto m : metadata) {
480     struct playback_track_metadata_v7 track = {
481             .base =
482                     {
483                             .usage = static_cast<audio_usage_t>(m.usage),
484                             .content_type = static_cast<audio_content_type_t>(m.content_type),
485                             .gain = static_cast<float>(m.gain),
486                     },
487             .channel_mask = AUDIO_CHANNEL_NONE,  // unused
488             .tags = "",
489     };
490 
491     tracks.push_back(track);
492   }
493 
494   source_metadata_v7_t data = {
495           .track_count = tracks.size(),
496           .tracks = tracks.data(),
497   };
498 
499   ::bluetooth::audio::le_audio::SourceMetadataChanged(data);
500 }
501 
sink_metadata_changed(::rust::Vec<SinkMetadata> metadata)502 void LeAudioClientIntf::sink_metadata_changed(::rust::Vec<SinkMetadata> metadata) {
503   if (metadata.empty()) {
504     log::warn("Received empty metadata.");
505     return;
506   }
507 
508   // This will be referenced across threads.
509   static std::vector<record_track_metadata_v7> tracks;
510   tracks.clear();
511   tracks.reserve(metadata.size());
512   for (auto m : metadata) {
513     struct record_track_metadata_v7 track = {
514             .base =
515                     {
516                             .source = static_cast<audio_source_t>(m.source),
517                             .gain = static_cast<float>(m.gain),
518                             .dest_device = AUDIO_DEVICE_IN_DEFAULT,
519                             .dest_device_address = "",  // unused
520                     },
521             .channel_mask = AUDIO_CHANNEL_NONE,  // unused
522             .tags = "",
523     };
524 
525     tracks.push_back(track);
526   }
527 
528   const sink_metadata_v7_t data = {
529           .track_count = tracks.size(),
530           .tracks = tracks.data(),
531   };
532 
533   ::bluetooth::audio::le_audio::SinkMetadataChanged(data);
534 }
535 }  // namespace rust
536 }  // namespace topshim
537 }  // namespace bluetooth
538