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