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