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 <fuchsia/bluetooth/bredr/cpp/fidl_test_base.h>
18 #include <gmock/gmock.h>
19 #include <zircon/errors.h>
20
21 #include <memory>
22
23 #include "fuchsia/bluetooth/bredr/cpp/fidl.h"
24 #include "fuchsia/bluetooth/cpp/fidl.h"
25 #include "lib/fidl/cpp/vector.h"
26 #include "lib/zx/socket.h"
27 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/adapter_test_fixture.h"
28 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/fake_adapter_test_fixture.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/gap/fake_pairing_delegate.h"
32 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_channel.h"
33 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_l2cap.h"
34 #include "pw_bluetooth_sapphire/internal/host/sdp/data_element.h"
35 #include "pw_bluetooth_sapphire/internal/host/sdp/sdp.h"
36 #include "pw_bluetooth_sapphire/internal/host/testing/fake_peer.h"
37 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
38 #include "pw_bluetooth_sapphire/internal/host/testing/test_packets.h"
39 #include "pw_unit_test/framework.h"
40
41 namespace bthost {
42 namespace {
43
44 namespace fbt = fuchsia::bluetooth;
45 namespace fidlbredr = fuchsia::bluetooth::bredr;
46 namespace android_emb = pw::bluetooth::vendor::android_hci;
47
48 using bt::l2cap::testing::FakeChannel;
49 using pw::bluetooth::AclPriority;
50 using FeaturesBits = pw::bluetooth::Controller::FeaturesBits;
51
NopAdvertiseCallback(fidlbredr::Profile_Advertise_Result)52 void NopAdvertiseCallback(fidlbredr::Profile_Advertise_Result) {}
53
54 const bt::DeviceAddress kTestDevAddr(bt::DeviceAddress::Type::kBREDR, {1});
55 constexpr bt::l2cap::Psm kPsm = bt::l2cap::kAVDTP;
56
57 constexpr uint16_t kSynchronousDataPacketLength = 64;
58 constexpr uint8_t kTotalNumSynchronousDataPackets = 1;
59
CreateScoConnectionParameters(fidlbredr::HfpParameterSet param_set=fidlbredr::HfpParameterSet::T2)60 fidlbredr::ScoConnectionParameters CreateScoConnectionParameters(
61 fidlbredr::HfpParameterSet param_set = fidlbredr::HfpParameterSet::T2) {
62 fidlbredr::ScoConnectionParameters params;
63 params.set_parameter_set(param_set);
64 params.set_air_coding_format(fbt::AssignedCodingFormat::MSBC);
65 params.set_air_frame_size(8u);
66 params.set_io_bandwidth(32000);
67 params.set_io_coding_format(fbt::AssignedCodingFormat::LINEAR_PCM);
68 params.set_io_frame_size(16u);
69 params.set_io_pcm_data_format(
70 fuchsia::hardware::audio::SampleFormat::PCM_SIGNED);
71 params.set_io_pcm_sample_payload_msb_position(3u);
72 params.set_path(fidlbredr::DataPath::OFFLOAD);
73 return params;
74 }
75
MakeFIDLServiceDefinition()76 fidlbredr::ServiceDefinition MakeFIDLServiceDefinition() {
77 fidlbredr::ServiceDefinition def;
78 def.mutable_service_class_uuids()->emplace_back(
79 fidl_helpers::UuidToFidl(bt::sdp::profile::kAudioSink));
80
81 fidlbredr::ProtocolDescriptor l2cap_proto;
82 l2cap_proto.set_protocol(fidlbredr::ProtocolIdentifier::L2CAP);
83 fidlbredr::DataElement l2cap_data_el;
84 l2cap_data_el.set_uint16(fidlbredr::PSM_AVDTP);
85 std::vector<fidlbredr::DataElement> l2cap_params;
86 l2cap_params.emplace_back(std::move(l2cap_data_el));
87 l2cap_proto.set_params(std::move(l2cap_params));
88
89 def.mutable_protocol_descriptor_list()->emplace_back(std::move(l2cap_proto));
90
91 fidlbredr::ProtocolDescriptor avdtp_proto;
92 avdtp_proto.set_protocol(fidlbredr::ProtocolIdentifier::AVDTP);
93 fidlbredr::DataElement avdtp_data_el;
94 avdtp_data_el.set_uint16(0x0103); // Version 1.3
95 std::vector<fidlbredr::DataElement> avdtp_params;
96 avdtp_params.emplace_back(std::move(avdtp_data_el));
97 avdtp_proto.set_params(std::move(avdtp_params));
98
99 def.mutable_protocol_descriptor_list()->emplace_back(std::move(avdtp_proto));
100
101 fidlbredr::ProfileDescriptor prof_desc;
102 prof_desc.set_profile_id(
103 fidlbredr::ServiceClassProfileIdentifier::ADVANCED_AUDIO_DISTRIBUTION);
104 prof_desc.set_major_version(1);
105 prof_desc.set_minor_version(3);
106 def.mutable_profile_descriptors()->emplace_back(std::move(prof_desc));
107
108 // Additional attributes are also OK.
109 fidlbredr::Attribute addl_attr;
110 addl_attr.set_id(0x000A); // Documentation URL ID
111 fidlbredr::DataElement doc_url_el;
112 doc_url_el.set_url("fuchsia.dev");
113 addl_attr.set_element(std::move(doc_url_el));
114 def.mutable_additional_attributes()->emplace_back(std::move(addl_attr));
115
116 return def;
117 }
118
MakeMapMceServiceDefinition()119 fidlbredr::ServiceDefinition MakeMapMceServiceDefinition() {
120 // MAP MCE service definition requires RFCOMM and OBEX.
121 fidlbredr::ServiceDefinition def;
122 def.mutable_service_class_uuids()->emplace_back(
123 fidl_helpers::UuidToFidl(bt::sdp::profile::kMessageNotificationServer));
124
125 // [[L2CAP], [RFCOMM, Channel#], [OBEX]]
126 fidlbredr::ProtocolDescriptor l2cap_proto;
127 l2cap_proto.set_protocol(fidlbredr::ProtocolIdentifier::L2CAP);
128 std::vector<fidlbredr::DataElement> l2cap_params;
129 l2cap_proto.set_params(std::move(l2cap_params));
130 def.mutable_protocol_descriptor_list()->emplace_back(std::move(l2cap_proto));
131 fidlbredr::ProtocolDescriptor rfcomm_proto;
132 rfcomm_proto.set_protocol(fidlbredr::ProtocolIdentifier::RFCOMM);
133 fidlbredr::DataElement rfcomm_data_el;
134 rfcomm_data_el.set_uint8(5); // Random RFCOMM channel
135 std::vector<fidlbredr::DataElement> rfcomm_params;
136 rfcomm_params.emplace_back(std::move(rfcomm_data_el));
137 rfcomm_proto.set_params(std::move(rfcomm_params));
138 def.mutable_protocol_descriptor_list()->emplace_back(std::move(rfcomm_proto));
139 fidlbredr::ProtocolDescriptor obex_proto;
140 obex_proto.set_protocol(fidlbredr::ProtocolIdentifier::OBEX);
141 std::vector<fidlbredr::DataElement> obex_params;
142 obex_proto.set_params(std::move(obex_params));
143 def.mutable_protocol_descriptor_list()->emplace_back(std::move(obex_proto));
144
145 // Additional protocols. NOTE: This is fictional and not part of a real MCE
146 // definition.
147 std::vector<fidlbredr::ProtocolDescriptor> additional_proto;
148 fidlbredr::ProtocolDescriptor additional_l2cap_proto;
149 additional_l2cap_proto.set_protocol(fidlbredr::ProtocolIdentifier::L2CAP);
150 fidlbredr::DataElement additional_l2cap_data_el;
151 additional_l2cap_data_el.set_uint16(fidlbredr::PSM_DYNAMIC);
152 std::vector<fidlbredr::DataElement> additional_l2cap_params;
153 additional_l2cap_params.emplace_back(std::move(additional_l2cap_data_el));
154 additional_l2cap_proto.set_params(std::move(additional_l2cap_params));
155 additional_proto.emplace_back(std::move(additional_l2cap_proto));
156 fidlbredr::ProtocolDescriptor additional_obex_proto;
157 additional_obex_proto.set_protocol(fidlbredr::ProtocolIdentifier::OBEX);
158 std::vector<fidlbredr::DataElement> additional_obex_params;
159 additional_obex_proto.set_params(std::move(additional_obex_params));
160 additional_proto.emplace_back(std::move(additional_obex_proto));
161 def.mutable_additional_protocol_descriptor_lists()->emplace_back(
162 std::move(additional_proto));
163
164 fidlbredr::Information info;
165 info.set_language("en");
166 info.set_name("foo_test");
167 def.mutable_information()->emplace_back(std::move(info));
168
169 fidlbredr::ProfileDescriptor prof_desc;
170 prof_desc.set_profile_id(
171 fidlbredr::ServiceClassProfileIdentifier::MESSAGE_ACCESS_PROFILE);
172 prof_desc.set_major_version(1);
173 prof_desc.set_minor_version(4);
174 def.mutable_profile_descriptors()->emplace_back(std::move(prof_desc));
175
176 // Additional attributes - one requests a dynamic PSM.
177 fidlbredr::Attribute goep_attr;
178 goep_attr.set_id(0x200); // GoepL2capPsm
179 fidlbredr::DataElement goep_el;
180 goep_el.set_uint16(fidlbredr::PSM_DYNAMIC);
181 goep_attr.set_element(std::move(goep_el));
182 def.mutable_additional_attributes()->emplace_back(std::move(goep_attr));
183
184 fidlbredr::Attribute addl_attr;
185 addl_attr.set_id(0x317); // MAP supported features
186 fidlbredr::DataElement addl_el;
187 addl_el.set_uint32(1); // Random features
188 addl_attr.set_element(std::move(addl_el));
189 def.mutable_additional_attributes()->emplace_back(std::move(addl_attr));
190
191 return def;
192 }
193
194 // Returns a basic protocol list element with a protocol descriptor list that
195 // only contains an L2CAP descriptor.
MakeL2capProtocolListElement()196 bt::sdp::DataElement MakeL2capProtocolListElement() {
197 bt::sdp::DataElement l2cap_uuid_el;
198 l2cap_uuid_el.Set(bt::UUID(bt::sdp::protocol::kL2CAP));
199 std::vector<bt::sdp::DataElement> l2cap_descriptor_list;
200 l2cap_descriptor_list.emplace_back(std::move(l2cap_uuid_el));
201 std::vector<bt::sdp::DataElement> protocols;
202 protocols.emplace_back(std::move(l2cap_descriptor_list));
203 bt::sdp::DataElement protocol_list_el;
204 protocol_list_el.Set(std::move(protocols));
205 return protocol_list_el;
206 }
207
208 using TestingBase = bthost::testing::AdapterTestFixture;
209 class ProfileServerTest : public TestingBase {
210 public:
211 ProfileServerTest() = default;
212 ~ProfileServerTest() override = default;
213
214 protected:
SetUp(FeaturesBits features)215 void SetUp(FeaturesBits features) {
216 bt::testing::FakeController::Settings settings;
217 settings.ApplyDualModeDefaults();
218 settings.synchronous_data_packet_length = kSynchronousDataPacketLength;
219 settings.total_num_synchronous_data_packets =
220 kTotalNumSynchronousDataPackets;
221 TestingBase::SetUp(settings, features);
222
223 fidlbredr::ProfileHandle profile_handle;
224 client_.Bind(std::move(profile_handle));
225 server_ = std::make_unique<ProfileServer>(adapter()->AsWeakPtr(),
226 client_.NewRequest(dispatcher()));
227 }
SetUp()228 void SetUp() override { SetUp(FeaturesBits{0}); }
229
TearDown()230 void TearDown() override {
231 RunLoopUntilIdle();
232 client_ = nullptr;
233 server_ = nullptr;
234 TestingBase::TearDown();
235 }
236
server() const237 ProfileServer* server() const { return server_.get(); }
238
client()239 fidlbredr::ProfilePtr& client() { return client_; }
240
peer_cache() const241 bt::gap::PeerCache* peer_cache() const { return adapter()->peer_cache(); }
242
243 private:
244 std::unique_ptr<ProfileServer> server_;
245 fidlbredr::ProfilePtr client_;
246
247 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ProfileServerTest);
248 };
249
250 class FakeConnectionReceiver
251 : public fidlbredr::testing::ConnectionReceiver_TestBase {
252 public:
FakeConnectionReceiver(fidl::InterfaceRequest<ConnectionReceiver> request,async_dispatcher_t * dispatcher)253 FakeConnectionReceiver(fidl::InterfaceRequest<ConnectionReceiver> request,
254 async_dispatcher_t* dispatcher)
255 : binding_(this, std::move(request), dispatcher),
256 connected_count_(0),
257 closed_(false) {
258 binding_.set_error_handler([&](zx_status_t /*status*/) { closed_ = true; });
259 }
260
Connected(fuchsia::bluetooth::PeerId peer_id,fidlbredr::Channel channel,std::vector<fidlbredr::ProtocolDescriptor> protocol)261 void Connected(fuchsia::bluetooth::PeerId peer_id,
262 fidlbredr::Channel channel,
263 std::vector<fidlbredr::ProtocolDescriptor> protocol) override {
264 peer_id_ = peer_id;
265 channel_ = std::move(channel);
266 protocol_ = std::move(protocol);
267 connected_count_++;
268 }
269
Revoke()270 void Revoke() { binding_.events().OnRevoke(); }
271
connected_count() const272 size_t connected_count() const { return connected_count_; }
peer_id() const273 const std::optional<fuchsia::bluetooth::PeerId>& peer_id() const {
274 return peer_id_;
275 }
channel() const276 const std::optional<fidlbredr::Channel>& channel() const { return channel_; }
protocol() const277 const std::optional<std::vector<fidlbredr::ProtocolDescriptor>>& protocol()
278 const {
279 return protocol_;
280 }
closed()281 bool closed() { return closed_; }
282
bind_ext_direction()283 std::optional<fidlbredr::AudioDirectionExtPtr> bind_ext_direction() {
284 if (!channel().has_value()) {
285 return std::nullopt;
286 }
287 fidlbredr::AudioDirectionExtPtr client =
288 channel_.value().mutable_ext_direction()->Bind();
289 return client;
290 }
291
take_channel()292 fidlbredr::Channel take_channel() {
293 fidlbredr::Channel channel = std::move(channel_.value());
294 channel_.reset();
295 return channel;
296 }
297
298 private:
299 fidl::Binding<ConnectionReceiver> binding_;
300 size_t connected_count_;
301 std::optional<fuchsia::bluetooth::PeerId> peer_id_;
302 std::optional<fidlbredr::Channel> channel_;
303 std::optional<std::vector<fidlbredr::ProtocolDescriptor>> protocol_;
304 bool closed_;
305
NotImplemented_(const std::string & name)306 void NotImplemented_(const std::string& name) override {
307 FAIL() << name << " is not implemented";
308 }
309 };
310
311 class FakeSearchResults : public fidlbredr::testing::SearchResults_TestBase {
312 public:
FakeSearchResults(fidl::InterfaceRequest<SearchResults> request,async_dispatcher_t * dispatcher)313 FakeSearchResults(fidl::InterfaceRequest<SearchResults> request,
314 async_dispatcher_t* dispatcher)
315 : binding_(this, std::move(request), dispatcher),
316 service_found_count_(0) {
317 binding_.set_error_handler([this](zx_status_t) { closed_ = true; });
318 }
319
ServiceFound(fuchsia::bluetooth::PeerId peer_id,fidl::VectorPtr<fidlbredr::ProtocolDescriptor> protocol,std::vector<fidlbredr::Attribute> attributes,ServiceFoundCallback callback)320 void ServiceFound(fuchsia::bluetooth::PeerId peer_id,
321 fidl::VectorPtr<fidlbredr::ProtocolDescriptor> protocol,
322 std::vector<fidlbredr::Attribute> attributes,
323 ServiceFoundCallback callback) override {
324 peer_id_ = peer_id;
325 attributes_ = std::move(attributes);
326 callback(fidlbredr::SearchResults_ServiceFound_Result::WithResponse(
327 fidlbredr::SearchResults_ServiceFound_Response()));
328 service_found_count_++;
329 }
330
closed() const331 bool closed() const { return closed_; }
service_found_count() const332 size_t service_found_count() const { return service_found_count_; }
peer_id() const333 const std::optional<fuchsia::bluetooth::PeerId>& peer_id() const {
334 return peer_id_;
335 }
attributes() const336 const std::optional<std::vector<fidlbredr::Attribute>>& attributes() const {
337 return attributes_;
338 }
339
340 private:
341 bool closed_ = false;
342 fidl::Binding<SearchResults> binding_;
343 std::optional<fuchsia::bluetooth::PeerId> peer_id_;
344 std::optional<std::vector<fidlbredr::Attribute>> attributes_;
345 size_t service_found_count_;
346
NotImplemented_(const std::string & name)347 void NotImplemented_(const std::string& name) override {
348 FAIL() << name << " is not implemented";
349 }
350 };
351
TEST_F(ProfileServerTest,ErrorOnInvalidDefinition)352 TEST_F(ProfileServerTest, ErrorOnInvalidDefinition) {
353 fidlbredr::ConnectionReceiverHandle receiver_handle;
354 fidl::InterfaceRequest<fidlbredr::ConnectionReceiver> request =
355 receiver_handle.NewRequest();
356
357 std::vector<fidlbredr::ServiceDefinition> services;
358 fidlbredr::ServiceDefinition def;
359 // Empty service definition is not allowed - it must contain at least a
360 // service UUID.
361
362 services.emplace_back(std::move(def));
363
364 size_t cb_count = 0;
365 auto cb = [&](fidlbredr::Profile_Advertise_Result result) {
366 cb_count++;
367 EXPECT_TRUE(result.is_err());
368 EXPECT_EQ(result.err(), fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
369 };
370
371 fidlbredr::ProfileAdvertiseRequest adv_request;
372 adv_request.set_services(std::move(services));
373 adv_request.set_receiver(std::move(receiver_handle));
374 client()->Advertise(std::move(adv_request), std::move(cb));
375
376 RunLoopUntilIdle();
377
378 ASSERT_EQ(cb_count, 1u);
379 // Server should close because it's an invalid definition.
380 zx_signals_t signals;
381 request.channel().wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time(0), &signals);
382 EXPECT_TRUE(signals & ZX_CHANNEL_PEER_CLOSED);
383 }
384
TEST_F(ProfileServerTest,ErrorOnMultipleAdvertiseRequests)385 TEST_F(ProfileServerTest, ErrorOnMultipleAdvertiseRequests) {
386 fidlbredr::ConnectionReceiverHandle receiver_handle1;
387 fidl::InterfaceRequest<fidlbredr::ConnectionReceiver> request1 =
388 receiver_handle1.NewRequest();
389
390 std::vector<fidlbredr::ServiceDefinition> services1;
391 services1.emplace_back(MakeFIDLServiceDefinition());
392
393 size_t cb1_count = 0;
394 auto cb1 = [&](fidlbredr::Profile_Advertise_Result result) {
395 cb1_count++;
396 EXPECT_TRUE(result.is_response());
397 };
398
399 fidlbredr::ProfileAdvertiseRequest adv_request1;
400 adv_request1.set_services(std::move(services1));
401 adv_request1.set_receiver(std::move(receiver_handle1));
402 client()->Advertise(std::move(adv_request1), std::move(cb1));
403
404 RunLoopUntilIdle();
405
406 // First callback should be invoked with success since the advertisement is
407 // valid.
408 ASSERT_EQ(cb1_count, 1u);
409
410 fidlbredr::ConnectionReceiverHandle receiver_handle2;
411 fidl::InterfaceRequest<fidlbredr::ConnectionReceiver> request2 =
412 receiver_handle2.NewRequest();
413
414 std::vector<fidlbredr::ServiceDefinition> services2;
415 services2.emplace_back(MakeFIDLServiceDefinition());
416
417 // Second callback should error because the second advertisement is requesting
418 // a taken PSM.
419 size_t cb2_count = 0;
420 auto cb2 = [&](fidlbredr::Profile_Advertise_Result response) {
421 cb2_count++;
422 EXPECT_TRUE(response.is_err());
423 EXPECT_EQ(response.err(), fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
424 };
425
426 fidlbredr::ProfileAdvertiseRequest adv_request2;
427 adv_request2.set_services(std::move(services2));
428 adv_request2.set_receiver(std::move(receiver_handle2));
429 client()->Advertise(std::move(adv_request2), std::move(cb2));
430
431 RunLoopUntilIdle();
432
433 ASSERT_EQ(cb1_count, 1u);
434 ASSERT_EQ(cb2_count, 1u);
435
436 // Second channel should close.
437 zx_signals_t signals;
438 request2.channel().wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time(0), &signals);
439 EXPECT_TRUE(signals & ZX_CHANNEL_PEER_CLOSED);
440 }
441
TEST_F(ProfileServerTest,ErrorOnInvalidConnectParametersNoPsm)442 TEST_F(ProfileServerTest, ErrorOnInvalidConnectParametersNoPsm) {
443 // Random peer, since we don't expect the connection.
444 fuchsia::bluetooth::PeerId peer_id{123};
445
446 // No PSM provided - this is invalid.
447 fidlbredr::L2capParameters l2cap_params;
448 fidlbredr::ConnectParameters conn_params;
449 l2cap_params.set_parameters(fbt::ChannelParameters());
450 conn_params.set_l2cap(std::move(l2cap_params));
451
452 // Expect an error result.
453 auto sock_cb = [](fidlbredr::Profile_Connect_Result result) {
454 EXPECT_TRUE(result.is_err());
455 EXPECT_EQ(result.err(), fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
456 };
457
458 client()->Connect(peer_id, std::move(conn_params), std::move(sock_cb));
459 RunLoopUntilIdle();
460 }
461
TEST_F(ProfileServerTest,ErrorOnInvalidConnectParametersRfcomm)462 TEST_F(ProfileServerTest, ErrorOnInvalidConnectParametersRfcomm) {
463 // Random peer, since we don't expect the connection.
464 fuchsia::bluetooth::PeerId peer_id{123};
465
466 // RFCOMM Parameters are provided - this is not supported.
467 fidlbredr::RfcommParameters rfcomm_params;
468 fidlbredr::ConnectParameters conn_params;
469 conn_params.set_rfcomm(std::move(rfcomm_params));
470
471 // Expect an error result.
472 auto sock_cb = [](fidlbredr::Profile_Connect_Result result) {
473 EXPECT_TRUE(result.is_err());
474 EXPECT_EQ(result.err(), fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
475 };
476
477 client()->Connect(peer_id, std::move(conn_params), std::move(sock_cb));
478 RunLoopUntilIdle();
479 }
480
TEST_F(ProfileServerTest,DynamicPsmAdvertisementIsUpdated)481 TEST_F(ProfileServerTest, DynamicPsmAdvertisementIsUpdated) {
482 fidlbredr::ConnectionReceiverHandle receiver_handle;
483 fidl::InterfaceRequest<fidlbredr::ConnectionReceiver> request =
484 receiver_handle.NewRequest();
485
486 std::vector<fidlbredr::ServiceDefinition> services;
487 services.emplace_back(MakeMapMceServiceDefinition());
488
489 size_t cb_count = 0;
490 auto cb = [&](fidlbredr::Profile_Advertise_Result result) {
491 cb_count++;
492 EXPECT_TRUE(result.is_response());
493 EXPECT_EQ(result.response().services().size(), 1u);
494 const auto registered_def =
495 std::move(result.response().mutable_services()->front());
496 const auto original_def = MakeMapMceServiceDefinition();
497 // The UUIDs, primary protocol list, & profile descriptors should be
498 // unchanged.
499 ASSERT_TRUE(::fidl::Equals(registered_def.service_class_uuids(),
500 original_def.service_class_uuids()));
501 ASSERT_TRUE(::fidl::Equals(registered_def.protocol_descriptor_list(),
502 original_def.protocol_descriptor_list()));
503 ASSERT_TRUE(::fidl::Equals(registered_def.profile_descriptors(),
504 original_def.profile_descriptors()));
505 // The additional protocol list should be updated with a randomly assigned
506 // dynamic PSM.
507 EXPECT_EQ(registered_def.additional_protocol_descriptor_lists().size(), 1u);
508 EXPECT_NE(registered_def.additional_protocol_descriptor_lists()
509 .front()
510 .front()
511 .params()
512 .front()
513 .uint16(),
514 fidlbredr::PSM_DYNAMIC);
515 // TODO(b/327758656): Verify information and additional attributes once
516 // implemented.
517 };
518
519 fidlbredr::ProfileAdvertiseRequest adv_request;
520 adv_request.set_services(std::move(services));
521 adv_request.set_receiver(std::move(receiver_handle));
522 client()->Advertise(std::move(adv_request), std::move(cb));
523
524 RunLoopUntilIdle();
525 EXPECT_EQ(cb_count, 1u);
526 }
527
TEST_F(ProfileServerTest,RevokeConnectionReceiverUnregistersAdvertisement)528 TEST_F(ProfileServerTest, RevokeConnectionReceiverUnregistersAdvertisement) {
529 fidlbredr::ConnectionReceiverHandle receiver_handle;
530 FakeConnectionReceiver connect_receiver(receiver_handle.NewRequest(),
531 dispatcher());
532
533 std::vector<fidlbredr::ServiceDefinition> services;
534 services.emplace_back(MakeFIDLServiceDefinition());
535
536 size_t cb_count = 0;
537 auto cb = [&](fidlbredr::Profile_Advertise_Result result) {
538 cb_count++;
539 EXPECT_TRUE(result.is_response());
540 };
541
542 fidlbredr::ProfileAdvertiseRequest adv_request;
543 adv_request.set_services(std::move(services));
544 adv_request.set_receiver(std::move(receiver_handle));
545 client()->Advertise(std::move(adv_request), std::move(cb));
546 RunLoopUntilIdle();
547
548 // Advertisement should be registered. The callback should be invoked with the
549 // advertised set of services, and the `ConnectionReceiver` should still be
550 // open.
551 ASSERT_EQ(cb_count, 1u);
552 ASSERT_FALSE(connect_receiver.closed());
553
554 // Server end of `ConnectionReceiver` revokes the advertisement.
555 connect_receiver.Revoke();
556 RunLoopUntilIdle();
557
558 // Profile server should drop the advertisement - the `connect_receiver`
559 // should be closed.
560 ASSERT_TRUE(connect_receiver.closed());
561 }
562
563 class ProfileServerTestConnectedPeer : public ProfileServerTest {
564 public:
565 ProfileServerTestConnectedPeer() = default;
566 ~ProfileServerTestConnectedPeer() override = default;
567
568 protected:
SetUp(FeaturesBits features)569 void SetUp(FeaturesBits features) {
570 ProfileServerTest::SetUp(features);
571 peer_ = peer_cache()->NewPeer(kTestDevAddr, /*connectable=*/true);
572 std::unique_ptr<bt::testing::FakePeer> fake_peer =
573 std::make_unique<bt::testing::FakePeer>(kTestDevAddr, pw_dispatcher());
574 test_device()->AddPeer(std::move(fake_peer));
575
576 std::optional<bt::hci::Result<>> status;
577 auto connect_cb = [this, &status](auto cb_status, auto cb_conn_ref) {
578 ASSERT_TRUE(cb_conn_ref);
579 status = cb_status;
580 connection_ = std::move(cb_conn_ref);
581 };
582
583 EXPECT_TRUE(adapter()->bredr()->Connect(peer_->identifier(), connect_cb));
584 EXPECT_EQ(bt::gap::Peer::ConnectionState::kInitializing,
585 peer_->bredr()->connection_state());
586
587 RunLoopUntilIdle();
588 ASSERT_TRUE(status.has_value());
589 EXPECT_EQ(fit::ok(), status.value());
590 ASSERT_TRUE(connection_);
591 EXPECT_EQ(peer_->identifier(), connection_->peer_id());
592 EXPECT_NE(bt::gap::Peer::ConnectionState::kNotConnected,
593 peer_->bredr()->connection_state());
594 }
595
SetUp()596 void SetUp() override { SetUp(FeaturesBits::kHciSco); }
597
TearDown()598 void TearDown() override {
599 connection_ = nullptr;
600 peer_ = nullptr;
601 ProfileServerTest::TearDown();
602 }
603
connection() const604 bt::gap::BrEdrConnection* connection() const { return connection_; }
605
peer() const606 bt::gap::Peer* peer() const { return peer_; }
607
608 private:
609 bt::gap::BrEdrConnection* connection_;
610 bt::gap::Peer* peer_;
611
612 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ProfileServerTestConnectedPeer);
613 };
614
615 class ProfileServerTestScoConnected : public ProfileServerTestConnectedPeer {
616 public:
SetUp()617 void SetUp() override {
618 fidlbredr::ScoConnectionParameters params =
619 CreateScoConnectionParameters(fidlbredr::HfpParameterSet::D0);
620 params.set_path(fidlbredr::DataPath::HOST);
621 SetUp(std::move(params));
622 }
623
SetUp(fidlbredr::ScoConnectionParameters conn_params)624 void SetUp(fidlbredr::ScoConnectionParameters conn_params) {
625 ProfileServerTestConnectedPeer::SetUp(FeaturesBits::kHciSco);
626
627 test_device()->set_configure_sco_cb(
628 [](auto, auto, auto, auto cb) { cb(PW_STATUS_OK); });
629 test_device()->set_reset_sco_cb([](auto cb) { cb(PW_STATUS_OK); });
630
631 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
632 sco_params_list.emplace_back(std::move(conn_params));
633
634 fidlbredr::ProfileConnectScoRequest request;
635 request.set_peer_id(
636 fuchsia::bluetooth::PeerId{peer()->identifier().value()});
637 request.set_initiator(false);
638 request.set_params(std::move(sco_params_list));
639 fidlbredr::ScoConnectionHandle connection_handle;
640 request.set_connection(connection_handle.NewRequest());
641
642 sco_connection_ = connection_handle.Bind();
643 sco_connection_.set_error_handler([this](zx_status_t status) {
644 sco_connection_ = nullptr;
645 sco_conn_error_ = status;
646 });
647
648 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
649 connection_complete;
650 sco_connection_.events().OnConnectionComplete =
651 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
652 connection_complete = std::move(request);
653 };
654
655 client()->ConnectSco(std::move(request));
656 RunLoopUntilIdle();
657 test_device()->SendConnectionRequest(peer()->address(),
658 pw::bluetooth::emboss::LinkType::SCO);
659 RunLoopUntilIdle();
660 ASSERT_TRUE(connection_complete.has_value());
661 ASSERT_TRUE(connection_complete->is_connected_params());
662
663 // OnConnectionComplete should never be called again.
664 sco_connection_.events().OnConnectionComplete =
665 [](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
666 FAIL();
667 };
668
669 // Find the link handle used for the SCO connection.
670 bt::testing::FakePeer* fake_peer =
671 test_device()->FindPeer(peer()->address());
672 ASSERT_TRUE(fake_peer);
673 // There are 2 connections: BR/EDR, SCO
674 ASSERT_EQ(fake_peer->logical_links().size(), 2u);
675 bt::testing::FakePeer::HandleSet links = fake_peer->logical_links();
676 // The link that is not the BR/EDR connection link must be the SCO link.
677 links.erase(connection()->link().handle());
678 sco_conn_handle_ = *links.begin();
679 }
680
TearDown()681 void TearDown() override { ProfileServerTestConnectedPeer::TearDown(); }
682
sco_connection()683 fidlbredr::ScoConnectionPtr& sco_connection() { return sco_connection_; }
684
sco_conn_error() const685 std::optional<zx_status_t> sco_conn_error() const { return sco_conn_error_; }
686
sco_handle() const687 bt::hci_spec::ConnectionHandle sco_handle() const { return sco_conn_handle_; }
688
689 private:
690 fidlbredr::ScoConnectionPtr sco_connection_;
691 bt::hci_spec::ConnectionHandle sco_conn_handle_;
692 std::optional<zx_status_t> sco_conn_error_;
693 };
694
695 class ProfileServerTestOffloadedScoConnected
696 : public ProfileServerTestScoConnected {
697 public:
SetUp()698 void SetUp() override {
699 fidlbredr::ScoConnectionParameters params =
700 CreateScoConnectionParameters(fidlbredr::HfpParameterSet::D0);
701 params.set_path(fidlbredr::DataPath::OFFLOAD);
702 ProfileServerTestScoConnected::SetUp(std::move(params));
703 }
704 };
705
TEST_F(ProfileServerTestConnectedPeer,ConnectL2capChannelParametersUseSocket)706 TEST_F(ProfileServerTestConnectedPeer, ConnectL2capChannelParametersUseSocket) {
707 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
708 std::make_unique<bt::gap::FakePairingDelegate>(
709 bt::sm::IOCapability::kDisplayYesNo);
710 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
711 // Approve pairing requests.
712 pairing_delegate->SetConfirmPairingCallback(
713 [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
714 pairing_delegate->SetCompletePairingCallback(
715 [&](bt::PeerId, bt::sm::Result<> status) {
716 EXPECT_EQ(fit::ok(), status);
717 });
718
719 bt::l2cap::ChannelParameters expected_params;
720 expected_params.mode =
721 bt::l2cap::RetransmissionAndFlowControlMode::kEnhancedRetransmission;
722 expected_params.max_rx_sdu_size = bt::l2cap::kMinACLMTU;
723 l2cap()->ExpectOutboundL2capChannel(
724 connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
725
726 // Expect a non-empty channel result.
727 std::optional<fidlbredr::Channel> channel;
728 auto chan_cb = [&channel](fidlbredr::Profile_Connect_Result result) {
729 EXPECT_TRUE(result.is_response());
730 channel = std::move(result.response().channel);
731 };
732 // Initiates pairing
733
734 fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
735
736 // Set L2CAP channel parameters
737 fbt::ChannelParameters chan_params;
738 fidlbredr::L2capParameters l2cap_params;
739 fidlbredr::ConnectParameters conn_params;
740 chan_params.set_channel_mode(fbt::ChannelMode::ENHANCED_RETRANSMISSION);
741 chan_params.set_max_rx_packet_size(bt::l2cap::kMinACLMTU);
742 l2cap_params.set_psm(kPsm);
743 l2cap_params.set_parameters(std::move(chan_params));
744 conn_params.set_l2cap(std::move(l2cap_params));
745
746 client()->Connect(peer_id, std::move(conn_params), std::move(chan_cb));
747 RunLoopUntilIdle();
748
749 ASSERT_TRUE(channel.has_value());
750 EXPECT_TRUE(channel->has_socket());
751 EXPECT_FALSE(channel->IsEmpty());
752 EXPECT_EQ(channel->channel_mode(), chan_params.channel_mode());
753 // FakeL2cap returns channels with max tx sdu size of kDefaultMTU.
754 EXPECT_EQ(channel->max_tx_sdu_size(), bt::l2cap::kDefaultMTU);
755 EXPECT_FALSE(channel->has_ext_direction());
756 EXPECT_FALSE(channel->has_flush_timeout());
757 }
758
TEST_F(ProfileServerTestConnectedPeer,ConnectL2capChannelParametersUseConnection)759 TEST_F(ProfileServerTestConnectedPeer,
760 ConnectL2capChannelParametersUseConnection) {
761 server()->set_use_sockets(false);
762
763 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
764 std::make_unique<bt::gap::FakePairingDelegate>(
765 bt::sm::IOCapability::kDisplayYesNo);
766 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
767 // Approve pairing requests.
768 pairing_delegate->SetConfirmPairingCallback(
769 [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
770 pairing_delegate->SetCompletePairingCallback(
771 [&](bt::PeerId, bt::sm::Result<> status) {
772 EXPECT_EQ(fit::ok(), status);
773 });
774
775 bt::l2cap::ChannelParameters expected_params;
776 expected_params.mode =
777 bt::l2cap::RetransmissionAndFlowControlMode::kEnhancedRetransmission;
778 expected_params.max_rx_sdu_size = bt::l2cap::kMinACLMTU;
779 l2cap()->ExpectOutboundL2capChannel(
780 connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
781
782 // Expect a non-empty channel result.
783 std::optional<fidlbredr::Channel> channel;
784 auto chan_cb = [&channel](fidlbredr::Profile_Connect_Result result) {
785 EXPECT_TRUE(result.is_response());
786 channel = std::move(result.response().channel);
787 };
788 // Initiates pairing
789
790 fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
791
792 // Set L2CAP channel parameters
793 fbt::ChannelParameters chan_params;
794 fidlbredr::L2capParameters l2cap_params;
795 fidlbredr::ConnectParameters conn_params;
796 chan_params.set_channel_mode(fbt::ChannelMode::ENHANCED_RETRANSMISSION);
797 chan_params.set_max_rx_packet_size(bt::l2cap::kMinACLMTU);
798 l2cap_params.set_psm(kPsm);
799 l2cap_params.set_parameters(std::move(chan_params));
800 conn_params.set_l2cap(std::move(l2cap_params));
801
802 client()->Connect(peer_id, std::move(conn_params), std::move(chan_cb));
803 RunLoopUntilIdle();
804
805 ASSERT_TRUE(channel.has_value());
806 EXPECT_TRUE(channel->has_connection());
807 EXPECT_FALSE(channel->IsEmpty());
808 EXPECT_EQ(channel->channel_mode(), chan_params.channel_mode());
809 // FakeL2cap returns channels with max tx sdu size of kDefaultMTU.
810 EXPECT_EQ(channel->max_tx_sdu_size(), bt::l2cap::kDefaultMTU);
811 EXPECT_FALSE(channel->has_ext_direction());
812 EXPECT_FALSE(channel->has_flush_timeout());
813 }
814
TEST_F(ProfileServerTestConnectedPeer,ConnectWithAuthenticationRequiredButLinkKeyNotAuthenticatedFails)815 TEST_F(ProfileServerTestConnectedPeer,
816 ConnectWithAuthenticationRequiredButLinkKeyNotAuthenticatedFails) {
817 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
818 std::make_unique<bt::gap::FakePairingDelegate>(
819 bt::sm::IOCapability::kNoInputNoOutput);
820 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
821 pairing_delegate->SetCompletePairingCallback(
822 [&](bt::PeerId, bt::sm::Result<> status) {
823 EXPECT_EQ(fit::ok(), status);
824 });
825
826 fbt::SecurityRequirements security;
827 security.set_authentication_required(true);
828
829 // Set L2CAP channel parameters
830 fbt::ChannelParameters chan_params;
831 fidlbredr::L2capParameters l2cap_params;
832 fidlbredr::ConnectParameters conn_params;
833 chan_params.set_security_requirements(std::move(security));
834 l2cap_params.set_psm(kPsm);
835 l2cap_params.set_parameters(std::move(chan_params));
836 conn_params.set_l2cap(std::move(l2cap_params));
837
838 size_t sock_cb_count = 0;
839 auto sock_cb = [&](fidlbredr::Profile_Connect_Result result) {
840 sock_cb_count++;
841 ASSERT_TRUE(result.is_err());
842 EXPECT_EQ(fuchsia::bluetooth::ErrorCode::FAILED, result.err());
843 };
844
845 fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
846
847 // Initiates pairing.
848 // FakeController will create an unauthenticated key.
849 client()->Connect(peer_id, std::move(conn_params), std::move(sock_cb));
850 RunLoopUntilIdle();
851
852 EXPECT_EQ(1u, sock_cb_count);
853 }
854
855 // Tests receiving an empty Channel results in an error propagated through the
856 // callback.
TEST_F(ProfileServerTestConnectedPeer,ConnectEmptyChannelResponse)857 TEST_F(ProfileServerTestConnectedPeer, ConnectEmptyChannelResponse) {
858 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
859 std::make_unique<bt::gap::FakePairingDelegate>(
860 bt::sm::IOCapability::kDisplayYesNo);
861 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
862 // Approve pairing requests.
863 pairing_delegate->SetConfirmPairingCallback(
864 [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
865 pairing_delegate->SetCompletePairingCallback(
866 [&](bt::PeerId, bt::sm::Result<> status) {
867 EXPECT_EQ(fit::ok(), status);
868 });
869
870 // Make the l2cap channel creation fail.
871 l2cap()->set_simulate_open_channel_failure(true);
872
873 bt::l2cap::ChannelParameters expected_params;
874 expected_params.mode =
875 bt::l2cap::RetransmissionAndFlowControlMode::kEnhancedRetransmission;
876 expected_params.max_rx_sdu_size = bt::l2cap::kMinACLMTU;
877 l2cap()->ExpectOutboundL2capChannel(
878 connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
879
880 fbt::ChannelParameters chan_params;
881 chan_params.set_channel_mode(fbt::ChannelMode::ENHANCED_RETRANSMISSION);
882 chan_params.set_max_rx_packet_size(bt::l2cap::kMinACLMTU);
883 auto sock_cb = [](fidlbredr::Profile_Connect_Result result) {
884 EXPECT_TRUE(result.is_err());
885 EXPECT_EQ(fuchsia::bluetooth::ErrorCode::FAILED, result.err());
886 };
887 // Initiates pairing
888
889 fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
890
891 // Set L2CAP channel parameters
892 fidlbredr::L2capParameters l2cap_params;
893 fidlbredr::ConnectParameters conn_params;
894 l2cap_params.set_psm(kPsm);
895 l2cap_params.set_parameters(std::move(chan_params));
896 conn_params.set_l2cap(std::move(l2cap_params));
897
898 client()->Connect(peer_id, std::move(conn_params), std::move(sock_cb));
899 RunLoopUntilIdle();
900 }
901
TEST_F(ProfileServerTestConnectedPeer,AdvertiseChannelParametersReceivedInOnChannelConnectedCallbackUseSocket)902 TEST_F(
903 ProfileServerTestConnectedPeer,
904 AdvertiseChannelParametersReceivedInOnChannelConnectedCallbackUseSocket) {
905 constexpr uint16_t kTxMtu = bt::l2cap::kMinACLMTU;
906
907 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
908 std::make_unique<bt::gap::FakePairingDelegate>(
909 bt::sm::IOCapability::kDisplayYesNo);
910 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
911
912 fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
913 FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
914 dispatcher());
915
916 std::vector<fidlbredr::ServiceDefinition> services;
917 services.emplace_back(MakeFIDLServiceDefinition());
918 fbt::ChannelParameters chan_params;
919 chan_params.set_channel_mode(fbt::ChannelMode::ENHANCED_RETRANSMISSION);
920
921 fidlbredr::ProfileAdvertiseRequest adv_request;
922 adv_request.set_services(std::move(services));
923 adv_request.set_parameters(std::move(chan_params));
924 adv_request.set_receiver(std::move(connect_receiver_handle));
925 client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
926 RunLoopUntilIdle();
927
928 ASSERT_EQ(connect_receiver.connected_count(), 0u);
929 EXPECT_TRUE(l2cap()->TriggerInboundL2capChannel(
930 connection()->link().handle(), kPsm, 0x40, 0x41, kTxMtu));
931 RunLoopUntilIdle();
932
933 ASSERT_EQ(connect_receiver.connected_count(), 1u);
934 ASSERT_EQ(connect_receiver.peer_id().value().value,
935 peer()->identifier().value());
936 ASSERT_TRUE(connect_receiver.channel().value().has_socket());
937 EXPECT_EQ(connect_receiver.channel().value().channel_mode(),
938 fbt::ChannelMode::ENHANCED_RETRANSMISSION);
939 EXPECT_EQ(connect_receiver.channel().value().max_tx_sdu_size(), kTxMtu);
940 EXPECT_FALSE(connect_receiver.channel().value().has_ext_direction());
941 EXPECT_FALSE(connect_receiver.channel().value().has_flush_timeout());
942 }
943
TEST_F(ProfileServerTestConnectedPeer,AdvertiseChannelParametersReceivedInOnChannelConnectedCallbackUseConnection)944 TEST_F(
945 ProfileServerTestConnectedPeer,
946 AdvertiseChannelParametersReceivedInOnChannelConnectedCallbackUseConnection) {
947 server()->set_use_sockets(false);
948
949 constexpr uint16_t kTxMtu = bt::l2cap::kMinACLMTU;
950
951 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
952 std::make_unique<bt::gap::FakePairingDelegate>(
953 bt::sm::IOCapability::kDisplayYesNo);
954 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
955
956 fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
957 FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
958 dispatcher());
959
960 std::vector<fidlbredr::ServiceDefinition> services;
961 services.emplace_back(MakeFIDLServiceDefinition());
962 fbt::ChannelParameters chan_params;
963 chan_params.set_channel_mode(fbt::ChannelMode::ENHANCED_RETRANSMISSION);
964
965 fidlbredr::ProfileAdvertiseRequest adv_request;
966 adv_request.set_services(std::move(services));
967 adv_request.set_parameters(std::move(chan_params));
968 adv_request.set_receiver(std::move(connect_receiver_handle));
969 client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
970 RunLoopUntilIdle();
971
972 ASSERT_EQ(connect_receiver.connected_count(), 0u);
973 EXPECT_TRUE(l2cap()->TriggerInboundL2capChannel(
974 connection()->link().handle(), kPsm, 0x40, 0x41, kTxMtu));
975 RunLoopUntilIdle();
976
977 ASSERT_EQ(connect_receiver.connected_count(), 1u);
978 ASSERT_EQ(connect_receiver.peer_id().value().value,
979 peer()->identifier().value());
980 ASSERT_TRUE(connect_receiver.channel().value().has_connection());
981 EXPECT_EQ(connect_receiver.channel().value().channel_mode(),
982 fbt::ChannelMode::ENHANCED_RETRANSMISSION);
983 EXPECT_EQ(connect_receiver.channel().value().max_tx_sdu_size(), kTxMtu);
984 EXPECT_FALSE(connect_receiver.channel().value().has_ext_direction());
985 EXPECT_FALSE(connect_receiver.channel().value().has_flush_timeout());
986 }
987
988 class AclPrioritySupportedTest : public ProfileServerTestConnectedPeer {
989 public:
SetUp()990 void SetUp() override {
991 ProfileServerTestConnectedPeer::SetUp(FeaturesBits::kSetAclPriorityCommand);
992 }
993 };
994
995 class PriorityTest : public AclPrioritySupportedTest,
996 public ::testing::WithParamInterface<
997 std::pair<fidlbredr::A2dpDirectionPriority, bool>> {};
998
TEST_P(PriorityTest,OutboundConnectAndSetPriority)999 TEST_P(PriorityTest, OutboundConnectAndSetPriority) {
1000 const fidlbredr::A2dpDirectionPriority kPriority = GetParam().first;
1001 const bool kExpectSuccess = GetParam().second;
1002
1003 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1004 std::make_unique<bt::gap::FakePairingDelegate>(
1005 bt::sm::IOCapability::kDisplayYesNo);
1006 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1007 // Approve pairing requests.
1008 pairing_delegate->SetConfirmPairingCallback(
1009 [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
1010 pairing_delegate->SetCompletePairingCallback(
1011 [&](bt::PeerId, bt::sm::Result<> status) {
1012 EXPECT_EQ(fit::ok(), status);
1013 });
1014
1015 l2cap()->ExpectOutboundL2capChannel(connection()->link().handle(),
1016 kPsm,
1017 0x40,
1018 0x41,
1019 bt::l2cap::ChannelParameters());
1020
1021 FakeChannel::WeakPtr fake_channel;
1022 l2cap()->set_channel_callback(
1023 [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
1024
1025 // Expect a non-empty channel result.
1026 std::optional<fidlbredr::Channel> channel;
1027 auto chan_cb = [&channel](fidlbredr::Profile_Connect_Result result) {
1028 ASSERT_TRUE(result.is_response());
1029 channel = std::move(result.response().channel);
1030 };
1031
1032 fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
1033
1034 // Set L2CAP channel parameters
1035 fidlbredr::L2capParameters l2cap_params;
1036 fidlbredr::ConnectParameters conn_params;
1037 l2cap_params.set_psm(kPsm);
1038 conn_params.set_l2cap(std::move(l2cap_params));
1039
1040 // Initiates pairing
1041 client()->Connect(peer_id, std::move(conn_params), std::move(chan_cb));
1042 RunLoopUntilIdle();
1043 ASSERT_TRUE(fake_channel.is_alive());
1044 ASSERT_TRUE(channel.has_value());
1045 ASSERT_TRUE(channel->has_ext_direction());
1046 fidlbredr::AudioDirectionExtPtr client =
1047 channel->mutable_ext_direction()->Bind();
1048
1049 size_t priority_cb_count = 0;
1050 fake_channel->set_acl_priority_fails(!kExpectSuccess);
1051 client->SetPriority(
1052 kPriority, [&](fidlbredr::AudioDirectionExt_SetPriority_Result result) {
1053 EXPECT_EQ(result.is_response(), kExpectSuccess);
1054 priority_cb_count++;
1055 });
1056
1057 RunLoopUntilIdle();
1058 EXPECT_EQ(priority_cb_count, 1u);
1059 client = nullptr;
1060 RunLoopUntilIdle();
1061
1062 if (kExpectSuccess) {
1063 switch (kPriority) {
1064 case fidlbredr::A2dpDirectionPriority::SOURCE:
1065 EXPECT_EQ(fake_channel->requested_acl_priority(), AclPriority::kSource);
1066 break;
1067 case fidlbredr::A2dpDirectionPriority::SINK:
1068 EXPECT_EQ(fake_channel->requested_acl_priority(), AclPriority::kSink);
1069 break;
1070 default:
1071 EXPECT_EQ(fake_channel->requested_acl_priority(), AclPriority::kNormal);
1072 }
1073 } else {
1074 EXPECT_EQ(fake_channel->requested_acl_priority(), AclPriority::kNormal);
1075 }
1076 }
1077
1078 const std::array<std::pair<fidlbredr::A2dpDirectionPriority, bool>, 4>
1079 kPriorityParams = {{{fidlbredr::A2dpDirectionPriority::SOURCE, false},
1080 {fidlbredr::A2dpDirectionPriority::SOURCE, true},
1081 {fidlbredr::A2dpDirectionPriority::SINK, true},
1082 {fidlbredr::A2dpDirectionPriority::NORMAL, true}}};
1083 INSTANTIATE_TEST_SUITE_P(ProfileServerTestConnectedPeer,
1084 PriorityTest,
1085 ::testing::ValuesIn(kPriorityParams));
1086
TEST_F(AclPrioritySupportedTest,InboundConnectAndSetPriority)1087 TEST_F(AclPrioritySupportedTest, InboundConnectAndSetPriority) {
1088 constexpr uint16_t kTxMtu = bt::l2cap::kMinACLMTU;
1089
1090 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1091 std::make_unique<bt::gap::FakePairingDelegate>(
1092 bt::sm::IOCapability::kDisplayYesNo);
1093 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1094
1095 FakeChannel::WeakPtr fake_channel;
1096 l2cap()->set_channel_callback(
1097 [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
1098
1099 fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
1100 FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
1101 dispatcher());
1102
1103 std::vector<fidlbredr::ServiceDefinition> services;
1104 services.emplace_back(MakeFIDLServiceDefinition());
1105 fidlbredr::ProfileAdvertiseRequest adv_request;
1106 adv_request.set_services(std::move(services));
1107 adv_request.set_receiver(std::move(connect_receiver_handle));
1108 client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
1109 RunLoopUntilIdle();
1110
1111 ASSERT_EQ(connect_receiver.connected_count(), 0u);
1112 EXPECT_TRUE(l2cap()->TriggerInboundL2capChannel(
1113 connection()->link().handle(), kPsm, 0x40, 0x41, kTxMtu));
1114
1115 RunLoopUntilIdle();
1116 ASSERT_EQ(connect_receiver.connected_count(), 1u);
1117 ASSERT_TRUE(connect_receiver.channel().has_value());
1118 ASSERT_TRUE(connect_receiver.channel().value().has_ext_direction());
1119 // Taking value() is safe because of the has_ext_direction() check.
1120 fidlbredr::AudioDirectionExtPtr client =
1121 connect_receiver.bind_ext_direction().value();
1122
1123 size_t priority_cb_count = 0;
1124 client->SetPriority(
1125 fidlbredr::A2dpDirectionPriority::SINK,
1126 [&](fidlbredr::AudioDirectionExt_SetPriority_Result result) {
1127 EXPECT_TRUE(result.is_response());
1128 priority_cb_count++;
1129 });
1130
1131 RunLoopUntilIdle();
1132 EXPECT_EQ(priority_cb_count, 1u);
1133 ASSERT_TRUE(fake_channel.is_alive());
1134 EXPECT_EQ(fake_channel->requested_acl_priority(), AclPriority::kSink);
1135 }
1136
1137 // Verifies that a socket channel relay is correctly set up such that bytes
1138 // written to the socket are sent to the channel.
TEST_F(ProfileServerTestConnectedPeer,ConnectReturnsValidSocket)1139 TEST_F(ProfileServerTestConnectedPeer, ConnectReturnsValidSocket) {
1140 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1141 std::make_unique<bt::gap::FakePairingDelegate>(
1142 bt::sm::IOCapability::kDisplayYesNo);
1143 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1144 // Approve pairing requests.
1145 pairing_delegate->SetConfirmPairingCallback(
1146 [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
1147 pairing_delegate->SetCompletePairingCallback(
1148 [&](bt::PeerId, bt::sm::Result<> status) {
1149 EXPECT_EQ(fit::ok(), status);
1150 });
1151
1152 bt::l2cap::ChannelParameters expected_params;
1153 l2cap()->ExpectOutboundL2capChannel(
1154 connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
1155
1156 std::optional<FakeChannel::WeakPtr> fake_chan;
1157 l2cap()->set_channel_callback(
1158 [&fake_chan](FakeChannel::WeakPtr chan) { fake_chan = std::move(chan); });
1159
1160 // Expect a non-empty channel result.
1161 std::optional<fidlbredr::Channel> channel;
1162 auto result_cb = [&channel](fidlbredr::Profile_Connect_Result result) {
1163 EXPECT_TRUE(result.is_response());
1164 channel = std::move(result.response().channel);
1165 };
1166
1167 fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
1168
1169 // Set L2CAP channel parameters
1170 fidlbredr::L2capParameters l2cap_params;
1171 fidlbredr::ConnectParameters conn_params;
1172 l2cap_params.set_psm(kPsm);
1173 l2cap_params.set_parameters(fbt::ChannelParameters());
1174 conn_params.set_l2cap(std::move(l2cap_params));
1175
1176 // Initiates pairing
1177 client()->Connect(peer_id, std::move(conn_params), std::move(result_cb));
1178 RunLoopUntilIdle();
1179
1180 ASSERT_TRUE(channel.has_value());
1181 ASSERT_TRUE(channel->has_socket());
1182 auto& socket = channel->socket();
1183
1184 ASSERT_TRUE(fake_chan.has_value());
1185 FakeChannel::WeakPtr fake_chan_ptr = fake_chan.value();
1186 size_t send_count = 0;
1187 fake_chan_ptr->SetSendCallback([&send_count](auto buffer) { send_count++; },
1188 pw_dispatcher());
1189
1190 const char write_data[2] = "a";
1191 size_t bytes_written = 0;
1192 auto status =
1193 socket.write(0, write_data, sizeof(write_data) - 1, &bytes_written);
1194 EXPECT_EQ(ZX_OK, status);
1195 EXPECT_EQ(1u, bytes_written);
1196 RunLoopUntilIdle();
1197 EXPECT_EQ(1u, send_count);
1198 }
1199
1200 // Verifies that a BrEdrConnectionServer is correctly set up such that bytes
1201 // written to the Connection are sent to the channel.
TEST_F(ProfileServerTestConnectedPeer,ConnectReturnsValidConnection)1202 TEST_F(ProfileServerTestConnectedPeer, ConnectReturnsValidConnection) {
1203 server()->set_use_sockets(false);
1204
1205 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1206 std::make_unique<bt::gap::FakePairingDelegate>(
1207 bt::sm::IOCapability::kDisplayYesNo);
1208 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1209 // Approve pairing requests.
1210 pairing_delegate->SetConfirmPairingCallback(
1211 [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
1212 pairing_delegate->SetCompletePairingCallback(
1213 [&](bt::PeerId, bt::sm::Result<> status) {
1214 EXPECT_EQ(fit::ok(), status);
1215 });
1216
1217 bt::l2cap::ChannelParameters expected_params;
1218 l2cap()->ExpectOutboundL2capChannel(
1219 connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
1220
1221 std::optional<FakeChannel::WeakPtr> fake_chan;
1222 l2cap()->set_channel_callback(
1223 [&fake_chan](FakeChannel::WeakPtr chan) { fake_chan = std::move(chan); });
1224
1225 // Expect a non-empty channel result.
1226 std::optional<fidlbredr::Channel> channel;
1227 auto result_cb = [&channel](fidlbredr::Profile_Connect_Result result) {
1228 EXPECT_TRUE(result.is_response());
1229 channel = std::move(result.response().channel);
1230 };
1231
1232 fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
1233
1234 // Set L2CAP channel parameters
1235 fidlbredr::L2capParameters l2cap_params;
1236 fidlbredr::ConnectParameters conn_params;
1237 l2cap_params.set_psm(kPsm);
1238 l2cap_params.set_parameters(fbt::ChannelParameters());
1239 conn_params.set_l2cap(std::move(l2cap_params));
1240
1241 // Initiates pairing
1242 client()->Connect(peer_id, std::move(conn_params), std::move(result_cb));
1243 RunLoopUntilIdle();
1244
1245 ASSERT_TRUE(channel.has_value());
1246 ASSERT_TRUE(channel->has_connection());
1247
1248 ASSERT_TRUE(fake_chan.has_value());
1249 ASSERT_TRUE(fake_chan.value()->activated());
1250 FakeChannel::WeakPtr fake_chan_ptr = fake_chan.value();
1251 int send_count = 0;
1252 fake_chan_ptr->SetSendCallback([&send_count](auto buffer) { send_count++; },
1253 pw_dispatcher());
1254
1255 fidl::InterfacePtr<fbt::Channel> conn = channel->mutable_connection()->Bind();
1256 int send_cb_count = 0;
1257 std::vector<fbt::Packet> packets{fbt::Packet{std::vector<uint8_t>{0x02}}};
1258 conn->Send(std::move(packets), [&](fbt::Channel_Send_Result result) {
1259 EXPECT_TRUE(result.is_response());
1260 send_cb_count++;
1261 });
1262 RunLoopUntilIdle();
1263 EXPECT_EQ(1, send_count);
1264 EXPECT_EQ(1, send_cb_count);
1265 }
1266
TEST_F(ProfileServerTestConnectedPeer,ConnectFailsDueToChannelActivationFailure)1267 TEST_F(ProfileServerTestConnectedPeer,
1268 ConnectFailsDueToChannelActivationFailure) {
1269 server()->set_use_sockets(false);
1270
1271 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1272 std::make_unique<bt::gap::FakePairingDelegate>(
1273 bt::sm::IOCapability::kDisplayYesNo);
1274 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1275 // Approve pairing requests.
1276 pairing_delegate->SetConfirmPairingCallback(
1277 [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
1278 pairing_delegate->SetCompletePairingCallback(
1279 [&](bt::PeerId, bt::sm::Result<> status) {
1280 EXPECT_EQ(fit::ok(), status);
1281 });
1282
1283 bt::l2cap::ChannelParameters expected_params;
1284 l2cap()->ExpectOutboundL2capChannel(
1285 connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
1286
1287 std::optional<FakeChannel::WeakPtr> fake_chan;
1288 l2cap()->set_channel_callback([&fake_chan](FakeChannel::WeakPtr chan) {
1289 chan->set_activate_fails(true);
1290 fake_chan = std::move(chan);
1291 });
1292
1293 int connect_cb_count = 0;
1294 auto connect_cb = [&](fidlbredr::Profile_Connect_Result result) {
1295 EXPECT_TRUE(result.is_err());
1296 connect_cb_count++;
1297 };
1298
1299 fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
1300
1301 fidlbredr::L2capParameters l2cap_params;
1302 fidlbredr::ConnectParameters conn_params;
1303 l2cap_params.set_psm(kPsm);
1304 l2cap_params.set_parameters(fbt::ChannelParameters());
1305 conn_params.set_l2cap(std::move(l2cap_params));
1306
1307 client()->Connect(peer_id, std::move(conn_params), std::move(connect_cb));
1308 RunLoopUntilIdle();
1309 EXPECT_EQ(connect_cb_count, 1);
1310 EXPECT_FALSE(fake_chan.value()->activated());
1311 }
1312
1313 // Verifies that a socket channel relay is correctly set up such that bytes
1314 // written to the socket are sent to the channel.
TEST_F(ProfileServerTestConnectedPeer,ConnectionReceiverReturnsValidSocket)1315 TEST_F(ProfileServerTestConnectedPeer, ConnectionReceiverReturnsValidSocket) {
1316 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1317 std::make_unique<bt::gap::FakePairingDelegate>(
1318 bt::sm::IOCapability::kDisplayYesNo);
1319 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1320
1321 fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
1322 FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
1323 dispatcher());
1324
1325 std::optional<FakeChannel::WeakPtr> fake_chan;
1326 l2cap()->set_channel_callback(
1327 [&fake_chan](FakeChannel::WeakPtr chan) { fake_chan = std::move(chan); });
1328
1329 std::vector<fidlbredr::ServiceDefinition> services;
1330 services.emplace_back(MakeFIDLServiceDefinition());
1331
1332 fidlbredr::ProfileAdvertiseRequest adv_request;
1333 adv_request.set_services(std::move(services));
1334 adv_request.set_receiver(std::move(connect_receiver_handle));
1335 client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
1336 RunLoopUntilIdle();
1337
1338 ASSERT_EQ(connect_receiver.connected_count(), 0u);
1339 EXPECT_TRUE(l2cap()->TriggerInboundL2capChannel(
1340 connection()->link().handle(), kPsm, 0x40, 0x41));
1341 RunLoopUntilIdle();
1342
1343 ASSERT_EQ(connect_receiver.connected_count(), 1u);
1344 ASSERT_EQ(connect_receiver.peer_id().value().value,
1345 peer()->identifier().value());
1346 ASSERT_TRUE(connect_receiver.channel().has_value());
1347 ASSERT_TRUE(connect_receiver.channel().value().has_socket());
1348 // Taking channel is safe because of the previous checks.
1349 fidlbredr::Channel channel = connect_receiver.take_channel();
1350
1351 ASSERT_TRUE(fake_chan.has_value());
1352 FakeChannel::WeakPtr fake_chan_ptr = fake_chan.value();
1353 size_t send_count = 0;
1354 fake_chan_ptr->SetSendCallback([&send_count](auto buffer) { send_count++; },
1355 pw_dispatcher());
1356
1357 const char write_data[2] = "a";
1358 size_t bytes_written = 0;
1359 int status = channel.socket().write(
1360 0, write_data, sizeof(write_data) - 1, &bytes_written);
1361 EXPECT_EQ(ZX_OK, status);
1362 EXPECT_EQ(1u, bytes_written);
1363 RunLoopUntilIdle();
1364 EXPECT_EQ(1u, send_count);
1365 }
1366
1367 // Verifies that a BrEdrConnectionServer is correctly set up such that bytes
1368 // written to the Connection are sent to the channel.
TEST_F(ProfileServerTestConnectedPeer,ConnectionReceiverReturnsValidConnection)1369 TEST_F(ProfileServerTestConnectedPeer,
1370 ConnectionReceiverReturnsValidConnection) {
1371 server()->set_use_sockets(false);
1372
1373 std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1374 std::make_unique<bt::gap::FakePairingDelegate>(
1375 bt::sm::IOCapability::kDisplayYesNo);
1376 adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1377
1378 fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
1379 FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
1380 dispatcher());
1381
1382 std::optional<FakeChannel::WeakPtr> fake_chan;
1383 l2cap()->set_channel_callback(
1384 [&fake_chan](FakeChannel::WeakPtr chan) { fake_chan = std::move(chan); });
1385
1386 std::vector<fidlbredr::ServiceDefinition> services;
1387 services.emplace_back(MakeFIDLServiceDefinition());
1388
1389 fidlbredr::ProfileAdvertiseRequest adv_request;
1390 adv_request.set_services(std::move(services));
1391 adv_request.set_receiver(std::move(connect_receiver_handle));
1392 client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
1393 RunLoopUntilIdle();
1394
1395 ASSERT_EQ(connect_receiver.connected_count(), 0u);
1396 EXPECT_TRUE(l2cap()->TriggerInboundL2capChannel(
1397 connection()->link().handle(), kPsm, 0x40, 0x41));
1398 RunLoopUntilIdle();
1399
1400 ASSERT_EQ(connect_receiver.connected_count(), 1u);
1401 ASSERT_EQ(connect_receiver.peer_id().value().value,
1402 peer()->identifier().value());
1403 ASSERT_TRUE(connect_receiver.channel().has_value());
1404 ASSERT_TRUE(connect_receiver.channel().value().has_connection());
1405 // Taking channel is safe because of the previous checks.
1406 fidlbredr::Channel channel = connect_receiver.take_channel();
1407
1408 ASSERT_TRUE(fake_chan.has_value());
1409 FakeChannel::WeakPtr fake_chan_ptr = fake_chan.value();
1410 int send_count = 0;
1411 fake_chan_ptr->SetSendCallback([&send_count](auto buffer) { send_count++; },
1412 pw_dispatcher());
1413
1414 fidl::InterfacePtr<fbt::Channel> conn = channel.mutable_connection()->Bind();
1415 int send_cb_count = 0;
1416 std::vector<fbt::Packet> packets{fbt::Packet{std::vector<uint8_t>{0x02}}};
1417 conn->Send(std::move(packets), [&](fbt::Channel_Send_Result result) {
1418 EXPECT_TRUE(result.is_response());
1419 send_cb_count++;
1420 });
1421 RunLoopUntilIdle();
1422 EXPECT_EQ(1, send_count);
1423 EXPECT_EQ(1, send_cb_count);
1424 }
1425
TEST_F(ProfileServerTest,ConnectScoWithInvalidParameters)1426 TEST_F(ProfileServerTest, ConnectScoWithInvalidParameters) {
1427 std::vector<fidlbredr::ScoConnectionParameters> bad_sco_params;
1428 bad_sco_params.emplace_back();
1429 fidlbredr::ProfileConnectScoRequest request;
1430 request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1431 request.set_initiator(true);
1432 request.set_params(std::move(bad_sco_params));
1433 fidlbredr::ScoConnectionHandle connection_handle;
1434 request.set_connection(connection_handle.NewRequest());
1435
1436 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1437 std::optional<zx_status_t> sco_connection_status;
1438 sco_connection.set_error_handler(
1439 [&](zx_status_t status) { sco_connection_status = status; });
1440 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1441 connection_complete;
1442 sco_connection.events().OnConnectionComplete =
1443 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1444 connection_complete = std::move(request);
1445 };
1446
1447 client()->ConnectSco(std::move(request));
1448 RunLoopUntilIdle();
1449 ASSERT_TRUE(connection_complete);
1450 ASSERT_TRUE(connection_complete->is_error());
1451 EXPECT_EQ(connection_complete->error(),
1452 fidlbredr::ScoErrorCode::INVALID_ARGUMENTS);
1453 EXPECT_FALSE(sco_connection.is_bound());
1454 }
1455
TEST_F(ProfileServerTest,ConnectScoWithMissingPeerId)1456 TEST_F(ProfileServerTest, ConnectScoWithMissingPeerId) {
1457 fidlbredr::ScoConnectionParameters sco_params =
1458 CreateScoConnectionParameters();
1459 EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1460 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1461 sco_params_list.emplace_back(std::move(sco_params));
1462 fidlbredr::ProfileConnectScoRequest request;
1463 request.set_initiator(true);
1464 request.set_params(std::move(sco_params_list));
1465 fidlbredr::ScoConnectionHandle connection_handle;
1466 request.set_connection(connection_handle.NewRequest());
1467
1468 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1469 std::optional<zx_status_t> sco_connection_status;
1470 sco_connection.set_error_handler(
1471 [&](zx_status_t status) { sco_connection_status = status; });
1472 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1473 connection_complete;
1474 sco_connection.events().OnConnectionComplete =
1475 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1476 connection_complete = std::move(request);
1477 };
1478
1479 client()->ConnectSco(std::move(request));
1480 RunLoopUntilIdle();
1481 ASSERT_TRUE(connection_complete);
1482 ASSERT_TRUE(connection_complete->is_error());
1483 EXPECT_EQ(connection_complete->error(),
1484 fidlbredr::ScoErrorCode::INVALID_ARGUMENTS);
1485 EXPECT_FALSE(sco_connection.is_bound());
1486 }
1487
TEST_F(ProfileServerTest,ConnectScoWithMissingConnectionDoesNotCrash)1488 TEST_F(ProfileServerTest, ConnectScoWithMissingConnectionDoesNotCrash) {
1489 fidlbredr::ScoConnectionParameters sco_params =
1490 CreateScoConnectionParameters();
1491 EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1492 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1493 sco_params_list.emplace_back(std::move(sco_params));
1494 fidlbredr::ProfileConnectScoRequest request;
1495 request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1496 request.set_initiator(true);
1497 request.set_params(std::move(sco_params_list));
1498 client()->ConnectSco(std::move(request));
1499 RunLoopUntilIdle();
1500 }
1501
TEST_F(ProfileServerTest,ConnectScoWithEmptyParameters)1502 TEST_F(ProfileServerTest, ConnectScoWithEmptyParameters) {
1503 fidlbredr::ScoConnectionHandle connection_handle;
1504 fidlbredr::ProfileConnectScoRequest request;
1505 request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1506 request.set_initiator(true);
1507 request.set_params({});
1508 request.set_connection(connection_handle.NewRequest());
1509
1510 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1511 std::optional<zx_status_t> sco_connection_status;
1512 sco_connection.set_error_handler(
1513 [&](zx_status_t status) { sco_connection_status = status; });
1514 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1515 connection_complete;
1516 sco_connection.events().OnConnectionComplete =
1517 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1518 connection_complete = std::move(request);
1519 };
1520
1521 client()->ConnectSco(std::move(request));
1522 RunLoopUntilIdle();
1523 ASSERT_TRUE(connection_complete);
1524 ASSERT_TRUE(connection_complete->is_error());
1525 EXPECT_EQ(connection_complete->error(),
1526 fidlbredr::ScoErrorCode::INVALID_ARGUMENTS);
1527 EXPECT_FALSE(sco_connection.is_bound());
1528 ASSERT_TRUE(sco_connection_status);
1529 EXPECT_EQ(sco_connection_status.value(), ZX_ERR_PEER_CLOSED);
1530 }
1531
TEST_F(ProfileServerTest,ConnectScoInitiatorWithTooManyParameters)1532 TEST_F(ProfileServerTest, ConnectScoInitiatorWithTooManyParameters) {
1533 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1534 sco_params_list.emplace_back(CreateScoConnectionParameters());
1535 sco_params_list.emplace_back(CreateScoConnectionParameters());
1536
1537 fidlbredr::ScoConnectionHandle connection_handle;
1538 fidlbredr::ProfileConnectScoRequest request;
1539 request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1540 request.set_initiator(true);
1541 request.set_params(std::move(sco_params_list));
1542 request.set_connection(connection_handle.NewRequest());
1543
1544 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1545 std::optional<zx_status_t> sco_connection_status;
1546 sco_connection.set_error_handler(
1547 [&](zx_status_t status) { sco_connection_status = status; });
1548 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1549 connection_complete;
1550 sco_connection.events().OnConnectionComplete =
1551 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1552 connection_complete = std::move(request);
1553 };
1554
1555 client()->ConnectSco(std::move(request));
1556 RunLoopUntilIdle();
1557 ASSERT_TRUE(connection_complete);
1558 ASSERT_TRUE(connection_complete->is_error());
1559 EXPECT_EQ(connection_complete->error(),
1560 fidlbredr::ScoErrorCode::INVALID_ARGUMENTS);
1561 EXPECT_FALSE(sco_connection.is_bound());
1562 ASSERT_TRUE(sco_connection_status);
1563 EXPECT_EQ(sco_connection_status.value(), ZX_ERR_PEER_CLOSED);
1564 }
1565
TEST_F(ProfileServerTest,ConnectScoWithUnconnectedPeerReturnsError)1566 TEST_F(ProfileServerTest, ConnectScoWithUnconnectedPeerReturnsError) {
1567 fidlbredr::ScoConnectionParameters sco_params =
1568 CreateScoConnectionParameters();
1569 EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1570 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1571 sco_params_list.emplace_back(std::move(sco_params));
1572
1573 fidlbredr::ScoConnectionHandle connection_handle;
1574 fidlbredr::ProfileConnectScoRequest request;
1575 request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1576 request.set_initiator(true);
1577 request.set_params(std::move(sco_params_list));
1578 request.set_connection(connection_handle.NewRequest());
1579
1580 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1581 std::optional<zx_status_t> sco_connection_status;
1582 sco_connection.set_error_handler(
1583 [&](zx_status_t status) { sco_connection_status = status; });
1584 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1585 connection_complete;
1586 sco_connection.events().OnConnectionComplete =
1587 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1588 connection_complete = std::move(request);
1589 };
1590
1591 client()->ConnectSco(std::move(request));
1592 RunLoopUntilIdle();
1593 ASSERT_TRUE(connection_complete);
1594 ASSERT_TRUE(connection_complete->is_error());
1595 EXPECT_EQ(connection_complete->error(), fidlbredr::ScoErrorCode::FAILURE);
1596 EXPECT_FALSE(sco_connection.is_bound());
1597 ASSERT_TRUE(sco_connection_status);
1598 EXPECT_EQ(sco_connection_status.value(), ZX_ERR_PEER_CLOSED);
1599 }
1600
TEST_F(ProfileServerTestConnectedPeer,ConnectScoInitiatorSuccess)1601 TEST_F(ProfileServerTestConnectedPeer, ConnectScoInitiatorSuccess) {
1602 fidlbredr::ScoConnectionParameters sco_params =
1603 CreateScoConnectionParameters(fidlbredr::HfpParameterSet::T1);
1604 EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1605 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1606 sco_params_list.emplace_back(std::move(sco_params));
1607
1608 fidlbredr::ScoConnectionHandle connection_handle;
1609 fidlbredr::ProfileConnectScoRequest request;
1610 request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1611 request.set_initiator(true);
1612 request.set_params(std::move(sco_params_list));
1613 request.set_connection(connection_handle.NewRequest());
1614
1615 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1616 std::optional<zx_status_t> sco_connection_status;
1617 sco_connection.set_error_handler(
1618 [&](zx_status_t status) { sco_connection_status = status; });
1619 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1620 connection_complete;
1621 sco_connection.events().OnConnectionComplete =
1622 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1623 connection_complete = std::move(request);
1624 };
1625
1626 client()->ConnectSco(std::move(request));
1627 RunLoopUntilIdle();
1628 ASSERT_TRUE(connection_complete);
1629 ASSERT_TRUE(connection_complete->is_connected_params());
1630 EXPECT_TRUE(sco_connection.is_bound());
1631 ASSERT_TRUE(connection_complete->connected_params().has_parameter_set());
1632 EXPECT_EQ(connection_complete->connected_params().parameter_set(),
1633 fidlbredr::HfpParameterSet::T1);
1634 ASSERT_TRUE(connection_complete->connected_params().has_max_tx_data_size());
1635 EXPECT_EQ(connection_complete->connected_params().max_tx_data_size(),
1636 kSynchronousDataPacketLength);
1637 }
1638
TEST_F(ProfileServerTestConnectedPeer,ConnectScoResponderSuccess)1639 TEST_F(ProfileServerTestConnectedPeer, ConnectScoResponderSuccess) {
1640 // Use 2 parameter sets to test that the profile server returns the second set
1641 // when a SCO connection request is received (T2 is ESCO only and D0 is SCO
1642 // only, so D0 will be used to accept the connection).
1643 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1644 sco_params_list.emplace_back(
1645 CreateScoConnectionParameters(fidlbredr::HfpParameterSet::T2));
1646 sco_params_list.emplace_back(
1647 CreateScoConnectionParameters(fidlbredr::HfpParameterSet::D0));
1648
1649 fidlbredr::ScoConnectionHandle connection_handle;
1650 fidlbredr::ProfileConnectScoRequest request;
1651 request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1652 request.set_initiator(false);
1653 request.set_params(std::move(sco_params_list));
1654 request.set_connection(connection_handle.NewRequest());
1655
1656 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1657 std::optional<zx_status_t> sco_connection_status;
1658 sco_connection.set_error_handler(
1659 [&](zx_status_t status) { sco_connection_status = status; });
1660 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1661 connection_complete;
1662 sco_connection.events().OnConnectionComplete =
1663 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1664 connection_complete = std::move(request);
1665 };
1666
1667 client()->ConnectSco(std::move(request));
1668 RunLoopUntilIdle();
1669 // Receive a SCO connection request. The D0 parameters will be used to accept
1670 // the request.
1671 test_device()->SendConnectionRequest(peer()->address(),
1672 pw::bluetooth::emboss::LinkType::SCO);
1673 RunLoopUntilIdle();
1674 ASSERT_TRUE(connection_complete);
1675 ASSERT_TRUE(connection_complete->is_connected_params());
1676 EXPECT_TRUE(sco_connection.is_bound());
1677 ASSERT_TRUE(connection_complete->connected_params().has_parameter_set());
1678 EXPECT_EQ(connection_complete->connected_params().parameter_set(),
1679 fidlbredr::HfpParameterSet::D0);
1680 }
1681
TEST_F(ProfileServerTestConnectedPeer,ScoConnectionReadBeforeConnectionComplete)1682 TEST_F(ProfileServerTestConnectedPeer,
1683 ScoConnectionReadBeforeConnectionComplete) {
1684 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1685 sco_params_list.emplace_back(
1686 CreateScoConnectionParameters(fidlbredr::HfpParameterSet::D0));
1687
1688 fidlbredr::ScoConnectionHandle connection_handle;
1689 fidlbredr::ProfileConnectScoRequest request;
1690 request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1691 request.set_initiator(false);
1692 request.set_params(std::move(sco_params_list));
1693 request.set_connection(connection_handle.NewRequest());
1694
1695 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1696 std::optional<zx_status_t> sco_connection_status;
1697 sco_connection.set_error_handler(
1698 [&](zx_status_t status) { sco_connection_status = status; });
1699 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1700 connection_complete;
1701 sco_connection.events().OnConnectionComplete =
1702 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1703 connection_complete = std::move(request);
1704 };
1705
1706 client()->ConnectSco(std::move(request));
1707 RunLoopUntilIdle();
1708 ASSERT_FALSE(connection_complete);
1709
1710 sco_connection->Read(
1711 [](fidlbredr::ScoConnection_Read_Result result) { FAIL(); });
1712 RunLoopUntilIdle();
1713 ASSERT_TRUE(sco_connection_status);
1714 EXPECT_EQ(sco_connection_status.value(), ZX_ERR_IO_REFUSED);
1715 }
1716
TEST_F(ProfileServerTestConnectedPeer,ScoConnectionWriteBeforeConnectionComplete)1717 TEST_F(ProfileServerTestConnectedPeer,
1718 ScoConnectionWriteBeforeConnectionComplete) {
1719 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1720 sco_params_list.emplace_back(
1721 CreateScoConnectionParameters(fidlbredr::HfpParameterSet::D0));
1722
1723 fidlbredr::ScoConnectionHandle connection_handle;
1724 fidlbredr::ProfileConnectScoRequest request;
1725 request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1726 request.set_initiator(false);
1727 request.set_params(std::move(sco_params_list));
1728 request.set_connection(connection_handle.NewRequest());
1729
1730 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1731 std::optional<zx_status_t> sco_connection_status;
1732 sco_connection.set_error_handler(
1733 [&](zx_status_t status) { sco_connection_status = status; });
1734 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1735 connection_complete;
1736 sco_connection.events().OnConnectionComplete =
1737 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1738 connection_complete = std::move(request);
1739 };
1740
1741 client()->ConnectSco(std::move(request));
1742 RunLoopUntilIdle();
1743 ASSERT_FALSE(connection_complete);
1744
1745 ::fuchsia::bluetooth::bredr::ScoConnectionWriteRequest write;
1746 write.set_data({0x00});
1747 sco_connection->Write(
1748 std::move(write),
1749 [](::fuchsia::bluetooth::bredr::ScoConnection_Write_Result result) {
1750 FAIL();
1751 });
1752 RunLoopUntilIdle();
1753 ASSERT_TRUE(sco_connection_status);
1754 EXPECT_EQ(sco_connection_status.value(), ZX_ERR_IO_REFUSED);
1755 }
1756
TEST_F(ProfileServerTestConnectedPeer,ConnectScoResponderUnconnectedPeerReturnsError)1757 TEST_F(ProfileServerTestConnectedPeer,
1758 ConnectScoResponderUnconnectedPeerReturnsError) {
1759 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1760 sco_params_list.emplace_back(CreateScoConnectionParameters());
1761
1762 fidlbredr::ScoConnectionHandle connection_handle;
1763 fidlbredr::ProfileConnectScoRequest request;
1764 request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1765 request.set_initiator(false);
1766 request.set_params(std::move(sco_params_list));
1767 request.set_connection(connection_handle.NewRequest());
1768
1769 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1770 std::optional<zx_status_t> sco_connection_status;
1771 sco_connection.set_error_handler(
1772 [&](zx_status_t status) { sco_connection_status = status; });
1773 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1774 connection_complete;
1775 sco_connection.events().OnConnectionComplete =
1776 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1777 connection_complete = std::move(request);
1778 };
1779
1780 client()->ConnectSco(std::move(request));
1781 RunLoopUntilIdle();
1782 ASSERT_TRUE(connection_complete);
1783 ASSERT_TRUE(connection_complete->is_error());
1784 EXPECT_EQ(connection_complete->error(), fidlbredr::ScoErrorCode::FAILURE);
1785 EXPECT_FALSE(sco_connection.is_bound());
1786 ASSERT_TRUE(sco_connection_status);
1787 EXPECT_EQ(sco_connection_status.value(), ZX_ERR_PEER_CLOSED);
1788 }
1789
TEST_F(ProfileServerTestConnectedPeer,ConnectScoInitiatorAndCloseProtocol)1790 TEST_F(ProfileServerTestConnectedPeer, ConnectScoInitiatorAndCloseProtocol) {
1791 fidlbredr::ScoConnectionParameters sco_params =
1792 CreateScoConnectionParameters();
1793 EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1794 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1795 sco_params_list.emplace_back(std::move(sco_params));
1796
1797 fidlbredr::ProfileConnectScoRequest request;
1798 request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1799 request.set_initiator(true);
1800 request.set_params(std::move(sco_params_list));
1801 fidlbredr::ScoConnectionHandle connection_handle;
1802 request.set_connection(connection_handle.NewRequest());
1803
1804 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1805 std::optional<zx_status_t> sco_connection_status;
1806 sco_connection.set_error_handler(
1807 [&](zx_status_t status) { sco_connection_status = status; });
1808 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1809 connection_complete;
1810 sco_connection.events().OnConnectionComplete =
1811 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1812 connection_complete = std::move(request);
1813 };
1814
1815 client()->ConnectSco(std::move(request));
1816 sco_connection.Unbind();
1817 RunLoopUntilIdle();
1818 ASSERT_FALSE(connection_complete);
1819 }
1820
1821 // Verifies that the profile server gracefully ignores connection results after
1822 // the receiver has closed.
TEST_F(ProfileServerTestConnectedPeer,ConnectScoInitiatorAndCloseReceiverBeforeCompleteEvent)1823 TEST_F(ProfileServerTestConnectedPeer,
1824 ConnectScoInitiatorAndCloseReceiverBeforeCompleteEvent) {
1825 fidlbredr::ScoConnectionParameters sco_params =
1826 CreateScoConnectionParameters();
1827 EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1828 std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1829 sco_params_list.emplace_back(std::move(sco_params));
1830
1831 test_device()->SetDefaultCommandStatus(
1832 bt::hci_spec::kEnhancedSetupSynchronousConnection,
1833 pw::bluetooth::emboss::StatusCode::SUCCESS);
1834 fidlbredr::ProfileConnectScoRequest request;
1835 request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1836 request.set_initiator(true);
1837 request.set_params(std::move(sco_params_list));
1838 fidlbredr::ScoConnectionHandle connection_handle;
1839 request.set_connection(connection_handle.NewRequest());
1840
1841 fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1842 std::optional<zx_status_t> sco_connection_status;
1843 sco_connection.set_error_handler(
1844 [&](zx_status_t status) { sco_connection_status = status; });
1845 std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1846 connection_complete;
1847 sco_connection.events().OnConnectionComplete =
1848 [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1849 connection_complete = std::move(request);
1850 };
1851
1852 client()->ConnectSco(std::move(request));
1853 sco_connection.Unbind();
1854 RunLoopUntilIdle();
1855 ASSERT_FALSE(connection_complete);
1856 test_device()->SendCommandChannelPacket(
1857 bt::testing::SynchronousConnectionCompletePacket(
1858 0x00,
1859 peer()->address(),
1860 bt::hci_spec::LinkType::kSCO,
1861 pw::bluetooth::emboss::StatusCode::CONNECTION_TIMEOUT));
1862 RunLoopUntilIdle();
1863 ASSERT_FALSE(connection_complete);
1864 }
1865
1866 class ProfileServerTestFakeAdapter
1867 : public bt::fidl::testing::FakeAdapterTestFixture {
1868 public:
1869 ProfileServerTestFakeAdapter() = default;
1870 ~ProfileServerTestFakeAdapter() override = default;
1871
SetUp()1872 void SetUp() override {
1873 FakeAdapterTestFixture::SetUp();
1874
1875 fidlbredr::ProfileHandle profile_handle;
1876 client_.Bind(std::move(profile_handle));
1877 server_ = std::make_unique<ProfileServer>(adapter()->AsWeakPtr(),
1878 client_.NewRequest(dispatcher()));
1879 }
1880
TearDown()1881 void TearDown() override { FakeAdapterTestFixture::TearDown(); }
1882
client()1883 fidlbredr::ProfilePtr& client() { return client_; }
1884
1885 private:
1886 std::unique_ptr<ProfileServer> server_;
1887 fidlbredr::ProfilePtr client_;
1888 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ProfileServerTestFakeAdapter);
1889 };
1890
TEST_F(ProfileServerTestFakeAdapter,ConnectChannelParametersContainsFlushTimeout)1891 TEST_F(ProfileServerTestFakeAdapter,
1892 ConnectChannelParametersContainsFlushTimeout) {
1893 const bt::PeerId kPeerId;
1894 const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
1895 const pw::chrono::SystemClock::duration kFlushTimeout(
1896 std::chrono::milliseconds(100));
1897
1898 FakeChannel::WeakPtr last_channel;
1899 adapter()->fake_bredr()->set_l2cap_channel_callback(
1900 [&](FakeChannel::WeakPtr chan) { last_channel = std::move(chan); });
1901
1902 // Set L2CAP channel parameters
1903 fbt::ChannelParameters chan_params;
1904 fidlbredr::L2capParameters l2cap_params;
1905 fidlbredr::ConnectParameters conn_params;
1906 chan_params.set_flush_timeout(kFlushTimeout.count());
1907 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
1908 l2cap_params.set_parameters(std::move(chan_params));
1909 conn_params.set_l2cap(std::move(l2cap_params));
1910
1911 std::optional<fidlbredr::Channel> response_channel;
1912 client()->Connect(kFidlPeerId,
1913 std::move(conn_params),
1914 [&](fidlbredr::Profile_Connect_Result result) {
1915 ASSERT_TRUE(result.is_response());
1916 response_channel = std::move(result.response().channel);
1917 });
1918 RunLoopUntilIdle();
1919 ASSERT_TRUE(last_channel.is_alive());
1920 EXPECT_EQ(last_channel->info().flush_timeout, std::optional(kFlushTimeout));
1921 ASSERT_TRUE(response_channel.has_value());
1922 ASSERT_TRUE(response_channel->has_flush_timeout());
1923 ASSERT_EQ(response_channel->flush_timeout(), kFlushTimeout.count());
1924 }
1925
TEST_F(ProfileServerTestFakeAdapter,AdvertiseChannelParametersContainsFlushTimeout)1926 TEST_F(ProfileServerTestFakeAdapter,
1927 AdvertiseChannelParametersContainsFlushTimeout) {
1928 const pw::chrono::SystemClock::duration kFlushTimeout(
1929 std::chrono::milliseconds(100));
1930 const bt::hci_spec::ConnectionHandle kHandle(1);
1931
1932 std::vector<fidlbredr::ServiceDefinition> services;
1933 services.emplace_back(MakeFIDLServiceDefinition());
1934 fbt::ChannelParameters chan_params;
1935 chan_params.set_flush_timeout(kFlushTimeout.count());
1936
1937 fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
1938 FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
1939 dispatcher());
1940
1941 fidlbredr::ProfileAdvertiseRequest adv_request;
1942 adv_request.set_services(std::move(services));
1943 adv_request.set_parameters(std::move(chan_params));
1944 adv_request.set_receiver(std::move(connect_receiver_handle));
1945 client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
1946 RunLoopUntilIdle();
1947
1948 ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 1u);
1949 auto service_iter = adapter()->fake_bredr()->registered_services().begin();
1950 EXPECT_EQ(service_iter->second.channel_params.flush_timeout,
1951 std::optional(kFlushTimeout));
1952
1953 bt::l2cap::ChannelInfo chan_info =
1954 bt::l2cap::ChannelInfo::MakeBasicMode(bt::l2cap::kDefaultMTU,
1955 bt::l2cap::kDefaultMTU,
1956 bt::l2cap::kAVDTP,
1957 kFlushTimeout);
1958 auto channel =
1959 std::make_unique<FakeChannel>(bt::l2cap::kFirstDynamicChannelId,
1960 bt::l2cap::kFirstDynamicChannelId,
1961 kHandle,
1962 bt::LinkType::kACL,
1963 chan_info);
1964 service_iter->second.connect_callback(channel->GetWeakPtr(),
1965 MakeL2capProtocolListElement());
1966 RunLoopUntilIdle();
1967 ASSERT_TRUE(connect_receiver.channel().has_value());
1968 fidlbredr::Channel fidl_channel = connect_receiver.take_channel();
1969 ASSERT_TRUE(fidl_channel.has_flush_timeout());
1970 EXPECT_EQ(fidl_channel.flush_timeout(), kFlushTimeout.count());
1971
1972 channel->Close();
1973 RunLoopUntilIdle();
1974 }
1975
TEST_F(ProfileServerTestFakeAdapter,ClientClosesAdvertisement)1976 TEST_F(ProfileServerTestFakeAdapter, ClientClosesAdvertisement) {
1977 fidlbredr::ConnectionReceiverHandle receiver_handle;
1978 fidl::InterfaceRequest<fidlbredr::ConnectionReceiver> request =
1979 receiver_handle.NewRequest();
1980
1981 std::vector<fidlbredr::ServiceDefinition> services;
1982 services.emplace_back(MakeFIDLServiceDefinition());
1983
1984 size_t cb_count = 0;
1985 auto cb = [&](fidlbredr::Profile_Advertise_Result result) {
1986 cb_count++;
1987 EXPECT_TRUE(result.is_response());
1988 };
1989
1990 fidlbredr::ProfileAdvertiseRequest adv_request;
1991 adv_request.set_services(std::move(services));
1992 adv_request.set_receiver(std::move(receiver_handle));
1993 client()->Advertise(std::move(adv_request), std::move(cb));
1994 RunLoopUntilIdle();
1995 ASSERT_EQ(cb_count, 1u);
1996 ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 1u);
1997
1998 // Client closes Advertisement by dropping the `ConnectionReceiver`. This is
1999 // OK, and the profile server should handle this by unregistering the
2000 // advertisement.
2001 request = receiver_handle.NewRequest();
2002 RunLoopUntilIdle();
2003 ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 0u);
2004 }
2005
TEST_F(ProfileServerTestFakeAdapter,AdvertiseWithMissingFields)2006 TEST_F(ProfileServerTestFakeAdapter, AdvertiseWithMissingFields) {
2007 size_t cb_ok_count = 0;
2008 auto adv_ok_cb = [&](fidlbredr::Profile_Advertise_Result result) {
2009 cb_ok_count++;
2010 EXPECT_TRUE(result.is_response());
2011 };
2012 size_t cb_err_count = 0;
2013 auto adv_err_cb = [&](fidlbredr::Profile_Advertise_Result result) {
2014 cb_err_count++;
2015 ASSERT_TRUE(result.is_err());
2016 EXPECT_EQ(result.err(), fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
2017 };
2018
2019 fidlbredr::ProfileAdvertiseRequest adv_request_missing_receiver;
2020 std::vector<fidlbredr::ServiceDefinition> services1;
2021 services1.emplace_back(MakeFIDLServiceDefinition());
2022 adv_request_missing_receiver.set_services(std::move(services1));
2023 adv_request_missing_receiver.set_parameters(
2024 ::fuchsia::bluetooth::ChannelParameters());
2025 client()->Advertise(std::move(adv_request_missing_receiver), adv_err_cb);
2026 RunLoopUntilIdle();
2027 ASSERT_EQ(cb_err_count, 1u);
2028 ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 0u);
2029
2030 fidlbredr::ConnectionReceiverHandle connect_receiver_handle1;
2031 FakeConnectionReceiver connect_receiver1(
2032 connect_receiver_handle1.NewRequest(), dispatcher());
2033
2034 fidlbredr::ProfileAdvertiseRequest adv_request_missing_services;
2035 adv_request_missing_services.set_receiver(
2036 std::move(connect_receiver_handle1));
2037 adv_request_missing_services.set_parameters(
2038 ::fuchsia::bluetooth::ChannelParameters());
2039 client()->Advertise(std::move(adv_request_missing_services), adv_err_cb);
2040 RunLoopUntilIdle();
2041 ASSERT_EQ(cb_err_count, 2u);
2042 ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 0u);
2043
2044 // Missing parameters is allowed.
2045 fidlbredr::ProfileAdvertiseRequest adv_request_missing_parameters;
2046 std::vector<fidlbredr::ServiceDefinition> services2;
2047 services2.emplace_back(MakeFIDLServiceDefinition());
2048 adv_request_missing_parameters.set_services(std::move(services2));
2049 fidlbredr::ConnectionReceiverHandle connect_receiver_handle2;
2050 FakeConnectionReceiver connect_receiver2(
2051 connect_receiver_handle2.NewRequest(), dispatcher());
2052 adv_request_missing_parameters.set_receiver(
2053 std::move(connect_receiver_handle2));
2054 client()->Advertise(std::move(adv_request_missing_parameters), adv_ok_cb);
2055 RunLoopUntilIdle();
2056 ASSERT_EQ(cb_ok_count, 1u);
2057 ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 1u);
2058 }
2059
TEST_F(ProfileServerTestFakeAdapter,L2capParametersExtRequestParametersSucceeds)2060 TEST_F(ProfileServerTestFakeAdapter,
2061 L2capParametersExtRequestParametersSucceeds) {
2062 const bt::PeerId kPeerId;
2063 const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
2064 const zx::duration kFlushTimeout(zx::msec(100));
2065 const uint16_t kMaxRxSduSize(200);
2066
2067 FakeChannel::WeakPtr last_channel;
2068 adapter()->fake_bredr()->set_l2cap_channel_callback(
2069 [&](FakeChannel::WeakPtr chan) { last_channel = chan; });
2070
2071 // Set L2CAP channel parameters
2072 fbt::ChannelParameters chan_params;
2073 fidlbredr::L2capParameters l2cap_params;
2074 fidlbredr::ConnectParameters conn_params;
2075 chan_params.set_channel_mode(fbt::ChannelMode::BASIC);
2076 chan_params.set_max_rx_packet_size(kMaxRxSduSize);
2077 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2078 l2cap_params.set_parameters(std::move(chan_params));
2079 conn_params.set_l2cap(std::move(l2cap_params));
2080
2081 std::optional<fidlbredr::Channel> response_channel;
2082 client()->Connect(kFidlPeerId,
2083 std::move(conn_params),
2084 [&](fidlbredr::Profile_Connect_Result result) {
2085 ASSERT_TRUE(result.is_response());
2086 response_channel = std::move(result.response().channel);
2087 });
2088 RunLoopUntilIdle();
2089 ASSERT_TRUE(last_channel.is_alive());
2090 EXPECT_FALSE(last_channel->info().flush_timeout.has_value());
2091 ASSERT_TRUE(response_channel.has_value());
2092 ASSERT_FALSE(response_channel->has_flush_timeout());
2093 ASSERT_TRUE(response_channel->has_ext_l2cap());
2094
2095 fbt::ChannelParameters request_chan_params;
2096 request_chan_params.set_flush_timeout(kFlushTimeout.get());
2097
2098 std::optional<fbt::ChannelParameters> result_chan_params;
2099 fidlbredr::L2capParametersExtPtr l2cap_client =
2100 response_channel->mutable_ext_l2cap()->Bind();
2101 l2cap_client->RequestParameters(
2102 std::move(request_chan_params),
2103 [&](fidlbredr::L2capParametersExt_RequestParameters_Result new_params) {
2104 result_chan_params = new_params.response().ResultValue_();
2105 });
2106 RunLoopUntilIdle();
2107 ASSERT_TRUE(result_chan_params.has_value());
2108 ASSERT_TRUE(result_chan_params->has_channel_mode());
2109 ASSERT_TRUE(result_chan_params->has_max_rx_packet_size());
2110 // TODO(fxbug.dev/42152567): set current security requirements in returned
2111 // channel parameters
2112 ASSERT_FALSE(result_chan_params->has_security_requirements());
2113 ASSERT_TRUE(result_chan_params->has_flush_timeout());
2114 EXPECT_EQ(result_chan_params->channel_mode(), fbt::ChannelMode::BASIC);
2115 EXPECT_EQ(result_chan_params->max_rx_packet_size(), kMaxRxSduSize);
2116 EXPECT_EQ(result_chan_params->flush_timeout(), kFlushTimeout.get());
2117 l2cap_client.Unbind();
2118 RunLoopUntilIdle();
2119 }
2120
TEST_F(ProfileServerTestFakeAdapter,L2capParametersExtRequestParametersFails)2121 TEST_F(ProfileServerTestFakeAdapter, L2capParametersExtRequestParametersFails) {
2122 const bt::PeerId kPeerId;
2123 const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
2124 const zx::duration kFlushTimeout(zx::msec(100));
2125
2126 FakeChannel::WeakPtr last_channel;
2127 adapter()->fake_bredr()->set_l2cap_channel_callback(
2128 [&](FakeChannel::WeakPtr chan) { last_channel = chan; });
2129
2130 // Set L2CAP channel parameters
2131 fidlbredr::L2capParameters l2cap_params;
2132 fidlbredr::ConnectParameters conn_params;
2133 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2134 conn_params.set_l2cap(std::move(l2cap_params));
2135
2136 std::optional<fidlbredr::Channel> response_channel;
2137 client()->Connect(kFidlPeerId,
2138 std::move(conn_params),
2139 [&](fidlbredr::Profile_Connect_Result result) {
2140 ASSERT_TRUE(result.is_response());
2141 response_channel = std::move(result.response().channel);
2142 });
2143 RunLoopUntilIdle();
2144 ASSERT_TRUE(last_channel.is_alive());
2145 EXPECT_FALSE(last_channel->info().flush_timeout.has_value());
2146 ASSERT_TRUE(response_channel.has_value());
2147 ASSERT_FALSE(response_channel->has_flush_timeout());
2148 ASSERT_TRUE(response_channel->has_ext_l2cap());
2149
2150 last_channel->set_flush_timeout_succeeds(false);
2151
2152 fbt::ChannelParameters request_chan_params;
2153 request_chan_params.set_flush_timeout(kFlushTimeout.get());
2154 std::optional<fbt::ChannelParameters> result_chan_params;
2155 fidlbredr::L2capParametersExtPtr l2cap_client =
2156 response_channel->mutable_ext_l2cap()->Bind();
2157 l2cap_client->RequestParameters(
2158 std::move(request_chan_params),
2159 [&](fidlbredr::L2capParametersExt_RequestParameters_Result new_params) {
2160 result_chan_params = new_params.response().ResultValue_();
2161 });
2162 RunLoopUntilIdle();
2163 ASSERT_TRUE(result_chan_params.has_value());
2164 EXPECT_FALSE(result_chan_params->has_flush_timeout());
2165 l2cap_client.Unbind();
2166 RunLoopUntilIdle();
2167 }
2168
TEST_F(ProfileServerTestFakeAdapter,L2capParametersExtRequestParametersClosedOnChannelClosed)2169 TEST_F(ProfileServerTestFakeAdapter,
2170 L2capParametersExtRequestParametersClosedOnChannelClosed) {
2171 const bt::PeerId kPeerId;
2172 const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
2173
2174 FakeChannel::WeakPtr last_channel;
2175 adapter()->fake_bredr()->set_l2cap_channel_callback(
2176 [&](FakeChannel::WeakPtr chan) { last_channel = chan; });
2177
2178 // Set L2CAP channel parameters
2179 fidlbredr::L2capParameters l2cap_params;
2180 fidlbredr::ConnectParameters conn_params;
2181 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2182 conn_params.set_l2cap(std::move(l2cap_params));
2183
2184 std::optional<fidlbredr::Channel> response_channel;
2185 client()->Connect(kFidlPeerId,
2186 std::move(conn_params),
2187 [&](fidlbredr::Profile_Connect_Result result) {
2188 ASSERT_TRUE(result.is_response());
2189 response_channel = std::move(result.response().channel);
2190 });
2191 RunLoopUntilIdle();
2192 ASSERT_TRUE(last_channel.is_alive());
2193 ASSERT_TRUE(response_channel.has_value());
2194
2195 fidlbredr::L2capParametersExtPtr l2cap_client =
2196 response_channel->mutable_ext_l2cap()->Bind();
2197 bool l2cap_client_closed = false;
2198 l2cap_client.set_error_handler(
2199 [&](zx_status_t /*status*/) { l2cap_client_closed = true; });
2200
2201 // Closing the channel should close l2cap_client (after running the loop).
2202 last_channel->Close();
2203 // Destroy the channel (like the real LogicalLink would) to verify that
2204 // ProfileServer doesn't try to use channel pointers.
2205 EXPECT_TRUE(adapter()->fake_bredr()->DestroyChannel(last_channel->id()));
2206
2207 // Any request for the closed channel should be ignored.
2208 fbt::ChannelParameters request_chan_params;
2209 std::optional<fbt::ChannelParameters> result_chan_params;
2210 l2cap_client->RequestParameters(
2211 std::move(request_chan_params),
2212 [&](fidlbredr::L2capParametersExt_RequestParameters_Result new_params) {
2213 result_chan_params = new_params.response().ResultValue_();
2214 });
2215 RunLoopUntilIdle();
2216 EXPECT_TRUE(l2cap_client_closed);
2217 EXPECT_FALSE(result_chan_params.has_value());
2218 l2cap_client.Unbind();
2219 RunLoopUntilIdle();
2220 }
2221
TEST_F(ProfileServerTestFakeAdapter,AudioDirectionExtRequestParametersClosedOnChannelClosed)2222 TEST_F(ProfileServerTestFakeAdapter,
2223 AudioDirectionExtRequestParametersClosedOnChannelClosed) {
2224 const bt::PeerId kPeerId;
2225 const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
2226
2227 FakeChannel::WeakPtr last_channel;
2228 adapter()->fake_bredr()->set_l2cap_channel_callback(
2229 [&](FakeChannel::WeakPtr chan) { last_channel = chan; });
2230
2231 // Set L2CAP channel parameters
2232 fidlbredr::L2capParameters l2cap_params;
2233 fidlbredr::ConnectParameters conn_params;
2234 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2235 conn_params.set_l2cap(std::move(l2cap_params));
2236
2237 std::optional<fidlbredr::Channel> response_channel;
2238 client()->Connect(kFidlPeerId,
2239 std::move(conn_params),
2240 [&](fidlbredr::Profile_Connect_Result result) {
2241 ASSERT_TRUE(result.is_response());
2242 response_channel = std::move(result.response().channel);
2243 });
2244 RunLoopUntilIdle();
2245 ASSERT_TRUE(last_channel.is_alive());
2246 ASSERT_TRUE(response_channel.has_value());
2247
2248 fidlbredr::AudioDirectionExtPtr audio_client =
2249 response_channel->mutable_ext_direction()->Bind();
2250 bool audio_client_closed = false;
2251 audio_client.set_error_handler(
2252 [&](zx_status_t /*status*/) { audio_client_closed = true; });
2253
2254 // Closing the channel should close audio_client (after running the loop).
2255 last_channel->Close();
2256 // Destroy the channel (like the real LogicalLink would) to verify that
2257 // ProfileServer doesn't try to use channel pointers.
2258 EXPECT_TRUE(adapter()->fake_bredr()->DestroyChannel(last_channel->id()));
2259
2260 // Any request for the closed channel should be ignored.
2261 size_t priority_cb_count = 0;
2262 audio_client->SetPriority(
2263 fidlbredr::A2dpDirectionPriority::NORMAL,
2264 [&](fidlbredr::AudioDirectionExt_SetPriority_Result result) {
2265 priority_cb_count++;
2266 });
2267
2268 RunLoopUntilIdle();
2269 EXPECT_TRUE(audio_client_closed);
2270 EXPECT_EQ(priority_cb_count, 0u);
2271 audio_client.Unbind();
2272 RunLoopUntilIdle();
2273 }
2274
TEST_F(ProfileServerTestFakeAdapter,AudioOffloadExtRequestParametersClosedOnChannelClosed)2275 TEST_F(ProfileServerTestFakeAdapter,
2276 AudioOffloadExtRequestParametersClosedOnChannelClosed) {
2277 const bt::PeerId kPeerId;
2278 const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
2279
2280 FakeChannel::WeakPtr last_channel;
2281 adapter()->fake_bredr()->set_l2cap_channel_callback(
2282 [&](FakeChannel::WeakPtr chan) { last_channel = std::move(chan); });
2283
2284 // Support Android Vendor Extensions to enable Audio Offload Extension
2285 adapter()->mutable_state().controller_features |=
2286 FeaturesBits::kAndroidVendorExtensions;
2287 bt::StaticPacket<
2288 android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2289 params;
2290 params.SetToZeros();
2291 params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2292 params.view().version_supported().major_number().Write(0);
2293 params.view().version_supported().minor_number().Write(98);
2294 params.view().a2dp_source_offload_capability_mask().aac().Write(true);
2295 adapter()->mutable_state().android_vendor_capabilities =
2296 bt::gap::AndroidVendorCapabilities::New(params.view());
2297
2298 // Set L2CAP channel parameters
2299 fidlbredr::L2capParameters l2cap_params;
2300 fidlbredr::ConnectParameters conn_params;
2301 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2302 conn_params.set_l2cap(std::move(l2cap_params));
2303
2304 std::optional<fidlbredr::Channel> response_channel;
2305 client()->Connect(kFidlPeerId,
2306 std::move(conn_params),
2307 [&](fidlbredr::Profile_Connect_Result result) {
2308 ASSERT_TRUE(result.is_response());
2309 response_channel = std::move(result.response().channel);
2310 });
2311 RunLoopUntilIdle();
2312 ASSERT_TRUE(last_channel.is_alive());
2313 ASSERT_TRUE(response_channel.has_value());
2314 ASSERT_TRUE(response_channel->has_ext_audio_offload());
2315
2316 fidlbredr::AudioOffloadExtPtr audio_client =
2317 response_channel->mutable_ext_audio_offload()->Bind();
2318 bool audio_client_closed = false;
2319 audio_client.set_error_handler(
2320 [&](zx_status_t /*status*/) { audio_client_closed = true; });
2321
2322 // Closing the channel should close |audio_client| (after running the loop).
2323 last_channel->Close();
2324 // Destroy the channel (like the real LogicalLink would) to verify that
2325 // ProfileServer doesn't try to use channel pointers.
2326 EXPECT_TRUE(adapter()->fake_bredr()->DestroyChannel(last_channel->id()));
2327
2328 // Any request for the closed channel should be ignored.
2329 std::optional<fidlbredr::AudioOffloadExt_GetSupportedFeatures_Response>
2330 result_features;
2331 audio_client->GetSupportedFeatures(
2332 [&result_features](
2333 fidlbredr::AudioOffloadExt_GetSupportedFeatures_Result features) {
2334 result_features = std::move(features.response());
2335 });
2336
2337 RunLoopUntilIdle();
2338 EXPECT_TRUE(audio_client_closed);
2339 EXPECT_FALSE(result_features.has_value());
2340 audio_client.Unbind();
2341 RunLoopUntilIdle();
2342 }
2343
2344 class ProfileServerInvalidSamplingFrequencyTest
2345 : public ProfileServerTestFakeAdapter,
2346 public ::testing::WithParamInterface<fidlbredr::AudioSamplingFrequency> {
2347 };
2348
2349 const std::vector<fidlbredr::AudioSamplingFrequency>
2350 kInvalidSamplingFrequencies = {
2351 fidlbredr::AudioSamplingFrequency::HZ_88200,
2352 fidlbredr::AudioSamplingFrequency::HZ_96000,
2353 };
2354
2355 INSTANTIATE_TEST_SUITE_P(ProfileServerTestFakeAdapter,
2356 ProfileServerInvalidSamplingFrequencyTest,
2357 ::testing::ValuesIn(kInvalidSamplingFrequencies));
2358
TEST_P(ProfileServerInvalidSamplingFrequencyTest,SbcInvalidSamplingFrequency)2359 TEST_P(ProfileServerInvalidSamplingFrequencyTest, SbcInvalidSamplingFrequency) {
2360 // enable a2dp offloading
2361 adapter()->mutable_state().controller_features |=
2362 FeaturesBits::kAndroidVendorExtensions;
2363
2364 // enable offloaded sbc encoding
2365 bt::StaticPacket<
2366 android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2367 params;
2368 params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2369 params.view().version_supported().major_number().Write(0);
2370 params.view().version_supported().minor_number().Write(98);
2371 params.view().a2dp_source_offload_capability_mask().sbc().Write(true);
2372 adapter()->mutable_state().android_vendor_capabilities =
2373 bt::gap::AndroidVendorCapabilities::New(params.view());
2374
2375 // set up a fake channel and connection
2376 FakeChannel::WeakPtr fake_channel;
2377 adapter()->fake_bredr()->set_l2cap_channel_callback(
2378 [&](auto chan) { fake_channel = std::move(chan); });
2379
2380 const bt::PeerId peer_id(1);
2381 const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2382
2383 fidlbredr::L2capParameters l2cap_params;
2384 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2385
2386 fbt::ChannelParameters chan_params;
2387 l2cap_params.set_parameters(std::move(chan_params));
2388
2389 fidlbredr::ConnectParameters conn_params;
2390 conn_params.set_l2cap(std::move(l2cap_params));
2391
2392 std::optional<fidlbredr::Channel> response_channel;
2393 client()->Connect(
2394 fidl_peer_id,
2395 std::move(conn_params),
2396 [&response_channel](fidlbredr::Profile_Connect_Result result) {
2397 ASSERT_TRUE(result.is_response());
2398 response_channel = std::move(result.response().channel);
2399 });
2400 RunLoopUntilIdle();
2401 ASSERT_TRUE(response_channel.has_value());
2402 ASSERT_TRUE(response_channel->has_ext_audio_offload());
2403
2404 // set up the bad configuration
2405 std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
2406 fidlbredr::AudioOffloadFeatures::New();
2407 std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
2408 fidlbredr::AudioSbcSupport::New();
2409 codec->set_sbc(std::move(*codec_value));
2410
2411 std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
2412 std::make_unique<fidlbredr::AudioEncoderSettings>();
2413 std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
2414 fuchsia::media::SbcEncoderSettings::New();
2415 encoder_settings->set_sbc(*encoder_settings_value);
2416
2417 std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
2418 std::make_unique<fidlbredr::AudioOffloadConfiguration>();
2419 config->set_codec(std::move(*codec));
2420 config->set_max_latency(10);
2421 config->set_scms_t_enable(true);
2422 config->set_sampling_frequency(GetParam());
2423 config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
2424 config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
2425 config->set_encoded_bit_rate(10);
2426 config->set_encoder_settings(std::move(*encoder_settings));
2427
2428 // attempt to start the audio offload
2429 fidl::InterfaceHandle<fidlbredr::AudioOffloadController> controller_handle;
2430 fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
2431 controller_handle.NewRequest();
2432 fidl::InterfacePtr<fidlbredr::AudioOffloadExt> audio_offload_ext_client =
2433 response_channel->mutable_ext_audio_offload()->Bind();
2434 audio_offload_ext_client->StartAudioOffload(std::move(*config),
2435 std::move(controller_request));
2436
2437 fidl::InterfacePtr<fidlbredr::AudioOffloadController>
2438 audio_offload_controller_client;
2439 audio_offload_controller_client.Bind(std::move(controller_handle));
2440
2441 std::optional<zx_status_t> audio_offload_controller_epitaph;
2442 audio_offload_controller_client.set_error_handler(
2443 [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
2444
2445 RunLoopUntilIdle();
2446
2447 // Verify that |audio_offload_controller_client| was closed with
2448 // |ZX_ERR_INTERNAL| epitaph
2449 ASSERT_TRUE(audio_offload_controller_epitaph.has_value());
2450 EXPECT_EQ(audio_offload_controller_epitaph.value(), ZX_ERR_NOT_SUPPORTED);
2451 }
2452
2453 class AndroidSupportedFeaturesTest
2454 : public ProfileServerTestFakeAdapter,
2455 public ::testing::WithParamInterface<
2456 std::pair<bool /*android_vendor_support*/,
2457 uint32_t /*android_vendor_capabilities*/>> {};
2458
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadExtGetSupportedFeatures)2459 TEST_P(AndroidSupportedFeaturesTest, AudioOffloadExtGetSupportedFeatures) {
2460 const bool android_vendor_ext_support = GetParam().first;
2461 const uint32_t a2dp_offload_capabilities = GetParam().second;
2462
2463 if (android_vendor_ext_support) {
2464 adapter()->mutable_state().controller_features |=
2465 FeaturesBits::kAndroidVendorExtensions;
2466
2467 bt::StaticPacket<
2468 android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2469 params;
2470 params.SetToZeros();
2471 params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2472 params.view().version_supported().major_number().Write(0);
2473 params.view().version_supported().minor_number().Write(98);
2474 params.view()
2475 .a2dp_source_offload_capability_mask()
2476 .BackingStorage()
2477 .UncheckedWriteUInt(a2dp_offload_capabilities);
2478 adapter()->mutable_state().android_vendor_capabilities =
2479 bt::gap::AndroidVendorCapabilities::New(params.view());
2480 }
2481
2482 const bt::PeerId peer_id(1);
2483 const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2484
2485 // Set L2CAP channel parameters
2486 fidlbredr::L2capParameters l2cap_params;
2487 fidlbredr::ConnectParameters conn_params;
2488 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2489 l2cap_params.set_parameters(fbt::ChannelParameters());
2490 conn_params.set_l2cap(std::move(l2cap_params));
2491
2492 std::optional<fidlbredr::Channel> response_channel;
2493 client()->Connect(
2494 fidl_peer_id,
2495 std::move(conn_params),
2496 [&response_channel](fidlbredr::Profile_Connect_Result result) {
2497 ASSERT_TRUE(result.is_response());
2498 response_channel = std::move(result.response().channel);
2499 });
2500 RunLoopUntilIdle();
2501 ASSERT_TRUE(response_channel.has_value());
2502 if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
2503 EXPECT_FALSE(response_channel->has_ext_audio_offload());
2504 return;
2505 }
2506 ASSERT_TRUE(response_channel->has_ext_audio_offload());
2507
2508 std::optional<fidlbredr::AudioOffloadExt_GetSupportedFeatures_Response>
2509 result_features;
2510 fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
2511 response_channel->mutable_ext_audio_offload()->Bind();
2512 audio_offload_ext_client->GetSupportedFeatures(
2513 [&result_features](
2514 fidlbredr::AudioOffloadExt_GetSupportedFeatures_Result features) {
2515 result_features = std::move(features.response());
2516 });
2517 RunLoopUntilIdle();
2518
2519 EXPECT_TRUE(result_features->has_audio_offload_features());
2520 const std::vector<fidlbredr::AudioOffloadFeatures>& audio_offload_features =
2521 result_features->audio_offload_features();
2522 const uint32_t audio_offload_features_size =
2523 std::bitset<std::numeric_limits<uint32_t>::digits>(
2524 a2dp_offload_capabilities)
2525 .count();
2526 EXPECT_EQ(audio_offload_features_size, audio_offload_features.size());
2527
2528 uint32_t capabilities = 0;
2529 const uint32_t sbc_capability =
2530 static_cast<uint32_t>(android_emb::A2dpCodecType::SBC);
2531 const uint32_t aac_capability =
2532 static_cast<uint32_t>(android_emb::A2dpCodecType::AAC);
2533 for (const fidlbredr::AudioOffloadFeatures& feature :
2534 audio_offload_features) {
2535 if (feature.is_sbc()) {
2536 capabilities |= sbc_capability;
2537 }
2538 if (feature.is_aac()) {
2539 capabilities |= aac_capability;
2540 }
2541 }
2542 EXPECT_EQ(capabilities, a2dp_offload_capabilities);
2543 }
2544
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadExtStartAudioOffloadSuccess)2545 TEST_P(AndroidSupportedFeaturesTest, AudioOffloadExtStartAudioOffloadSuccess) {
2546 const bool android_vendor_ext_support = GetParam().first;
2547 const uint32_t a2dp_offload_capabilities = GetParam().second;
2548
2549 if (android_vendor_ext_support) {
2550 adapter()->mutable_state().controller_features |=
2551 FeaturesBits::kAndroidVendorExtensions;
2552
2553 bt::StaticPacket<
2554 android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2555 params;
2556 params.SetToZeros();
2557 params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2558 params.view().version_supported().major_number().Write(0);
2559 params.view().version_supported().minor_number().Write(98);
2560 params.view()
2561 .a2dp_source_offload_capability_mask()
2562 .BackingStorage()
2563 .UncheckedWriteUInt(a2dp_offload_capabilities);
2564 adapter()->mutable_state().android_vendor_capabilities =
2565 bt::gap::AndroidVendorCapabilities::New(params.view());
2566 }
2567
2568 const bt::PeerId peer_id(1);
2569 const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2570
2571 // Set L2CAP channel parameters
2572 fidlbredr::L2capParameters l2cap_params;
2573 fidlbredr::ConnectParameters conn_params;
2574 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2575 l2cap_params.set_parameters(fbt::ChannelParameters());
2576 conn_params.set_l2cap(std::move(l2cap_params));
2577
2578 std::optional<fidlbredr::Channel> response_channel;
2579 client()->Connect(
2580 fidl_peer_id,
2581 std::move(conn_params),
2582 [&response_channel](fidlbredr::Profile_Connect_Result result) {
2583 ASSERT_TRUE(result.is_response());
2584 response_channel = std::move(result.response().channel);
2585 });
2586 RunLoopUntilIdle();
2587 ASSERT_TRUE(response_channel.has_value());
2588 if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
2589 EXPECT_FALSE(response_channel->has_ext_audio_offload());
2590 return;
2591 }
2592 ASSERT_TRUE(response_channel->has_ext_audio_offload());
2593
2594 // Set Audio Offload Configuration Values
2595 std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
2596 fidlbredr::AudioOffloadFeatures::New();
2597 std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
2598 fidlbredr::AudioSbcSupport::New();
2599 codec->set_sbc(std::move(*codec_value));
2600
2601 std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
2602 std::make_unique<fidlbredr::AudioEncoderSettings>();
2603 std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
2604 fuchsia::media::SbcEncoderSettings::New();
2605 encoder_settings->set_sbc(*encoder_settings_value);
2606
2607 std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
2608 std::make_unique<fidlbredr::AudioOffloadConfiguration>();
2609 config->set_codec(std::move(*codec));
2610 config->set_max_latency(10);
2611 config->set_scms_t_enable(true);
2612 config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
2613 config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
2614 config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
2615 config->set_encoded_bit_rate(10);
2616 config->set_encoder_settings(std::move(*encoder_settings));
2617
2618 fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
2619 response_channel->mutable_ext_audio_offload()->Bind();
2620 fidlbredr::AudioOffloadControllerHandle controller_handle;
2621 fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
2622 controller_handle.NewRequest();
2623 audio_offload_ext_client->StartAudioOffload(std::move(*config),
2624 std::move(controller_request));
2625
2626 fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
2627 audio_offload_controller_client.Bind(std::move(controller_handle));
2628
2629 std::optional<zx_status_t> audio_offload_controller_epitaph;
2630 audio_offload_controller_client.set_error_handler(
2631 [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
2632
2633 size_t on_started_count = 0;
2634 audio_offload_controller_client.events().OnStarted = [&]() {
2635 on_started_count++;
2636 };
2637
2638 RunLoopUntilIdle();
2639
2640 // Verify that OnStarted event was sent successfully
2641 EXPECT_EQ(on_started_count, 1u);
2642
2643 // Verify that |audio_offload_controller_client| was not closed with an
2644 // epitaph
2645 ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
2646 }
2647
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadExtStartAudioOffloadFail)2648 TEST_P(AndroidSupportedFeaturesTest, AudioOffloadExtStartAudioOffloadFail) {
2649 FakeChannel::WeakPtr fake_channel;
2650 adapter()->fake_bredr()->set_l2cap_channel_callback(
2651 [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
2652
2653 const bool android_vendor_ext_support = GetParam().first;
2654 const uint32_t a2dp_offload_capabilities = GetParam().second;
2655
2656 if (android_vendor_ext_support) {
2657 adapter()->mutable_state().controller_features |=
2658 FeaturesBits::kAndroidVendorExtensions;
2659
2660 bt::StaticPacket<
2661 android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2662 params;
2663 params.SetToZeros();
2664 params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2665 params.view().version_supported().major_number().Write(0);
2666 params.view().version_supported().minor_number().Write(98);
2667 params.view()
2668 .a2dp_source_offload_capability_mask()
2669 .BackingStorage()
2670 .UncheckedWriteUInt(a2dp_offload_capabilities);
2671 adapter()->mutable_state().android_vendor_capabilities =
2672 bt::gap::AndroidVendorCapabilities::New(params.view());
2673 }
2674
2675 const bt::PeerId peer_id(1);
2676 const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2677
2678 // Set L2CAP channel parameters
2679 fidlbredr::L2capParameters l2cap_params;
2680 fidlbredr::ConnectParameters conn_params;
2681 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2682 l2cap_params.set_parameters(fbt::ChannelParameters());
2683 conn_params.set_l2cap(std::move(l2cap_params));
2684
2685 std::optional<fidlbredr::Channel> response_channel;
2686 client()->Connect(
2687 fidl_peer_id,
2688 std::move(conn_params),
2689 [&response_channel](fidlbredr::Profile_Connect_Result result) {
2690 ASSERT_TRUE(result.is_response());
2691 response_channel = std::move(result.response().channel);
2692 });
2693 RunLoopUntilIdle();
2694 ASSERT_TRUE(response_channel.has_value());
2695 if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
2696 EXPECT_FALSE(response_channel->has_ext_audio_offload());
2697 return;
2698 }
2699 ASSERT_TRUE(response_channel->has_ext_audio_offload());
2700
2701 // Make A2DP offloading fail, resulting in |ZX_ERR_INTERNAL| epitaph
2702 ASSERT_TRUE(fake_channel.is_alive());
2703 fake_channel->set_a2dp_offload_fails(bt::HostError::kFailed);
2704
2705 // Set Audio Offload Configuration Values
2706 std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
2707 fidlbredr::AudioOffloadFeatures::New();
2708 std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
2709 fidlbredr::AudioSbcSupport::New();
2710 codec->set_sbc(std::move(*codec_value));
2711
2712 std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
2713 std::make_unique<fidlbredr::AudioEncoderSettings>();
2714 std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
2715 fuchsia::media::SbcEncoderSettings::New();
2716 encoder_settings->set_sbc(*encoder_settings_value);
2717
2718 std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
2719 std::make_unique<fidlbredr::AudioOffloadConfiguration>();
2720 config->set_codec(std::move(*codec));
2721 config->set_max_latency(10);
2722 config->set_scms_t_enable(true);
2723 config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
2724 config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
2725 config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
2726 config->set_encoded_bit_rate(10);
2727 config->set_encoder_settings(std::move(*encoder_settings));
2728
2729 fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
2730 response_channel->mutable_ext_audio_offload()->Bind();
2731 fidlbredr::AudioOffloadControllerHandle controller_handle;
2732 fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
2733 controller_handle.NewRequest();
2734 audio_offload_ext_client->StartAudioOffload(std::move(*config),
2735 std::move(controller_request));
2736
2737 fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
2738 audio_offload_controller_client.Bind(std::move(controller_handle));
2739
2740 std::optional<zx_status_t> audio_offload_controller_epitaph;
2741 audio_offload_controller_client.set_error_handler(
2742 [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
2743
2744 size_t cb_count = 0;
2745 audio_offload_controller_client.events().OnStarted = [&]() { cb_count++; };
2746
2747 RunLoopUntilIdle();
2748 EXPECT_EQ(cb_count, 0u);
2749
2750 // Verify that |audio_offload_controller_client| was closed with
2751 // |ZX_ERR_INTERNAL| epitaph
2752 ASSERT_TRUE(audio_offload_controller_epitaph.has_value());
2753 EXPECT_EQ(audio_offload_controller_epitaph.value(), ZX_ERR_INTERNAL);
2754
2755 bt::l2cap::A2dpOffloadStatus a2dp_offload_status =
2756 fake_channel->a2dp_offload_status();
2757 EXPECT_EQ(bt::l2cap::A2dpOffloadStatus::kStopped, a2dp_offload_status);
2758 }
2759
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadExtStartAudioOffloadInProgress)2760 TEST_P(AndroidSupportedFeaturesTest,
2761 AudioOffloadExtStartAudioOffloadInProgress) {
2762 FakeChannel::WeakPtr fake_channel;
2763 adapter()->fake_bredr()->set_l2cap_channel_callback(
2764 [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
2765
2766 const bool android_vendor_ext_support = GetParam().first;
2767 const uint32_t a2dp_offload_capabilities = GetParam().second;
2768
2769 if (android_vendor_ext_support) {
2770 adapter()->mutable_state().controller_features |=
2771 FeaturesBits::kAndroidVendorExtensions;
2772
2773 bt::StaticPacket<
2774 android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2775 params;
2776 params.SetToZeros();
2777 params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2778 params.view().version_supported().major_number().Write(0);
2779 params.view().version_supported().minor_number().Write(98);
2780 params.view()
2781 .a2dp_source_offload_capability_mask()
2782 .BackingStorage()
2783 .UncheckedWriteUInt(a2dp_offload_capabilities);
2784 adapter()->mutable_state().android_vendor_capabilities =
2785 bt::gap::AndroidVendorCapabilities::New(params.view());
2786 }
2787
2788 const bt::PeerId peer_id(1);
2789 const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2790
2791 // Set L2CAP channel parameters
2792 fidlbredr::L2capParameters l2cap_params;
2793 fidlbredr::ConnectParameters conn_params;
2794 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2795 l2cap_params.set_parameters(fbt::ChannelParameters());
2796 conn_params.set_l2cap(std::move(l2cap_params));
2797
2798 std::optional<fidlbredr::Channel> response_channel;
2799 client()->Connect(
2800 fidl_peer_id,
2801 std::move(conn_params),
2802 [&response_channel](fidlbredr::Profile_Connect_Result result) {
2803 ASSERT_TRUE(result.is_response());
2804 response_channel = std::move(result.response().channel);
2805 });
2806 RunLoopUntilIdle();
2807 ASSERT_TRUE(response_channel.has_value());
2808 if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
2809 EXPECT_FALSE(response_channel->has_ext_audio_offload());
2810 return;
2811 }
2812 ASSERT_TRUE(response_channel->has_ext_audio_offload());
2813
2814 // Make A2DP offloading fail, resulting in |ZX_ERR_ALREADY_BOUND| epitaph
2815 ASSERT_TRUE(fake_channel.is_alive());
2816 fake_channel->set_a2dp_offload_fails(bt::HostError::kInProgress);
2817
2818 // Set Audio Offload Configuration Values
2819 std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
2820 fidlbredr::AudioOffloadFeatures::New();
2821 std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
2822 fidlbredr::AudioSbcSupport::New();
2823 codec->set_sbc(std::move(*codec_value));
2824
2825 std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
2826 std::make_unique<fidlbredr::AudioEncoderSettings>();
2827 std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
2828 fuchsia::media::SbcEncoderSettings::New();
2829 encoder_settings->set_sbc(*encoder_settings_value);
2830
2831 std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
2832 std::make_unique<fidlbredr::AudioOffloadConfiguration>();
2833 config->set_codec(std::move(*codec));
2834 config->set_max_latency(10);
2835 config->set_scms_t_enable(true);
2836 config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
2837 config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
2838 config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
2839 config->set_encoded_bit_rate(10);
2840 config->set_encoder_settings(std::move(*encoder_settings));
2841
2842 fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
2843 response_channel->mutable_ext_audio_offload()->Bind();
2844 fidlbredr::AudioOffloadControllerHandle controller_handle;
2845 fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
2846 controller_handle.NewRequest();
2847 audio_offload_ext_client->StartAudioOffload(std::move(*config),
2848 std::move(controller_request));
2849
2850 fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
2851 audio_offload_controller_client.Bind(std::move(controller_handle));
2852
2853 std::optional<zx_status_t> audio_offload_controller_epitaph;
2854 audio_offload_controller_client.set_error_handler(
2855 [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
2856
2857 size_t cb_count = 0;
2858 audio_offload_controller_client.events().OnStarted = [&]() { cb_count++; };
2859
2860 RunLoopUntilIdle();
2861 EXPECT_EQ(cb_count, 0u);
2862
2863 // Verify that |audio_offload_controller_client| was closed with
2864 // |ZX_ERR_ALREADY_BOUND| epitaph
2865 ASSERT_TRUE(audio_offload_controller_epitaph.has_value());
2866 EXPECT_EQ(audio_offload_controller_epitaph.value(), ZX_ERR_ALREADY_BOUND);
2867 }
2868
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadExtStartAudioOffloadControllerError)2869 TEST_P(AndroidSupportedFeaturesTest,
2870 AudioOffloadExtStartAudioOffloadControllerError) {
2871 FakeChannel::WeakPtr fake_channel;
2872 adapter()->fake_bredr()->set_l2cap_channel_callback(
2873 [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
2874
2875 const bool android_vendor_ext_support = GetParam().first;
2876 const uint32_t a2dp_offload_capabilities = GetParam().second;
2877
2878 if (android_vendor_ext_support) {
2879 adapter()->mutable_state().controller_features |=
2880 FeaturesBits::kAndroidVendorExtensions;
2881
2882 bt::StaticPacket<
2883 android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2884 params;
2885 params.SetToZeros();
2886 params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2887 params.view().version_supported().major_number().Write(0);
2888 params.view().version_supported().minor_number().Write(98);
2889 params.view()
2890 .a2dp_source_offload_capability_mask()
2891 .BackingStorage()
2892 .UncheckedWriteUInt(a2dp_offload_capabilities);
2893 adapter()->mutable_state().android_vendor_capabilities =
2894 bt::gap::AndroidVendorCapabilities::New(params.view());
2895 }
2896
2897 const bt::PeerId peer_id(1);
2898 const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2899
2900 // Set L2CAP channel parameters
2901 fidlbredr::L2capParameters l2cap_params;
2902 fidlbredr::ConnectParameters conn_params;
2903 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2904 l2cap_params.set_parameters(fbt::ChannelParameters());
2905 conn_params.set_l2cap(std::move(l2cap_params));
2906
2907 std::optional<fidlbredr::Channel> response_channel;
2908 client()->Connect(
2909 fidl_peer_id,
2910 std::move(conn_params),
2911 [&response_channel](fidlbredr::Profile_Connect_Result result) {
2912 ASSERT_TRUE(result.is_response());
2913 response_channel = std::move(result.response().channel);
2914 });
2915 RunLoopUntilIdle();
2916 ASSERT_TRUE(response_channel.has_value());
2917 if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
2918 EXPECT_FALSE(response_channel->has_ext_audio_offload());
2919 return;
2920 }
2921 ASSERT_TRUE(response_channel->has_ext_audio_offload());
2922
2923 // Set Audio Offload Configuration Values
2924 std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
2925 fidlbredr::AudioOffloadFeatures::New();
2926 std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
2927 fidlbredr::AudioSbcSupport::New();
2928 codec->set_sbc(std::move(*codec_value));
2929
2930 std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
2931 std::make_unique<fidlbredr::AudioEncoderSettings>();
2932 std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
2933 fuchsia::media::SbcEncoderSettings::New();
2934 encoder_settings->set_sbc(*encoder_settings_value);
2935
2936 std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
2937 std::make_unique<fidlbredr::AudioOffloadConfiguration>();
2938 config->set_codec(std::move(*codec));
2939 config->set_max_latency(10);
2940 config->set_scms_t_enable(true);
2941 config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
2942 config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
2943 config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
2944 config->set_encoded_bit_rate(10);
2945 config->set_encoder_settings(std::move(*encoder_settings));
2946
2947 fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
2948 response_channel->mutable_ext_audio_offload()->Bind();
2949 fidlbredr::AudioOffloadControllerHandle controller_handle;
2950 fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
2951 controller_handle.NewRequest();
2952 audio_offload_ext_client->StartAudioOffload(std::move(*config),
2953 std::move(controller_request));
2954
2955 fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
2956 audio_offload_controller_client.Bind(std::move(controller_handle));
2957
2958 std::optional<zx_status_t> audio_offload_controller_epitaph;
2959 audio_offload_controller_client.set_error_handler(
2960 [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
2961
2962 size_t cb_count = 0;
2963 audio_offload_controller_client.events().OnStarted = [&]() { cb_count++; };
2964
2965 // Close client end of protocol to trigger audio offload error handler
2966 audio_offload_controller_client.Unbind();
2967
2968 RunLoopUntilIdle();
2969 EXPECT_EQ(cb_count, 0u);
2970 ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
2971 }
2972
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadControllerStopSuccess)2973 TEST_P(AndroidSupportedFeaturesTest, AudioOffloadControllerStopSuccess) {
2974 const bool android_vendor_ext_support = GetParam().first;
2975 const uint32_t a2dp_offload_capabilities = GetParam().second;
2976
2977 if (android_vendor_ext_support) {
2978 adapter()->mutable_state().controller_features |=
2979 FeaturesBits::kAndroidVendorExtensions;
2980
2981 bt::StaticPacket<
2982 android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2983 params;
2984 params.SetToZeros();
2985 params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2986 params.view().version_supported().major_number().Write(0);
2987 params.view().version_supported().minor_number().Write(98);
2988 params.view()
2989 .a2dp_source_offload_capability_mask()
2990 .BackingStorage()
2991 .UncheckedWriteUInt(a2dp_offload_capabilities);
2992 adapter()->mutable_state().android_vendor_capabilities =
2993 bt::gap::AndroidVendorCapabilities::New(params.view());
2994 }
2995
2996 const bt::PeerId peer_id(1);
2997 const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2998
2999 // Set L2CAP channel parameters
3000 fidlbredr::L2capParameters l2cap_params;
3001 fidlbredr::ConnectParameters conn_params;
3002 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
3003 l2cap_params.set_parameters(fbt::ChannelParameters());
3004 conn_params.set_l2cap(std::move(l2cap_params));
3005
3006 std::optional<fidlbredr::Channel> response_channel;
3007 client()->Connect(
3008 fidl_peer_id,
3009 std::move(conn_params),
3010 [&response_channel](fidlbredr::Profile_Connect_Result result) {
3011 ASSERT_TRUE(result.is_response());
3012 response_channel = std::move(result.response().channel);
3013 });
3014 RunLoopUntilIdle();
3015 ASSERT_TRUE(response_channel.has_value());
3016 if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
3017 EXPECT_FALSE(response_channel->has_ext_audio_offload());
3018 return;
3019 }
3020 ASSERT_TRUE(response_channel->has_ext_audio_offload());
3021
3022 // Set Audio Offload Configuration Values
3023 std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
3024 fidlbredr::AudioOffloadFeatures::New();
3025 std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
3026 fidlbredr::AudioSbcSupport::New();
3027 codec->set_sbc(std::move(*codec_value));
3028
3029 std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
3030 std::make_unique<fidlbredr::AudioEncoderSettings>();
3031 std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
3032 fuchsia::media::SbcEncoderSettings::New();
3033 encoder_settings->set_sbc(*encoder_settings_value);
3034
3035 std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
3036 std::make_unique<fidlbredr::AudioOffloadConfiguration>();
3037 config->set_codec(std::move(*codec));
3038 config->set_max_latency(10);
3039 config->set_scms_t_enable(true);
3040 config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
3041 config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
3042 config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
3043 config->set_encoded_bit_rate(10);
3044 config->set_encoder_settings(std::move(*encoder_settings));
3045
3046 fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
3047 response_channel->mutable_ext_audio_offload()->Bind();
3048 fidlbredr::AudioOffloadControllerHandle controller_handle;
3049 fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
3050 controller_handle.NewRequest();
3051 audio_offload_ext_client->StartAudioOffload(std::move(*config),
3052 std::move(controller_request));
3053
3054 fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
3055 audio_offload_controller_client.Bind(std::move(controller_handle));
3056
3057 std::optional<zx_status_t> audio_offload_controller_epitaph;
3058 audio_offload_controller_client.set_error_handler(
3059 [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
3060
3061 size_t on_started_count = 0;
3062 audio_offload_controller_client.events().OnStarted = [&]() {
3063 on_started_count++;
3064 };
3065
3066 RunLoopUntilIdle();
3067
3068 // Verify that OnStarted event was sent successfully
3069 EXPECT_EQ(on_started_count, 1u);
3070
3071 // Verify that |audio_offload_controller_client| was not closed with an
3072 // epitaph
3073 ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
3074
3075 bool stop_callback_called = false;
3076 auto callback = [&stop_callback_called](
3077 fidlbredr::AudioOffloadController_Stop_Result result) {
3078 stop_callback_called = true;
3079 };
3080
3081 audio_offload_controller_client->Stop(std::move(callback));
3082
3083 RunLoopUntilIdle();
3084
3085 // Verify that audio offload was stopped successfully
3086 ASSERT_TRUE(stop_callback_called);
3087 }
3088
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadControllerStopFail)3089 TEST_P(AndroidSupportedFeaturesTest, AudioOffloadControllerStopFail) {
3090 FakeChannel::WeakPtr fake_channel;
3091 adapter()->fake_bredr()->set_l2cap_channel_callback(
3092 [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
3093
3094 const bool android_vendor_ext_support = GetParam().first;
3095 const uint32_t a2dp_offload_capabilities = GetParam().second;
3096
3097 if (android_vendor_ext_support) {
3098 adapter()->mutable_state().controller_features |=
3099 FeaturesBits::kAndroidVendorExtensions;
3100
3101 bt::StaticPacket<
3102 android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
3103 params;
3104 params.SetToZeros();
3105 params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
3106 params.view().version_supported().major_number().Write(0);
3107 params.view().version_supported().minor_number().Write(98);
3108 params.view()
3109 .a2dp_source_offload_capability_mask()
3110 .BackingStorage()
3111 .UncheckedWriteUInt(a2dp_offload_capabilities);
3112 adapter()->mutable_state().android_vendor_capabilities =
3113 bt::gap::AndroidVendorCapabilities::New(params.view());
3114 }
3115
3116 const bt::PeerId peer_id(1);
3117 const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
3118
3119 // Set L2CAP channel parameters
3120 fidlbredr::L2capParameters l2cap_params;
3121 fidlbredr::ConnectParameters conn_params;
3122 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
3123 l2cap_params.set_parameters(fbt::ChannelParameters());
3124 conn_params.set_l2cap(std::move(l2cap_params));
3125
3126 std::optional<fidlbredr::Channel> response_channel;
3127 client()->Connect(
3128 fidl_peer_id,
3129 std::move(conn_params),
3130 [&response_channel](fidlbredr::Profile_Connect_Result result) {
3131 ASSERT_TRUE(result.is_response());
3132 response_channel = std::move(result.response().channel);
3133 });
3134 RunLoopUntilIdle();
3135 ASSERT_TRUE(response_channel.has_value());
3136 if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
3137 EXPECT_FALSE(response_channel->has_ext_audio_offload());
3138 return;
3139 }
3140 ASSERT_TRUE(response_channel->has_ext_audio_offload());
3141
3142 // Set Audio Offload Configuration Values
3143 std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
3144 fidlbredr::AudioOffloadFeatures::New();
3145 std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
3146 fidlbredr::AudioSbcSupport::New();
3147 codec->set_sbc(std::move(*codec_value));
3148
3149 std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
3150 std::make_unique<fidlbredr::AudioEncoderSettings>();
3151 std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
3152 fuchsia::media::SbcEncoderSettings::New();
3153 encoder_settings->set_sbc(*encoder_settings_value);
3154
3155 std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
3156 std::make_unique<fidlbredr::AudioOffloadConfiguration>();
3157 config->set_codec(std::move(*codec));
3158 config->set_max_latency(10);
3159 config->set_scms_t_enable(true);
3160 config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
3161 config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
3162 config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
3163 config->set_encoded_bit_rate(10);
3164 config->set_encoder_settings(std::move(*encoder_settings));
3165
3166 fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
3167 response_channel->mutable_ext_audio_offload()->Bind();
3168 fidlbredr::AudioOffloadControllerHandle controller_handle;
3169 fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
3170 controller_handle.NewRequest();
3171 audio_offload_ext_client->StartAudioOffload(std::move(*config),
3172 std::move(controller_request));
3173
3174 fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
3175 audio_offload_controller_client.Bind(std::move(controller_handle));
3176
3177 std::optional<zx_status_t> audio_offload_controller_epitaph;
3178 audio_offload_controller_client.set_error_handler(
3179 [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
3180
3181 size_t on_started_count = 0;
3182 audio_offload_controller_client.events().OnStarted = [&]() {
3183 on_started_count++;
3184 };
3185
3186 RunLoopUntilIdle();
3187
3188 // Verify that OnStarted event was sent successfully
3189 EXPECT_EQ(on_started_count, 1u);
3190
3191 // Verify that |audio_offload_controller_client| was not closed with an
3192 // epitaph
3193 ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
3194
3195 // Make A2DP offloading fail, resulting in |ZX_ERR_UNAVAILABLE| epitaph
3196 ASSERT_TRUE(fake_channel.is_alive());
3197 fake_channel->set_a2dp_offload_fails(bt::HostError::kInProgress);
3198
3199 size_t cb_count = 0;
3200 audio_offload_controller_client->Stop(
3201 [&cb_count](fidlbredr::AudioOffloadController_Stop_Result result) {
3202 cb_count++;
3203 });
3204
3205 RunLoopUntilIdle();
3206
3207 EXPECT_EQ(cb_count, 0u);
3208
3209 // Verify that |audio_offload_controller_client| was closed with
3210 // |ZX_ERR_UNAVAILABLE| epitaph
3211 ASSERT_TRUE(audio_offload_controller_epitaph.has_value());
3212 EXPECT_EQ(audio_offload_controller_epitaph.value(), ZX_ERR_UNAVAILABLE);
3213 }
3214
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadControllerStopAfterAlreadyStopped)3215 TEST_P(AndroidSupportedFeaturesTest,
3216 AudioOffloadControllerStopAfterAlreadyStopped) {
3217 const bool android_vendor_ext_support = GetParam().first;
3218 const uint32_t a2dp_offload_capabilities = GetParam().second;
3219
3220 if (android_vendor_ext_support) {
3221 adapter()->mutable_state().controller_features |=
3222 FeaturesBits::kAndroidVendorExtensions;
3223
3224 bt::StaticPacket<
3225 android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
3226 params;
3227 params.SetToZeros();
3228 params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
3229 params.view().version_supported().major_number().Write(0);
3230 params.view().version_supported().minor_number().Write(98);
3231 params.view()
3232 .a2dp_source_offload_capability_mask()
3233 .BackingStorage()
3234 .UncheckedWriteUInt(a2dp_offload_capabilities);
3235 adapter()->mutable_state().android_vendor_capabilities =
3236 bt::gap::AndroidVendorCapabilities::New(params.view());
3237 }
3238
3239 const bt::PeerId peer_id(1);
3240 const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
3241
3242 // Set L2CAP channel parameters
3243 fidlbredr::L2capParameters l2cap_params;
3244 fidlbredr::ConnectParameters conn_params;
3245 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
3246 l2cap_params.set_parameters(fbt::ChannelParameters());
3247 conn_params.set_l2cap(std::move(l2cap_params));
3248
3249 std::optional<fidlbredr::Channel> response_channel;
3250 client()->Connect(
3251 fidl_peer_id,
3252 std::move(conn_params),
3253 [&response_channel](fidlbredr::Profile_Connect_Result result) {
3254 ASSERT_TRUE(result.is_response());
3255 response_channel = std::move(result.response().channel);
3256 });
3257 RunLoopUntilIdle();
3258 ASSERT_TRUE(response_channel.has_value());
3259 if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
3260 EXPECT_FALSE(response_channel->has_ext_audio_offload());
3261 return;
3262 }
3263 ASSERT_TRUE(response_channel->has_ext_audio_offload());
3264
3265 // Set Audio Offload Configuration Values
3266 std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
3267 fidlbredr::AudioOffloadFeatures::New();
3268 std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
3269 fidlbredr::AudioSbcSupport::New();
3270 codec->set_sbc(std::move(*codec_value));
3271
3272 std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
3273 std::make_unique<fidlbredr::AudioEncoderSettings>();
3274 std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
3275 fuchsia::media::SbcEncoderSettings::New();
3276 encoder_settings->set_sbc(*encoder_settings_value);
3277
3278 std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
3279 std::make_unique<fidlbredr::AudioOffloadConfiguration>();
3280 config->set_codec(std::move(*codec));
3281 config->set_max_latency(10);
3282 config->set_scms_t_enable(true);
3283 config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
3284 config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
3285 config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
3286 config->set_encoded_bit_rate(10);
3287 config->set_encoder_settings(std::move(*encoder_settings));
3288
3289 fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
3290 response_channel->mutable_ext_audio_offload()->Bind();
3291 fidlbredr::AudioOffloadControllerHandle controller_handle;
3292 fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
3293 controller_handle.NewRequest();
3294 audio_offload_ext_client->StartAudioOffload(std::move(*config),
3295 std::move(controller_request));
3296
3297 fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
3298 audio_offload_controller_client.Bind(std::move(controller_handle));
3299
3300 std::optional<zx_status_t> audio_offload_controller_epitaph;
3301 audio_offload_controller_client.set_error_handler(
3302 [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
3303
3304 size_t on_started_count = 0;
3305 audio_offload_controller_client.events().OnStarted = [&]() {
3306 on_started_count++;
3307 };
3308
3309 RunLoopUntilIdle();
3310
3311 // Verify that OnStarted event was sent successfully
3312 EXPECT_EQ(on_started_count, 1u);
3313
3314 // Verify that |audio_offload_controller_client| was not closed with an
3315 // epitaph
3316 ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
3317
3318 bool stop_callback_called = false;
3319 auto callback = [&stop_callback_called](
3320 fidlbredr::AudioOffloadController_Stop_Result result) {
3321 stop_callback_called = true;
3322 };
3323
3324 audio_offload_controller_client->Stop(std::move(callback));
3325
3326 RunLoopUntilIdle();
3327
3328 // Verify that audio offload stopped successfully
3329 ASSERT_TRUE(stop_callback_called);
3330
3331 size_t cb_count = 0;
3332 audio_offload_controller_client->Stop(
3333 [&cb_count](fidlbredr::AudioOffloadController_Stop_Result result) {
3334 cb_count++;
3335 });
3336
3337 RunLoopUntilIdle();
3338
3339 // Verify that stopping audio offload has no effect when it's already stopped
3340 EXPECT_EQ(cb_count, 1u);
3341 }
3342
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadControllerUnbindStopsAudioOffload)3343 TEST_P(AndroidSupportedFeaturesTest,
3344 AudioOffloadControllerUnbindStopsAudioOffload) {
3345 FakeChannel::WeakPtr fake_channel;
3346 adapter()->fake_bredr()->set_l2cap_channel_callback(
3347 [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
3348
3349 const bool android_vendor_ext_support = GetParam().first;
3350 const uint32_t a2dp_offload_capabilities = GetParam().second;
3351
3352 if (android_vendor_ext_support) {
3353 adapter()->mutable_state().controller_features |=
3354 FeaturesBits::kAndroidVendorExtensions;
3355
3356 bt::StaticPacket<
3357 android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
3358 params;
3359 params.SetToZeros();
3360 params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
3361 params.view().version_supported().major_number().Write(0);
3362 params.view().version_supported().minor_number().Write(98);
3363 params.view()
3364 .a2dp_source_offload_capability_mask()
3365 .BackingStorage()
3366 .UncheckedWriteUInt(a2dp_offload_capabilities);
3367 adapter()->mutable_state().android_vendor_capabilities =
3368 bt::gap::AndroidVendorCapabilities::New(params.view());
3369 }
3370
3371 const bt::PeerId peer_id(1);
3372 const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
3373
3374 // Set L2CAP channel parameters
3375 fidlbredr::L2capParameters l2cap_params;
3376 fidlbredr::ConnectParameters conn_params;
3377 l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
3378 l2cap_params.set_parameters(fbt::ChannelParameters());
3379 conn_params.set_l2cap(std::move(l2cap_params));
3380
3381 std::optional<fidlbredr::Channel> response_channel;
3382 client()->Connect(
3383 fidl_peer_id,
3384 std::move(conn_params),
3385 [&response_channel](fidlbredr::Profile_Connect_Result result) {
3386 ASSERT_TRUE(result.is_response());
3387 response_channel = std::move(result.response().channel);
3388 });
3389 RunLoopUntilIdle();
3390 ASSERT_TRUE(response_channel.has_value());
3391 if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
3392 EXPECT_FALSE(response_channel->has_ext_audio_offload());
3393 return;
3394 }
3395 ASSERT_TRUE(response_channel->has_ext_audio_offload());
3396
3397 // Set Audio Offload Configuration Values
3398 std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
3399 fidlbredr::AudioOffloadFeatures::New();
3400 std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
3401 fidlbredr::AudioSbcSupport::New();
3402 codec->set_sbc(std::move(*codec_value));
3403
3404 std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
3405 std::make_unique<fidlbredr::AudioEncoderSettings>();
3406 std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
3407 fuchsia::media::SbcEncoderSettings::New();
3408 encoder_settings->set_sbc(*encoder_settings_value);
3409
3410 std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
3411 std::make_unique<fidlbredr::AudioOffloadConfiguration>();
3412 config->set_codec(std::move(*codec));
3413 config->set_max_latency(10);
3414 config->set_scms_t_enable(true);
3415 config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
3416 config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
3417 config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
3418 config->set_encoded_bit_rate(10);
3419 config->set_encoder_settings(std::move(*encoder_settings));
3420
3421 fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
3422 response_channel->mutable_ext_audio_offload()->Bind();
3423 fidlbredr::AudioOffloadControllerHandle controller_handle;
3424 fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
3425 controller_handle.NewRequest();
3426 audio_offload_ext_client->StartAudioOffload(std::move(*config),
3427 std::move(controller_request));
3428
3429 fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
3430 audio_offload_controller_client.Bind(std::move(controller_handle));
3431
3432 std::optional<zx_status_t> audio_offload_controller_epitaph;
3433 audio_offload_controller_client.set_error_handler(
3434 [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
3435
3436 size_t on_started_count = 0;
3437 audio_offload_controller_client.events().OnStarted = [&]() {
3438 on_started_count++;
3439 };
3440
3441 RunLoopUntilIdle();
3442
3443 // Verify that OnStarted event was sent successfully
3444 EXPECT_EQ(on_started_count, 1u);
3445
3446 // Verify that |audio_offload_controller_client| was not closed with an
3447 // epitaph
3448 ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
3449
3450 bt::l2cap::A2dpOffloadStatus a2dp_offload_status =
3451 fake_channel->a2dp_offload_status();
3452
3453 // Verify that |a2dp_offload_status| is set to started
3454 ASSERT_EQ(bt::l2cap::A2dpOffloadStatus::kStarted, a2dp_offload_status);
3455
3456 audio_offload_controller_client.Unbind();
3457
3458 RunLoopUntilIdle();
3459
3460 // Verify that client is unbound from fidl channel
3461 ASSERT_FALSE(audio_offload_controller_client.is_bound());
3462
3463 a2dp_offload_status = fake_channel->a2dp_offload_status();
3464
3465 // Verify that |a2dp_offload_status| is set to stopped
3466 ASSERT_EQ(bt::l2cap::A2dpOffloadStatus::kStopped, a2dp_offload_status);
3467 }
3468
3469 const std::vector<std::pair<bool, uint32_t>> kVendorCapabilitiesParams = {
3470 {{true, static_cast<uint32_t>(android_emb::A2dpCodecType::SBC)},
3471 {true, static_cast<uint32_t>(android_emb::A2dpCodecType::AAC)},
3472 {true,
3473 static_cast<uint32_t>(android_emb::A2dpCodecType::SBC) |
3474 static_cast<uint32_t>(android_emb::A2dpCodecType::AAC)},
3475 {true, 0},
3476 {false, 0}}};
3477 INSTANTIATE_TEST_SUITE_P(ProfileServerTestFakeAdapter,
3478 AndroidSupportedFeaturesTest,
3479 ::testing::ValuesIn(kVendorCapabilitiesParams));
3480
TEST_F(ProfileServerTestFakeAdapter,ServiceUuidSearchResultRelayedToFidlClient)3481 TEST_F(ProfileServerTestFakeAdapter,
3482 ServiceUuidSearchResultRelayedToFidlClient) {
3483 fidlbredr::SearchResultsHandle search_results_handle;
3484 FakeSearchResults search_results(search_results_handle.NewRequest(),
3485 dispatcher());
3486
3487 fidlbredr::ServiceClassProfileIdentifier search_uuid =
3488 fidlbredr::ServiceClassProfileIdentifier::AUDIO_SINK;
3489
3490 EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 0u);
3491 EXPECT_EQ(search_results.service_found_count(), 0u);
3492
3493 // FIDL client registers a service search.
3494 fidlbredr::ProfileSearchRequest request;
3495 request.set_service_uuid(search_uuid);
3496 request.set_attr_ids({});
3497 request.set_results(std::move(search_results_handle));
3498 client()->Search(std::move(request));
3499 RunLoopUntilIdle();
3500
3501 EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 1u);
3502
3503 // Trigger a match on the service search with some data. Should be received by
3504 // the FIDL client.
3505 bt::PeerId peer_id = bt::PeerId{10};
3506 bt::UUID uuid(static_cast<uint32_t>(search_uuid));
3507
3508 bt::sdp::AttributeId attr_id = 50; // Random Attribute ID
3509 bt::sdp::DataElement elem = bt::sdp::DataElement();
3510 elem.SetUrl("https://foobar.dev"); // Random URL
3511 auto attributes = std::map<bt::sdp::AttributeId, bt::sdp::DataElement>();
3512 attributes.emplace(attr_id, std::move(elem));
3513 adapter()->fake_bredr()->TriggerServiceFound(
3514 peer_id, uuid, std::move(attributes));
3515
3516 RunLoopUntilIdle();
3517
3518 EXPECT_EQ(search_results.service_found_count(), 1u);
3519 EXPECT_EQ(search_results.peer_id().value().value, peer_id.value());
3520 EXPECT_EQ(search_results.attributes().value().size(), 1u);
3521 EXPECT_EQ(search_results.attributes().value()[0].id(), attr_id);
3522 EXPECT_EQ(search_results.attributes().value()[0].element().url(),
3523 std::string("https://foobar.dev"));
3524 }
3525
TEST_F(ProfileServerTestFakeAdapter,FullUuidSearchResultRelayedToFidlClient)3526 TEST_F(ProfileServerTestFakeAdapter, FullUuidSearchResultRelayedToFidlClient) {
3527 fidlbredr::SearchResultsHandle search_results_handle;
3528 FakeSearchResults search_results(search_results_handle.NewRequest(),
3529 dispatcher());
3530
3531 EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 0u);
3532 EXPECT_EQ(search_results.service_found_count(), 0u);
3533
3534 // FIDL client registers a service search.
3535 fuchsia::bluetooth::Uuid search_uuid =
3536 fidl_helpers::UuidToFidl(bt::sdp::profile::kHandsfree);
3537 fidlbredr::ProfileSearchRequest request;
3538 request.set_full_uuid(search_uuid);
3539 request.set_attr_ids({});
3540 request.set_results(std::move(search_results_handle));
3541 client()->Search(std::move(request));
3542 RunLoopUntilIdle();
3543
3544 EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 1u);
3545
3546 // Trigger a match on the service search with some data. Should be received by
3547 // the FIDL client.
3548 bt::PeerId peer_id = bt::PeerId{10};
3549 bt::UUID uuid = bt::sdp::profile::kHandsfree;
3550
3551 bt::sdp::AttributeId attr_id = 50; // Random Attribute ID
3552 bt::sdp::DataElement elem = bt::sdp::DataElement();
3553 elem.SetUrl("https://foobar.dev"); // Random URL
3554 auto attributes = std::map<bt::sdp::AttributeId, bt::sdp::DataElement>();
3555 attributes.emplace(attr_id, std::move(elem));
3556 adapter()->fake_bredr()->TriggerServiceFound(
3557 peer_id, uuid, std::move(attributes));
3558
3559 RunLoopUntilIdle();
3560
3561 EXPECT_EQ(search_results.service_found_count(), 1u);
3562 EXPECT_EQ(search_results.peer_id().value().value, peer_id.value());
3563 EXPECT_EQ(search_results.attributes().value().size(), 1u);
3564 EXPECT_EQ(search_results.attributes().value()[0].id(), attr_id);
3565 EXPECT_EQ(search_results.attributes().value()[0].element().url(),
3566 std::string("https://foobar.dev"));
3567 }
3568
TEST_F(ProfileServerTestFakeAdapter,SearchWithMissingUuidFails)3569 TEST_F(ProfileServerTestFakeAdapter, SearchWithMissingUuidFails) {
3570 fidlbredr::SearchResultsHandle search_results_handle;
3571 FakeSearchResults search_results(search_results_handle.NewRequest(),
3572 dispatcher());
3573
3574 // Neither `service_uuid` nor `full_uid` is set
3575 fidlbredr::ProfileSearchRequest request;
3576 request.set_results(std::move(search_results_handle));
3577 client()->Search(std::move(request));
3578 RunLoopUntilIdle();
3579 EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 0u);
3580 EXPECT_TRUE(search_results.closed());
3581 }
3582
TEST_F(ProfileServerTestFakeAdapter,SearchWithServiceAndFullUuidFails)3583 TEST_F(ProfileServerTestFakeAdapter, SearchWithServiceAndFullUuidFails) {
3584 fidlbredr::SearchResultsHandle search_results_handle;
3585 FakeSearchResults search_results(search_results_handle.NewRequest(),
3586 dispatcher());
3587
3588 fidlbredr::ServiceClassProfileIdentifier search_uuid =
3589 fidlbredr::ServiceClassProfileIdentifier::AUDIO_SINK;
3590
3591 fidlbredr::ProfileSearchRequest request;
3592 request.set_results(std::move(search_results_handle));
3593 request.set_service_uuid(search_uuid);
3594 request.set_full_uuid(fidl_helpers::UuidToFidl(bt::sdp::profile::kAudioSink));
3595 client()->Search(std::move(request));
3596 RunLoopUntilIdle();
3597 EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 0u);
3598 EXPECT_TRUE(search_results.closed());
3599 }
3600
TEST_F(ProfileServerTestFakeAdapter,SearchWithMissingResultsClientFails)3601 TEST_F(ProfileServerTestFakeAdapter, SearchWithMissingResultsClientFails) {
3602 // results is not set
3603 fidlbredr::ProfileSearchRequest request;
3604 request.set_service_uuid(
3605 fidlbredr::ServiceClassProfileIdentifier::AUDIO_SINK);
3606 client()->Search(std::move(request));
3607 RunLoopUntilIdle();
3608 EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 0u);
3609 }
3610
TEST_F(ProfileServerTestFakeAdapter,SearchWithMissingAttrIdsSucceeds)3611 TEST_F(ProfileServerTestFakeAdapter, SearchWithMissingAttrIdsSucceeds) {
3612 fidlbredr::SearchResultsHandle search_results_handle;
3613 FakeSearchResults search_results(search_results_handle.NewRequest(),
3614 dispatcher());
3615
3616 fidlbredr::ProfileSearchRequest request;
3617 request.set_service_uuid(
3618 fidlbredr::ServiceClassProfileIdentifier::AUDIO_SINK);
3619 request.set_results(std::move(search_results_handle));
3620 client()->Search(std::move(request));
3621 RunLoopUntilIdle();
3622 EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 1u);
3623 }
3624
TEST_F(ProfileServerTestScoConnected,ScoConnectionRead2Packets)3625 TEST_F(ProfileServerTestScoConnected, ScoConnectionRead2Packets) {
3626 // Queue a read request before the packet is received.
3627 std::optional<fidlbredr::RxPacketStatus> packet_status;
3628 std::optional<std::vector<uint8_t>> packet;
3629 sco_connection()->Read(
3630 [&](::fuchsia::bluetooth::bredr::ScoConnection_Read_Result result) {
3631 ASSERT_TRUE(result.is_response());
3632 packet_status = result.response().status_flag();
3633 packet = std::move(*result.response().mutable_data());
3634 });
3635 RunLoopUntilIdle();
3636 EXPECT_FALSE(packet_status);
3637 EXPECT_FALSE(packet);
3638
3639 bt::StaticByteBuffer packet_buffer_0(
3640 bt::LowerBits(sco_handle()),
3641 bt::UpperBits(sco_handle()) |
3642 0x30, // handle + packet status flag: kDataPartiallyLost
3643 0x01, // payload length
3644 0x00 // payload
3645 );
3646 bt::BufferView packet_buffer_0_payload =
3647 packet_buffer_0.view(sizeof(bt::hci_spec::SynchronousDataHeader));
3648 test_device()->SendScoDataChannelPacket(packet_buffer_0);
3649 RunLoopUntilIdle();
3650 ASSERT_TRUE(packet_status);
3651 EXPECT_EQ(packet_status.value(),
3652 fidlbredr::RxPacketStatus::DATA_PARTIALLY_LOST);
3653 ASSERT_TRUE(packet);
3654 EXPECT_THAT(packet.value(),
3655 ::testing::ElementsAreArray(packet_buffer_0_payload));
3656 packet_status.reset();
3657 packet.reset();
3658
3659 // Receive a second packet. This time, receive the packet before Read() is
3660 // called.
3661 bt::StaticByteBuffer packet_buffer_1(
3662 bt::LowerBits(sco_handle()),
3663 bt::UpperBits(
3664 sco_handle()), // handle + packet status flag: kCorrectlyReceived
3665 0x01, // payload length
3666 0x01 // payload
3667 );
3668 bt::BufferView packet_buffer_1_payload =
3669 packet_buffer_1.view(sizeof(bt::hci_spec::SynchronousDataHeader));
3670 test_device()->SendScoDataChannelPacket(packet_buffer_1);
3671 RunLoopUntilIdle();
3672
3673 sco_connection()->Read(
3674 [&](::fuchsia::bluetooth::bredr::ScoConnection_Read_Result result) {
3675 ASSERT_TRUE(result.is_response());
3676 packet_status = result.response().status_flag();
3677 packet = std::move(*result.response().mutable_data());
3678 });
3679 RunLoopUntilIdle();
3680 ASSERT_TRUE(packet_status);
3681 EXPECT_EQ(packet_status.value(),
3682 fidlbredr::RxPacketStatus::CORRECTLY_RECEIVED_DATA);
3683 ASSERT_TRUE(packet);
3684 EXPECT_THAT(packet.value(),
3685 ::testing::ElementsAreArray(packet_buffer_1_payload));
3686 }
3687
TEST_F(ProfileServerTestScoConnected,ScoConnectionReadWhileReadPendingClosesConnection)3688 TEST_F(ProfileServerTestScoConnected,
3689 ScoConnectionReadWhileReadPendingClosesConnection) {
3690 std::optional<fidlbredr::RxPacketStatus> packet_status_0;
3691 std::optional<std::vector<uint8_t>> packet_0;
3692 sco_connection()->Read(
3693 [&](::fuchsia::bluetooth::bredr::ScoConnection_Read_Result result) {
3694 ASSERT_TRUE(result.is_response());
3695 packet_status_0 = result.response().status_flag();
3696 packet_0 = std::move(*result.response().mutable_data());
3697 });
3698
3699 RunLoopUntilIdle();
3700 EXPECT_FALSE(packet_status_0);
3701 EXPECT_FALSE(packet_0);
3702
3703 std::optional<fidlbredr::RxPacketStatus> packet_status_1;
3704 std::optional<std::vector<uint8_t>> packet_1;
3705 sco_connection()->Read(
3706 [&](::fuchsia::bluetooth::bredr::ScoConnection_Read_Result result) {
3707 ASSERT_TRUE(result.is_response());
3708 packet_status_1 = result.response().status_flag();
3709 packet_1 = std::move(*result.response().mutable_data());
3710 });
3711
3712 RunLoopUntilIdle();
3713 EXPECT_FALSE(packet_status_0);
3714 EXPECT_FALSE(packet_0);
3715 EXPECT_FALSE(packet_status_1);
3716 EXPECT_FALSE(packet_1);
3717 EXPECT_FALSE(sco_connection());
3718 ASSERT_TRUE(sco_conn_error());
3719 EXPECT_EQ(sco_conn_error().value(), ZX_ERR_BAD_STATE);
3720 }
3721
TEST_F(ProfileServerTestOffloadedScoConnected,ScoConnectionReadFails)3722 TEST_F(ProfileServerTestOffloadedScoConnected, ScoConnectionReadFails) {
3723 sco_connection()->Read(
3724 [&](::fuchsia::bluetooth::bredr::ScoConnection_Read_Result result) {
3725 FAIL();
3726 });
3727 RunLoopUntilIdle();
3728 EXPECT_FALSE(sco_connection());
3729 ASSERT_TRUE(sco_conn_error());
3730 EXPECT_EQ(sco_conn_error().value(), ZX_ERR_IO_NOT_PRESENT);
3731 }
3732
TEST_F(ProfileServerTestScoConnected,ScoConnectionWriteTwice)3733 TEST_F(ProfileServerTestScoConnected, ScoConnectionWriteTwice) {
3734 bt::StaticByteBuffer payload_0(0x00);
3735 bt::DynamicByteBuffer packet_buffer_0 = bt::testing::ScoDataPacket(
3736 sco_handle(),
3737 bt::hci_spec::SynchronousDataPacketStatusFlag::kCorrectlyReceived,
3738 payload_0.view());
3739
3740 bt::StaticByteBuffer payload_1(0x01);
3741 bt::DynamicByteBuffer packet_buffer_1 = bt::testing::ScoDataPacket(
3742 sco_handle(),
3743 bt::hci_spec::SynchronousDataPacketStatusFlag::kCorrectlyReceived,
3744 payload_1.view());
3745
3746 int sco_cb_count = 0;
3747 test_device()->SetScoDataCallback([&](const bt::ByteBuffer& buffer) {
3748 if (sco_cb_count == 0) {
3749 EXPECT_THAT(buffer, ::testing::ElementsAreArray(packet_buffer_0));
3750 } else if (sco_cb_count == 1) {
3751 EXPECT_THAT(buffer, ::testing::ElementsAreArray(packet_buffer_1));
3752 } else {
3753 ADD_FAILURE() << "Unexpected packet sent";
3754 }
3755 sco_cb_count++;
3756 });
3757 int write_cb_0_count = 0;
3758 fidlbredr::ScoConnectionWriteRequest request_0;
3759 request_0.set_data(payload_0.ToVector());
3760 sco_connection()->Write(std::move(request_0),
3761 [&](fidlbredr::ScoConnection_Write_Result result) {
3762 ASSERT_TRUE(result.is_response());
3763 write_cb_0_count++;
3764 });
3765 RunLoopUntilIdle();
3766 EXPECT_EQ(sco_cb_count, 1);
3767 EXPECT_EQ(write_cb_0_count, 1);
3768
3769 int write_cb_1_count = 0;
3770 fidlbredr::ScoConnectionWriteRequest request_1;
3771 request_1.set_data(payload_1.ToVector());
3772 sco_connection()->Write(std::move(request_1),
3773 [&](fidlbredr::ScoConnection_Write_Result result) {
3774 ASSERT_TRUE(result.is_response());
3775 write_cb_1_count++;
3776 });
3777 RunLoopUntilIdle();
3778 EXPECT_EQ(sco_cb_count, 2);
3779 EXPECT_EQ(write_cb_1_count, 1);
3780
3781 test_device()->ClearScoDataCallback();
3782 }
3783
TEST_F(ProfileServerTestScoConnected,ScoConnectionWriteMissingDataField)3784 TEST_F(ProfileServerTestScoConnected, ScoConnectionWriteMissingDataField) {
3785 int write_cb_count = 0;
3786 // The `data` field is not set.
3787 fidlbredr::ScoConnectionWriteRequest request;
3788 sco_connection()->Write(
3789 std::move(request),
3790 [&](fidlbredr::ScoConnection_Write_Result result) { write_cb_count++; });
3791 RunLoopUntilIdle();
3792 EXPECT_EQ(write_cb_count, 0);
3793 EXPECT_FALSE(sco_connection());
3794 ASSERT_TRUE(sco_conn_error());
3795 EXPECT_EQ(sco_conn_error().value(), ZX_ERR_INVALID_ARGS);
3796 }
3797
TEST_F(ProfileServerTestOffloadedScoConnected,ScoConnectionWriteFails)3798 TEST_F(ProfileServerTestOffloadedScoConnected, ScoConnectionWriteFails) {
3799 int write_cb_count = 0;
3800 fidlbredr::ScoConnectionWriteRequest request;
3801 request.set_data({0x00});
3802 sco_connection()->Write(
3803 std::move(request),
3804 [&](fidlbredr::ScoConnection_Write_Result result) { write_cb_count++; });
3805 RunLoopUntilIdle();
3806 EXPECT_EQ(write_cb_count, 0);
3807 EXPECT_FALSE(sco_connection());
3808 ASSERT_TRUE(sco_conn_error());
3809 EXPECT_EQ(sco_conn_error().value(), ZX_ERR_IO_NOT_PRESENT);
3810 }
3811
3812 } // namespace
3813 } // namespace bthost
3814