1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/profile_server.h"
16
17 #include <string.h>
18 #include <zircon/status.h>
19 #include <zircon/syscalls/clock.h>
20
21 #include <cstddef>
22 #include <memory>
23
24 #include "fuchsia/bluetooth/bredr/cpp/fidl.h"
25 #include "lib/fidl/cpp/binding.h"
26 #include "lib/fidl/cpp/interface_ptr.h"
27 #include "lib/fpromise/result.h"
28 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/helpers.h"
29 #include "pw_bluetooth_sapphire/internal/host/common/host_error.h"
30 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
31 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h"
32 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h"
33 #include "pw_intrusive_ptr/intrusive_ptr.h"
34 #include "zircon/errors.h"
35
36 namespace fidlbredr = fuchsia::bluetooth::bredr;
37 namespace fbt = fuchsia::bluetooth;
38 namespace android_emb = pw::bluetooth::vendor::android_hci;
39 using fidlbredr::DataElement;
40 using fidlbredr::Profile;
41 using pw::bluetooth::AclPriority;
42 using FeaturesBits = pw::bluetooth::Controller::FeaturesBits;
43
44 namespace bthost {
45
46 namespace {
47
FidlToChannelParameters(const fbt::ChannelParameters & fidl)48 bt::l2cap::ChannelParameters FidlToChannelParameters(
49 const fbt::ChannelParameters& fidl) {
50 bt::l2cap::ChannelParameters params;
51 if (fidl.has_channel_mode()) {
52 switch (fidl.channel_mode()) {
53 case fbt::ChannelMode::BASIC:
54 params.mode = bt::l2cap::RetransmissionAndFlowControlMode::kBasic;
55 break;
56 case fbt::ChannelMode::ENHANCED_RETRANSMISSION:
57 params.mode = bt::l2cap::RetransmissionAndFlowControlMode::
58 kEnhancedRetransmission;
59 break;
60 default:
61 BT_PANIC("FIDL channel parameter contains invalid mode");
62 }
63 }
64 if (fidl.has_max_rx_packet_size()) {
65 params.max_rx_sdu_size = fidl.max_rx_packet_size();
66 }
67 if (fidl.has_flush_timeout()) {
68 params.flush_timeout = std::chrono::nanoseconds(fidl.flush_timeout());
69 }
70 return params;
71 }
72
ChannelModeToFidl(const bt::l2cap::AnyChannelMode & mode)73 fbt::ChannelMode ChannelModeToFidl(const bt::l2cap::AnyChannelMode& mode) {
74 if (auto* flow_control_mode =
75 std::get_if<bt::l2cap::RetransmissionAndFlowControlMode>(&mode)) {
76 switch (*flow_control_mode) {
77 case bt::l2cap::RetransmissionAndFlowControlMode::kBasic:
78 return fbt::ChannelMode::BASIC;
79 break;
80 case bt::l2cap::RetransmissionAndFlowControlMode::kEnhancedRetransmission:
81 return fbt::ChannelMode::ENHANCED_RETRANSMISSION;
82 break;
83 default:
84 // Intentionally unhandled, fall through to PANIC.
85 break;
86 }
87 }
88 BT_PANIC("Could not convert channel parameter mode to unsupported FIDL mode");
89 }
90
ChannelInfoToFidlChannelParameters(const bt::l2cap::ChannelInfo & info)91 fbt::ChannelParameters ChannelInfoToFidlChannelParameters(
92 const bt::l2cap::ChannelInfo& info) {
93 fbt::ChannelParameters params;
94 params.set_channel_mode(ChannelModeToFidl(info.mode));
95 params.set_max_rx_packet_size(info.max_rx_sdu_size);
96 if (info.flush_timeout) {
97 params.set_flush_timeout(info.flush_timeout->count());
98 }
99 return params;
100 }
101
102 // NOLINTNEXTLINE(misc-no-recursion)
DataElementToFidl(const bt::sdp::DataElement * in)103 fidlbredr::DataElementPtr DataElementToFidl(const bt::sdp::DataElement* in) {
104 auto elem = std::make_unique<fidlbredr::DataElement>();
105 bt_log(TRACE, "fidl", "DataElementToFidl: %s", in->ToString().c_str());
106 PW_DCHECK(in);
107 switch (in->type()) {
108 case bt::sdp::DataElement::Type::kUnsignedInt: {
109 switch (in->size()) {
110 case bt::sdp::DataElement::Size::kOneByte:
111 elem->set_uint8(*in->Get<uint8_t>());
112 break;
113 case bt::sdp::DataElement::Size::kTwoBytes:
114 elem->set_uint16(*in->Get<uint16_t>());
115 break;
116 case bt::sdp::DataElement::Size::kFourBytes:
117 elem->set_uint32(*in->Get<uint32_t>());
118 break;
119 case bt::sdp::DataElement::Size::kEightBytes:
120 elem->set_uint64(*in->Get<uint64_t>());
121 break;
122 default:
123 bt_log(INFO, "fidl", "no 128-bit integer support in FIDL yet");
124 return nullptr;
125 }
126 return elem;
127 }
128 case bt::sdp::DataElement::Type::kSignedInt: {
129 switch (in->size()) {
130 case bt::sdp::DataElement::Size::kOneByte:
131 elem->set_int8(*in->Get<int8_t>());
132 break;
133 case bt::sdp::DataElement::Size::kTwoBytes:
134 elem->set_int16(*in->Get<int16_t>());
135 break;
136 case bt::sdp::DataElement::Size::kFourBytes:
137 elem->set_int32(*in->Get<int32_t>());
138 break;
139 case bt::sdp::DataElement::Size::kEightBytes:
140 elem->set_int64(*in->Get<int64_t>());
141 break;
142 default:
143 bt_log(INFO, "fidl", "no 128-bit integer support in FIDL yet");
144 return nullptr;
145 }
146 return elem;
147 }
148 case bt::sdp::DataElement::Type::kUuid: {
149 auto uuid = in->Get<bt::UUID>();
150 PW_DCHECK(uuid);
151 elem->set_uuid(fidl_helpers::UuidToFidl(*uuid));
152 return elem;
153 }
154 case bt::sdp::DataElement::Type::kString: {
155 auto bytes = in->Get<bt::DynamicByteBuffer>();
156 PW_DCHECK(bytes);
157 std::vector<uint8_t> data(bytes->cbegin(), bytes->cend());
158 elem->set_str(data);
159 return elem;
160 }
161 case bt::sdp::DataElement::Type::kBoolean: {
162 elem->set_b(*in->Get<bool>());
163 return elem;
164 }
165 case bt::sdp::DataElement::Type::kSequence: {
166 std::vector<fidlbredr::DataElementPtr> elems;
167 const bt::sdp::DataElement* it;
168 for (size_t idx = 0; (it = in->At(idx)); ++idx) {
169 elems.emplace_back(DataElementToFidl(it));
170 }
171 elem->set_sequence(std::move(elems));
172 return elem;
173 }
174 case bt::sdp::DataElement::Type::kAlternative: {
175 std::vector<fidlbredr::DataElementPtr> elems;
176 const bt::sdp::DataElement* it;
177 for (size_t idx = 0; (it = in->At(idx)); ++idx) {
178 elems.emplace_back(DataElementToFidl(it));
179 }
180 elem->set_alternatives(std::move(elems));
181 return elem;
182 }
183 case bt::sdp::DataElement::Type::kUrl: {
184 elem->set_url(*in->GetUrl());
185 return elem;
186 }
187 case bt::sdp::DataElement::Type::kNull: {
188 bt_log(INFO, "fidl", "no support for null DataElement types in FIDL");
189 return nullptr;
190 }
191 }
192 }
193
DataElementToProtocolDescriptor(const bt::sdp::DataElement * in)194 fidlbredr::ProtocolDescriptorPtr DataElementToProtocolDescriptor(
195 const bt::sdp::DataElement* in) {
196 auto desc = std::make_unique<fidlbredr::ProtocolDescriptor>();
197 if (in->type() != bt::sdp::DataElement::Type::kSequence) {
198 bt_log(DEBUG,
199 "fidl",
200 "DataElement type is not kSequence (in: %s)",
201 bt_str(*in));
202 return nullptr;
203 }
204 const auto protocol_uuid = in->At(0)->Get<bt::UUID>();
205 if (!protocol_uuid) {
206 bt_log(DEBUG,
207 "fidl",
208 "first DataElement in sequence is not type kUUID (in: %s)",
209 bt_str(*in));
210 return nullptr;
211 }
212 desc->set_protocol(
213 static_cast<fidlbredr::ProtocolIdentifier>(*protocol_uuid->As16Bit()));
214 const bt::sdp::DataElement* it;
215 std::vector<fidlbredr::DataElement> params;
216 for (size_t idx = 1; (it = in->At(idx)); ++idx) {
217 params.push_back(std::move(*DataElementToFidl(it)));
218 }
219 desc->set_params(std::move(params));
220
221 return desc;
222 }
223
FidlToAclPriority(fidlbredr::A2dpDirectionPriority in)224 AclPriority FidlToAclPriority(fidlbredr::A2dpDirectionPriority in) {
225 switch (in) {
226 case fidlbredr::A2dpDirectionPriority::SOURCE:
227 return AclPriority::kSource;
228 case fidlbredr::A2dpDirectionPriority::SINK:
229 return AclPriority::kSink;
230 default:
231 return AclPriority::kNormal;
232 }
233 }
234
235 } // namespace
236
ProfileServer(bt::gap::Adapter::WeakPtr adapter,fidl::InterfaceRequest<Profile> request)237 ProfileServer::ProfileServer(bt::gap::Adapter::WeakPtr adapter,
238 fidl::InterfaceRequest<Profile> request)
239 : ServerBase(this, std::move(request)),
240 advertised_total_(0),
241 searches_total_(0),
242 adapter_(std::move(adapter)),
243 weak_self_(this) {}
244
~ProfileServer()245 ProfileServer::~ProfileServer() {
246 sco_connection_servers_.clear();
247
248 if (adapter().is_alive()) {
249 // Unregister anything that we have registered.
250 for (const auto& it : current_advertised_) {
251 adapter()->bredr()->UnregisterService(it.second.registration_handle);
252 }
253 for (const auto& it : searches_) {
254 adapter()->bredr()->RemoveServiceSearch(it.second.search_id);
255 }
256 }
257 }
258
RequestParameters(fuchsia::bluetooth::ChannelParameters requested,RequestParametersCallback callback)259 void ProfileServer::L2capParametersExt::RequestParameters(
260 fuchsia::bluetooth::ChannelParameters requested,
261 RequestParametersCallback callback) {
262 if (requested.has_flush_timeout()) {
263 channel_->SetBrEdrAutomaticFlushTimeout(
264 std::chrono::nanoseconds(requested.flush_timeout()),
265 [chan = channel_, cb = std::move(callback)](auto result) {
266 if (result.is_ok()) {
267 bt_log(DEBUG,
268 "fidl",
269 "L2capParametersExt::RequestParameters: setting flush "
270 "timeout succeeded");
271 } else {
272 bt_log(INFO,
273 "fidl",
274 "L2capParametersExt::RequestParameters: setting flush "
275 "timeout failed");
276 }
277 // Return the current parameters even if the request failed.
278 // TODO(fxbug.dev/42152567): set current security requirements in
279 // returned channel parameters
280 cb(fidlbredr::L2capParametersExt_RequestParameters_Result::
281 WithResponse(
282 fidlbredr::L2capParametersExt_RequestParameters_Response(
283 ChannelInfoToFidlChannelParameters(chan->info()))));
284 });
285 return;
286 }
287
288 // No other channel parameters are supported, so just return the current
289 // parameters.
290 // TODO(fxbug.dev/42152567): set current security requirements in returned
291 // channel parameters
292 callback(fidlbredr::L2capParametersExt_RequestParameters_Result::WithResponse(
293 fidlbredr::L2capParametersExt_RequestParameters_Response(
294 ChannelInfoToFidlChannelParameters(channel_->info()))));
295 }
296
handle_unknown_method(uint64_t ordinal,bool method_has_response)297 void ProfileServer::L2capParametersExt::handle_unknown_method(
298 uint64_t ordinal, bool method_has_response) {
299 bt_log(WARN, "fidl", "L2capParametersExt: unknown method received");
300 }
301
GetSupportedFeatures(GetSupportedFeaturesCallback callback)302 void ProfileServer::AudioOffloadExt::GetSupportedFeatures(
303 GetSupportedFeaturesCallback callback) {
304 fidlbredr::AudioOffloadExt_GetSupportedFeatures_Response response;
305 std::vector<fidlbredr::AudioOffloadFeatures>* mutable_audio_offload_features =
306 response.mutable_audio_offload_features();
307 const bt::gap::AdapterState& adapter_state = adapter_->state();
308
309 if (!adapter_state.IsControllerFeatureSupported(
310 FeaturesBits::kAndroidVendorExtensions)) {
311 callback(
312 fidlbredr::AudioOffloadExt_GetSupportedFeatures_Result::WithResponse(
313 std::move(response)));
314 return;
315 }
316
317 const uint32_t a2dp_offload_capabilities =
318 adapter_state.android_vendor_capabilities
319 ->a2dp_source_offload_capability_mask();
320 const uint32_t sbc_capability =
321 static_cast<uint32_t>(android_emb::A2dpCodecType::SBC);
322 const uint32_t aac_capability =
323 static_cast<uint32_t>(android_emb::A2dpCodecType::AAC);
324
325 if (a2dp_offload_capabilities & sbc_capability) {
326 fidlbredr::AudioSbcSupport audio_sbc_support;
327 mutable_audio_offload_features->push_back(
328 fidlbredr::AudioOffloadFeatures::WithSbc(std::move(audio_sbc_support)));
329 }
330 if (a2dp_offload_capabilities & aac_capability) {
331 fidlbredr::AudioAacSupport audio_aac_support;
332 mutable_audio_offload_features->push_back(
333 fidlbredr::AudioOffloadFeatures::WithAac(std::move(audio_aac_support)));
334 }
335
336 callback(fidlbredr::AudioOffloadExt_GetSupportedFeatures_Result::WithResponse(
337 std::move(response)));
338 }
339
StartAudioOffload(fidlbredr::AudioOffloadConfiguration audio_offload_configuration,fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller)340 void ProfileServer::AudioOffloadExt::StartAudioOffload(
341 fidlbredr::AudioOffloadConfiguration audio_offload_configuration,
342 fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller) {
343 auto audio_offload_controller_server =
344 std::make_unique<AudioOffloadController>(std::move(controller), channel_);
345 WeakPtr<AudioOffloadController> server_ptr =
346 audio_offload_controller_server->GetWeakPtr();
347
348 std::unique_ptr<bt::l2cap::A2dpOffloadManager::Configuration> config =
349 AudioOffloadConfigFromFidl(audio_offload_configuration);
350 if (!config) {
351 bt_log(ERROR, "fidl", "%s: invalid config received", __FUNCTION__);
352 server_ptr->Close(/*epitaph_value=*/ZX_ERR_NOT_SUPPORTED);
353 return;
354 }
355
356 auto error_handler = [this, server_ptr](zx_status_t status) {
357 if (!server_ptr.is_alive()) {
358 bt_log(ERROR, "fidl", "audio offload controller server was destroyed");
359 return;
360 }
361
362 bt_log(DEBUG,
363 "fidl",
364 "audio offload controller server closed (reason: %s)",
365 zx_status_get_string(status));
366 if (!profile_server_.audio_offload_controller_server_) {
367 bt_log(WARN,
368 "fidl",
369 "could not find controller server in audio offload controller "
370 "error callback");
371 }
372
373 bt::hci::ResultCallback<> stop_cb =
374 [server_ptr](
375 fit::result<bt::Error<pw::bluetooth::emboss::StatusCode>> result) {
376 if (result.is_error()) {
377 bt_log(ERROR,
378 "fidl",
379 "stopping audio offload failed in error handler: %s",
380 bt_str(result));
381 server_ptr->Close(/*epitaph_value=*/ZX_ERR_UNAVAILABLE);
382 return;
383 }
384 bt_log(ERROR,
385 "fidl",
386 "stopping audio offload complete: %s",
387 bt_str(result));
388 };
389 channel_->StopA2dpOffload(std::move(stop_cb));
390 };
391 audio_offload_controller_server->set_error_handler(error_handler);
392 profile_server_.audio_offload_controller_server_ =
393 std::move(audio_offload_controller_server);
394
395 auto callback =
396 [this, server_ptr](
397 fit::result<bt::Error<pw::bluetooth::emboss::StatusCode>> result) {
398 if (!server_ptr.is_alive()) {
399 bt_log(
400 ERROR, "fidl", "audio offload controller server was destroyed");
401 return;
402 }
403 if (result.is_error()) {
404 bt_log(ERROR, "fidl", "StartAudioOffload failed: %s", bt_str(result));
405
406 auto host_error = result.error_value().host_error();
407 if (host_error == bt::HostError::kInProgress) {
408 server_ptr->Close(/*epitaph_value=*/ZX_ERR_ALREADY_BOUND);
409 } else if (host_error == bt::HostError::kFailed) {
410 server_ptr->Close(/*epitaph_value=*/ZX_ERR_INTERNAL);
411 } else {
412 server_ptr->Close(/*epitaph_value=*/ZX_ERR_UNAVAILABLE);
413 }
414 profile_server_.audio_offload_controller_server_ = nullptr;
415 return;
416 }
417 // Send OnStarted event to tell Rust Profiles that we've finished
418 // offloading
419 server_ptr->SendOnStartedEvent();
420 };
421 channel_->StartA2dpOffload(*config, std::move(callback));
422 }
423
Stop(AudioOffloadController::StopCallback callback)424 void ProfileServer::AudioOffloadController::Stop(
425 AudioOffloadController::StopCallback callback) {
426 if (!channel_.is_alive()) {
427 bt_log(ERROR, "fidl", "Audio offload controller server was destroyed");
428 return;
429 }
430
431 channel_->StopA2dpOffload(
432 [stop_callback = std::move(callback),
433 this](fit::result<bt::Error<pw::bluetooth::emboss::StatusCode>> result) {
434 if (result.is_error()) {
435 bt_log(
436 ERROR,
437 "fidl",
438 "Stop a2dp offload failed with error %s. Closing with "
439 "ZX_ERR_UNAVAILABLE",
440 bt::HostErrorToString(result.error_value().host_error()).c_str());
441 Close(/*epitaph_value=*/ZX_ERR_UNAVAILABLE);
442 return;
443 }
444 stop_callback(
445 fidlbredr::AudioOffloadController_Stop_Result::WithResponse({}));
446 });
447 }
448
449 std::unique_ptr<bt::l2cap::A2dpOffloadManager::Configuration>
AudioOffloadConfigFromFidl(fidlbredr::AudioOffloadConfiguration & audio_offload_configuration)450 ProfileServer::AudioOffloadExt::AudioOffloadConfigFromFidl(
451 fidlbredr::AudioOffloadConfiguration& audio_offload_configuration) {
452 auto codec =
453 fidl_helpers::FidlToCodecType(audio_offload_configuration.codec());
454 if (!codec.has_value()) {
455 bt_log(WARN, "fidl", "%s: invalid codec", __FUNCTION__);
456 return nullptr;
457 }
458
459 std::unique_ptr<bt::l2cap::A2dpOffloadManager::Configuration> config =
460 std::make_unique<bt::l2cap::A2dpOffloadManager::Configuration>();
461
462 std::optional<android_emb::A2dpSamplingFrequency> sampling_frequency =
463 fidl_helpers::FidlToSamplingFrequency(
464 audio_offload_configuration.sampling_frequency());
465 if (!sampling_frequency.has_value()) {
466 bt_log(WARN, "fidl", "Invalid sampling frequency");
467 return nullptr;
468 }
469
470 std::optional<android_emb::A2dpBitsPerSample> audio_bits_per_sample =
471 fidl_helpers::FidlToBitsPerSample(
472 audio_offload_configuration.bits_per_sample());
473 if (!audio_bits_per_sample.has_value()) {
474 bt_log(WARN, "fidl", "Invalid audio bits per sample");
475 return nullptr;
476 }
477
478 std::optional<android_emb::A2dpChannelMode> audio_channel_mode =
479 fidl_helpers::FidlToChannelMode(
480 audio_offload_configuration.channel_mode());
481 if (!audio_channel_mode.has_value()) {
482 bt_log(WARN, "fidl", "Invalid channel mode");
483 return nullptr;
484 }
485
486 config->codec = codec.value();
487 config->max_latency = audio_offload_configuration.max_latency();
488 config->scms_t_enable = fidl_helpers::FidlToScmsTEnable(
489 audio_offload_configuration.scms_t_enable());
490 config->sampling_frequency = sampling_frequency.value();
491 config->bits_per_sample = audio_bits_per_sample.value();
492 config->channel_mode = audio_channel_mode.value();
493 config->encoded_audio_bit_rate =
494 audio_offload_configuration.encoded_bit_rate();
495
496 if (audio_offload_configuration.encoder_settings().is_sbc()) {
497 if (audio_offload_configuration.sampling_frequency() ==
498 fuchsia::bluetooth::bredr::AudioSamplingFrequency::HZ_88200 ||
499 audio_offload_configuration.sampling_frequency() ==
500 fuchsia::bluetooth::bredr::AudioSamplingFrequency::HZ_96000) {
501 bt_log(WARN,
502 "fidl",
503 "%s: sbc encoder cannot use sampling frequency %hhu",
504 __FUNCTION__,
505 static_cast<uint8_t>(
506 audio_offload_configuration.sampling_frequency()));
507 return nullptr;
508 }
509
510 config->sbc_configuration = fidl_helpers::FidlToEncoderSettingsSbc(
511 audio_offload_configuration.encoder_settings(),
512 audio_offload_configuration.sampling_frequency(),
513 audio_offload_configuration.channel_mode());
514 } else if (audio_offload_configuration.encoder_settings().is_aac()) {
515 config->aac_configuration = fidl_helpers::FidlToEncoderSettingsAac(
516 audio_offload_configuration.encoder_settings(),
517 audio_offload_configuration.sampling_frequency(),
518 audio_offload_configuration.channel_mode());
519 }
520
521 return config;
522 }
523
handle_unknown_method(uint64_t ordinal,bool method_has_response)524 void ProfileServer::AudioOffloadExt::handle_unknown_method(
525 uint64_t ordinal, bool method_has_response) {
526 bt_log(WARN, "fidl", "AudioOffloadExt: unknown method received");
527 }
528
handle_unknown_method(uint64_t ordinal,bool method_has_response)529 void ProfileServer::AudioOffloadController::handle_unknown_method(
530 uint64_t ordinal, bool method_has_response) {
531 bt_log(WARN, "fidl", "AudioOffloadController: unknown method received");
532 }
533
ScoConnectionServer(fidl::InterfaceRequest<fuchsia::bluetooth::bredr::ScoConnection> request,ProfileServer * profile_server)534 ProfileServer::ScoConnectionServer::ScoConnectionServer(
535 fidl::InterfaceRequest<fuchsia::bluetooth::bredr::ScoConnection> request,
536 ProfileServer* profile_server)
537 : ServerBase(this, std::move(request)),
538 profile_server_(profile_server),
539 weak_self_(this) {
540 binding()->set_error_handler([this](zx_status_t) { Close(ZX_ERR_CANCELED); });
541 }
542
~ScoConnectionServer()543 ProfileServer::ScoConnectionServer::~ScoConnectionServer() {
544 if (connection_.is_alive()) {
545 connection_->Deactivate();
546 }
547 }
548
Activate()549 void ProfileServer::ScoConnectionServer::Activate() {
550 auto rx_callback = [this] { TryRead(); };
551 auto closed_cb = [this] { Close(ZX_ERR_PEER_CLOSED); };
552 bool activated =
553 connection_->Activate(std::move(rx_callback), std::move(closed_cb));
554 if (!activated) {
555 OnError(fidlbredr::ScoErrorCode::FAILURE);
556 }
557 }
558
OnError(::fuchsia::bluetooth::bredr::ScoErrorCode error)559 void ProfileServer::ScoConnectionServer::OnError(
560 ::fuchsia::bluetooth::bredr::ScoErrorCode error) {
561 OnConnectionComplete(
562 ::fuchsia::bluetooth::bredr::ScoConnectionOnConnectionCompleteRequest::
563 WithError(std::move(error))); // NOLINT(performance-move-const-arg)
564 Close(ZX_ERR_PEER_CLOSED);
565 }
566
Read(ReadCallback callback)567 void ProfileServer::ScoConnectionServer::Read(ReadCallback callback) {
568 if (!connection_.is_alive()) {
569 Close(ZX_ERR_IO_REFUSED);
570 return;
571 }
572
573 if (connection_->parameters().view().input_data_path().Read() !=
574 pw::bluetooth::emboss::ScoDataPath::HCI) {
575 bt_log(WARN, "fidl", "%s called for an offloaded SCO connection", __func__);
576 Close(ZX_ERR_IO_NOT_PRESENT);
577 return;
578 }
579
580 if (read_cb_) {
581 bt_log(WARN,
582 "fidl",
583 "%s called when a read callback was already present",
584 __func__);
585 Close(ZX_ERR_BAD_STATE);
586 return;
587 }
588 read_cb_ = std::move(callback);
589 TryRead();
590 }
591
Write(fidlbredr::ScoConnectionWriteRequest request,WriteCallback callback)592 void ProfileServer::ScoConnectionServer::Write(
593 fidlbredr::ScoConnectionWriteRequest request, WriteCallback callback) {
594 if (!connection_.is_alive()) {
595 Close(ZX_ERR_IO_REFUSED);
596 return;
597 }
598
599 if (connection_->parameters().view().output_data_path().Read() !=
600 pw::bluetooth::emboss::ScoDataPath::HCI) {
601 bt_log(WARN, "fidl", "%s called for a non-HCI SCO connection", __func__);
602 Close(ZX_ERR_IO_NOT_PRESENT);
603 return;
604 }
605
606 if (!request.has_data()) {
607 Close(ZX_ERR_INVALID_ARGS);
608 return;
609 }
610 std::vector<uint8_t> data = std::move(*request.mutable_data());
611
612 auto buffer = std::make_unique<bt::DynamicByteBuffer>(data.size());
613 buffer->Write(data.data(), data.size());
614 if (!connection_->Send(std::move(buffer))) {
615 bt_log(WARN, "fidl", "%s: failed to send SCO packet", __func__);
616 Close(ZX_ERR_IO);
617 return;
618 }
619 callback(fidlbredr::ScoConnection_Write_Result::WithResponse(
620 fidlbredr::ScoConnection_Write_Response()));
621 }
622
handle_unknown_method(uint64_t ordinal,bool method_has_response)623 void ProfileServer::ScoConnectionServer::handle_unknown_method(
624 uint64_t ordinal, bool method_has_response) {
625 bt_log(WARN,
626 "fidl",
627 "ScoConnectionServer received unknown method with ordinal %lu",
628 ordinal);
629 }
630
TryRead()631 void ProfileServer::ScoConnectionServer::TryRead() {
632 if (!read_cb_) {
633 return;
634 }
635 std::unique_ptr<bt::hci::ScoDataPacket> packet = connection_->Read();
636 if (!packet) {
637 return;
638 }
639 std::vector<uint8_t> payload;
640 fidlbredr::RxPacketStatus status =
641 fidl_helpers::ScoPacketStatusToFidl(packet->packet_status_flag());
642 if (packet->packet_status_flag() !=
643 bt::hci_spec::SynchronousDataPacketStatusFlag::kNoDataReceived) {
644 payload = packet->view().payload_data().ToVector();
645 }
646 fidlbredr::ScoConnection_Read_Response response;
647 response.set_data(std::move(payload));
648 response.set_status_flag(status);
649 read_cb_(
650 fidlbredr::ScoConnection_Read_Result::WithResponse(std::move(response)));
651 }
652
Close(zx_status_t epitaph)653 void ProfileServer::ScoConnectionServer::Close(zx_status_t epitaph) {
654 if (connection_.is_alive()) {
655 connection_->Deactivate();
656 }
657 binding()->Close(epitaph);
658 profile_server_->sco_connection_servers_.erase(this);
659 }
660
Advertise(fuchsia::bluetooth::bredr::ProfileAdvertiseRequest request,AdvertiseCallback callback)661 void ProfileServer::Advertise(
662 fuchsia::bluetooth::bredr::ProfileAdvertiseRequest request,
663 AdvertiseCallback callback) {
664 if (!request.has_services() || !request.has_receiver()) {
665 callback(fidlbredr::Profile_Advertise_Result::WithErr(
666 fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS));
667 return;
668 }
669 if (!request.has_parameters()) {
670 request.set_parameters(fbt::ChannelParameters());
671 }
672 std::vector<bt::sdp::ServiceRecord> registering;
673
674 for (auto& definition : request.services()) {
675 auto rec = fidl_helpers::ServiceDefinitionToServiceRecord(definition);
676 // Drop the receiver on error.
677 if (rec.is_error()) {
678 bt_log(WARN,
679 "fidl",
680 "%s: Failed to create service record from service defintion",
681 __FUNCTION__);
682 callback(
683 fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS));
684 return;
685 }
686 registering.emplace_back(std::move(rec.value()));
687 }
688
689 PW_CHECK(adapter().is_alive());
690 PW_CHECK(adapter()->bredr());
691
692 uint64_t next = advertised_total_ + 1;
693
694 auto registration_handle = adapter()->bredr()->RegisterService(
695 std::move(registering),
696 FidlToChannelParameters(request.parameters()),
697 [this, next](auto channel, const auto& protocol_list) {
698 OnChannelConnected(next, std::move(channel), std::move(protocol_list));
699 });
700
701 if (!registration_handle) {
702 bt_log(WARN, "fidl", "%s: Failed to register service", __FUNCTION__);
703 callback(fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS));
704 return;
705 };
706
707 const auto registered_records =
708 adapter()->bredr()->GetRegisteredServices(registration_handle);
709 std::vector<fuchsia::bluetooth::bredr::ServiceDefinition>
710 registered_definitions;
711 for (auto& record : registered_records) {
712 auto def = fidl_helpers::ServiceRecordToServiceDefinition(record);
713 // Shouldn't fail in practice; the records are all well-formed and validated
714 // earlier in this function.
715 if (def.is_error()) {
716 bt_log(WARN,
717 "fidl",
718 "Failed to construct service definition from record: %lu",
719 def.error());
720 continue;
721 }
722 registered_definitions.emplace_back(std::move(def.value()));
723 }
724
725 fidlbredr::ConnectionReceiverPtr receiver =
726 request.mutable_receiver()->Bind();
727 // Monitor events on the `ConnectionReceiver`. Remove the service if the FIDL
728 // client revokes the service registration.
729 receiver.events().OnRevoke = [this, ad_id = next]() {
730 bt_log(DEBUG,
731 "fidl",
732 "Connection receiver revoked. Ending service advertisement %lu",
733 ad_id);
734 OnConnectionReceiverClosed(ad_id);
735 };
736 // Errors on the `ConnectionReceiver` will result in service unregistration.
737 receiver.set_error_handler([this, ad_id = next](zx_status_t status) {
738 bt_log(DEBUG,
739 "fidl",
740 "Connection receiver closed with error: %s. Ending service "
741 "advertisement %lu",
742 zx_status_get_string(status),
743 ad_id);
744 OnConnectionReceiverClosed(ad_id);
745 });
746
747 current_advertised_.try_emplace(
748 next, std::move(receiver), registration_handle);
749 advertised_total_ = next;
750 fuchsia::bluetooth::bredr::Profile_Advertise_Response result;
751 result.set_services(std::move(registered_definitions));
752 callback(fuchsia::bluetooth::bredr::Profile_Advertise_Result::WithResponse(
753 std::move(result)));
754 }
755
Search(::fuchsia::bluetooth::bredr::ProfileSearchRequest request)756 void ProfileServer::Search(
757 ::fuchsia::bluetooth::bredr::ProfileSearchRequest request) {
758 if (!request.has_results()) {
759 bt_log(WARN, "fidl", "%s: missing search results client", __FUNCTION__);
760 return;
761 }
762
763 bt::UUID search_uuid;
764 if (request.has_full_uuid() && request.has_service_uuid()) {
765 bt_log(WARN,
766 "fidl",
767 "%s: Cannot request both full and service UUID",
768 __FUNCTION__);
769 return;
770 } else if (request.has_service_uuid()) {
771 search_uuid = bt::UUID(static_cast<uint32_t>(request.service_uuid()));
772 } else if (request.has_full_uuid()) {
773 search_uuid = fidl_helpers::UuidFromFidl(request.full_uuid());
774 } else {
775 bt_log(WARN, "fidl", "%s: missing service or full UUID", __FUNCTION__);
776 return;
777 }
778
779 std::unordered_set<bt::sdp::AttributeId> attributes;
780 if (request.has_attr_ids() && !request.attr_ids().empty()) {
781 attributes.insert(request.attr_ids().begin(), request.attr_ids().end());
782 // Always request the ProfileDescriptor for the event
783 attributes.insert(bt::sdp::kBluetoothProfileDescriptorList);
784 }
785
786 PW_DCHECK(adapter().is_alive());
787
788 auto next = searches_total_ + 1;
789
790 auto search_id = adapter()->bredr()->AddServiceSearch(
791 search_uuid,
792 std::move(attributes),
793 [this, next](auto id, const auto& attrs) {
794 OnServiceFound(next, id, attrs);
795 });
796
797 if (!search_id) {
798 return;
799 }
800
801 auto results_ptr = request.mutable_results()->Bind();
802 results_ptr.set_error_handler(
803 [this, next](zx_status_t status) { OnSearchResultError(next, status); });
804
805 searches_.try_emplace(next, std::move(results_ptr), search_id);
806 searches_total_ = next;
807 }
808
Connect(fuchsia::bluetooth::PeerId peer_id,fidlbredr::ConnectParameters connection,ConnectCallback callback)809 void ProfileServer::Connect(fuchsia::bluetooth::PeerId peer_id,
810 fidlbredr::ConnectParameters connection,
811 ConnectCallback callback) {
812 bt::PeerId id{peer_id.value};
813
814 // Anything other than L2CAP is not supported by this server.
815 if (!connection.is_l2cap()) {
816 bt_log(
817 WARN,
818 "fidl",
819 "%s: non-l2cap connections are not supported (is_rfcomm: %d, peer: %s)",
820 __FUNCTION__,
821 connection.is_rfcomm(),
822 bt_str(id));
823 callback(fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS));
824 return;
825 }
826
827 // The L2CAP parameters must include a PSM. ChannelParameters are optional.
828 auto l2cap_params = std::move(connection.l2cap());
829 if (!l2cap_params.has_psm()) {
830 bt_log(WARN,
831 "fidl",
832 "%s: missing l2cap psm (peer: %s)",
833 __FUNCTION__,
834 bt_str(id));
835 callback(fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS));
836 return;
837 }
838 uint16_t psm = l2cap_params.psm();
839
840 fbt::ChannelParameters parameters =
841 std::move(*l2cap_params.mutable_parameters());
842
843 auto connected_cb = [self = weak_self_.GetWeakPtr(),
844 cb = callback.share(),
845 id](bt::l2cap::Channel::WeakPtr chan) {
846 if (!chan.is_alive()) {
847 bt_log(INFO,
848 "fidl",
849 "Connect: Channel socket is empty, returning failed. (peer: %s)",
850 bt_str(id));
851 cb(fpromise::error(fuchsia::bluetooth::ErrorCode::FAILED));
852 return;
853 }
854
855 if (!self.is_alive()) {
856 cb(fpromise::error(fuchsia::bluetooth::ErrorCode::FAILED));
857 return;
858 }
859
860 std::optional<fuchsia::bluetooth::bredr::Channel> fidl_chan =
861 self->ChannelToFidl(std::move(chan));
862 if (!fidl_chan) {
863 cb(fpromise::error(fuchsia::bluetooth::ErrorCode::FAILED));
864 return;
865 }
866
867 cb(fpromise::ok(std::move(fidl_chan.value())));
868 };
869 PW_DCHECK(adapter().is_alive());
870
871 adapter()->bredr()->OpenL2capChannel(
872 id,
873 psm,
874 fidl_helpers::FidlToBrEdrSecurityRequirements(parameters),
875 FidlToChannelParameters(parameters),
876 std::move(connected_cb));
877 }
878
ConnectSco(::fuchsia::bluetooth::bredr::ProfileConnectScoRequest request)879 void ProfileServer::ConnectSco(
880 ::fuchsia::bluetooth::bredr::ProfileConnectScoRequest request) {
881 if (!request.has_connection()) {
882 bt_log(WARN, "fidl", "%s missing connection", __FUNCTION__);
883 return;
884 }
885 std::unique_ptr<ScoConnectionServer> connection =
886 std::make_unique<ScoConnectionServer>(
887 std::move(*request.mutable_connection()), this);
888 ScoConnectionServer* connection_raw = connection.get();
889 WeakPtr<ScoConnectionServer> connection_weak = connection->GetWeakPtr();
890
891 if (!request.has_peer_id() || !request.has_initiator() ||
892 !request.has_params() || request.params().empty()) {
893 connection->OnError(fidlbredr::ScoErrorCode::INVALID_ARGUMENTS);
894 return;
895 }
896 bt::PeerId peer_id(request.peer_id().value);
897
898 if (request.initiator() && request.params().size() != 1u) {
899 bt_log(WARN,
900 "fidl",
901 "%s: too many parameters in initiator request (peer: %s)",
902 __FUNCTION__,
903 bt_str(peer_id));
904 connection->OnError(fidlbredr::ScoErrorCode::INVALID_ARGUMENTS);
905 return;
906 }
907
908 auto params_result =
909 fidl_helpers::FidlToScoParametersVector(request.params());
910 if (params_result.is_error()) {
911 bt_log(WARN,
912 "fidl",
913 "%s: invalid parameters (peer: %s)",
914 __FUNCTION__,
915 bt_str(peer_id));
916 connection->OnError(fidlbredr::ScoErrorCode::INVALID_ARGUMENTS);
917 return;
918 }
919 connection->set_parameters(std::move(*request.mutable_params()));
920 auto params = params_result.value();
921
922 sco_connection_servers_.emplace(connection_raw, std::move(connection));
923
924 if (request.initiator()) {
925 auto callback = [self = weak_self_.GetWeakPtr(), connection_weak](
926 bt::sco::ScoConnectionManager::OpenConnectionResult
927 result) mutable {
928 // The connection may complete after this server is destroyed.
929 if (!self.is_alive()) {
930 // Prevent leaking connections.
931 if (result.is_ok()) {
932 result.value()->Deactivate();
933 }
934 return;
935 }
936 if (result.is_error()) {
937 self->OnScoConnectionResult(connection_weak, result.take_error());
938 return;
939 }
940 self->OnScoConnectionResult(
941 connection_weak,
942 fit::ok(std::make_pair(std::move(result.value()),
943 /*parameter index=*/0u)));
944 };
945 // If the BR/EDR connection doesn't exist, no handle will be returned and
946 // the callback will be synchronously called with an error.
947 std::optional<bt::gap::Adapter::BrEdr::ScoRequestHandle> handle =
948 adapter()->bredr()->OpenScoConnection(
949 peer_id, params.front(), std::move(callback));
950 if (handle && connection_weak.is_alive()) {
951 connection_weak->set_request_handle(std::move(*handle));
952 }
953 return;
954 }
955
956 auto callback = [self = weak_self_.GetWeakPtr(), connection_weak](
957 bt::sco::ScoConnectionManager::AcceptConnectionResult
958 result) mutable {
959 // The connection may complete after this server is destroyed.
960 if (!self.is_alive()) {
961 // Prevent leaking connections.
962 if (result.is_ok()) {
963 result.value().first->Deactivate();
964 }
965 return;
966 }
967
968 self->OnScoConnectionResult(connection_weak, std::move(result));
969 };
970 // If the BR/EDR connection doesn't exist, no handle will be returned and the
971 // callback will be synchronously called with an error.
972 std::optional<bt::gap::Adapter::BrEdr::ScoRequestHandle> handle =
973 adapter()->bredr()->AcceptScoConnection(
974 peer_id, params, std::move(callback));
975 if (handle && connection_weak.is_alive()) {
976 connection_weak->set_request_handle(std::move(*handle));
977 }
978 }
979
handle_unknown_method(uint64_t ordinal,bool method_has_response)980 void ProfileServer::handle_unknown_method(uint64_t ordinal,
981 bool method_has_response) {
982 bt_log(WARN, "fidl", "ProfileServer: unknown method received");
983 }
984
OnChannelConnected(uint64_t ad_id,bt::l2cap::Channel::WeakPtr channel,const bt::sdp::DataElement & protocol_list)985 void ProfileServer::OnChannelConnected(
986 uint64_t ad_id,
987 bt::l2cap::Channel::WeakPtr channel,
988 const bt::sdp::DataElement& protocol_list) {
989 auto it = current_advertised_.find(ad_id);
990 if (it == current_advertised_.end()) {
991 // The receiver has disappeared, do nothing.
992 return;
993 }
994
995 PW_DCHECK(adapter().is_alive());
996 auto handle = channel->link_handle();
997 auto id = adapter()->bredr()->GetPeerId(handle);
998
999 // The protocol that is connected should be L2CAP, because that is the only
1000 // thing that we can connect. We can't say anything about what the higher
1001 // level protocols will be.
1002 auto prot_seq = protocol_list.At(0);
1003 PW_CHECK(prot_seq);
1004
1005 fidlbredr::ProtocolDescriptorPtr desc =
1006 DataElementToProtocolDescriptor(prot_seq);
1007 PW_CHECK(desc);
1008
1009 fuchsia::bluetooth::PeerId peer_id{id.value()};
1010
1011 std::vector<fidlbredr::ProtocolDescriptor> list;
1012 list.emplace_back(std::move(*desc));
1013
1014 std::optional<fuchsia::bluetooth::bredr::Channel> fidl_chan =
1015 ChannelToFidl(std::move(channel));
1016 if (!fidl_chan) {
1017 bt_log(INFO, "fidl", "ChannelToFidl failed. Ignoring channel.");
1018 return;
1019 }
1020
1021 it->second.receiver->Connected(
1022 peer_id, std::move(fidl_chan.value()), std::move(list));
1023 }
1024
OnConnectionReceiverClosed(uint64_t ad_id)1025 void ProfileServer::OnConnectionReceiverClosed(uint64_t ad_id) {
1026 auto it = current_advertised_.find(ad_id);
1027 if (it == current_advertised_.end() || !adapter().is_alive()) {
1028 return;
1029 }
1030
1031 adapter()->bredr()->UnregisterService(it->second.registration_handle);
1032
1033 current_advertised_.erase(it);
1034 }
1035
OnSearchResultError(uint64_t search_id,zx_status_t status)1036 void ProfileServer::OnSearchResultError(uint64_t search_id,
1037 zx_status_t status) {
1038 bt_log(DEBUG,
1039 "fidl",
1040 "Search result closed, ending search %lu reason %s",
1041 search_id,
1042 zx_status_get_string(status));
1043
1044 auto it = searches_.find(search_id);
1045
1046 if (it == searches_.end() || !adapter().is_alive()) {
1047 return;
1048 }
1049
1050 adapter()->bredr()->RemoveServiceSearch(it->second.search_id);
1051
1052 searches_.erase(it);
1053 }
1054
OnServiceFound(uint64_t search_id,bt::PeerId peer_id,const std::map<bt::sdp::AttributeId,bt::sdp::DataElement> & attributes)1055 void ProfileServer::OnServiceFound(
1056 uint64_t search_id,
1057 bt::PeerId peer_id,
1058 const std::map<bt::sdp::AttributeId, bt::sdp::DataElement>& attributes) {
1059 auto search_it = searches_.find(search_id);
1060 if (search_it == searches_.end()) {
1061 // Search was de-registered.
1062 return;
1063 }
1064
1065 // Convert ProfileDescriptor Attribute
1066 auto it = attributes.find(bt::sdp::kProtocolDescriptorList);
1067
1068 fidl::VectorPtr<fidlbredr::ProtocolDescriptor> descriptor_list;
1069
1070 if (it != attributes.end()) {
1071 std::vector<fidlbredr::ProtocolDescriptor> list;
1072 size_t idx = 0;
1073 auto* sdp_list_element = it->second.At(idx);
1074 while (sdp_list_element != nullptr) {
1075 fidlbredr::ProtocolDescriptorPtr desc =
1076 DataElementToProtocolDescriptor(sdp_list_element);
1077 if (!desc) {
1078 break;
1079 }
1080 list.push_back(std::move(*desc));
1081 sdp_list_element = it->second.At(++idx);
1082 }
1083 descriptor_list = std::move(list);
1084 }
1085
1086 // Add the rest of the attributes
1087 std::vector<fidlbredr::Attribute> fidl_attrs;
1088
1089 for (const auto& it : attributes) {
1090 auto attr = std::make_unique<fidlbredr::Attribute>();
1091 attr->set_id(it.first);
1092 attr->set_element(std::move(*DataElementToFidl(&it.second)));
1093 fidl_attrs.emplace_back(std::move(*attr));
1094 }
1095
1096 fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
1097
1098 search_it->second.results->ServiceFound(fidl_peer_id,
1099 std::move(descriptor_list),
1100 std::move(fidl_attrs),
1101 [](auto) {});
1102 }
1103
OnScoConnectionResult(WeakPtr<ScoConnectionServer> & server,bt::sco::ScoConnectionManager::AcceptConnectionResult result)1104 void ProfileServer::OnScoConnectionResult(
1105 WeakPtr<ScoConnectionServer>& server,
1106 bt::sco::ScoConnectionManager::AcceptConnectionResult result) {
1107 if (result.is_error()) {
1108 if (!server.is_alive()) {
1109 return;
1110 }
1111
1112 bt_log(INFO,
1113 "fidl",
1114 "%s: SCO connection failed (status: %s)",
1115 __FUNCTION__,
1116 bt::HostErrorToString(result.error_value()).c_str());
1117
1118 fidlbredr::ScoErrorCode fidl_error = fidlbredr::ScoErrorCode::FAILURE;
1119 if (result.error_value() == bt::HostError::kCanceled) {
1120 fidl_error = fidlbredr::ScoErrorCode::CANCELLED;
1121 }
1122 if (result.error_value() == bt::HostError::kParametersRejected) {
1123 fidl_error = fidlbredr::ScoErrorCode::PARAMETERS_REJECTED;
1124 }
1125 server->OnError(fidl_error);
1126 return;
1127 }
1128
1129 bt::sco::ScoConnection::WeakPtr connection = std::move(result.value().first);
1130 const uint16_t max_tx_data_size = connection->max_tx_sdu_size();
1131
1132 if (!server.is_alive()) {
1133 connection->Deactivate();
1134 return;
1135 }
1136 server->set_connection(std::move(connection));
1137
1138 server->Activate();
1139 if (!server.is_alive()) {
1140 return;
1141 }
1142
1143 size_t parameter_index = result.value().second;
1144 PW_CHECK(parameter_index < server->parameters().size(),
1145 "parameter_index (%zu) >= request->parameters.size() (%zu)",
1146 parameter_index,
1147 server->parameters().size());
1148 fidlbredr::ScoConnectionParameters parameters =
1149 fidl::Clone(server->parameters()[parameter_index]);
1150 parameters.set_max_tx_data_size(max_tx_data_size);
1151 server->OnConnectedParams(std::move(parameters));
1152 }
1153
OnAudioDirectionExtError(AudioDirectionExt * ext_server,zx_status_t status)1154 void ProfileServer::OnAudioDirectionExtError(AudioDirectionExt* ext_server,
1155 zx_status_t status) {
1156 bt_log(DEBUG,
1157 "fidl",
1158 "audio direction ext server closed (reason: %s)",
1159 zx_status_get_string(status));
1160 auto handle = audio_direction_ext_servers_.extract(ext_server->unique_id());
1161 if (handle.empty()) {
1162 bt_log(WARN,
1163 "fidl",
1164 "could not find ext server in audio direction ext error callback");
1165 }
1166 }
1167
1168 fidl::InterfaceHandle<fidlbredr::AudioDirectionExt>
BindAudioDirectionExtServer(bt::l2cap::Channel::WeakPtr channel)1169 ProfileServer::BindAudioDirectionExtServer(
1170 bt::l2cap::Channel::WeakPtr channel) {
1171 fidl::InterfaceHandle<fidlbredr::AudioDirectionExt> client;
1172
1173 bt::l2cap::Channel::UniqueId unique_id = channel->unique_id();
1174
1175 auto audio_direction_ext_server = std::make_unique<AudioDirectionExt>(
1176 client.NewRequest(), std::move(channel));
1177 AudioDirectionExt* server_ptr = audio_direction_ext_server.get();
1178
1179 audio_direction_ext_server->set_error_handler(
1180 [this, server_ptr](zx_status_t status) {
1181 OnAudioDirectionExtError(server_ptr, status);
1182 });
1183
1184 audio_direction_ext_servers_[unique_id] =
1185 std::move(audio_direction_ext_server);
1186
1187 return client;
1188 }
1189
OnL2capParametersExtError(L2capParametersExt * ext_server,zx_status_t status)1190 void ProfileServer::OnL2capParametersExtError(L2capParametersExt* ext_server,
1191 zx_status_t status) {
1192 bt_log(DEBUG,
1193 "fidl",
1194 "fidl parameters ext server closed (reason: %s)",
1195 zx_status_get_string(status));
1196 auto handle = l2cap_parameters_ext_servers_.extract(ext_server->unique_id());
1197 if (handle.empty()) {
1198 bt_log(WARN,
1199 "fidl",
1200 "could not find ext server in l2cap parameters ext error callback");
1201 }
1202 }
1203
1204 fidl::InterfaceHandle<fidlbredr::L2capParametersExt>
BindL2capParametersExtServer(bt::l2cap::Channel::WeakPtr channel)1205 ProfileServer::BindL2capParametersExtServer(
1206 bt::l2cap::Channel::WeakPtr channel) {
1207 fidl::InterfaceHandle<fidlbredr::L2capParametersExt> client;
1208
1209 bt::l2cap::Channel::UniqueId unique_id = channel->unique_id();
1210
1211 auto l2cap_parameters_ext_server = std::make_unique<L2capParametersExt>(
1212 client.NewRequest(), std::move(channel));
1213 L2capParametersExt* server_ptr = l2cap_parameters_ext_server.get();
1214
1215 l2cap_parameters_ext_server->set_error_handler(
1216 [this, server_ptr](zx_status_t status) {
1217 OnL2capParametersExtError(server_ptr, status);
1218 });
1219
1220 l2cap_parameters_ext_servers_[unique_id] =
1221 std::move(l2cap_parameters_ext_server);
1222 return client;
1223 }
1224
OnAudioOffloadExtError(AudioOffloadExt * ext_server,zx_status_t status)1225 void ProfileServer::OnAudioOffloadExtError(AudioOffloadExt* ext_server,
1226 zx_status_t status) {
1227 bt_log(DEBUG,
1228 "fidl",
1229 "audio offload ext server closed (reason: %s)",
1230 zx_status_get_string(status));
1231 auto handle = audio_offload_ext_servers_.extract(ext_server->unique_id());
1232 if (handle.empty()) {
1233 bt_log(WARN,
1234 "fidl",
1235 "could not find ext server in audio offload ext error callback");
1236 }
1237 }
1238
1239 fidl::InterfaceHandle<fidlbredr::AudioOffloadExt>
BindAudioOffloadExtServer(bt::l2cap::Channel::WeakPtr channel)1240 ProfileServer::BindAudioOffloadExtServer(bt::l2cap::Channel::WeakPtr channel) {
1241 fidl::InterfaceHandle<fidlbredr::AudioOffloadExt> client;
1242
1243 bt::l2cap::Channel::UniqueId unique_id = channel->unique_id();
1244
1245 std::unique_ptr<bthost::ProfileServer::AudioOffloadExt>
1246 audio_offload_ext_server = std::make_unique<AudioOffloadExt>(
1247 *this, client.NewRequest(), std::move(channel), adapter_);
1248 AudioOffloadExt* server_ptr = audio_offload_ext_server.get();
1249
1250 audio_offload_ext_server->set_error_handler(
1251 [this, server_ptr](zx_status_t status) {
1252 OnAudioOffloadExtError(server_ptr, status);
1253 });
1254
1255 audio_offload_ext_servers_[unique_id] = std::move(audio_offload_ext_server);
1256
1257 return client;
1258 }
1259
1260 std::optional<fidl::InterfaceHandle<fuchsia::bluetooth::Channel>>
BindChannelServer(bt::l2cap::Channel::WeakPtr channel,fit::callback<void ()> closed_callback)1261 ProfileServer::BindChannelServer(bt::l2cap::Channel::WeakPtr channel,
1262 fit::callback<void()> closed_callback) {
1263 fidl::InterfaceHandle<fbt::Channel> client;
1264
1265 bt::l2cap::Channel::UniqueId unique_id = channel->unique_id();
1266
1267 std::unique_ptr<bthost::ChannelServer> connection_server =
1268 ChannelServer::Create(
1269 client.NewRequest(), std::move(channel), std::move(closed_callback));
1270 if (!connection_server) {
1271 return std::nullopt;
1272 }
1273
1274 channel_servers_[unique_id] = std::move(connection_server);
1275 return client;
1276 }
1277
ChannelToFidl(bt::l2cap::Channel::WeakPtr channel)1278 std::optional<fuchsia::bluetooth::bredr::Channel> ProfileServer::ChannelToFidl(
1279 bt::l2cap::Channel::WeakPtr channel) {
1280 PW_CHECK(channel.is_alive());
1281 fidlbredr::Channel fidl_chan;
1282 fidl_chan.set_channel_mode(ChannelModeToFidl(channel->mode()));
1283 fidl_chan.set_max_tx_sdu_size(channel->max_tx_sdu_size());
1284 if (channel->info().flush_timeout) {
1285 fidl_chan.set_flush_timeout(channel->info().flush_timeout->count());
1286 }
1287
1288 auto closed_cb = [this, unique_id = channel->unique_id()]() {
1289 bt_log(DEBUG,
1290 "fidl",
1291 "Channel closed_cb called, destroying servers (unique_id: %d)",
1292 unique_id);
1293 channel_servers_.erase(unique_id);
1294 l2cap_parameters_ext_servers_.erase(unique_id);
1295 audio_direction_ext_servers_.erase(unique_id);
1296 audio_offload_ext_servers_.erase(unique_id);
1297 audio_offload_controller_server_ = nullptr;
1298 };
1299 if (use_sockets_) {
1300 auto sock = l2cap_socket_factory_.MakeSocketForChannel(
1301 channel, std::move(closed_cb));
1302 fidl_chan.set_socket(std::move(sock));
1303 } else {
1304 std::optional<fidl::InterfaceHandle<fuchsia::bluetooth::Channel>>
1305 connection = BindChannelServer(channel, std::move(closed_cb));
1306 if (!connection) {
1307 return std::nullopt;
1308 }
1309 fidl_chan.set_connection(std::move(connection.value()));
1310 }
1311
1312 if (adapter()->state().IsControllerFeatureSupported(
1313 FeaturesBits::kSetAclPriorityCommand)) {
1314 fidl_chan.set_ext_direction(BindAudioDirectionExtServer(channel));
1315 }
1316
1317 if (adapter()->state().IsControllerFeatureSupported(
1318 FeaturesBits::kAndroidVendorExtensions) &&
1319 adapter()
1320 ->state()
1321 .android_vendor_capabilities->a2dp_source_offload_capability_mask()) {
1322 fidl_chan.set_ext_audio_offload(BindAudioOffloadExtServer(channel));
1323 }
1324
1325 fidl_chan.set_ext_l2cap(BindL2capParametersExtServer(channel));
1326
1327 return fidl_chan;
1328 }
1329
SetPriority(fuchsia::bluetooth::bredr::A2dpDirectionPriority priority,SetPriorityCallback callback)1330 void ProfileServer::AudioDirectionExt::SetPriority(
1331 fuchsia::bluetooth::bredr::A2dpDirectionPriority priority,
1332 SetPriorityCallback callback) {
1333 channel_->RequestAclPriority(
1334 FidlToAclPriority(priority), [cb = std::move(callback)](auto result) {
1335 if (result.is_ok()) {
1336 cb(fpromise::ok());
1337 return;
1338 }
1339 bt_log(DEBUG, "fidl", "ACL priority request failed");
1340 cb(fpromise::error(fuchsia::bluetooth::ErrorCode::FAILED));
1341 });
1342 }
1343
handle_unknown_method(uint64_t ordinal,bool method_has_response)1344 void ProfileServer::AudioDirectionExt::handle_unknown_method(
1345 uint64_t ordinal, bool method_has_response) {
1346 bt_log(WARN, "fidl", "AudioDirectionExt: unknown method received");
1347 }
1348
1349 } // namespace bthost
1350