xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/fuchsia/host/fidl/profile_server.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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