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