• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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