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