1 /*
2 * Copyright 2021 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
3 * www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "state_machine.h"
19
20 #include <bluetooth/log.h>
21 #include <gmock/gmock.h>
22 #include <gtest/gtest.h>
23 #include <log/log.h>
24
25 #include <functional>
26
27 #include "bta/le_audio/content_control_id_keeper.h"
28 #include "bta_gatt_api_mock.h"
29 #include "bta_gatt_queue_mock.h"
30 #include "btm_api_mock.h"
31 #include "client_parser.h"
32 #include "common/init_flags.h"
33 #include "fake_osi.h"
34 #include "hci/controller_interface_mock.h"
35 #include "internal_include/stack_config.h"
36 #include "le_audio/le_audio_types.h"
37 #include "le_audio_set_configuration_provider.h"
38 #include "mock_codec_manager.h"
39 #include "mock_csis_client.h"
40 #include "stack/include/bt_types.h"
41 #include "test/common/mock_functions.h"
42 #include "test/mock/mock_main_shim_entry.h"
43 #include "test/mock/mock_stack_btm_iso.h"
44 #include "types/bt_transport.h"
45
46 using ::bluetooth::le_audio::DeviceConnectState;
47 using ::bluetooth::le_audio::codec_spec_caps::
48 kLeAudioCodecChannelCountSingleChannel;
49 using ::bluetooth::le_audio::codec_spec_caps::
50 kLeAudioCodecChannelCountTwoChannel;
51 using ::bluetooth::le_audio::types::LeAudioContextType;
52 using ::testing::_;
53 using ::testing::AnyNumber;
54 using ::testing::AtLeast;
55 using ::testing::DoAll;
56 using ::testing::Invoke;
57 using ::testing::NiceMock;
58 using ::testing::Return;
59 using ::testing::SaveArg;
60 using ::testing::Test;
61
62 extern struct fake_osi_alarm_set_on_mloop fake_osi_alarm_set_on_mloop_;
63
64 void osi_property_set_bool(const char* key, bool value);
65
66 constexpr uint8_t media_ccid = 0xC0;
67 constexpr auto media_context = LeAudioContextType::MEDIA;
68
69 constexpr uint8_t call_ccid = 0xD0;
70 constexpr auto call_context = LeAudioContextType::CONVERSATIONAL;
71
72 const std::string kSmpOptions("mock smp options");
get_pts_avrcp_test(void)73 bool get_pts_avrcp_test(void) { return false; }
get_pts_secure_only_mode(void)74 bool get_pts_secure_only_mode(void) { return false; }
get_pts_conn_updates_disabled(void)75 bool get_pts_conn_updates_disabled(void) { return false; }
get_pts_crosskey_sdp_disable(void)76 bool get_pts_crosskey_sdp_disable(void) { return false; }
get_pts_smp_options(void)77 const std::string* get_pts_smp_options(void) { return &kSmpOptions; }
get_pts_smp_failure_case(void)78 int get_pts_smp_failure_case(void) { return 123; }
get_pts_force_eatt_for_notifications(void)79 bool get_pts_force_eatt_for_notifications(void) { return false; }
get_pts_connect_eatt_unconditionally(void)80 bool get_pts_connect_eatt_unconditionally(void) { return false; }
get_pts_connect_eatt_before_encryption(void)81 bool get_pts_connect_eatt_before_encryption(void) { return false; }
get_pts_unencrypt_broadcast(void)82 bool get_pts_unencrypt_broadcast(void) { return false; }
get_pts_eatt_peripheral_collision_support(void)83 bool get_pts_eatt_peripheral_collision_support(void) { return false; }
get_pts_force_le_audio_multiple_contexts_metadata(void)84 bool get_pts_force_le_audio_multiple_contexts_metadata(void) { return false; }
get_pts_le_audio_disable_ases_before_stopping(void)85 bool get_pts_le_audio_disable_ases_before_stopping(void) { return false; }
get_all(void)86 config_t* get_all(void) { return nullptr; }
87
88 stack_config_t mock_stack_config{
89 .get_pts_avrcp_test = get_pts_avrcp_test,
90 .get_pts_secure_only_mode = get_pts_secure_only_mode,
91 .get_pts_conn_updates_disabled = get_pts_conn_updates_disabled,
92 .get_pts_crosskey_sdp_disable = get_pts_crosskey_sdp_disable,
93 .get_pts_smp_options = get_pts_smp_options,
94 .get_pts_smp_failure_case = get_pts_smp_failure_case,
95 .get_pts_force_eatt_for_notifications =
96 get_pts_force_eatt_for_notifications,
97 .get_pts_connect_eatt_unconditionally =
98 get_pts_connect_eatt_unconditionally,
99 .get_pts_connect_eatt_before_encryption =
100 get_pts_connect_eatt_before_encryption,
101 .get_pts_unencrypt_broadcast = get_pts_unencrypt_broadcast,
102 .get_pts_eatt_peripheral_collision_support =
103 get_pts_eatt_peripheral_collision_support,
104 .get_pts_force_le_audio_multiple_contexts_metadata =
105 get_pts_force_le_audio_multiple_contexts_metadata,
106 .get_pts_le_audio_disable_ases_before_stopping =
107 get_pts_le_audio_disable_ases_before_stopping,
108 .get_all = get_all,
109 };
stack_config_get_interface(void)110 const stack_config_t* stack_config_get_interface(void) {
111 return &mock_stack_config;
112 }
113
114 namespace bluetooth::le_audio {
115 namespace internal {
116
117 // Just some arbitrary initial handles - it has no real meaning
118 #define ATTR_HANDLE_ASCS_POOL_START (0x0000 | 32)
119 #define ATTR_HANDLE_PACS_POOL_START (0xFF00 | 64)
120
121 constexpr LeAudioContextType kContextTypeUnspecified =
122 static_cast<LeAudioContextType>(0x0001);
123 constexpr LeAudioContextType kContextTypeConversational =
124 static_cast<LeAudioContextType>(0x0002);
125 constexpr LeAudioContextType kContextTypeMedia =
126 static_cast<LeAudioContextType>(0x0004);
127 constexpr LeAudioContextType kContextTypeLive =
128 static_cast<LeAudioContextType>(0x0040);
129 constexpr LeAudioContextType kContextTypeSoundEffects =
130 static_cast<LeAudioContextType>(0x0080);
131 constexpr LeAudioContextType kContextTypeRingtone =
132 static_cast<LeAudioContextType>(0x0200);
133
134 namespace codec_specific {
135
136 constexpr uint8_t kLc3CodingFormat = 0x06;
137
138 // Reference Codec Capabilities values to test against
139 constexpr uint8_t kCapTypeSupportedSamplingFrequencies = 0x01;
140 constexpr uint8_t kCapTypeSupportedFrameDurations = 0x02;
141 constexpr uint8_t kCapTypeAudioChannelCount = 0x03;
142 constexpr uint8_t kCapTypeSupportedOctetsPerCodecFrame = 0x04;
143 // constexpr uint8_t kCapTypeSupportedLc3CodecFramesPerSdu = 0x05;
144
145 // constexpr uint8_t kCapSamplingFrequency8000Hz = 0x0001;
146 // constexpr uint8_t kCapSamplingFrequency11025Hz = 0x0002;
147 constexpr uint8_t kCapSamplingFrequency16000Hz = 0x0004;
148 // constexpr uint8_t kCapSamplingFrequency22050Hz = 0x0008;
149 // constexpr uint8_t kCapSamplingFrequency24000Hz = 0x0010;
150 constexpr uint8_t kCapSamplingFrequency32000Hz = 0x0020;
151 // constexpr uint8_t kCapSamplingFrequency44100Hz = 0x0040;
152 constexpr uint8_t kCapSamplingFrequency48000Hz = 0x0080;
153 // constexpr uint8_t kCapSamplingFrequency88200Hz = 0x0100;
154 // constexpr uint8_t kCapSamplingFrequency96000Hz = 0x0200;
155 // constexpr uint8_t kCapSamplingFrequency176400Hz = 0x0400;
156 // constexpr uint8_t kCapSamplingFrequency192000Hz = 0x0800;
157 // constexpr uint8_t kCapSamplingFrequency384000Hz = 0x1000;
158
159 constexpr uint8_t kCapFrameDuration7p5ms = 0x01;
160 constexpr uint8_t kCapFrameDuration10ms = 0x02;
161 // constexpr uint8_t kCapFrameDuration7p5msPreferred = 0x10;
162 constexpr uint8_t kCapFrameDuration10msPreferred = 0x20;
163 } // namespace codec_specific
164
165 namespace ascs {
166 constexpr uint8_t kAseStateIdle = 0x00;
167 constexpr uint8_t kAseStateCodecConfigured = 0x01;
168 constexpr uint8_t kAseStateQoSConfigured = 0x02;
169 constexpr uint8_t kAseStateEnabling = 0x03;
170 constexpr uint8_t kAseStateStreaming = 0x04;
171 constexpr uint8_t kAseStateDisabling = 0x05;
172 constexpr uint8_t kAseStateReleasing = 0x06;
173
174 // constexpr uint8_t kAseParamDirectionServerIsAudioSink = 0x01;
175 // constexpr uint8_t kAseParamDirectionServerIsAudioSource = 0x02;
176
177 constexpr uint8_t kAseParamFramingUnframedSupported = 0x00;
178 // constexpr uint8_t kAseParamFramingUnframedNotSupported = 0x01;
179
180 // constexpr uint8_t kAseParamPreferredPhy1M = 0x01;
181 // constexpr uint8_t kAseParamPreferredPhy2M = 0x02;
182 // constexpr uint8_t kAseParamPreferredPhyCoded = 0x04;
183
184 constexpr uint8_t kAseCtpOpcodeMaxVal = client_parser::ascs::kCtpOpcodeRelease;
185
186 } // namespace ascs
187
GetTestAddress(uint8_t index)188 static RawAddress GetTestAddress(uint8_t index) {
189 return {{0xC0, 0xDE, 0xC0, 0xDE, 0x00, index}};
190 }
191
192 class MockLeAudioGroupStateMachineCallbacks
193 : public LeAudioGroupStateMachine::Callbacks {
194 public:
195 MockLeAudioGroupStateMachineCallbacks() = default;
196 MockLeAudioGroupStateMachineCallbacks(
197 const MockLeAudioGroupStateMachineCallbacks&) = delete;
198 MockLeAudioGroupStateMachineCallbacks& operator=(
199 const MockLeAudioGroupStateMachineCallbacks&) = delete;
200
201 ~MockLeAudioGroupStateMachineCallbacks() override = default;
202 MOCK_METHOD((void), StatusReportCb,
203 (int group_id, bluetooth::le_audio::GroupStreamStatus status),
204 (override));
205 MOCK_METHOD((void), OnStateTransitionTimeout, (int group_id), (override));
206 MOCK_METHOD((void), OnUpdatedCisConfiguration,
207 (int group_id, uint8_t direction), (override));
208 MOCK_METHOD((void), OnDeviceAutonomousStateTransitionTimeout,
209 (LeAudioDevice * leAudioDevice), (override));
210 };
211
212 class MockAseRemoteStateMachine {
213 public:
214 MockAseRemoteStateMachine() = default;
215 MockAseRemoteStateMachine& operator=(const MockAseRemoteStateMachine&) =
216 delete;
217 ~MockAseRemoteStateMachine() = default;
218 MOCK_METHOD((void), AseCtpConfigureCodecHandler,
219 (LeAudioDevice * device, std::vector<uint8_t> value,
220 GATT_WRITE_OP_CB cb, void* cb_data));
221 MOCK_METHOD((void), AseCtpConfigureQosHandler,
222 (LeAudioDevice * device, std::vector<uint8_t> value,
223 GATT_WRITE_OP_CB cb, void* cb_data));
224 MOCK_METHOD((void), AseCtpEnableHandler,
225 (LeAudioDevice * device, std::vector<uint8_t> value,
226 GATT_WRITE_OP_CB cb, void* cb_data));
227 MOCK_METHOD((void), AseCtpReceiverStartReadyHandler,
228 (LeAudioDevice * device, std::vector<uint8_t> value,
229 GATT_WRITE_OP_CB cb, void* cb_data));
230 MOCK_METHOD((void), AseCtpDisableHandler,
231 (LeAudioDevice * device, std::vector<uint8_t> value,
232 GATT_WRITE_OP_CB cb, void* cb_data));
233 MOCK_METHOD((void), AseCtpReceiverStopReadyHandler,
234 (LeAudioDevice * device, std::vector<uint8_t> value,
235 GATT_WRITE_OP_CB cb, void* cb_data));
236 MOCK_METHOD((void), AseCtpUpdateMetadataHandler,
237 (LeAudioDevice * device, std::vector<uint8_t> value,
238 GATT_WRITE_OP_CB cb, void* cb_data));
239 MOCK_METHOD((void), AseCtpReleaseHandler,
240 (LeAudioDevice * device, std::vector<uint8_t> value,
241 GATT_WRITE_OP_CB cb, void* cb_data));
242 };
243
244 class StateMachineTestBase : public Test {
245 protected:
246 uint8_t ase_id_last_assigned = types::ase::kAseIdInvalid;
247 uint8_t additional_snk_ases = 0;
248 uint8_t additional_src_ases = 0;
249 uint8_t channel_count_ = kLeAudioCodecChannelCountSingleChannel;
250 uint16_t sample_freq_ = codec_specific::kCapSamplingFrequency16000Hz |
251 codec_specific::kCapSamplingFrequency32000Hz;
252 uint8_t channel_allocations_sink_ =
253 ::bluetooth::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft |
254 ::bluetooth::le_audio::codec_spec_conf::kLeAudioLocationFrontRight;
255 uint8_t channel_allocations_source_ =
256 ::bluetooth::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft |
257 ::bluetooth::le_audio::codec_spec_conf::kLeAudioLocationFrontRight;
258
259 /* Use to simulated error status on Cis creation */
260 bool overwrite_cis_status_;
261 bool use_cis_retry_cnt_;
262 int retry_cis_established_cnt_;
263 bool do_not_send_cis_establish_event_;
264 uint8_t overwrite_cis_status_idx_;
265 std::vector<uint8_t> cis_status_;
266
267 /* Keep ASE in releasing state */
268 bool stay_in_releasing_state_;
269
270 /* Use for single test to simulate late ASE notifications */
271 bool stop_inject_configured_ase_after_first_ase_configured_;
272
SetUp()273 virtual void SetUp() override {
274 __android_log_set_minimum_priority(ANDROID_LOG_DEBUG);
275 reset_mock_function_count_map();
276 bluetooth::manager::SetMockBtmInterface(&btm_interface);
277 gatt::SetMockBtaGattInterface(&gatt_interface);
278 gatt::SetMockBtaGattQueue(&gatt_queue);
279 bluetooth::hci::testing::mock_controller_ = &controller_;
280
281 overwrite_cis_status_idx_ = 0;
282 use_cis_retry_cnt_ = false;
283 retry_cis_established_cnt_ = 0;
284 overwrite_cis_status_ = false;
285 do_not_send_cis_establish_event_ = false;
286 stay_in_releasing_state_ = false;
287 stop_inject_configured_ase_after_first_ase_configured_ = false;
288 cis_status_.clear();
289
290 LeAudioGroupStateMachine::Initialize(&mock_callbacks_);
291
292 ContentControlIdKeeper::GetInstance()->Start();
293
294 ON_CALL(mock_callbacks_, StatusReportCb(_, _))
295 .WillByDefault(Invoke(
296 [](int group_id, bluetooth::le_audio::GroupStreamStatus status) {
297 log::debug("[Testing] StatusReportCb: group id: {}, status: {}",
298 group_id, status);
299 }));
300
301 MockCsisClient::SetMockInstanceForTesting(&mock_csis_client_module_);
302 ON_CALL(mock_csis_client_module_, Get())
303 .WillByDefault(Return(&mock_csis_client_module_));
304 ON_CALL(mock_csis_client_module_, IsCsisClientRunning())
305 .WillByDefault(Return(true));
306 ON_CALL(mock_csis_client_module_, GetDeviceList(_))
307 .WillByDefault(Invoke([this](int group_id) { return addresses_; }));
308 ON_CALL(mock_csis_client_module_, GetDesiredSize(_))
309 .WillByDefault(
310 Invoke([this](int group_id) { return (int)(addresses_.size()); }));
311
312 // Support 2M Phy
313 ON_CALL(btm_interface, IsPhy2mSupported(_, _)).WillByDefault(Return(true));
314 ON_CALL(btm_interface, GetHCIConnHandle(_, _))
315 .WillByDefault(
316 Invoke([](RawAddress const& remote_bda, tBT_TRANSPORT transport) {
317 return remote_bda.IsEmpty()
318 ? HCI_INVALID_HANDLE
319 : ((uint16_t)(remote_bda.address[0] ^
320 remote_bda.address[1] ^
321 remote_bda.address[2]))
322 << 8 |
323 (remote_bda.address[3] ^ remote_bda.address[4] ^
324 remote_bda.address[5]);
325 }));
326
327 ON_CALL(gatt_queue, WriteCharacteristic(_, _, _, GATT_WRITE_NO_RSP, _, _))
328 .WillByDefault(Invoke([this](uint16_t conn_id, uint16_t handle,
329 std::vector<uint8_t> value,
330 tGATT_WRITE_TYPE write_type,
331 GATT_WRITE_OP_CB cb, void* cb_data) {
332 for (auto& dev : le_audio_devices_) {
333 if (dev->conn_id_ == conn_id) {
334 // Control point write handler
335 if (dev->ctp_hdls_.val_hdl == handle) {
336 HandleCtpOperation(dev.get(), value, cb, cb_data);
337 }
338 break;
339 }
340 }
341 }));
342
343 ConfigureIsoManagerMock();
344 }
345
HandleCtpOperation(LeAudioDevice * device,std::vector<uint8_t> value,GATT_WRITE_OP_CB cb,void * cb_data)346 void HandleCtpOperation(LeAudioDevice* device, std::vector<uint8_t> value,
347 GATT_WRITE_OP_CB cb, void* cb_data) {
348 auto opcode = value[0];
349
350 // Verify against valid opcode range
351 ASSERT_LT(opcode, ascs::kAseCtpOpcodeMaxVal + 1);
352 ASSERT_NE(opcode, 0);
353
354 switch (opcode) {
355 case client_parser::ascs::kCtpOpcodeCodecConfiguration:
356 ase_ctp_handler.AseCtpConfigureCodecHandler(device, std::move(value),
357 cb, cb_data);
358 break;
359 case client_parser::ascs::kCtpOpcodeQosConfiguration:
360 ase_ctp_handler.AseCtpConfigureQosHandler(device, std::move(value), cb,
361 cb_data);
362 break;
363 case client_parser::ascs::kCtpOpcodeEnable:
364 ase_ctp_handler.AseCtpEnableHandler(device, std::move(value), cb,
365 cb_data);
366 break;
367 case client_parser::ascs::kCtpOpcodeReceiverStartReady:
368 ase_ctp_handler.AseCtpReceiverStartReadyHandler(
369 device, std::move(value), cb, cb_data);
370 break;
371 case client_parser::ascs::kCtpOpcodeDisable:
372 ase_ctp_handler.AseCtpDisableHandler(device, std::move(value), cb,
373 cb_data);
374 break;
375 case client_parser::ascs::kCtpOpcodeReceiverStopReady:
376 ase_ctp_handler.AseCtpReceiverStopReadyHandler(device, std::move(value),
377 cb, cb_data);
378 break;
379 case client_parser::ascs::kCtpOpcodeUpdateMetadata:
380 ase_ctp_handler.AseCtpUpdateMetadataHandler(device, std::move(value),
381 cb, cb_data);
382 break;
383 case client_parser::ascs::kCtpOpcodeRelease:
384 ase_ctp_handler.AseCtpReleaseHandler(device, std::move(value), cb,
385 cb_data);
386 break;
387 default:
388 break;
389 };
390 }
391
392 /* Helper function to make a deterministic (and unique on the entire device)
393 * connection handle for a given cis.
394 */
395 #define UNIQUE_CIS_CONN_HANDLE(cig_id, cis_index) (cig_id << 8 | cis_index)
396
ConfigureIsoManagerMock()397 void ConfigureIsoManagerMock() {
398 iso_manager_ = bluetooth::hci::IsoManager::GetInstance();
399 ASSERT_NE(iso_manager_, nullptr);
400 iso_manager_->Start();
401
402 mock_iso_manager_ = MockIsoManager::GetInstance();
403 ASSERT_NE(mock_iso_manager_, nullptr);
404
405 ON_CALL(*mock_iso_manager_, CreateCig)
406 .WillByDefault(
407 [this](uint8_t cig_id,
408 bluetooth::hci::iso_manager::cig_create_params p) {
409 log::debug("CreateCig");
410
411 auto& group = le_audio_device_groups_[cig_id];
412 if (group) {
413 std::vector<uint16_t> conn_handles;
414 // Fake connection ID for each cis in a request
415 for (auto i = 0u; i < p.cis_cfgs.size(); ++i) {
416 conn_handles.push_back(UNIQUE_CIS_CONN_HANDLE(cig_id, i));
417 }
418 auto status = HCI_SUCCESS;
419 if (group_create_command_disallowed_) {
420 group_create_command_disallowed_ = false;
421 status = HCI_ERR_COMMAND_DISALLOWED;
422 }
423
424 LeAudioGroupStateMachine::Get()->ProcessHciNotifOnCigCreate(
425 group.get(), status, cig_id, conn_handles);
426 }
427 });
428
429 ON_CALL(*mock_iso_manager_, RemoveCig)
430 .WillByDefault([this](uint8_t cig_id, bool force) {
431 log::debug("CreateRemove");
432
433 auto& group = le_audio_device_groups_[cig_id];
434 if (group) {
435 // Fake connection ID for each cis in a request
436 LeAudioGroupStateMachine::Get()->ProcessHciNotifOnCigRemove(
437 0, group.get());
438 }
439 });
440
441 ON_CALL(*mock_iso_manager_, SetupIsoDataPath)
442 .WillByDefault([this](uint16_t conn_handle,
443 bluetooth::hci::iso_manager::iso_data_path_params
444 p) {
445 log::debug("SetupIsoDataPath");
446
447 auto dev_it =
448 std::find_if(le_audio_devices_.begin(), le_audio_devices_.end(),
449 [&conn_handle](auto& dev) {
450 auto ases = dev->GetAsesByCisConnHdl(conn_handle);
451 return (ases.sink || ases.source);
452 });
453 if (dev_it == le_audio_devices_.end()) {
454 log::error("Device not found");
455 return;
456 }
457
458 for (auto& kv_pair : le_audio_device_groups_) {
459 auto& group = kv_pair.second;
460 if (group->IsDeviceInTheGroup(dev_it->get())) {
461 LeAudioGroupStateMachine::Get()->ProcessHciNotifSetupIsoDataPath(
462 group.get(), dev_it->get(), 0, conn_handle);
463 return;
464 }
465 }
466 });
467
468 ON_CALL(*mock_iso_manager_, RemoveIsoDataPath)
469 .WillByDefault([this](uint16_t conn_handle, uint8_t iso_direction) {
470 log::debug("RemoveIsoDataPath");
471
472 auto dev_it =
473 std::find_if(le_audio_devices_.begin(), le_audio_devices_.end(),
474 [&conn_handle](auto& dev) {
475 auto ases = dev->GetAsesByCisConnHdl(conn_handle);
476 return (ases.sink || ases.source);
477 });
478 if (dev_it == le_audio_devices_.end()) {
479 log::error("Device not found");
480 return;
481 }
482
483 for (auto& kv_pair : le_audio_device_groups_) {
484 auto& group = kv_pair.second;
485 if (group->IsDeviceInTheGroup(dev_it->get())) {
486 LeAudioGroupStateMachine::Get()->ProcessHciNotifRemoveIsoDataPath(
487 group.get(), dev_it->get(), 0, conn_handle);
488 return;
489 }
490 }
491 });
492
493 ON_CALL(*mock_iso_manager_, EstablishCis)
494 .WillByDefault([this](bluetooth::hci::iso_manager::cis_establish_params
495 conn_params) {
496 log::debug("EstablishCis");
497
498 if (do_not_send_cis_establish_event_) {
499 log::debug("Don't send cis establish event");
500 return;
501 }
502
503 for (auto& pair : conn_params.conn_pairs) {
504 auto dev_it = std::find_if(
505 le_audio_devices_.begin(), le_audio_devices_.end(),
506 [&pair](auto& dev) {
507 auto ases = dev->GetAsesByCisConnHdl(pair.cis_conn_handle);
508 return (ases.sink || ases.source);
509 });
510 if (dev_it == le_audio_devices_.end()) {
511 log::error("Device not found");
512 return;
513 }
514
515 for (auto& kv_pair : le_audio_device_groups_) {
516 auto& group = kv_pair.second;
517 if (group->IsDeviceInTheGroup(dev_it->get())) {
518 bluetooth::hci::iso_manager::cis_establish_cmpl_evt evt;
519
520 // Fill proper values if needed
521 if (use_cis_retry_cnt_) {
522 if (retry_cis_established_cnt_ > 0) {
523 evt.status = HCI_ERR_CONN_FAILED_ESTABLISHMENT;
524 retry_cis_established_cnt_--;
525 } else {
526 evt.status = 0;
527 }
528 } else if (overwrite_cis_status_) {
529 evt.status = cis_status_[overwrite_cis_status_idx_++];
530 /* Reset the index */
531 if (cis_status_.size() == overwrite_cis_status_idx_) {
532 overwrite_cis_status_idx_ = 0;
533 }
534 } else {
535 evt.status = 0;
536 }
537
538 evt.cig_id = group->group_id_;
539 evt.cis_conn_hdl = pair.cis_conn_handle;
540 evt.cig_sync_delay = 0;
541 evt.cis_sync_delay = 0;
542 evt.trans_lat_mtos = 0;
543 evt.trans_lat_stom = 0;
544 evt.phy_mtos = 0;
545 evt.phy_stom = 0;
546 evt.nse = 0;
547 evt.bn_mtos = 0;
548 evt.bn_stom = 0;
549 evt.ft_mtos = 0;
550 evt.ft_stom = 0;
551 evt.max_pdu_mtos = 0;
552 evt.max_pdu_stom = 0;
553 evt.iso_itv = 0;
554
555 LeAudioGroupStateMachine::Get()->ProcessHciNotifCisEstablished(
556 group.get(), dev_it->get(), &evt);
557 break;
558 }
559 }
560 }
561 });
562
563 ON_CALL(*mock_iso_manager_, DisconnectCis)
564 .WillByDefault([this](uint16_t cis_handle, uint8_t reason) {
565 log::debug("DisconnectCis");
566
567 auto dev_it =
568 std::find_if(le_audio_devices_.begin(), le_audio_devices_.end(),
569 [&cis_handle](auto& dev) {
570 auto ases = dev->GetAsesByCisConnHdl(cis_handle);
571 return (ases.sink || ases.source);
572 });
573 if (dev_it == le_audio_devices_.end()) {
574 log::error("Device not found");
575 return;
576 }
577
578 // When we disconnect the remote with HCI_ERR_PEER_USER, we
579 // should be getting HCI_ERR_CONN_CAUSE_LOCAL_HOST from HCI.
580 if (reason == HCI_ERR_PEER_USER) {
581 reason = HCI_ERR_CONN_CAUSE_LOCAL_HOST;
582 }
583
584 for (auto& kv_pair : le_audio_device_groups_) {
585 auto& group = kv_pair.second;
586 if (group->IsDeviceInTheGroup(dev_it->get())) {
587 bluetooth::hci::iso_manager::cis_disconnected_evt evt{
588 .reason = reason,
589 .cig_id = static_cast<uint8_t>(group->group_id_),
590 .cis_conn_hdl = cis_handle,
591 };
592 LeAudioGroupStateMachine::Get()->ProcessHciNotifCisDisconnected(
593 group.get(), dev_it->get(), &evt);
594 return;
595 }
596 }
597 });
598 }
599
ConfigCodecManagerMock(types::CodecLocation location)600 void ConfigCodecManagerMock(types::CodecLocation location) {
601 codec_manager_ = bluetooth::le_audio::CodecManager::GetInstance();
602 ASSERT_NE(codec_manager_, nullptr);
603 std::vector<bluetooth::le_audio::btle_audio_codec_config_t>
604 mock_offloading_preference(0);
605 codec_manager_->Start(mock_offloading_preference);
606 mock_codec_manager_ = MockCodecManager::GetInstance();
607 ASSERT_NE(mock_codec_manager_, nullptr);
608 ON_CALL(*mock_codec_manager_, GetCodecLocation())
609 .WillByDefault(Return(location));
610 // Regardless of the codec location, return all the possible configurations
611 ON_CALL(*mock_codec_manager_, IsDualBiDirSwbSupported)
612 .WillByDefault(Return(true));
613 ON_CALL(*mock_codec_manager_, CheckCodecConfigIsBiDirSwb)
614 .WillByDefault(
615 Invoke([](const set_configurations::AudioSetConfiguration& config)
616 -> bool {
617 return AudioSetConfigurationProvider::Get()
618 ->CheckConfigurationIsBiDirSwb(config);
619 }));
620 ON_CALL(*mock_codec_manager_, GetCodecConfig)
621 .WillByDefault(Invoke([](const bluetooth::le_audio::CodecManager::
622 UnicastConfigurationRequirements&
623 requirements,
624 bluetooth::le_audio::CodecManager::
625 UnicastConfigurationVerifier verifier) {
626 auto configs =
627 *bluetooth::le_audio::AudioSetConfigurationProvider::Get()
628 ->GetConfigurations(requirements.audio_context_type);
629 // Note: This dual bidir SWB exclusion logic has to match the
630 // CodecManager::GetCodecConfig() implementation.
631 if (!CodecManager::GetInstance()->IsDualBiDirSwbSupported()) {
632 configs.erase(
633 std::remove_if(configs.begin(), configs.end(),
634 [](auto const& el) {
635 if (el->confs.source.empty()) return false;
636 return AudioSetConfigurationProvider::Get()
637 ->CheckConfigurationIsDualBiDirSwb(*el);
638 }),
639 configs.end());
640 }
641
642 auto cfg = verifier(requirements, &configs);
643 if (cfg == nullptr) {
644 return std::unique_ptr<
645 bluetooth::le_audio::set_configurations::AudioSetConfiguration>(
646 nullptr);
647 }
648 return std::make_unique<
649 bluetooth::le_audio::set_configurations::AudioSetConfiguration>(
650 *cfg);
651 }));
652 }
653
TearDown()654 void TearDown() override {
655 /* Clear the alarm on tear down in case test case ends when the
656 * alarm is scheduled
657 */
658 alarm_cancel(nullptr);
659
660 iso_manager_->Stop();
661 mock_iso_manager_ = nullptr;
662 codec_manager_->Stop();
663 mock_codec_manager_ = nullptr;
664
665 gatt::SetMockBtaGattQueue(nullptr);
666 gatt::SetMockBtaGattInterface(nullptr);
667 bluetooth::manager::SetMockBtmInterface(nullptr);
668
669 le_audio_devices_.clear();
670 addresses_.clear();
671 cached_codec_configuration_map_.clear();
672 cached_qos_configuration_map_.clear();
673 cached_ase_to_cis_id_map_.clear();
674 cached_remote_qos_configuration_for_ase_.clear();
675 LeAudioGroupStateMachine::Cleanup();
676 ::bluetooth::le_audio::AudioSetConfigurationProvider::Cleanup();
677 bluetooth::hci::testing::mock_controller_ = nullptr;
678 }
679
PrepareConnectedDevice(uint8_t id,DeviceConnectState initial_connect_state,uint8_t num_ase_snk,uint8_t num_ase_src)680 std::shared_ptr<LeAudioDevice> PrepareConnectedDevice(
681 uint8_t id, DeviceConnectState initial_connect_state, uint8_t num_ase_snk,
682 uint8_t num_ase_src) {
683 auto leAudioDevice = std::make_shared<LeAudioDevice>(GetTestAddress(id),
684 initial_connect_state);
685 leAudioDevice->conn_id_ = id;
686 leAudioDevice->SetConnectionState(DeviceConnectState::CONNECTED);
687
688 uint16_t attr_handle = ATTR_HANDLE_ASCS_POOL_START;
689 leAudioDevice->snk_audio_locations_hdls_.val_hdl = attr_handle++;
690 leAudioDevice->snk_audio_locations_hdls_.ccc_hdl = attr_handle++;
691 leAudioDevice->src_audio_locations_hdls_.val_hdl = attr_handle++;
692 leAudioDevice->src_audio_locations_hdls_.ccc_hdl = attr_handle++;
693 leAudioDevice->audio_avail_hdls_.val_hdl = attr_handle++;
694 leAudioDevice->audio_avail_hdls_.ccc_hdl = attr_handle++;
695 leAudioDevice->audio_supp_cont_hdls_.val_hdl = attr_handle++;
696 leAudioDevice->audio_supp_cont_hdls_.ccc_hdl = attr_handle++;
697 leAudioDevice->ctp_hdls_.val_hdl = attr_handle++;
698 leAudioDevice->ctp_hdls_.ccc_hdl = attr_handle++;
699
700 // Add some Sink ASEs
701 while (num_ase_snk) {
702 types::ase ase(0, 0, 0x01);
703 ase.hdls.val_hdl = attr_handle++;
704 ase.hdls.ccc_hdl = attr_handle++;
705
706 leAudioDevice->ases_.push_back(std::move(ase));
707 num_ase_snk--;
708 }
709
710 // Add some Source ASEs
711 while (num_ase_src) {
712 types::ase ase(0, 0, 0x02);
713 ase.hdls.val_hdl = attr_handle++;
714 ase.hdls.ccc_hdl = attr_handle++;
715
716 leAudioDevice->ases_.push_back(std::move(ase));
717 num_ase_src--;
718 }
719
720 le_audio_devices_.push_back(leAudioDevice);
721 addresses_.push_back(leAudioDevice->address_);
722
723 return std::move(leAudioDevice);
724 }
725
GroupTheDevice(int group_id,const std::shared_ptr<LeAudioDevice> & leAudioDevice)726 LeAudioDeviceGroup* GroupTheDevice(
727 int group_id, const std::shared_ptr<LeAudioDevice>& leAudioDevice) {
728 if (le_audio_device_groups_.count(group_id) == 0) {
729 le_audio_device_groups_[group_id] =
730 std::make_unique<LeAudioDeviceGroup>(group_id);
731 }
732
733 auto& group = le_audio_device_groups_[group_id];
734
735 group->AddNode(leAudioDevice);
736 if (group->IsEmpty()) return nullptr;
737
738 return &(*group);
739 }
740
InjectAclDisconnected(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)741 void InjectAclDisconnected(LeAudioDeviceGroup* group,
742 LeAudioDevice* leAudioDevice) {
743 // Do what the client.cc does when handling the disconnection event
744 leAudioDevice->conn_id_ = GATT_INVALID_CONN_ID;
745 leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTED);
746 LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected(
747 group, leAudioDevice);
748 }
749
InjectReleasingAndIdleState(LeAudioDeviceGroup * group,LeAudioDevice * device)750 void InjectReleasingAndIdleState(LeAudioDeviceGroup* group,
751 LeAudioDevice* device) {
752 for (auto& ase : device->ases_) {
753 if (ase.id == bluetooth::le_audio::types::ase::kAseIdInvalid) {
754 continue;
755 }
756 // Simulate autonomus RELEASE and moving to IDLE state
757 InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing,
758 nullptr);
759 InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle,
760 nullptr);
761 }
762 }
763
InjectCachedConfiguratuibForActiveAses(LeAudioDeviceGroup * group,LeAudioDevice * device)764 void InjectCachedConfiguratuibForActiveAses(LeAudioDeviceGroup* group,
765 LeAudioDevice* device) {
766 for (auto& ase : device->ases_) {
767 if (!ase.active) {
768 continue;
769 }
770 log::info("ID : {}, status {}", ase.id,
771 bluetooth::common::ToString(ase.state));
772
773 InjectAseStateNotification(&ase, device, group,
774 ascs::kAseStateCodecConfigured,
775 &cached_codec_configuration_map_[ase.id]);
776 }
777 }
778
InjectAseStateNotification(types::ase * ase,LeAudioDevice * device,LeAudioDeviceGroup * group,uint8_t new_state,void * new_state_params)779 void InjectAseStateNotification(types::ase* ase, LeAudioDevice* device,
780 LeAudioDeviceGroup* group, uint8_t new_state,
781 void* new_state_params) {
782 // Prepare additional params
783 switch (new_state) {
784 case ascs::kAseStateCodecConfigured: {
785 client_parser::ascs::ase_codec_configured_state_params* conf =
786 static_cast<
787 client_parser::ascs::ase_codec_configured_state_params*>(
788 new_state_params);
789 std::vector<uint8_t> notif_value(25 + conf->codec_spec_conf.size());
790 auto* p = notif_value.data();
791
792 UINT8_TO_STREAM(p, ase->id == types::ase::kAseIdInvalid
793 ? ++ase_id_last_assigned
794 : ase->id);
795 UINT8_TO_STREAM(p, new_state);
796
797 UINT8_TO_STREAM(p, conf->framing);
798 UINT8_TO_STREAM(p, conf->preferred_phy);
799 UINT8_TO_STREAM(p, conf->preferred_retrans_nb);
800 UINT16_TO_STREAM(p, conf->max_transport_latency);
801 UINT24_TO_STREAM(p, conf->pres_delay_min);
802 UINT24_TO_STREAM(p, conf->pres_delay_max);
803 UINT24_TO_STREAM(p, conf->preferred_pres_delay_min);
804 UINT24_TO_STREAM(p, conf->preferred_pres_delay_max);
805
806 // CodecID:
807 UINT8_TO_STREAM(p, conf->codec_id.coding_format);
808 UINT16_TO_STREAM(p, conf->codec_id.vendor_company_id);
809 UINT16_TO_STREAM(p, conf->codec_id.vendor_codec_id);
810
811 // Codec Spec. Conf. Length and Data
812 UINT8_TO_STREAM(p, conf->codec_spec_conf.size());
813 memcpy(p, conf->codec_spec_conf.data(), conf->codec_spec_conf.size());
814
815 LeAudioGroupStateMachine::Get()->ProcessGattNotifEvent(
816 notif_value.data(), notif_value.size(), ase, device, group);
817 } break;
818
819 case ascs::kAseStateQoSConfigured: {
820 client_parser::ascs::ase_qos_configured_state_params* conf =
821 static_cast<client_parser::ascs::ase_qos_configured_state_params*>(
822 new_state_params);
823 std::vector<uint8_t> notif_value(17);
824 auto* p = notif_value.data();
825
826 // Prepare header
827 UINT8_TO_STREAM(p, ase->id == types::ase::kAseIdInvalid
828 ? ++ase_id_last_assigned
829 : ase->id);
830 UINT8_TO_STREAM(p, new_state);
831
832 UINT8_TO_STREAM(p, conf->cig_id);
833 UINT8_TO_STREAM(p, conf->cis_id);
834 UINT24_TO_STREAM(p, conf->sdu_interval);
835 UINT8_TO_STREAM(p, conf->framing);
836 UINT8_TO_STREAM(p, conf->phy);
837 UINT16_TO_STREAM(p, conf->max_sdu);
838 UINT8_TO_STREAM(p, conf->retrans_nb);
839 UINT16_TO_STREAM(p, conf->max_transport_latency);
840 UINT24_TO_STREAM(p, conf->pres_delay);
841
842 cached_remote_qos_configuration_for_ase_[ase] = notif_value;
843
844 LeAudioGroupStateMachine::Get()->ProcessGattNotifEvent(
845 notif_value.data(), notif_value.size(), ase, device, group);
846 } break;
847
848 case ascs::kAseStateEnabling:
849 // fall-through
850 case ascs::kAseStateStreaming:
851 // fall-through
852 case ascs::kAseStateDisabling: {
853 client_parser::ascs::ase_transient_state_params* params =
854 static_cast<client_parser::ascs::ase_transient_state_params*>(
855 new_state_params);
856 std::vector<uint8_t> notif_value(5 + params->metadata.size());
857 auto* p = notif_value.data();
858
859 // Prepare header
860 UINT8_TO_STREAM(p, ase->id == types::ase::kAseIdInvalid
861 ? ++ase_id_last_assigned
862 : ase->id);
863
864 UINT8_TO_STREAM(p, new_state);
865
866 UINT8_TO_STREAM(p, group->group_id_);
867 UINT8_TO_STREAM(p, ase->cis_id);
868 UINT8_TO_STREAM(p, params->metadata.size());
869 memcpy(p, params->metadata.data(), params->metadata.size());
870
871 LeAudioGroupStateMachine::Get()->ProcessGattNotifEvent(
872 notif_value.data(), notif_value.size(), ase, device, group);
873 } break;
874
875 case ascs::kAseStateReleasing:
876 // fall-through
877 case ascs::kAseStateIdle: {
878 std::vector<uint8_t> notif_value(2);
879 auto* p = notif_value.data();
880
881 // Prepare header
882 UINT8_TO_STREAM(p, ase->id == types::ase::kAseIdInvalid
883 ? ++ase_id_last_assigned
884 : ase->id);
885 UINT8_TO_STREAM(p, new_state);
886
887 LeAudioGroupStateMachine::Get()->ProcessGattNotifEvent(
888 notif_value.data(), notif_value.size(), ase, device, group);
889 } break;
890
891 default:
892 break;
893 };
894 }
895
InsertPacRecord(std::vector<types::acs_ac_record> & recs,uint16_t sampling_frequencies_bitfield,uint8_t supported_frame_durations_bitfield,uint8_t audio_channel_count_bitfield,uint16_t supported_octets_per_codec_frame_min,uint16_t supported_octets_per_codec_frame_max,uint8_t coding_format=codec_specific::kLc3CodingFormat,uint16_t vendor_company_id=0x0000,uint16_t vendor_codec_id=0x0000,std::vector<uint8_t> metadata={})896 static void InsertPacRecord(
897 std::vector<types::acs_ac_record>& recs,
898 uint16_t sampling_frequencies_bitfield,
899 uint8_t supported_frame_durations_bitfield,
900 uint8_t audio_channel_count_bitfield,
901 uint16_t supported_octets_per_codec_frame_min,
902 uint16_t supported_octets_per_codec_frame_max,
903 uint8_t coding_format = codec_specific::kLc3CodingFormat,
904 uint16_t vendor_company_id = 0x0000, uint16_t vendor_codec_id = 0x0000,
905 std::vector<uint8_t> metadata = {}) {
906 auto ltv_map = types::LeAudioLtvMap({
907 {codec_specific::kCapTypeSupportedSamplingFrequencies,
908 {(uint8_t)(sampling_frequencies_bitfield),
909 (uint8_t)(sampling_frequencies_bitfield >> 8)}},
910 {codec_specific::kCapTypeSupportedFrameDurations,
911 {supported_frame_durations_bitfield}},
912 {codec_specific::kCapTypeAudioChannelCount,
913 {audio_channel_count_bitfield}},
914 {codec_specific::kCapTypeSupportedOctetsPerCodecFrame,
915 {
916 // Min
917 (uint8_t)(supported_octets_per_codec_frame_min),
918 (uint8_t)(supported_octets_per_codec_frame_min >> 8),
919 // Max
920 (uint8_t)(supported_octets_per_codec_frame_max),
921 (uint8_t)(supported_octets_per_codec_frame_max >> 8),
922 }},
923 });
924 recs.push_back({
925 .codec_id =
926 {
927 .coding_format = coding_format,
928 .vendor_company_id = vendor_company_id,
929 .vendor_codec_id = vendor_codec_id,
930 },
931 .codec_spec_caps = ltv_map,
932 .codec_spec_caps_raw = ltv_map.RawPacket(),
933 .metadata = std::move(metadata),
934 });
935 }
936
InjectInitialIdleNotification(LeAudioDeviceGroup * group)937 void InjectInitialIdleNotification(LeAudioDeviceGroup* group) {
938 for (auto* device = group->GetFirstDevice(); device != nullptr;
939 device = group->GetNextDevice(device)) {
940 for (auto& ase : device->ases_) {
941 InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle,
942 nullptr);
943 }
944 }
945 }
946
InjectInitialConfiguredNotification(LeAudioDeviceGroup * group)947 void InjectInitialConfiguredNotification(LeAudioDeviceGroup* group) {
948 for (auto* device = group->GetFirstDevice(); device != nullptr;
949 device = group->GetNextDevice(device)) {
950 for (auto& ase : device->ases_) {
951 client_parser::ascs::ase_codec_configured_state_params
952 codec_configured_state_params;
953 InjectAseStateNotification(&ase, device, group,
954 ascs::kAseStateCodecConfigured,
955 &codec_configured_state_params);
956 }
957 }
958 }
959
InjectInitialIdleAndConfiguredNotification(LeAudioDeviceGroup * group)960 void InjectInitialIdleAndConfiguredNotification(LeAudioDeviceGroup* group) {
961 for (auto* device = group->GetFirstDevice(); device != nullptr;
962 device = group->GetNextDevice(device)) {
963 int i = 0;
964 for (auto& ase : device->ases_) {
965 if (i % 2 == 1) {
966 InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle,
967 nullptr);
968 } else {
969 client_parser::ascs::ase_codec_configured_state_params
970 codec_configured_state_params;
971 InjectAseStateNotification(&ase, device, group,
972 ascs::kAseStateCodecConfigured,
973 &codec_configured_state_params);
974 }
975 i++;
976 }
977 }
978 }
979
InjectInitialInvalidNotification(LeAudioDeviceGroup * group)980 void InjectInitialInvalidNotification(LeAudioDeviceGroup* group) {
981 for (auto* device = group->GetFirstDevice(); device != nullptr;
982 device = group->GetNextDevice(device)) {
983 int i = 0;
984 for (auto& ase : device->ases_) {
985 if (i % 2 == 1) {
986 client_parser::ascs::ase_qos_configured_state_params
987 qos_configured_state_params;
988 InjectAseStateNotification(&ase, device, group,
989 ascs::kAseStateQoSConfigured,
990 &qos_configured_state_params);
991 } else {
992 client_parser::ascs::ase_transient_state_params enable_params;
993 InjectAseStateNotification(&ase, device, group,
994 ascs::kAseStateEnabling, &enable_params);
995 }
996 i++;
997 }
998 }
999 }
1000
MultipleTestDevicePrepare(int leaudio_group_id,LeAudioContextType context_type,uint16_t device_cnt,types::AudioContexts update_contexts,bool insert_default_pac_records=true,bool second_device_0_ases=false)1001 void MultipleTestDevicePrepare(int leaudio_group_id,
1002 LeAudioContextType context_type,
1003 uint16_t device_cnt,
1004 types::AudioContexts update_contexts,
1005 bool insert_default_pac_records = true,
1006 bool second_device_0_ases = false) {
1007 // Prepare fake connected device group
1008 DeviceConnectState initial_connect_state =
1009 DeviceConnectState::CONNECTING_BY_USER;
1010 int total_devices = device_cnt;
1011 bluetooth::le_audio::LeAudioDeviceGroup* group = nullptr;
1012
1013 uint8_t num_ase_snk;
1014 uint8_t num_ase_src;
1015 switch (context_type) {
1016 case kContextTypeRingtone:
1017 num_ase_snk = 1 + additional_snk_ases;
1018 num_ase_src = 0 + additional_src_ases;
1019 break;
1020
1021 case kContextTypeMedia:
1022 num_ase_snk = 2 + additional_snk_ases;
1023 num_ase_src = 0 + additional_src_ases;
1024 break;
1025
1026 case kContextTypeConversational:
1027 num_ase_snk = 1 + additional_snk_ases;
1028 num_ase_src = 1 + additional_src_ases;
1029 break;
1030
1031 case kContextTypeLive:
1032 num_ase_snk = 1 + additional_snk_ases;
1033 num_ase_src = 1 + additional_src_ases;
1034 break;
1035
1036 default:
1037 ASSERT_TRUE(false);
1038 }
1039
1040 while (device_cnt) {
1041 std::shared_ptr<LeAudioDevice> leAudioDevice;
1042
1043 if (device_cnt == 2 && second_device_0_ases == true) {
1044 leAudioDevice =
1045 PrepareConnectedDevice(device_cnt--, initial_connect_state, 0, 0);
1046 } else {
1047 leAudioDevice = PrepareConnectedDevice(
1048 device_cnt--, initial_connect_state, num_ase_snk, num_ase_src);
1049 }
1050
1051 if (insert_default_pac_records) {
1052 uint16_t attr_handle = ATTR_HANDLE_PACS_POOL_START;
1053
1054 /* As per spec, unspecified shall be supported */
1055 auto snk_context_type = kContextTypeUnspecified | update_contexts;
1056 auto src_context_type = kContextTypeUnspecified | update_contexts;
1057
1058 // Prepare Sink Published Audio Capability records
1059 if ((kContextTypeRingtone | kContextTypeMedia |
1060 kContextTypeConversational | kContextTypeLive)
1061 .test(context_type)) {
1062 // Set target ASE configurations
1063 std::vector<types::acs_ac_record> pac_recs;
1064
1065 InsertPacRecord(pac_recs, sample_freq_,
1066 codec_specific::kCapFrameDuration10ms |
1067 codec_specific::kCapFrameDuration7p5ms |
1068 codec_specific::kCapFrameDuration10msPreferred,
1069 channel_count_, 30, 120);
1070
1071 types::hdl_pair handle_pair;
1072 handle_pair.val_hdl = attr_handle++;
1073 handle_pair.ccc_hdl = attr_handle++;
1074
1075 leAudioDevice->snk_pacs_.emplace_back(
1076 std::make_tuple(std::move(handle_pair), pac_recs));
1077
1078 snk_context_type.set(context_type);
1079 leAudioDevice->snk_audio_locations_ = channel_allocations_sink_;
1080 }
1081
1082 // Prepare Source Published Audio Capability records
1083 if ((context_type == kContextTypeConversational) ||
1084 (context_type == kContextTypeLive)) {
1085 // Set target ASE configurations
1086 std::vector<types::acs_ac_record> pac_recs;
1087
1088 InsertPacRecord(pac_recs,
1089 codec_specific::kCapSamplingFrequency16000Hz |
1090 codec_specific::kCapSamplingFrequency32000Hz,
1091 codec_specific::kCapFrameDuration10ms |
1092 codec_specific::kCapFrameDuration7p5ms |
1093 codec_specific::kCapFrameDuration10msPreferred,
1094 0b00000001, 30, 120);
1095
1096 types::hdl_pair handle_pair;
1097 handle_pair.val_hdl = attr_handle++;
1098 handle_pair.ccc_hdl = attr_handle++;
1099
1100 leAudioDevice->src_pacs_.emplace_back(
1101 std::make_tuple(std::move(handle_pair), pac_recs));
1102 src_context_type.set(context_type);
1103
1104 leAudioDevice->src_audio_locations_ = channel_allocations_source_;
1105 }
1106
1107 leAudioDevice->SetSupportedContexts(
1108 {.sink = snk_context_type, .source = src_context_type});
1109 leAudioDevice->SetAvailableContexts(
1110 {.sink = snk_context_type, .source = src_context_type});
1111 }
1112
1113 group = GroupTheDevice(leaudio_group_id, std::move(leAudioDevice));
1114 /* Set the location and direction to the group (done in client.cc)*/
1115 group->ReloadAudioLocations();
1116 group->ReloadAudioDirections();
1117 }
1118
1119 /* Stimulate update of available context map and configuration cache */
1120 group->UpdateAudioContextAvailability();
1121 group->UpdateAudioSetConfigurationCache(context_type);
1122
1123 ASSERT_NE(group, nullptr);
1124 ASSERT_EQ(group->Size(), total_devices);
1125 }
1126
PrepareSingleTestDeviceGroup(int leaudio_group_id,LeAudioContextType context_type,uint16_t device_cnt=1,types::AudioContexts update_contexts=types::AudioContexts (),bool second_device_0_ases=false)1127 LeAudioDeviceGroup* PrepareSingleTestDeviceGroup(
1128 int leaudio_group_id, LeAudioContextType context_type,
1129 uint16_t device_cnt = 1,
1130 types::AudioContexts update_contexts = types::AudioContexts(),
1131 bool second_device_0_ases = false) {
1132 MultipleTestDevicePrepare(leaudio_group_id, context_type, device_cnt,
1133 update_contexts, true, second_device_0_ases);
1134 return le_audio_device_groups_.count(leaudio_group_id)
1135 ? le_audio_device_groups_[leaudio_group_id].get()
1136 : nullptr;
1137 }
1138
PrepareConfigureCodecHandler(LeAudioDeviceGroup * group,int verify_ase_count=0,bool caching=false,bool inject_configured=true)1139 void PrepareConfigureCodecHandler(LeAudioDeviceGroup* group,
1140 int verify_ase_count = 0,
1141 bool caching = false,
1142 bool inject_configured = true) {
1143 ON_CALL(ase_ctp_handler, AseCtpConfigureCodecHandler)
1144 .WillByDefault(Invoke([group, verify_ase_count, caching,
1145 inject_configured,
1146 this](LeAudioDevice* device,
1147 std::vector<uint8_t> value,
1148 GATT_WRITE_OP_CB cb, void* cb_data) {
1149 auto num_ase = value[1];
1150
1151 // Verify ase count if needed
1152 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
1153
1154 // Inject Configured ASE state notification for each requested ASE
1155 auto* ase_p = &value[2];
1156 for (auto i = 0u; i < num_ase; ++i) {
1157 client_parser::ascs::ase_codec_configured_state_params
1158 codec_configured_state_params;
1159
1160 /* Check if this is a valid ASE ID */
1161 auto ase_id = *ase_p++;
1162 auto it = std::find_if(
1163 device->ases_.begin(), device->ases_.end(),
1164 [ase_id](auto& ase) { return (ase.id == ase_id); });
1165 ASSERT_NE(it, device->ases_.end());
1166 const auto ase = &(*it);
1167
1168 // Skip target latency param
1169 ase_p++;
1170
1171 codec_configured_state_params.preferred_phy = *ase_p++;
1172 codec_configured_state_params.codec_id.coding_format = ase_p[0];
1173 codec_configured_state_params.codec_id.vendor_company_id =
1174 (uint16_t)(ase_p[1] << 8 | ase_p[2]),
1175 codec_configured_state_params.codec_id.vendor_codec_id =
1176 (uint16_t)(ase_p[3] << 8 | ase_p[4]),
1177 ase_p += 5;
1178
1179 auto codec_spec_param_len = *ase_p++;
1180 auto num_handled_bytes = ase_p - value.data();
1181 codec_configured_state_params.codec_spec_conf =
1182 std::vector<uint8_t>(
1183 value.begin() + num_handled_bytes,
1184 value.begin() + num_handled_bytes + codec_spec_param_len);
1185 ase_p += codec_spec_param_len;
1186
1187 // Some initial QoS settings
1188 codec_configured_state_params.framing =
1189 ascs::kAseParamFramingUnframedSupported;
1190 codec_configured_state_params.preferred_retrans_nb = 0x04;
1191 codec_configured_state_params.max_transport_latency = 0x0010;
1192 codec_configured_state_params.pres_delay_min = 0xABABAB;
1193 codec_configured_state_params.pres_delay_max = 0xCDCDCD;
1194 codec_configured_state_params.preferred_pres_delay_min =
1195 types::kPresDelayNoPreference;
1196 codec_configured_state_params.preferred_pres_delay_max =
1197 types::kPresDelayNoPreference;
1198
1199 if (caching) {
1200 cached_codec_configuration_map_[ase_id] =
1201 codec_configured_state_params;
1202 }
1203
1204 if (inject_configured) {
1205 InjectAseStateNotification(ase, device, group,
1206 ascs::kAseStateCodecConfigured,
1207 &codec_configured_state_params);
1208 }
1209
1210 if (stop_inject_configured_ase_after_first_ase_configured_) {
1211 return;
1212 }
1213 }
1214 }));
1215 }
1216
PrepareConfigureQosHandler(LeAudioDeviceGroup * group,int verify_ase_count=0,bool caching=false)1217 void PrepareConfigureQosHandler(LeAudioDeviceGroup* group,
1218 int verify_ase_count = 0,
1219 bool caching = false) {
1220 ON_CALL(ase_ctp_handler, AseCtpConfigureQosHandler)
1221 .WillByDefault(Invoke([group, verify_ase_count, caching, this](
1222 LeAudioDevice* device,
1223 std::vector<uint8_t> value,
1224 GATT_WRITE_OP_CB cb, void* cb_data) {
1225 auto num_ase = value[1];
1226
1227 // Verify ase count if needed
1228 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
1229
1230 // Inject Configured QoS state notification for each requested ASE
1231 auto* ase_p = &value[2];
1232 for (auto i = 0u; i < num_ase; ++i) {
1233 client_parser::ascs::ase_qos_configured_state_params
1234 qos_configured_state_params;
1235
1236 /* Check if this is a valid ASE ID */
1237 auto ase_id = *ase_p++;
1238 auto it = std::find_if(
1239 device->ases_.begin(), device->ases_.end(),
1240 [ase_id](auto& ase) { return (ase.id == ase_id); });
1241 ASSERT_NE(it, device->ases_.end());
1242 const auto ase = &(*it);
1243
1244 qos_configured_state_params.cig_id = *ase_p++;
1245 qos_configured_state_params.cis_id = *ase_p++;
1246
1247 qos_configured_state_params.sdu_interval =
1248 (uint32_t)((ase_p[0] << 16) | (ase_p[1] << 8) | ase_p[2]);
1249 ase_p += 3;
1250
1251 qos_configured_state_params.framing = *ase_p++;
1252 qos_configured_state_params.phy = *ase_p++;
1253 qos_configured_state_params.max_sdu =
1254 (uint16_t)((ase_p[0] << 8) | ase_p[1]);
1255 ase_p += 2;
1256
1257 qos_configured_state_params.retrans_nb = *ase_p++;
1258 qos_configured_state_params.max_transport_latency =
1259 (uint16_t)((ase_p[0] << 8) | ase_p[1]);
1260 ase_p += 2;
1261
1262 qos_configured_state_params.pres_delay =
1263 (uint16_t)((ase_p[0] << 16) | (ase_p[1] << 8) | ase_p[2]);
1264 ase_p += 3;
1265
1266 if (caching) {
1267 log::info("Device: {}", device->address_);
1268 if (cached_ase_to_cis_id_map_.count(device->address_) > 0) {
1269 auto ase_list = cached_ase_to_cis_id_map_.at(device->address_);
1270 if (ase_list.count(ase_id) > 0) {
1271 auto cis_id = ase_list.at(ase_id);
1272 ASSERT_EQ(cis_id, qos_configured_state_params.cis_id);
1273 } else {
1274 ase_list[ase_id] = qos_configured_state_params.cis_id;
1275 }
1276 } else {
1277 std::map<int, int> ase_map;
1278 ase_map[ase_id] = qos_configured_state_params.cis_id;
1279
1280 cached_ase_to_cis_id_map_[device->address_] = ase_map;
1281 }
1282 cached_qos_configuration_map_[ase_id] =
1283 qos_configured_state_params;
1284 }
1285
1286 InjectAseStateNotification(ase, device, group,
1287 ascs::kAseStateQoSConfigured,
1288 &qos_configured_state_params);
1289 }
1290 }));
1291 }
1292
PrepareCtpNotificationError(LeAudioDeviceGroup * group,uint8_t opcode,uint8_t response_code,uint8_t reason)1293 void PrepareCtpNotificationError(LeAudioDeviceGroup* group, uint8_t opcode,
1294 uint8_t response_code, uint8_t reason) {
1295 auto foo = [group, opcode, response_code, reason](
1296 LeAudioDevice* device, std::vector<uint8_t> value,
1297 GATT_WRITE_OP_CB cb, void* cb_data) {
1298 auto num_ase = value[1];
1299 std::vector<uint8_t> notif_value(
1300 2 + num_ase * sizeof(struct client_parser::ascs::ctp_ase_entry));
1301 auto* p = notif_value.data();
1302
1303 UINT8_TO_STREAM(p, opcode);
1304 UINT8_TO_STREAM(p, num_ase);
1305
1306 auto* ase_p = &value[2];
1307 for (auto i = 0u; i < num_ase; ++i) {
1308 /* Check if this is a valid ASE ID */
1309 auto ase_id = *ase_p++;
1310 auto it =
1311 std::find_if(device->ases_.begin(), device->ases_.end(),
1312 [ase_id](auto& ase) { return (ase.id == ase_id); });
1313 ASSERT_NE(it, device->ases_.end());
1314
1315 auto meta_len = *ase_p++;
1316 auto num_handled_bytes = ase_p - value.data();
1317 ase_p += meta_len;
1318
1319 client_parser::ascs::ase_transient_state_params enable_params = {
1320 .metadata = std::vector<uint8_t>(
1321 value.begin() + num_handled_bytes,
1322 value.begin() + num_handled_bytes + meta_len)};
1323
1324 // Inject error response
1325 UINT8_TO_STREAM(p, ase_id);
1326 UINT8_TO_STREAM(p, response_code);
1327 UINT8_TO_STREAM(p, reason);
1328 }
1329
1330 LeAudioGroupStateMachine::Get()->ProcessGattCtpNotification(
1331 group, notif_value.data(), notif_value.size());
1332 };
1333
1334 switch (opcode) {
1335 case client_parser::ascs::kCtpOpcodeCodecConfiguration:
1336 ON_CALL(ase_ctp_handler, AseCtpConfigureCodecHandler)
1337 .WillByDefault(Invoke(foo));
1338 break;
1339 case client_parser::ascs::kCtpOpcodeQosConfiguration:
1340 ON_CALL(ase_ctp_handler, AseCtpConfigureQosHandler)
1341 .WillByDefault(Invoke(foo));
1342 break;
1343 case client_parser::ascs::kCtpOpcodeEnable:
1344 ON_CALL(ase_ctp_handler, AseCtpEnableHandler)
1345 .WillByDefault(Invoke(foo));
1346 break;
1347 case client_parser::ascs::kCtpOpcodeReceiverStartReady:
1348 ON_CALL(ase_ctp_handler, AseCtpReceiverStartReadyHandler)
1349 .WillByDefault(Invoke(foo));
1350 break;
1351 case client_parser::ascs::kCtpOpcodeDisable:
1352 ON_CALL(ase_ctp_handler, AseCtpDisableHandler)
1353 .WillByDefault(Invoke(foo));
1354 break;
1355 case client_parser::ascs::kCtpOpcodeReceiverStopReady:
1356 ON_CALL(ase_ctp_handler, AseCtpReceiverStopReadyHandler)
1357 .WillByDefault(Invoke(foo));
1358 break;
1359 case client_parser::ascs::kCtpOpcodeUpdateMetadata:
1360 ON_CALL(ase_ctp_handler, AseCtpUpdateMetadataHandler)
1361 .WillByDefault(Invoke(foo));
1362 break;
1363 case client_parser::ascs::kCtpOpcodeRelease:
1364 ON_CALL(ase_ctp_handler, AseCtpReleaseHandler)
1365 .WillByDefault(Invoke(foo));
1366 break;
1367 default:
1368 break;
1369 };
1370 }
1371
PrepareEnableHandler(LeAudioDeviceGroup * group,int verify_ase_count=0,bool inject_enabling=true,bool incject_streaming=true)1372 void PrepareEnableHandler(LeAudioDeviceGroup* group, int verify_ase_count = 0,
1373 bool inject_enabling = true,
1374 bool incject_streaming = true) {
1375 ON_CALL(ase_ctp_handler, AseCtpEnableHandler)
1376 .WillByDefault(Invoke([group, verify_ase_count, inject_enabling,
1377 incject_streaming,
1378 this](LeAudioDevice* device,
1379 std::vector<uint8_t> value,
1380 GATT_WRITE_OP_CB cb, void* cb_data) {
1381 auto num_ase = value[1];
1382
1383 // Verify ase count if needed
1384 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
1385
1386 // Inject Streaming ASE state notification for each requested ASE
1387 auto* ase_p = &value[2];
1388 for (auto i = 0u; i < num_ase; ++i) {
1389 /* Check if this is a valid ASE ID */
1390 auto ase_id = *ase_p++;
1391 auto it = std::find_if(
1392 device->ases_.begin(), device->ases_.end(),
1393 [ase_id](auto& ase) { return (ase.id == ase_id); });
1394 ASSERT_NE(it, device->ases_.end());
1395 const auto ase = &(*it);
1396
1397 auto meta_len = *ase_p++;
1398 auto num_handled_bytes = ase_p - value.data();
1399 ase_p += meta_len;
1400
1401 client_parser::ascs::ase_transient_state_params enable_params = {
1402 .metadata = std::vector<uint8_t>(
1403 value.begin() + num_handled_bytes,
1404 value.begin() + num_handled_bytes + meta_len)};
1405
1406 // Server does the 'ReceiverStartReady' on its own - goes to
1407 // Streaming, when in Sink role
1408 if (ase->direction &
1409 bluetooth::le_audio::types::kLeAudioDirectionSink) {
1410 if (inject_enabling)
1411 InjectAseStateNotification(ase, device, group,
1412 ascs::kAseStateEnabling,
1413 &enable_params);
1414 if (incject_streaming) {
1415 InjectAseStateNotification(ase, device, group,
1416 ascs::kAseStateStreaming,
1417 &enable_params);
1418 }
1419 } else {
1420 InjectAseStateNotification(
1421 ase, device, group, ascs::kAseStateEnabling, &enable_params);
1422 }
1423 }
1424 }));
1425 }
1426
PrepareDisableHandler(LeAudioDeviceGroup * group,int verify_ase_count=0)1427 void PrepareDisableHandler(LeAudioDeviceGroup* group,
1428 int verify_ase_count = 0) {
1429 ON_CALL(ase_ctp_handler, AseCtpDisableHandler)
1430 .WillByDefault(Invoke([group, verify_ase_count, this](
1431 LeAudioDevice* device,
1432 std::vector<uint8_t> value,
1433 GATT_WRITE_OP_CB cb, void* cb_data) {
1434 auto num_ase = value[1];
1435
1436 // Verify ase count if needed
1437 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
1438 ASSERT_EQ(value.size(), 2ul + num_ase);
1439
1440 // Inject Disabling & QoS Conf. ASE state notification for each ASE
1441 auto* ase_p = &value[2];
1442 for (auto i = 0u; i < num_ase; ++i) {
1443 /* Check if this is a valid ASE ID */
1444 auto ase_id = *ase_p++;
1445 auto it = std::find_if(
1446 device->ases_.begin(), device->ases_.end(),
1447 [ase_id](auto& ase) { return (ase.id == ase_id); });
1448 ASSERT_NE(it, device->ases_.end());
1449 const auto ase = &(*it);
1450
1451 // The Disabling state is present for Source ASE
1452 if (ase->direction &
1453 bluetooth::le_audio::types::kLeAudioDirectionSource) {
1454 client_parser::ascs::ase_transient_state_params disabling_params =
1455 {.metadata = {}};
1456 InjectAseStateNotification(ase, device, group,
1457 ascs::kAseStateDisabling,
1458 &disabling_params);
1459 }
1460
1461 // Server does the 'ReceiverStopReady' on its own - goes to
1462 // Streaming, when in Sink role
1463 if (ase->direction &
1464 bluetooth::le_audio::types::kLeAudioDirectionSink) {
1465 // FIXME: For now our fake peer does not remember qos params
1466 client_parser::ascs::ase_qos_configured_state_params
1467 qos_configured_state_params;
1468 InjectAseStateNotification(ase, device, group,
1469 ascs::kAseStateQoSConfigured,
1470 &qos_configured_state_params);
1471 }
1472 }
1473 }));
1474 }
1475
PrepareReceiverStartReadyHandler(LeAudioDeviceGroup * group,int verify_ase_count=0)1476 void PrepareReceiverStartReadyHandler(LeAudioDeviceGroup* group,
1477 int verify_ase_count = 0) {
1478 ON_CALL(ase_ctp_handler, AseCtpReceiverStartReadyHandler)
1479 .WillByDefault(Invoke([group, verify_ase_count, this](
1480 LeAudioDevice* device,
1481 std::vector<uint8_t> value,
1482 GATT_WRITE_OP_CB cb, void* cb_data) {
1483 auto num_ase = value[1];
1484
1485 // Verify ase count if needed
1486 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
1487
1488 // Inject Streaming ASE state notification for each Source ASE
1489 auto* ase_p = &value[2];
1490 for (auto i = 0u; i < num_ase; ++i) {
1491 /* Check if this is a valid ASE ID */
1492 auto ase_id = *ase_p++;
1493 auto it = std::find_if(
1494 device->ases_.begin(), device->ases_.end(),
1495 [ase_id](auto& ase) { return (ase.id == ase_id); });
1496 ASSERT_NE(it, device->ases_.end());
1497
1498 // Once we did the 'ReceiverStartReady' the server goes to
1499 // Streaming, when in Source role
1500 const auto& ase = &(*it);
1501 client_parser::ascs::ase_transient_state_params streaming_params = {
1502 .metadata = ase->metadata};
1503 InjectAseStateNotification(ase, device, group,
1504 ascs::kAseStateStreaming,
1505 &streaming_params);
1506 }
1507 }));
1508 }
1509
PrepareReceiverStopReady(LeAudioDeviceGroup * group,int verify_ase_count=0)1510 void PrepareReceiverStopReady(LeAudioDeviceGroup* group,
1511 int verify_ase_count = 0) {
1512 ON_CALL(ase_ctp_handler, AseCtpReceiverStopReadyHandler)
1513 .WillByDefault(
1514 Invoke([group, verify_ase_count, this](
1515 LeAudioDevice* device, std::vector<uint8_t> value,
1516 GATT_WRITE_OP_CB cb, void* cb_data) {
1517 auto num_ase = value[1];
1518
1519 // Verify ase count if needed
1520 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
1521
1522 // Inject QoS configured ASE state notification for each Source
1523 // ASE
1524 auto* ase_p = &value[2];
1525 for (auto i = 0u; i < num_ase; ++i) {
1526 /* Check if this is a valid ASE ID */
1527 auto ase_id = *ase_p++;
1528 auto it = std::find_if(
1529 device->ases_.begin(), device->ases_.end(),
1530 [ase_id](auto& ase) { return (ase.id == ase_id); });
1531 ASSERT_NE(it, device->ases_.end());
1532
1533 const auto& ase = &(*it);
1534
1535 // FIXME: For now our fake peer does not remember qos params
1536 client_parser::ascs::ase_qos_configured_state_params
1537 qos_configured_state_params;
1538 InjectAseStateNotification(ase, device, group,
1539 ascs::kAseStateQoSConfigured,
1540 &qos_configured_state_params);
1541 }
1542 }));
1543 }
1544
PrepareReleaseHandler(LeAudioDeviceGroup * group,int verify_ase_count=0,bool inject_disconnect_device=false,LeAudioDevice * dev=nullptr)1545 void PrepareReleaseHandler(LeAudioDeviceGroup* group,
1546 int verify_ase_count = 0,
1547 bool inject_disconnect_device = false,
1548 LeAudioDevice* dev = nullptr) {
1549 ON_CALL(ase_ctp_handler, AseCtpReleaseHandler)
1550 .WillByDefault(
1551 Invoke([group, verify_ase_count, inject_disconnect_device, dev,
1552 this](LeAudioDevice* device, std::vector<uint8_t> value,
1553 GATT_WRITE_OP_CB cb, void* cb_data) {
1554 if (dev != nullptr && device != dev) {
1555 log::info("Do nothing for {}", dev->address_);
1556 return;
1557 }
1558
1559 auto num_ase = value[1];
1560
1561 // Verify ase count if needed
1562 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
1563 ASSERT_EQ(value.size(), 2ul + num_ase);
1564
1565 if (inject_disconnect_device) {
1566 InjectAclDisconnected(group, device);
1567 return;
1568 }
1569
1570 // Inject Releasing & Idle ASE state notification for each ASE
1571 auto* ase_p = &value[2];
1572 for (auto i = 0u; i < num_ase; ++i) {
1573 /* Check if this is a valid ASE ID */
1574 auto ase_id = *ase_p++;
1575 auto it = std::find_if(
1576 device->ases_.begin(), device->ases_.end(),
1577 [ase_id](auto& ase) { return (ase.id == ase_id); });
1578 ASSERT_NE(it, device->ases_.end());
1579 const auto ase = &(*it);
1580
1581 InjectAseStateNotification(ase, device, group,
1582 ascs::kAseStateReleasing, nullptr);
1583
1584 if (stay_in_releasing_state_) {
1585 continue;
1586 }
1587
1588 /* Check if codec configuration is cached */
1589 if (cached_codec_configuration_map_.count(ase_id) > 0) {
1590 InjectAseStateNotification(
1591 ase, device, group, ascs::kAseStateCodecConfigured,
1592 &cached_codec_configuration_map_[ase_id]);
1593 } else {
1594 // Release - no caching
1595 InjectAseStateNotification(ase, device, group,
1596 ascs::kAseStateIdle, nullptr);
1597 }
1598 }
1599 }));
1600 }
1601
1602 MockCsisClient mock_csis_client_module_;
1603 NiceMock<bluetooth::manager::MockBtmInterface> btm_interface;
1604 gatt::MockBtaGattInterface gatt_interface;
1605 gatt::MockBtaGattQueue gatt_queue;
1606
1607 bluetooth::hci::IsoManager* iso_manager_;
1608 MockIsoManager* mock_iso_manager_;
1609 bluetooth::le_audio::CodecManager* codec_manager_;
1610 MockCodecManager* mock_codec_manager_;
1611
1612 MockAseRemoteStateMachine ase_ctp_handler;
1613 std::map<int, client_parser::ascs::ase_codec_configured_state_params>
1614 cached_codec_configuration_map_;
1615 std::map<int, client_parser::ascs::ase_qos_configured_state_params>
1616 cached_qos_configuration_map_;
1617
1618 std::map<RawAddress, std::map<int, int>> cached_ase_to_cis_id_map_;
1619 std::map<types::ase*, std::vector<uint8_t>>
1620 cached_remote_qos_configuration_for_ase_;
1621
1622 MockLeAudioGroupStateMachineCallbacks mock_callbacks_;
1623 std::vector<std::shared_ptr<LeAudioDevice>> le_audio_devices_;
1624 std::vector<RawAddress> addresses_;
1625 std::map<uint8_t, std::unique_ptr<LeAudioDeviceGroup>>
1626 le_audio_device_groups_;
1627 bool group_create_command_disallowed_ = false;
1628 bluetooth::hci::testing::MockControllerInterface controller_;
1629 };
1630
1631 class StateMachineTest : public StateMachineTestBase {
SetUp()1632 void SetUp() override {
1633 ConfigCodecManagerMock(types::CodecLocation::HOST);
1634 ::bluetooth::le_audio::AudioSetConfigurationProvider::Initialize(
1635 ::bluetooth::le_audio::types::CodecLocation::HOST);
1636 StateMachineTestBase::SetUp();
1637 }
1638 };
1639
1640 class StateMachineTestNoSwb : public StateMachineTestBase {
SetUp()1641 void SetUp() override {
1642 ConfigCodecManagerMock(types::CodecLocation::HOST);
1643 ::bluetooth::le_audio::AudioSetConfigurationProvider::Initialize(
1644 ::bluetooth::le_audio::types::CodecLocation::HOST);
1645 ON_CALL(*mock_codec_manager_, IsDualBiDirSwbSupported)
1646 .WillByDefault(Return(false));
1647 StateMachineTestBase::SetUp();
1648 }
1649 };
1650
1651 class StateMachineTestAdsp : public StateMachineTestBase {
SetUp()1652 void SetUp() override {
1653 ConfigCodecManagerMock(types::CodecLocation::ADSP);
1654 ::bluetooth::le_audio::AudioSetConfigurationProvider::Initialize(
1655 ::bluetooth::le_audio::types::CodecLocation::ADSP);
1656 StateMachineTestBase::SetUp();
1657 }
1658 };
1659
TEST_F(StateMachineTest,testInit)1660 TEST_F(StateMachineTest, testInit) {
1661 ASSERT_NE(LeAudioGroupStateMachine::Get(), nullptr);
1662 }
1663
TEST_F(StateMachineTest,testCleanup)1664 TEST_F(StateMachineTest, testCleanup) {
1665 ASSERT_NE(LeAudioGroupStateMachine::Get(), nullptr);
1666 LeAudioGroupStateMachine::Cleanup();
1667 EXPECT_DEATH(LeAudioGroupStateMachine::Get(), "");
1668 }
1669
TEST_F(StateMachineTest,testConfigureCodecSingle)1670 TEST_F(StateMachineTest, testConfigureCodecSingle) {
1671 /* Device is banded headphones with 1x snk + 0x src ase
1672 * (1xunidirectional CIS) with channel count 2 (for stereo
1673 */
1674 const auto context_type = kContextTypeRingtone;
1675 const int leaudio_group_id = 2;
1676 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
1677 kLeAudioCodecChannelCountTwoChannel;
1678
1679 // Prepare fake connected device group
1680 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
1681
1682 /* Since we prepared device with Ringtone context in mind, only one ASE
1683 * should have been configured.
1684 */
1685 auto* leAudioDevice = group->GetFirstDevice();
1686 PrepareConfigureCodecHandler(group, 1);
1687
1688 /* Start the configuration and stream Media content.
1689 * Expect 1 time for the Codec Config call only. */
1690 EXPECT_CALL(gatt_queue,
1691 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
1692 GATT_WRITE_NO_RSP, _, _))
1693 .Times(1);
1694
1695 /* Do nothing on the CigCreate, so the state machine stays in the configure
1696 * state */
1697 ON_CALL(*mock_iso_manager_, CreateCig).WillByDefault(Return());
1698 EXPECT_CALL(*mock_iso_manager_, CreateCig).Times(1);
1699
1700 InjectInitialIdleNotification(group);
1701
1702 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1703 group, context_type,
1704 {.sink = types::AudioContexts(context_type),
1705 .source = types::AudioContexts(context_type)}));
1706
1707 // Check if group has transitioned to a proper state
1708 ASSERT_EQ(group->GetState(),
1709 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
1710
1711 /* Cancel is called when group goes to streaming. */
1712 ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
1713 }
1714
TEST_F(StateMachineTest,testConfigureCodecMulti)1715 TEST_F(StateMachineTest, testConfigureCodecMulti) {
1716 const auto context_type = kContextTypeMedia;
1717 const auto leaudio_group_id = 2;
1718 const auto num_devices = 2;
1719
1720 // Prepare multiple fake connected devices in a group
1721 auto* group =
1722 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
1723 ASSERT_EQ(group->Size(), num_devices);
1724
1725 PrepareConfigureCodecHandler(group);
1726
1727 auto expected_devices_written = 0;
1728 auto* leAudioDevice = group->GetFirstDevice();
1729 while (leAudioDevice) {
1730 EXPECT_CALL(gatt_queue,
1731 WriteCharacteristic(leAudioDevice->conn_id_,
1732 leAudioDevice->ctp_hdls_.val_hdl, _,
1733 GATT_WRITE_NO_RSP, _, _))
1734 .Times(AtLeast(1));
1735 expected_devices_written++;
1736 leAudioDevice = group->GetNextDevice(leAudioDevice);
1737 }
1738 ASSERT_EQ(expected_devices_written, num_devices);
1739
1740 InjectInitialIdleNotification(group);
1741
1742 /* Do nothing on the CigCreate, so the state machine stays in the configure
1743 * state */
1744 ON_CALL(*mock_iso_manager_, CreateCig).WillByDefault(Return());
1745 EXPECT_CALL(*mock_iso_manager_, CreateCig).Times(1);
1746
1747 // Start the configuration and stream the content
1748 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1749 group, context_type,
1750 {.sink = types::AudioContexts(context_type),
1751 .source = types::AudioContexts(context_type)}));
1752
1753 // Check if group has transitioned to a proper state
1754 ASSERT_EQ(group->GetState(),
1755 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
1756
1757 /* Cancel is called when group goes to streaming. */
1758 ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
1759 }
1760
TEST_F(StateMachineTest,testConfigureQosSingle)1761 TEST_F(StateMachineTest, testConfigureQosSingle) {
1762 /* Device is banded headphones with 2x snk + 1x src ase
1763 * (1x bidirectional + 1xunidirectional CIS)
1764 */
1765 additional_snk_ases = 1;
1766 additional_src_ases = 1;
1767 const auto context_type = kContextTypeRingtone;
1768 const int leaudio_group_id = 3;
1769
1770 // Prepare fake connected device group
1771 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
1772
1773 /* Since we prepared device with Ringtone context in mind, only one ASE
1774 * should have been configured.
1775 */
1776 auto* leAudioDevice = group->GetFirstDevice();
1777 PrepareConfigureCodecHandler(group, 2);
1778 PrepareConfigureQosHandler(group, 2);
1779
1780 // Start the configuration and stream Media content
1781 EXPECT_CALL(gatt_queue,
1782 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
1783 GATT_WRITE_NO_RSP, _, _))
1784 .Times(3);
1785
1786 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1787 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
1788 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
1789 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1790 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1791 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1792
1793 InjectInitialIdleNotification(group);
1794
1795 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1796 group, context_type,
1797 {.sink = types::AudioContexts(context_type),
1798 .source = types::AudioContexts(context_type)}));
1799
1800 // Check if group has transitioned to a proper state
1801 ASSERT_EQ(group->GetState(),
1802 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
1803
1804 ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
1805 }
1806
TEST_F(StateMachineTest,testConfigureQosSingleRecoverCig)1807 TEST_F(StateMachineTest, testConfigureQosSingleRecoverCig) {
1808 /* Device is banded headphones with 2x snk + 1x src ase
1809 * (1x bidirectional + 1xunidirectional CIS)
1810 */
1811 additional_snk_ases = 1;
1812 additional_src_ases = 1;
1813 const auto context_type = kContextTypeRingtone;
1814 const int leaudio_group_id = 3;
1815
1816 /* Assume that on previous BT OFF CIG was not removed */
1817 group_create_command_disallowed_ = true;
1818
1819 // Prepare fake connected device group
1820 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
1821
1822 /* Since we prepared device with Ringtone context in mind, only one ASE
1823 * should have been configured.
1824 */
1825 auto* leAudioDevice = group->GetFirstDevice();
1826 PrepareConfigureCodecHandler(group, 2);
1827 PrepareConfigureQosHandler(group, 2);
1828
1829 // Start the configuration and stream Media content
1830 EXPECT_CALL(gatt_queue,
1831 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
1832 GATT_WRITE_NO_RSP, _, _))
1833 .Times(3);
1834
1835 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2);
1836 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
1837 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
1838 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
1839 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1840 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1841
1842 InjectInitialIdleNotification(group);
1843
1844 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1845 group, context_type,
1846 {.sink = types::AudioContexts(context_type),
1847 .source = types::AudioContexts(context_type)}));
1848
1849 // Check if group has transitioned to a proper state
1850 ASSERT_EQ(group->GetState(),
1851 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
1852 ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
1853 }
1854
TEST_F(StateMachineTest,testConfigureQosMultiple)1855 TEST_F(StateMachineTest, testConfigureQosMultiple) {
1856 const auto context_type = kContextTypeMedia;
1857 const auto leaudio_group_id = 3;
1858 const auto num_devices = 2;
1859
1860 // Prepare multiple fake connected devices in a group
1861 auto* group =
1862 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
1863 ASSERT_EQ(group->Size(), num_devices);
1864
1865 PrepareConfigureCodecHandler(group);
1866 PrepareConfigureQosHandler(group);
1867
1868 auto* leAudioDevice = group->GetFirstDevice();
1869 auto expected_devices_written = 0;
1870 while (leAudioDevice) {
1871 EXPECT_CALL(gatt_queue,
1872 WriteCharacteristic(leAudioDevice->conn_id_,
1873 leAudioDevice->ctp_hdls_.val_hdl, _,
1874 GATT_WRITE_NO_RSP, _, _))
1875 .Times(AtLeast(2));
1876 expected_devices_written++;
1877 leAudioDevice = group->GetNextDevice(leAudioDevice);
1878 }
1879 ASSERT_EQ(expected_devices_written, num_devices);
1880
1881 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1882 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
1883 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
1884 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1885 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1886 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1887
1888 InjectInitialIdleNotification(group);
1889
1890 // Start the configuration and stream Media content
1891 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1892 group, context_type,
1893 {.sink = types::AudioContexts(context_type),
1894 .source = types::AudioContexts(context_type)}));
1895
1896 // Check if group has transitioned to a proper state
1897 ASSERT_EQ(group->GetState(),
1898 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
1899 ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
1900 }
1901
TEST_F(StateMachineTest,testConfigureQosFailed)1902 TEST_F(StateMachineTest, testConfigureQosFailed) {
1903 const auto context_type = kContextTypeMedia;
1904 const auto leaudio_group_id = 3;
1905 const auto num_devices = 2;
1906
1907 // Check if CIG is properly cleared when QoS failed
1908
1909 // Prepare multiple fake connected devices in a group
1910 auto* group =
1911 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
1912 ASSERT_EQ(group->Size(), num_devices);
1913
1914 PrepareConfigureCodecHandler(group);
1915 PrepareCtpNotificationError(
1916 group, client_parser::ascs::kCtpOpcodeQosConfiguration,
1917 client_parser::ascs::kCtpResponseCodeInvalidConfigurationParameterValue,
1918 client_parser::ascs::kCtpResponsePhy);
1919 PrepareReleaseHandler(group);
1920
1921 auto* leAudioDevice = group->GetFirstDevice();
1922 auto expected_devices_written = 0;
1923 while (leAudioDevice) {
1924 EXPECT_CALL(gatt_queue,
1925 WriteCharacteristic(leAudioDevice->conn_id_,
1926 leAudioDevice->ctp_hdls_.val_hdl, _,
1927 GATT_WRITE_NO_RSP, _, _))
1928 .Times(AtLeast(2));
1929 expected_devices_written++;
1930 leAudioDevice = group->GetNextDevice(leAudioDevice);
1931 }
1932 ASSERT_EQ(expected_devices_written, num_devices);
1933
1934 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1935 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
1936 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
1937 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1938 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1939 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
1940
1941 InjectInitialIdleNotification(group);
1942
1943 // Start the configuration and stream Media content
1944 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1945 group, context_type,
1946 {.sink = types::AudioContexts(context_type),
1947 .source = types::AudioContexts(context_type)}));
1948
1949 // Check if group has transitioned to a proper state
1950 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
1951 ASSERT_EQ(2, get_func_call_count("alarm_cancel"));
1952
1953 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
1954 }
1955
TEST_F(StateMachineTest,testDeviceDisconnectedWhileCigCreated)1956 TEST_F(StateMachineTest, testDeviceDisconnectedWhileCigCreated) {
1957 const auto context_type = kContextTypeMedia;
1958 const auto leaudio_group_id = 3;
1959 const auto num_devices = 1;
1960
1961 // verify proper cleaning when group is disconnected while CIG is creating.
1962
1963 // Prepare fake connected device in a group
1964 auto* group =
1965 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
1966 ASSERT_EQ(group->Size(), num_devices);
1967
1968 PrepareConfigureCodecHandler(group);
1969
1970 ON_CALL(*mock_iso_manager_, CreateCig).WillByDefault(Return());
1971
1972 auto* leAudioDevice = group->GetFirstDevice();
1973 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
1974 leAudioDevice->ctp_hdls_.val_hdl,
1975 _, GATT_WRITE_NO_RSP, _, _))
1976 .Times(1);
1977
1978 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1979 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
1980 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
1981 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1982 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1983
1984 InjectInitialIdleNotification(group);
1985
1986 // Start the configuration and stream Media content
1987 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1988 group, context_type,
1989 {.sink = types::AudioContexts(context_type),
1990 .source = types::AudioContexts(context_type)}));
1991
1992 // Check if group has transitioned to a proper state
1993 ASSERT_EQ(group->GetState(),
1994 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
1995
1996 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
1997
1998 InjectAclDisconnected(group, leAudioDevice);
1999 std::vector<uint16_t> conn_handles = {0x0001, 0x0002};
2000 int cig_id = 1;
2001
2002 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2003 LeAudioGroupStateMachine::Get()->ProcessHciNotifOnCigCreate(
2004 group, HCI_SUCCESS, cig_id, conn_handles);
2005
2006 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
2007 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
2008 }
2009
TEST_F(StateMachineTest,testStreamCreationError)2010 TEST_F(StateMachineTest, testStreamCreationError) {
2011 /* Device is banded headphones with 1x snk + 0x src ase
2012 * (1xunidirectional CIS) with channel count 2 (for stereo
2013 */
2014 const auto context_type = kContextTypeRingtone;
2015 const int leaudio_group_id = 4;
2016 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
2017 kLeAudioCodecChannelCountTwoChannel;
2018
2019 // Prepare fake connected device group
2020 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2021
2022 /* Ringtone with channel count 1 for single device and 1 ASE sink will
2023 * end up with 1 Sink ASE being configured.
2024 */
2025 PrepareConfigureCodecHandler(group, 1);
2026 PrepareConfigureQosHandler(group, 1);
2027 PrepareCtpNotificationError(
2028 group, client_parser::ascs::kCtpOpcodeEnable,
2029 client_parser::ascs::kCtpResponseCodeUnspecifiedError,
2030 client_parser::ascs::kCtpResponseNoReason);
2031 PrepareReleaseHandler(group);
2032
2033 auto* leAudioDevice = group->GetFirstDevice();
2034
2035 /*
2036 * 1 - Configure ASE
2037 * 2 - QoS ASE
2038 * 3 - Enable ASE
2039 * 4 - Release ASE
2040 */
2041 EXPECT_CALL(gatt_queue,
2042 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2043 GATT_WRITE_NO_RSP, _, _))
2044 .Times(4);
2045
2046 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2047 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
2048 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
2049 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2050 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2051 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2052
2053 InjectInitialIdleNotification(group);
2054
2055 // Validate GroupStreamStatus
2056 EXPECT_CALL(
2057 mock_callbacks_,
2058 StatusReportCb(leaudio_group_id,
2059 bluetooth::le_audio::GroupStreamStatus::RELEASING));
2060 EXPECT_CALL(mock_callbacks_,
2061 StatusReportCb(leaudio_group_id,
2062 bluetooth::le_audio::GroupStreamStatus::IDLE));
2063
2064 // Start the configuration and stream Media content
2065 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2066 group, context_type,
2067 {.sink = types::AudioContexts(context_type),
2068 .source = types::AudioContexts(context_type)}));
2069
2070 // Check if group has transitioned to a proper state
2071 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2072 ASSERT_EQ(2, get_func_call_count("alarm_cancel"));
2073 }
2074
TEST_F(StateMachineTest,testStreamSingle)2075 TEST_F(StateMachineTest, testStreamSingle) {
2076 /* Device is banded headphones with 1x snk + 0x src ase
2077 * (1xunidirectional CIS) with channel count 2 (for stereo
2078 */
2079 const auto context_type = kContextTypeRingtone;
2080 const int leaudio_group_id = 4;
2081 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
2082 kLeAudioCodecChannelCountTwoChannel;
2083
2084 // Prepare fake connected device group
2085 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2086
2087 /* Ringtone with channel count 1 for single device and 1 ASE sink will
2088 * end up with 1 Sink ASE being configured.
2089 */
2090 PrepareConfigureCodecHandler(group, 1);
2091 PrepareConfigureQosHandler(group, 1);
2092 PrepareEnableHandler(group, 1);
2093
2094 auto* leAudioDevice = group->GetFirstDevice();
2095 EXPECT_CALL(gatt_queue,
2096 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2097 GATT_WRITE_NO_RSP, _, _))
2098 .Times(3);
2099
2100 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2101 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
2102 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
2103 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2104 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2105 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
2106
2107 InjectInitialIdleNotification(group);
2108
2109 // Validate GroupStreamStatus
2110 EXPECT_CALL(
2111 mock_callbacks_,
2112 StatusReportCb(leaudio_group_id,
2113 bluetooth::le_audio::GroupStreamStatus::STREAMING));
2114
2115 // Start the configuration and stream Media content
2116 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2117 group, context_type,
2118 {.sink = types::AudioContexts(context_type),
2119 .source = types::AudioContexts(context_type)}));
2120
2121 // Check if group has transitioned to a proper state
2122 ASSERT_EQ(group->GetState(),
2123 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2124 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
2125 }
2126
TEST_F(StateMachineTest,testStreamSingleRetryCisFailure)2127 TEST_F(StateMachineTest, testStreamSingleRetryCisFailure) {
2128 /* Device is banded headphones with 1x snk + 0x src ase
2129 * (1xunidirectional CIS) with channel count 2 (for stereo
2130 */
2131 const auto context_type = kContextTypeRingtone;
2132 const int leaudio_group_id = 4;
2133 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
2134 kLeAudioCodecChannelCountTwoChannel;
2135
2136 // Prepare fake connected device group
2137 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2138
2139 /* Ringtone with channel count 1 for single device and 1 ASE sink will
2140 * end up with 1 Sink ASE being configured.
2141 */
2142 PrepareConfigureCodecHandler(group, 1);
2143 PrepareConfigureQosHandler(group, 1);
2144 PrepareEnableHandler(group, 1);
2145 PrepareReleaseHandler(group);
2146
2147 use_cis_retry_cnt_ = true;
2148 retry_cis_established_cnt_ = 4;
2149
2150 auto* leAudioDevice = group->GetFirstDevice();
2151 EXPECT_CALL(gatt_queue,
2152 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2153 GATT_WRITE_NO_RSP, _, _))
2154 .Times(4);
2155
2156 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2157 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(3);
2158 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
2159 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2160 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2161 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2162
2163 InjectInitialIdleNotification(group);
2164
2165 // Validate GroupStreamStatus
2166 EXPECT_CALL(
2167 mock_callbacks_,
2168 StatusReportCb(leaudio_group_id,
2169 bluetooth::le_audio::GroupStreamStatus::RELEASING));
2170 EXPECT_CALL(mock_callbacks_,
2171 StatusReportCb(leaudio_group_id,
2172 bluetooth::le_audio::GroupStreamStatus::IDLE));
2173
2174 // Start the configuration and stream Media content
2175 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2176 group, context_type,
2177 {.sink = types::AudioContexts(context_type),
2178 .source = types::AudioContexts(context_type)}));
2179
2180 // Check if group has transitioned to a proper state
2181 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2182 ASSERT_EQ(2, get_func_call_count("alarm_cancel"));
2183 }
2184
TEST_F(StateMachineTest,testStreamSingleRetryCisSuccess)2185 TEST_F(StateMachineTest, testStreamSingleRetryCisSuccess) {
2186 /* Device is banded headphones with 1x snk + 0x src ase
2187 * (1xunidirectional CIS) with channel count 2 (for stereo
2188 */
2189 const auto context_type = kContextTypeRingtone;
2190 const int leaudio_group_id = 4;
2191 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
2192 kLeAudioCodecChannelCountTwoChannel;
2193
2194 // Prepare fake connected device group
2195 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2196
2197 /* Ringtone with channel count 1 for single device and 1 ASE sink will
2198 * end up with 1 Sink ASE being configured.
2199 */
2200 PrepareConfigureCodecHandler(group, 1);
2201 PrepareConfigureQosHandler(group, 1);
2202 PrepareEnableHandler(group, 1);
2203
2204 use_cis_retry_cnt_ = true;
2205 retry_cis_established_cnt_ = 2;
2206
2207 auto* leAudioDevice = group->GetFirstDevice();
2208 EXPECT_CALL(gatt_queue,
2209 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2210 GATT_WRITE_NO_RSP, _, _))
2211 .Times(3);
2212
2213 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2214 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(3);
2215 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
2216 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2217 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2218 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
2219
2220 InjectInitialIdleNotification(group);
2221
2222 // Validate GroupStreamStatus
2223 EXPECT_CALL(
2224 mock_callbacks_,
2225 StatusReportCb(leaudio_group_id,
2226 bluetooth::le_audio::GroupStreamStatus::STREAMING));
2227
2228 // Start the configuration and stream Media content
2229 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2230 group, context_type,
2231 {.sink = types::AudioContexts(context_type),
2232 .source = types::AudioContexts(context_type)}));
2233
2234 // Check if group has transitioned to a proper state
2235 ASSERT_EQ(group->GetState(),
2236 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2237 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
2238 }
2239
TEST_F(StateMachineTest,testStreamSkipEnablingSink)2240 TEST_F(StateMachineTest, testStreamSkipEnablingSink) {
2241 /* Device is banded headphones with 2x snk + none src ase
2242 * (2x unidirectional CIS)
2243 */
2244
2245 /* Not, that when remote device skip Enabling it is considered as an error and
2246 * group will not be able to go to Streaming state.
2247 * It is because, Android is not creating CISes before all ASEs gets into
2248 * Enabling state, therefore it is impossible to remote device to skip
2249 * Enabling state.
2250 */
2251 const auto context_type = kContextTypeMedia;
2252 const int leaudio_group_id = 4;
2253
2254 // Prepare fake connected device group
2255 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2256
2257 /* For Media context type with channel count 1 and two ASEs,
2258 * there should have be 2 Ases configured configured.
2259 */
2260 PrepareConfigureCodecHandler(group, 2);
2261 PrepareConfigureQosHandler(group, 2);
2262 PrepareEnableHandler(group, 2, false);
2263
2264 /*
2265 * 1. Configure
2266 * 2. QoS Config
2267 * 3. Enable
2268 * 4. Release
2269 */
2270 auto* leAudioDevice = group->GetFirstDevice();
2271 EXPECT_CALL(gatt_queue,
2272 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2273 GATT_WRITE_NO_RSP, _, _))
2274 .Times(4);
2275
2276 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2277 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
2278 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
2279 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2280 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2281 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
2282
2283 InjectInitialIdleNotification(group);
2284
2285 // Validate GroupStreamStatus
2286 EXPECT_CALL(mock_callbacks_,
2287 StatusReportCb(leaudio_group_id,
2288 bluetooth::le_audio::GroupStreamStatus::STREAMING))
2289 .Times(0);
2290
2291 EXPECT_CALL(mock_callbacks_,
2292 StatusReportCb(leaudio_group_id,
2293 bluetooth::le_audio::GroupStreamStatus::RELEASING))
2294 .Times(1);
2295
2296 // Start the configuration and stream Media content
2297 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2298 group, context_type,
2299 {.sink = types::AudioContexts(context_type),
2300 .source = types::AudioContexts(context_type)}));
2301
2302 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
2303 }
2304
TEST_F(StateMachineTest,testStreamSkipEnablingSinkSource)2305 TEST_F(StateMachineTest, testStreamSkipEnablingSinkSource) {
2306 /* Device is banded headphones with 2x snk + 1x src ase
2307 * (1x bidirectional CIS)
2308 */
2309 const auto context_type = kContextTypeConversational;
2310 const int leaudio_group_id = 4;
2311
2312 additional_snk_ases = 1;
2313
2314 // Prepare fake connected device group
2315 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2316
2317 /* Since we prepared device with Conversional context in mind,
2318 * 2 Sink ASEs and 1 Source ASE should have been configured.
2319 */
2320 PrepareConfigureCodecHandler(group, 3);
2321 PrepareConfigureQosHandler(group, 3);
2322 PrepareEnableHandler(group, 3, false);
2323 PrepareReceiverStartReadyHandler(group, 1);
2324
2325 /*
2326 * 1. Codec Config
2327 * 2. Qos Config
2328 * 3. Enable
2329 * 4. Release
2330 */
2331 auto* leAudioDevice = group->GetFirstDevice();
2332 EXPECT_CALL(gatt_queue,
2333 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2334 GATT_WRITE_NO_RSP, _, _))
2335 .Times(4);
2336
2337 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2338 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
2339 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
2340 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2341 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2342 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
2343
2344 InjectInitialIdleNotification(group);
2345
2346 // Validate GroupStreamStatus
2347 EXPECT_CALL(mock_callbacks_,
2348 StatusReportCb(leaudio_group_id,
2349 bluetooth::le_audio::GroupStreamStatus::STREAMING))
2350 .Times(0);
2351 EXPECT_CALL(mock_callbacks_,
2352 StatusReportCb(leaudio_group_id,
2353 bluetooth::le_audio::GroupStreamStatus::RELEASING))
2354 .Times(1);
2355
2356 // Start the configuration and stream Media content
2357 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2358 group, context_type,
2359 {.sink = types::AudioContexts(context_type),
2360 .source = types::AudioContexts(context_type)}));
2361
2362 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
2363 }
2364
TEST_F(StateMachineTest,testStreamMultipleMedia_OneMemberHasNoAses)2365 TEST_F(StateMachineTest, testStreamMultipleMedia_OneMemberHasNoAses) {
2366 const auto context_type = kContextTypeMedia;
2367 const auto leaudio_group_id = 4;
2368 const auto num_devices = 2;
2369
2370 // Prepare multiple fake connected devices in a group. This time one device
2371 // has 0 Ases
2372 auto* group =
2373 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices,
2374 types::AudioContexts(), true);
2375 ASSERT_EQ(group->Size(), num_devices);
2376
2377 PrepareConfigureCodecHandler(group);
2378 PrepareConfigureQosHandler(group);
2379 PrepareEnableHandler(group);
2380 PrepareReceiverStartReadyHandler(group);
2381
2382 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2383 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1));
2384 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
2385 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2386 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2387 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
2388
2389 InjectInitialIdleNotification(group);
2390
2391 /* Check there are two devices*/
2392 auto* leAudioDevice = group->GetFirstDevice();
2393 LeAudioDevice* lastDevice = nullptr;
2394 /*
2395 * First set member has no ASEs, no operations on control point are expected
2396 * 0
2397 */
2398 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
2399 leAudioDevice->ctp_hdls_.val_hdl,
2400 _, GATT_WRITE_NO_RSP, _, _))
2401 .Times(0);
2402
2403 auto expected_devices_written = 0;
2404 while (leAudioDevice) {
2405 expected_devices_written++;
2406 lastDevice = leAudioDevice;
2407 leAudioDevice = group->GetNextDevice(leAudioDevice);
2408 }
2409 ASSERT_EQ(expected_devices_written, num_devices);
2410
2411 /*
2412 * Second device will be configured for Streaming. Expecting 3 operations:
2413 * 1. Codec Config
2414 * 2. QoS Config
2415 * 3. Enable
2416 */
2417 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
2418 lastDevice->ctp_hdls_.val_hdl, _,
2419 GATT_WRITE_NO_RSP, _, _))
2420 .Times(3);
2421
2422 // Validate GroupStreamStatus
2423 EXPECT_CALL(
2424 mock_callbacks_,
2425 StatusReportCb(leaudio_group_id,
2426 bluetooth::le_audio::GroupStreamStatus::STREAMING));
2427
2428 // Start the configuration and stream Media content
2429 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2430 group, context_type,
2431 {.sink = types::AudioContexts(context_type),
2432 .source = types::AudioContexts(context_type)}));
2433
2434 // Check if group has transitioned to a proper state
2435 ASSERT_EQ(group->GetState(),
2436 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2437 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
2438 }
2439
TEST_F(StateMachineTest,testStreamMultipleMedia_OneMemberHasNoAsesAndNotConnected)2440 TEST_F(StateMachineTest,
2441 testStreamMultipleMedia_OneMemberHasNoAsesAndNotConnected) {
2442 const auto context_type = kContextTypeMedia;
2443 const auto leaudio_group_id = 4;
2444 const auto num_devices = 2;
2445
2446 // Prepare multiple fake connected devices in a group. This time one device
2447 // has 0 Ases
2448 auto* group =
2449 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices,
2450 types::AudioContexts(), true);
2451 ASSERT_EQ(group->Size(), num_devices);
2452
2453 PrepareConfigureCodecHandler(group);
2454 PrepareConfigureQosHandler(group);
2455 PrepareEnableHandler(group);
2456 PrepareReceiverStartReadyHandler(group);
2457
2458 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2459 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1));
2460 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
2461 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2462 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2463 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
2464
2465 InjectInitialIdleNotification(group);
2466
2467 /* Check there are two devices*/
2468 auto* leAudioDevice = group->GetFirstDevice();
2469 LeAudioDevice* lastDevice = nullptr;
2470 /*
2471 * First set member has no ASEs, no operations on control point are expected
2472 * 0
2473 */
2474 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
2475 leAudioDevice->ctp_hdls_.val_hdl,
2476 _, GATT_WRITE_NO_RSP, _, _))
2477 .Times(0);
2478
2479 /* Device with 0 Ases is disconnected */
2480 InjectAclDisconnected(group, leAudioDevice);
2481
2482 auto expected_devices_written = 0;
2483 while (leAudioDevice) {
2484 expected_devices_written++;
2485 lastDevice = leAudioDevice;
2486 leAudioDevice = group->GetNextDevice(leAudioDevice);
2487 }
2488 ASSERT_EQ(expected_devices_written, num_devices);
2489
2490 /*
2491 * Second device will be configured for Streaming. Expecting 3 operations:
2492 * 1. Codec Config
2493 * 2. QoS Config
2494 * 3. Enable
2495 */
2496 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
2497 lastDevice->ctp_hdls_.val_hdl, _,
2498 GATT_WRITE_NO_RSP, _, _))
2499 .Times(3);
2500
2501 // Validate GroupStreamStatus
2502 EXPECT_CALL(
2503 mock_callbacks_,
2504 StatusReportCb(leaudio_group_id,
2505 bluetooth::le_audio::GroupStreamStatus::STREAMING));
2506
2507 // Start the configuration and stream Media content
2508 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2509 group, context_type,
2510 {.sink = types::AudioContexts(context_type),
2511 .source = types::AudioContexts(context_type)}));
2512
2513 // Check if group has transitioned to a proper state
2514 ASSERT_EQ(group->GetState(),
2515 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2516 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
2517 }
2518
TEST_F(StateMachineTest,testStreamMultipleConversational)2519 TEST_F(StateMachineTest, testStreamMultipleConversational) {
2520 const auto context_type = kContextTypeConversational;
2521 const auto leaudio_group_id = 4;
2522 const auto num_devices = 2;
2523
2524 // Prepare multiple fake connected devices in a group
2525 auto* group =
2526 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
2527 ASSERT_EQ(group->Size(), num_devices);
2528
2529 PrepareConfigureCodecHandler(group);
2530 PrepareConfigureQosHandler(group);
2531 PrepareEnableHandler(group);
2532 PrepareReceiverStartReadyHandler(group);
2533
2534 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2535 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1));
2536 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4);
2537 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2538 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2539 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
2540
2541 InjectInitialIdleNotification(group);
2542
2543 auto* leAudioDevice = group->GetFirstDevice();
2544 auto expected_devices_written = 0;
2545 while (leAudioDevice) {
2546 EXPECT_CALL(gatt_queue,
2547 WriteCharacteristic(leAudioDevice->conn_id_,
2548 leAudioDevice->ctp_hdls_.val_hdl, _,
2549 GATT_WRITE_NO_RSP, _, _))
2550 .Times(4);
2551 expected_devices_written++;
2552 leAudioDevice = group->GetNextDevice(leAudioDevice);
2553 }
2554 ASSERT_EQ(expected_devices_written, num_devices);
2555
2556 // Validate GroupStreamStatus
2557 EXPECT_CALL(
2558 mock_callbacks_,
2559 StatusReportCb(leaudio_group_id,
2560 bluetooth::le_audio::GroupStreamStatus::STREAMING));
2561
2562 // Start the configuration and stream Media content
2563 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2564 group, context_type,
2565 {.sink = types::AudioContexts(context_type),
2566 .source = types::AudioContexts(context_type)}));
2567
2568 // Check if group has transitioned to a proper state
2569 ASSERT_EQ(group->GetState(),
2570 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2571 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
2572 }
2573
2574 MATCHER_P(dataPathDirIsEq, expected, "") {
2575 return (arg.data_path_dir == expected);
2576 }
2577
TEST_F(StateMachineTest,testFailedStreamMultipleConversational)2578 TEST_F(StateMachineTest, testFailedStreamMultipleConversational) {
2579 /* Testing here CIS Failed to be established */
2580 const auto context_type = kContextTypeConversational;
2581 const auto leaudio_group_id = 4;
2582 const auto num_devices = 2;
2583 overwrite_cis_status_ = true;
2584
2585 cis_status_.resize(2);
2586 cis_status_[0] = 0x00;
2587 cis_status_[1] = 0x0e; // Failed to be established
2588
2589 // Prepare multiple fake connected devices in a group
2590 auto* group =
2591 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
2592 ASSERT_EQ(group->Size(), num_devices);
2593
2594 PrepareConfigureCodecHandler(group);
2595 PrepareConfigureQosHandler(group);
2596 PrepareEnableHandler(group);
2597 PrepareReceiverStartReadyHandler(group);
2598 PrepareReleaseHandler(group);
2599
2600 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2601 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1));
2602
2603 /* Bidirectional CIS data path is configured in tw ocalls and removed for both
2604 * directions with a single call.
2605 */
2606 EXPECT_CALL(*mock_iso_manager_,
2607 SetupIsoDataPath(
2608 _, dataPathDirIsEq(
2609 bluetooth::hci::iso_manager::kIsoDataPathDirectionIn)))
2610 .Times(1);
2611 EXPECT_CALL(
2612 *mock_iso_manager_,
2613 SetupIsoDataPath(
2614 _, dataPathDirIsEq(
2615 bluetooth::hci::iso_manager::kIsoDataPathDirectionOut)))
2616 .Times(1);
2617 EXPECT_CALL(
2618 *mock_iso_manager_,
2619 RemoveIsoDataPath(
2620 _, bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput |
2621 bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput))
2622 .Times(1);
2623
2624 /* This check is the major one in this test, as we want to make sure,
2625 * it will not be called twice but only once (when both bidirectional ASEs are
2626 * not in the STREAMING or ENABLING state)
2627 */
2628 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
2629
2630 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2631
2632 InjectInitialIdleNotification(group);
2633
2634 auto* leAudioDevice = group->GetFirstDevice();
2635
2636 /* First device Control Point actions
2637 * Codec Config
2638 * QoS Config
2639 * Enable
2640 * Receiver ready
2641 * Release
2642 */
2643 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
2644 leAudioDevice->ctp_hdls_.val_hdl,
2645 _, GATT_WRITE_NO_RSP, _, _))
2646 .Times(5);
2647 leAudioDevice = group->GetNextDevice(leAudioDevice);
2648
2649 /* Second device Control Point actions
2650 * Codec Config
2651 * QoS Config
2652 * Enable (failed on CIS established - therefore no Receiver Ready)
2653 * Release
2654 */
2655 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
2656 leAudioDevice->ctp_hdls_.val_hdl,
2657 _, GATT_WRITE_NO_RSP, _, _))
2658 .Times(4);
2659
2660 /* Prepare DisconnectCis mock to not symulate CisDisconnection */
2661 ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return());
2662
2663 // Start the configuration and stream Media content
2664 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2665 group, context_type,
2666 {.sink = types::AudioContexts(context_type),
2667 .source = types::AudioContexts(context_type)}));
2668
2669 // Check if group has transitioned to a proper state
2670 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2671
2672 /* Called twice. One when change target state from Streaming to IDLE,
2673 * and second time, when state machine entered IDLE.
2674 */
2675 ASSERT_EQ(2, get_func_call_count("alarm_cancel"));
2676 }
2677
TEST_F(StateMachineTest,testAttachToStreamWhileFirstDeviceIsStartingStream)2678 TEST_F(StateMachineTest, testAttachToStreamWhileFirstDeviceIsStartingStream) {
2679 /* Testing here CIS Failed to be established */
2680 const auto context_type = kContextTypeConversational;
2681 const auto leaudio_group_id = 4;
2682 const auto num_devices = 2;
2683
2684 // Prepare multiple fake connected devices in a group
2685 auto* group =
2686 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
2687 ASSERT_EQ(group->Size(), num_devices);
2688
2689 PrepareConfigureCodecHandler(group);
2690 PrepareConfigureQosHandler(group);
2691 PrepareEnableHandler(group, 0, true /* inject enabling */,
2692 false /* inject streaming*/);
2693 PrepareReleaseHandler(group);
2694
2695 InjectInitialIdleNotification(group);
2696 auto firstDevice = group->GetFirstDevice();
2697 auto lastDevice = group->GetNextDevice(firstDevice);
2698
2699 /* Disconnect first device */
2700 InjectAclDisconnected(group, firstDevice);
2701
2702 // Start the configuration and stream Media content
2703 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2704 group, context_type,
2705 {.sink = types::AudioContexts(context_type),
2706 .source = types::AudioContexts(context_type)}));
2707
2708 // Now, group is not yet in the streaming state. Let's simulated the other
2709 // device got connected
2710 firstDevice->conn_id_ = 1;
2711 firstDevice->SetConnectionState(DeviceConnectState::CONNECTED);
2712
2713 for (auto& ase : lastDevice->ases_) {
2714 std::vector<uint8_t> params{};
2715 if (ase.active) {
2716 InjectAseStateNotification(&ase, lastDevice, group,
2717 ascs::kAseStateStreaming, ¶ms);
2718 }
2719 }
2720
2721 // Check if group has transitioned to a proper state
2722 ASSERT_EQ(group->GetState(),
2723 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2724 }
2725
TEST_F(StateMachineTest,testFailedStreamCreation)2726 TEST_F(StateMachineTest, testFailedStreamCreation) {
2727 /* Testing here different error than CIS Failed to be established */
2728 const auto context_type = kContextTypeConversational;
2729 const auto leaudio_group_id = 4;
2730 const auto num_devices = 2;
2731
2732 // Prepare multiple fake connected devices in a group
2733 auto* group =
2734 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
2735 ASSERT_EQ(group->Size(), num_devices);
2736
2737 PrepareConfigureCodecHandler(group);
2738 PrepareConfigureQosHandler(group);
2739 PrepareEnableHandler(group, 0, true /* inject enabling */,
2740 false /* inject streaming*/);
2741 PrepareReleaseHandler(group);
2742
2743 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2744 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
2745 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
2746 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2747 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
2748 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2749
2750 /* Prepare DisconnectCis mock to not symulate CisDisconnection */
2751 ON_CALL(*mock_iso_manager_, EstablishCis).WillByDefault(Return());
2752
2753 InjectInitialIdleNotification(group);
2754
2755 auto* leAudioDevice = group->GetFirstDevice();
2756
2757 /* First device Control Point actions
2758 * Codec Config
2759 * QoS Config
2760 * Enable
2761 * Release
2762 */
2763 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
2764 leAudioDevice->ctp_hdls_.val_hdl,
2765 _, GATT_WRITE_NO_RSP, _, _))
2766 .Times(4);
2767 leAudioDevice = group->GetNextDevice(leAudioDevice);
2768
2769 /* Second device Control Point actions
2770 * Codec Config
2771 * QoS Config
2772 * Enable (failed on CIS established - therefore no Receiver Ready)
2773 * Release
2774 */
2775 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
2776 leAudioDevice->ctp_hdls_.val_hdl,
2777 _, GATT_WRITE_NO_RSP, _, _))
2778 .Times(4);
2779
2780 // Start the configuration and stream Media content
2781 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2782 group, context_type,
2783 {.sink = types::AudioContexts(context_type),
2784 .source = types::AudioContexts(context_type)}));
2785
2786 bluetooth::hci::iso_manager::cis_establish_cmpl_evt evt;
2787 evt.status = HCI_ERR_LMP_RESPONSE_TIMEOUT;
2788
2789 LeAudioGroupStateMachine::Get()->ProcessHciNotifCisEstablished(
2790 group, leAudioDevice, &evt);
2791
2792 // Check if group has transitioned to a proper state
2793 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2794
2795 /* Called twice. One when change target state from Streaming to IDLE,
2796 * and second time, when state machine entered IDLE.
2797 */
2798 ASSERT_EQ(2, get_func_call_count("alarm_cancel"));
2799 }
2800
TEST_F(StateMachineTest,remoteRejectsEnable)2801 TEST_F(StateMachineTest, remoteRejectsEnable) {
2802 /* Testing here CIS Failed to be established */
2803 const auto context_type = kContextTypeConversational;
2804 const auto leaudio_group_id = 4;
2805 const auto num_devices = 2;
2806
2807 // Prepare multiple fake connected devices in a group
2808 auto* group =
2809 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
2810 ASSERT_EQ(group->Size(), num_devices);
2811
2812 PrepareConfigureCodecHandler(group);
2813 PrepareConfigureQosHandler(group);
2814 PrepareCtpNotificationError(
2815 group, client_parser::ascs::kCtpOpcodeEnable,
2816 client_parser::ascs::kCtpResponseCodeUnspecifiedError,
2817 client_parser::ascs::kCtpResponseNoReason);
2818 PrepareReleaseHandler(group);
2819
2820 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2821 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
2822 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
2823 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2824 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2825 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2826
2827 InjectInitialIdleNotification(group);
2828
2829 auto* leAudioDevice = group->GetFirstDevice();
2830
2831 /* First device Control Point actions
2832 * Codec Config
2833 * QoS Config
2834 * Enable
2835 * Release
2836 */
2837 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
2838 leAudioDevice->ctp_hdls_.val_hdl,
2839 _, GATT_WRITE_NO_RSP, _, _))
2840 .Times(4);
2841 leAudioDevice = group->GetNextDevice(leAudioDevice);
2842
2843 /* Second device Control Point actions
2844 * Codec Config
2845 * QoS Config
2846 * Release
2847 */
2848 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
2849 leAudioDevice->ctp_hdls_.val_hdl,
2850 _, GATT_WRITE_NO_RSP, _, _))
2851 .Times(3);
2852
2853 // Start the configuration and stream Media content
2854 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2855 group, context_type,
2856 {.sink = types::AudioContexts(context_type),
2857 .source = types::AudioContexts(context_type)}));
2858
2859 // Check if group has transitioned to a proper state
2860 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2861 ASSERT_EQ(2, get_func_call_count("alarm_cancel"));
2862 }
2863
TEST_F(StateMachineTest,testStreamMultiple)2864 TEST_F(StateMachineTest, testStreamMultiple) {
2865 const auto context_type = kContextTypeMedia;
2866 const auto leaudio_group_id = 4;
2867 const auto num_devices = 2;
2868
2869 // Prepare multiple fake connected devices in a group
2870 auto* group =
2871 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
2872 ASSERT_EQ(group->Size(), num_devices);
2873
2874 PrepareConfigureCodecHandler(group);
2875 PrepareConfigureQosHandler(group);
2876 PrepareEnableHandler(group);
2877
2878 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2879 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1));
2880 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
2881 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2882 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2883 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
2884
2885 InjectInitialIdleNotification(group);
2886
2887 auto* leAudioDevice = group->GetFirstDevice();
2888 auto expected_devices_written = 0;
2889 while (leAudioDevice) {
2890 EXPECT_CALL(gatt_queue,
2891 WriteCharacteristic(leAudioDevice->conn_id_,
2892 leAudioDevice->ctp_hdls_.val_hdl, _,
2893 GATT_WRITE_NO_RSP, _, _))
2894 .Times(AtLeast(3));
2895 expected_devices_written++;
2896 leAudioDevice = group->GetNextDevice(leAudioDevice);
2897 }
2898 ASSERT_EQ(expected_devices_written, num_devices);
2899
2900 // Validate GroupStreamStatus
2901 EXPECT_CALL(
2902 mock_callbacks_,
2903 StatusReportCb(leaudio_group_id,
2904 bluetooth::le_audio::GroupStreamStatus::STREAMING));
2905
2906 // Start the configuration and stream Media content
2907 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2908 group, context_type,
2909 {.sink = types::AudioContexts(context_type),
2910 .source = types::AudioContexts(context_type)}));
2911
2912 // Check if group has transitioned to a proper state
2913 ASSERT_EQ(group->GetState(),
2914 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2915 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
2916 }
2917
TEST_F(StateMachineTest,testUpdateMetadataMultiple)2918 TEST_F(StateMachineTest, testUpdateMetadataMultiple) {
2919 const auto context_type = kContextTypeMedia;
2920 const auto leaudio_group_id = 4;
2921 const auto num_devices = 2;
2922
2923 auto supported_contexts =
2924 types::AudioContexts(kContextTypeMedia | kContextTypeSoundEffects);
2925
2926 // Prepare multiple fake connected devices in a group
2927 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type,
2928 num_devices, supported_contexts);
2929 ASSERT_EQ(group->Size(), num_devices);
2930
2931 PrepareConfigureCodecHandler(group);
2932 PrepareConfigureQosHandler(group);
2933 PrepareEnableHandler(group);
2934
2935 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2936 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1));
2937 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
2938 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2939 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2940 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
2941
2942 InjectInitialIdleNotification(group);
2943
2944 auto* leAudioDevice = group->GetFirstDevice();
2945 auto expected_devices_written = 0;
2946 while (leAudioDevice) {
2947 EXPECT_CALL(gatt_queue,
2948 WriteCharacteristic(leAudioDevice->conn_id_,
2949 leAudioDevice->ctp_hdls_.val_hdl, _,
2950 GATT_WRITE_NO_RSP, _, _))
2951 .Times(AtLeast(3));
2952 expected_devices_written++;
2953 leAudioDevice = group->GetNextDevice(leAudioDevice);
2954 }
2955 ASSERT_EQ(expected_devices_written, num_devices);
2956
2957 // Validate GroupStreamStatus
2958 EXPECT_CALL(
2959 mock_callbacks_,
2960 StatusReportCb(leaudio_group_id,
2961 bluetooth::le_audio::GroupStreamStatus::STREAMING));
2962
2963 // Start the configuration and stream Media content
2964 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2965 group, context_type,
2966 {.sink = types::AudioContexts(context_type),
2967 .source = types::AudioContexts(context_type)}));
2968
2969 testing::Mock::VerifyAndClearExpectations(&gatt_queue);
2970
2971 // Check if group has transitioned to a proper state
2972 ASSERT_EQ(group->GetState(),
2973 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2974
2975 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
2976 reset_mock_function_count_map();
2977
2978 // Make sure all devices get the metadata update
2979 leAudioDevice = group->GetFirstDevice();
2980 expected_devices_written = 0;
2981 while (leAudioDevice) {
2982 EXPECT_CALL(gatt_queue,
2983 WriteCharacteristic(leAudioDevice->conn_id_,
2984 leAudioDevice->ctp_hdls_.val_hdl, _,
2985 GATT_WRITE_NO_RSP, _, _))
2986 .Times(1);
2987 expected_devices_written++;
2988 leAudioDevice = group->GetNextDevice(leAudioDevice);
2989 }
2990 ASSERT_EQ(expected_devices_written, num_devices);
2991
2992 const auto metadata_context_type =
2993 kContextTypeMedia | kContextTypeSoundEffects;
2994 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2995 group, context_type,
2996 {.sink = metadata_context_type, .source = metadata_context_type}));
2997
2998 /* This is just update metadata - watchdog is not used */
2999 ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
3000 }
3001
TEST_F(StateMachineTest,testUpdateMetadataMultiple_NoUpdatesOnKeyTouch)3002 TEST_F(StateMachineTest, testUpdateMetadataMultiple_NoUpdatesOnKeyTouch) {
3003 const auto context_type = kContextTypeMedia;
3004 const auto leaudio_group_id = 4;
3005 const auto num_devices = 2;
3006
3007 /* Only Media is supported and available, */
3008 auto supported_contexts = types::AudioContexts(kContextTypeMedia);
3009
3010 // Prepare multiple fake connected devices in a group
3011 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type,
3012 num_devices, supported_contexts);
3013 ASSERT_EQ(group->Size(), num_devices);
3014
3015 PrepareConfigureCodecHandler(group);
3016 PrepareConfigureQosHandler(group);
3017 PrepareEnableHandler(group);
3018
3019 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3020 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1));
3021 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
3022 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
3023 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
3024 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
3025
3026 InjectInitialIdleNotification(group);
3027
3028 auto* leAudioDevice = group->GetFirstDevice();
3029 auto expected_devices_written = 0;
3030 while (leAudioDevice) {
3031 EXPECT_CALL(gatt_queue,
3032 WriteCharacteristic(leAudioDevice->conn_id_,
3033 leAudioDevice->ctp_hdls_.val_hdl, _,
3034 GATT_WRITE_NO_RSP, _, _))
3035 .Times(AtLeast(3));
3036 expected_devices_written++;
3037 leAudioDevice = group->GetNextDevice(leAudioDevice);
3038 }
3039 ASSERT_EQ(expected_devices_written, num_devices);
3040
3041 // Validate GroupStreamStatus
3042 EXPECT_CALL(
3043 mock_callbacks_,
3044 StatusReportCb(leaudio_group_id,
3045 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3046
3047 // Start the configuration and stream Media content
3048 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
3049 group, context_type,
3050 {.sink = types::AudioContexts(context_type),
3051 .source = types::AudioContexts(context_type)}));
3052
3053 testing::Mock::VerifyAndClearExpectations(&gatt_queue);
3054
3055 // Check if group has transitioned to a proper state
3056 ASSERT_EQ(group->GetState(),
3057 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3058
3059 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3060 reset_mock_function_count_map();
3061
3062 // Make sure all devices get the metadata update
3063 leAudioDevice = group->GetFirstDevice();
3064 expected_devices_written = 0;
3065 while (leAudioDevice) {
3066 EXPECT_CALL(gatt_queue,
3067 WriteCharacteristic(leAudioDevice->conn_id_,
3068 leAudioDevice->ctp_hdls_.val_hdl, _,
3069 GATT_WRITE_NO_RSP, _, _))
3070 .Times(0);
3071 expected_devices_written++;
3072 leAudioDevice = group->GetNextDevice(leAudioDevice);
3073 }
3074 ASSERT_EQ(expected_devices_written, num_devices);
3075
3076 const auto metadata_context_type =
3077 kContextTypeMedia | kContextTypeSoundEffects;
3078 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
3079 group, context_type,
3080 {.sink = metadata_context_type, .source = metadata_context_type}));
3081
3082 /* This is just update metadata - watchdog is not used */
3083 ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
3084 }
3085
TEST_F(StateMachineTest,testDisableSingle)3086 TEST_F(StateMachineTest, testDisableSingle) {
3087 /* Device is banded headphones with 2x snk + 0x src ase
3088 * (2xunidirectional CIS)
3089 */
3090 additional_snk_ases = 1;
3091 const auto context_type = kContextTypeRingtone;
3092 const int leaudio_group_id = 4;
3093
3094 // Prepare fake connected device group
3095 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
3096
3097 /* Ringtone context plus additional ASE with channel count 1
3098 * gives us 2 ASE which should have been configured.
3099 */
3100 PrepareConfigureCodecHandler(group, 2);
3101 PrepareConfigureQosHandler(group, 2);
3102 PrepareEnableHandler(group, 2);
3103 PrepareDisableHandler(group, 2);
3104
3105 auto* leAudioDevice = group->GetFirstDevice();
3106 EXPECT_CALL(gatt_queue,
3107 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
3108 GATT_WRITE_NO_RSP, _, _))
3109 .Times(4);
3110
3111 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3112 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3113 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
3114 EXPECT_CALL(
3115 *mock_iso_manager_,
3116 RemoveIsoDataPath(
3117 _, bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput))
3118 .Times(2);
3119 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
3120 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
3121
3122 InjectInitialIdleNotification(group);
3123
3124 EXPECT_CALL(
3125 mock_callbacks_,
3126 StatusReportCb(leaudio_group_id,
3127 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3128
3129 // Start the configuration and stream Media content
3130 LeAudioGroupStateMachine::Get()->StartStream(
3131 group, context_type,
3132 {.sink = types::AudioContexts(context_type),
3133 .source = types::AudioContexts(context_type)});
3134
3135 // Check if group has transitioned to a proper state
3136 ASSERT_EQ(group->GetState(),
3137 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3138
3139 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3140 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3141 reset_mock_function_count_map();
3142
3143 // Validate GroupStreamStatus
3144 EXPECT_CALL(
3145 mock_callbacks_,
3146 StatusReportCb(leaudio_group_id,
3147 bluetooth::le_audio::GroupStreamStatus::SUSPENDING));
3148 EXPECT_CALL(
3149 mock_callbacks_,
3150 StatusReportCb(leaudio_group_id,
3151 bluetooth::le_audio::GroupStreamStatus::SUSPENDED));
3152
3153 // Suspend the stream
3154 LeAudioGroupStateMachine::Get()->SuspendStream(group);
3155
3156 // Check if group has transition to a proper state
3157 ASSERT_EQ(group->GetState(),
3158 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
3159
3160 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3161 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3162 }
3163
TEST_F(StateMachineTest,testDisableMultiple)3164 TEST_F(StateMachineTest, testDisableMultiple) {
3165 const auto context_type = kContextTypeMedia;
3166 const auto leaudio_group_id = 4;
3167 const auto num_devices = 2;
3168
3169 // Prepare multiple fake connected devices in a group
3170 auto* group =
3171 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3172 ASSERT_EQ(group->Size(), num_devices);
3173
3174 PrepareConfigureCodecHandler(group);
3175 PrepareConfigureQosHandler(group);
3176 PrepareEnableHandler(group);
3177 PrepareDisableHandler(group);
3178
3179 auto* leAudioDevice = group->GetFirstDevice();
3180 auto expected_devices_written = 0;
3181 while (leAudioDevice) {
3182 EXPECT_CALL(gatt_queue,
3183 WriteCharacteristic(leAudioDevice->conn_id_,
3184 leAudioDevice->ctp_hdls_.val_hdl, _,
3185 GATT_WRITE_NO_RSP, _, _))
3186 .Times(AtLeast(4));
3187 expected_devices_written++;
3188 leAudioDevice = group->GetNextDevice(leAudioDevice);
3189 }
3190 ASSERT_EQ(expected_devices_written, num_devices);
3191
3192 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3193 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3194 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
3195 EXPECT_CALL(
3196 *mock_iso_manager_,
3197 RemoveIsoDataPath(
3198 _, bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput))
3199 .Times(2);
3200 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
3201 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
3202
3203 InjectInitialIdleNotification(group);
3204
3205 // Start the configuration and stream Media content
3206 LeAudioGroupStateMachine::Get()->StartStream(
3207 group, context_type,
3208 {.sink = types::AudioContexts(context_type),
3209 .source = types::AudioContexts(context_type)});
3210
3211 // Check if group has transitioned to a proper state
3212 ASSERT_EQ(group->GetState(),
3213 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3214 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3215 reset_mock_function_count_map();
3216
3217 // Validate GroupStreamStatus
3218 EXPECT_CALL(
3219 mock_callbacks_,
3220 StatusReportCb(leaudio_group_id,
3221 bluetooth::le_audio::GroupStreamStatus::SUSPENDING));
3222 EXPECT_CALL(
3223 mock_callbacks_,
3224 StatusReportCb(leaudio_group_id,
3225 bluetooth::le_audio::GroupStreamStatus::SUSPENDED));
3226
3227 // Suspend the stream
3228 LeAudioGroupStateMachine::Get()->SuspendStream(group);
3229
3230 // Check if group has transitioned to a proper state
3231 ASSERT_EQ(group->GetState(),
3232 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
3233 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3234 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3235 }
3236
TEST_F(StateMachineTest,testDisableBidirectional)3237 TEST_F(StateMachineTest, testDisableBidirectional) {
3238 /* Device is banded headphones with 2x snk + 1x src ase
3239 * (1x bidirectional + 1xunidirectional CIS)
3240 */
3241 additional_snk_ases = 1;
3242 const auto context_type = kContextTypeConversational;
3243 const int leaudio_group_id = 4;
3244
3245 // Prepare fake connected device group
3246 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
3247
3248 /* Since we prepared device with Conversional context in mind, Sink and Source
3249 * ASEs should have been configured.
3250 */
3251 PrepareConfigureCodecHandler(group, 3);
3252 PrepareConfigureQosHandler(group, 3);
3253 PrepareEnableHandler(group, 3);
3254 PrepareDisableHandler(group, 3);
3255 PrepareReceiverStartReadyHandler(group, 1);
3256 PrepareReceiverStopReady(group, 1);
3257
3258 auto* leAudioDevice = group->GetFirstDevice();
3259 EXPECT_CALL(gatt_queue,
3260 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
3261 GATT_WRITE_NO_RSP, _, _))
3262 .Times(AtLeast(4));
3263
3264 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3265 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3266 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
3267 bool removed_bidirectional = false;
3268 bool removed_unidirectional = false;
3269
3270 /* Check data path removal */
3271 ON_CALL(*mock_iso_manager_, RemoveIsoDataPath)
3272 .WillByDefault(Invoke([&removed_bidirectional, &removed_unidirectional,
3273 this](uint16_t conn_handle,
3274 uint8_t data_path_dir) {
3275 /* Set flags for verification */
3276 if (data_path_dir ==
3277 (bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput |
3278 bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput)) {
3279 removed_bidirectional = true;
3280 } else if (data_path_dir == bluetooth::hci::iso_manager::
3281 kRemoveIsoDataPathDirectionInput) {
3282 removed_unidirectional = true;
3283 }
3284
3285 /* Copied from default handler of RemoveIsoDataPath*/
3286 auto dev_it =
3287 std::find_if(le_audio_devices_.begin(), le_audio_devices_.end(),
3288 [&conn_handle](auto& dev) {
3289 auto ases = dev->GetAsesByCisConnHdl(conn_handle);
3290 return (ases.sink || ases.source);
3291 });
3292 if (dev_it == le_audio_devices_.end()) {
3293 return;
3294 }
3295
3296 for (auto& kv_pair : le_audio_device_groups_) {
3297 auto& group = kv_pair.second;
3298 if (group->IsDeviceInTheGroup(dev_it->get())) {
3299 LeAudioGroupStateMachine::Get()->ProcessHciNotifRemoveIsoDataPath(
3300 group.get(), dev_it->get(), 0, conn_handle);
3301 return;
3302 }
3303 }
3304 /* End of copy */
3305 }));
3306
3307 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
3308 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
3309
3310 // Start the configuration and stream Media content
3311 LeAudioGroupStateMachine::Get()->StartStream(
3312 group, context_type,
3313 {.sink = types::AudioContexts(context_type),
3314 .source = types::AudioContexts(context_type)});
3315
3316 // Check if group has transitioned to a proper state
3317 ASSERT_EQ(group->GetState(),
3318 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3319
3320 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3321 reset_mock_function_count_map();
3322
3323 // Validate GroupStreamStatus
3324 EXPECT_CALL(
3325 mock_callbacks_,
3326 StatusReportCb(leaudio_group_id,
3327 bluetooth::le_audio::GroupStreamStatus::SUSPENDING));
3328 EXPECT_CALL(
3329 mock_callbacks_,
3330 StatusReportCb(leaudio_group_id,
3331 bluetooth::le_audio::GroupStreamStatus::SUSPENDED));
3332
3333 // Suspend the stream
3334 LeAudioGroupStateMachine::Get()->SuspendStream(group);
3335
3336 // Check if group has transitioned to a proper state
3337 ASSERT_EQ(group->GetState(),
3338 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
3339 ASSERT_EQ(removed_bidirectional, true);
3340 ASSERT_EQ(removed_unidirectional, true);
3341
3342 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3343 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3344 }
3345
TEST_F(StateMachineTest,testReleaseSingle)3346 TEST_F(StateMachineTest, testReleaseSingle) {
3347 /* Device is banded headphones with 1x snk + 0x src ase
3348 * (1xunidirectional CIS) with channel count 2 (for stereo)
3349 */
3350 const auto context_type = kContextTypeRingtone;
3351 const int leaudio_group_id = 4;
3352 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
3353 kLeAudioCodecChannelCountTwoChannel;
3354
3355 // Prepare fake connected device group
3356 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
3357
3358 /* Since we prepared device with Ringtone context in mind, only one ASE
3359 * should have been configured.
3360 */
3361 PrepareConfigureCodecHandler(group, 1);
3362 PrepareConfigureQosHandler(group, 1);
3363 PrepareEnableHandler(group, 1);
3364 PrepareDisableHandler(group, 1);
3365 PrepareReleaseHandler(group, 1);
3366
3367 auto* leAudioDevice = group->GetFirstDevice();
3368 EXPECT_CALL(gatt_queue,
3369 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
3370 GATT_WRITE_NO_RSP, _, _))
3371 .Times(4);
3372
3373 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3374 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3375 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
3376 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1);
3377 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
3378 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
3379
3380 InjectInitialIdleNotification(group);
3381
3382 // Start the configuration and stream Media content
3383 LeAudioGroupStateMachine::Get()->StartStream(
3384 group, context_type,
3385 {.sink = types::AudioContexts(context_type),
3386 .source = types::AudioContexts(context_type)});
3387
3388 // Check if group has transitioned to a proper state
3389 ASSERT_EQ(group->GetState(),
3390 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3391 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3392 reset_mock_function_count_map();
3393 // Validate GroupStreamStatus
3394 EXPECT_CALL(
3395 mock_callbacks_,
3396 StatusReportCb(leaudio_group_id,
3397 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3398 EXPECT_CALL(mock_callbacks_,
3399 StatusReportCb(leaudio_group_id,
3400 bluetooth::le_audio::GroupStreamStatus::IDLE));
3401
3402 // Stop the stream
3403 LeAudioGroupStateMachine::Get()->StopStream(group);
3404
3405 // Check if group has transitioned to a proper state
3406 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
3407 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3408 }
3409
TEST_F(StateMachineTest,testReleaseCachingSingle)3410 TEST_F(StateMachineTest, testReleaseCachingSingle) {
3411 /* Device is banded headphones with 1x snk + 0x src ase
3412 * (1xunidirectional CIS)
3413 */
3414 const auto context_type = kContextTypeRingtone;
3415 const int leaudio_group_id = 4;
3416 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
3417 kLeAudioCodecChannelCountTwoChannel;
3418
3419 // Prepare fake connected device group
3420 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
3421
3422 /* Since we prepared device with Ringtone context in mind, only one ASE
3423 * should have been configured.
3424 */
3425 PrepareConfigureCodecHandler(group, 1, true);
3426 PrepareConfigureQosHandler(group, 1);
3427 PrepareEnableHandler(group, 1);
3428 PrepareDisableHandler(group, 1);
3429 PrepareReleaseHandler(group, 1);
3430
3431 auto* leAudioDevice = group->GetFirstDevice();
3432 EXPECT_CALL(gatt_queue,
3433 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
3434 GATT_WRITE_NO_RSP, _, _))
3435 .Times(4);
3436
3437 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3438 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3439 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
3440 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1);
3441 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
3442 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
3443
3444 InjectInitialIdleNotification(group);
3445
3446 // Validate GroupStreamStatus
3447 EXPECT_CALL(
3448 mock_callbacks_,
3449 StatusReportCb(leaudio_group_id,
3450 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3451
3452 EXPECT_CALL(
3453 mock_callbacks_,
3454 StatusReportCb(
3455 leaudio_group_id,
3456 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
3457 EXPECT_CALL(
3458 mock_callbacks_,
3459 StatusReportCb(leaudio_group_id,
3460 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3461
3462 // Start the configuration and stream Media content
3463 LeAudioGroupStateMachine::Get()->StartStream(
3464 group, context_type,
3465 {.sink = types::AudioContexts(context_type),
3466 .source = types::AudioContexts(context_type)});
3467
3468 // Check if group has transitioned to a proper state
3469 ASSERT_EQ(group->GetState(),
3470 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3471
3472 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3473 reset_mock_function_count_map();
3474
3475 // Stop the stream
3476 LeAudioGroupStateMachine::Get()->StopStream(group);
3477
3478 // Check if group has transitioned to a proper state
3479 ASSERT_EQ(group->GetState(),
3480 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
3481
3482 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3483 }
3484
TEST_F(StateMachineTest,testStreamCaching_NoReconfigurationNeeded_SingleDevice)3485 TEST_F(StateMachineTest,
3486 testStreamCaching_NoReconfigurationNeeded_SingleDevice) {
3487 const auto context_type = kContextTypeRingtone;
3488 const int leaudio_group_id = 4;
3489 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
3490 kLeAudioCodecChannelCountTwoChannel;
3491
3492 additional_snk_ases = 2;
3493 // Prepare fake connected device group
3494 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
3495
3496 /* Since we prepared device with Ringtone context in mind and with no Source
3497 * ASEs, therefor only one ASE should have been configured.
3498 */
3499 PrepareConfigureCodecHandler(group, 1, true);
3500 PrepareConfigureQosHandler(group, 1, true);
3501 PrepareEnableHandler(group, 1);
3502 PrepareDisableHandler(group, 1);
3503 PrepareReleaseHandler(group, 1);
3504
3505 /* Ctp messages we expect:
3506 * 1. Codec Config
3507 * 2. QoS Config
3508 * 3. Enable
3509 * 4. Release
3510 * 5. QoS Config (because device stays in Configured state)
3511 * 6. Enable
3512 */
3513 auto* leAudioDevice = group->GetFirstDevice();
3514 EXPECT_CALL(gatt_queue,
3515 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
3516 GATT_WRITE_NO_RSP, _, _))
3517 .Times(6);
3518
3519 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2);
3520 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2);
3521 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
3522 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1);
3523 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
3524 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
3525
3526 InjectInitialIdleNotification(group);
3527
3528 // Validate GroupStreamStatus
3529 EXPECT_CALL(
3530 mock_callbacks_,
3531 StatusReportCb(leaudio_group_id,
3532 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3533
3534 EXPECT_CALL(
3535 mock_callbacks_,
3536 StatusReportCb(
3537 leaudio_group_id,
3538 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
3539
3540 EXPECT_CALL(mock_callbacks_,
3541 StatusReportCb(leaudio_group_id,
3542 bluetooth::le_audio::GroupStreamStatus::STREAMING))
3543 .Times(2);
3544
3545 // Start the configuration and stream Ringtone content
3546 LeAudioGroupStateMachine::Get()->StartStream(
3547 group, context_type,
3548 {.sink = types::AudioContexts(context_type),
3549 .source = types::AudioContexts(context_type)});
3550
3551 // Check if group has transitioned to a proper state
3552 ASSERT_EQ(group->GetState(),
3553 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3554
3555 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3556 reset_mock_function_count_map();
3557
3558 // Stop the stream
3559 LeAudioGroupStateMachine::Get()->StopStream(group);
3560
3561 // Check if group has transitioned to a proper state
3562 ASSERT_EQ(group->GetState(),
3563 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
3564
3565 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3566 reset_mock_function_count_map();
3567
3568 // Start the configuration and stream Media content
3569 LeAudioGroupStateMachine::Get()->StartStream(
3570 group, context_type,
3571 {.sink = types::AudioContexts(context_type),
3572 .source = types::AudioContexts(context_type)});
3573
3574 // Check if group has transitioned to a proper state
3575 ASSERT_EQ(group->GetState(),
3576 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3577
3578 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3579 reset_mock_function_count_map();
3580 }
3581
TEST_F(StateMachineTest,test_StreamCaching_ReconfigureForContextChange_SingleDevice)3582 TEST_F(StateMachineTest,
3583 test_StreamCaching_ReconfigureForContextChange_SingleDevice) {
3584 auto context_type = kContextTypeConversational;
3585 const int leaudio_group_id = 4;
3586 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
3587 kLeAudioCodecChannelCountTwoChannel;
3588
3589 additional_snk_ases = 2;
3590 /* Prepare fake connected device group with update of Media and Conversational
3591 * contexts
3592 */
3593 auto* group = PrepareSingleTestDeviceGroup(
3594 leaudio_group_id, context_type, 1,
3595 kContextTypeConversational | kContextTypeMedia);
3596
3597 /* Don't validate ASE here, as after reconfiguration different ASE number
3598 * will be used.
3599 * For the first configuration (CONVERSTATIONAL) there will be 2 ASEs (Sink
3600 * and Source) After reconfiguration (MEDIA) there will be single ASE.
3601 */
3602 PrepareConfigureCodecHandler(group, 0, true);
3603 PrepareConfigureQosHandler(group, 0, true);
3604 PrepareEnableHandler(group);
3605 PrepareReceiverStartReadyHandler(group);
3606 PrepareReleaseHandler(group);
3607
3608 /* Ctp messages we expect:
3609 * 1. Codec Config
3610 * 2. QoS Config
3611 * 3. Enable
3612 * 4. Release
3613 * 5. Codec Config
3614 * 6. QoS Config
3615 * 7. Enable
3616 */
3617 auto* leAudioDevice = group->GetFirstDevice();
3618 EXPECT_CALL(gatt_queue,
3619 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
3620 GATT_WRITE_NO_RSP, _, _))
3621 .Times(8);
3622
3623 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2);
3624 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2);
3625
3626 /* 2 times for first configuration (1 Sink, 1 Source), 1 time for second
3627 * configuration (1 Sink)*/
3628 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
3629
3630 uint8_t value =
3631 bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput |
3632 bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput;
3633 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, value)).Times(1);
3634 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
3635 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
3636
3637 InjectInitialIdleNotification(group);
3638
3639 // Validate GroupStreamStatus
3640 EXPECT_CALL(
3641 mock_callbacks_,
3642 StatusReportCb(leaudio_group_id,
3643 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3644
3645 EXPECT_CALL(
3646 mock_callbacks_,
3647 StatusReportCb(
3648 leaudio_group_id,
3649 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
3650
3651 EXPECT_CALL(mock_callbacks_,
3652 StatusReportCb(leaudio_group_id,
3653 bluetooth::le_audio::GroupStreamStatus::STREAMING))
3654 .Times(2);
3655
3656 // Start the configuration and stream Conversational content
3657 LeAudioGroupStateMachine::Get()->StartStream(
3658 group, context_type,
3659 {.sink = types::AudioContexts(context_type),
3660 .source = types::AudioContexts(context_type)});
3661
3662 // Check if group has transitioned to a proper state
3663 ASSERT_EQ(group->GetState(),
3664 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3665
3666 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3667 reset_mock_function_count_map();
3668
3669 // Stop the stream
3670 LeAudioGroupStateMachine::Get()->StopStream(group);
3671
3672 // Check if group has transitioned to a proper state
3673 ASSERT_EQ(group->GetState(),
3674 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
3675
3676 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3677 reset_mock_function_count_map();
3678
3679 // Start the configuration and stream Media content
3680 context_type = kContextTypeMedia;
3681 LeAudioGroupStateMachine::Get()->StartStream(
3682 group, context_type,
3683 {.sink = types::AudioContexts(context_type),
3684 .source = types::AudioContexts(context_type)});
3685
3686 // Check if group has transitioned to a proper state
3687 ASSERT_EQ(group->GetState(),
3688 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3689 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3690 }
3691
TEST_F(StateMachineTest,testReleaseMultiple)3692 TEST_F(StateMachineTest, testReleaseMultiple) {
3693 const auto context_type = kContextTypeMedia;
3694 const auto leaudio_group_id = 6;
3695 const auto num_devices = 2;
3696
3697 // Prepare multiple fake connected devices in a group
3698 auto* group =
3699 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3700 ASSERT_EQ(group->Size(), num_devices);
3701
3702 PrepareConfigureCodecHandler(group);
3703 PrepareConfigureQosHandler(group);
3704 PrepareEnableHandler(group);
3705 PrepareDisableHandler(group);
3706 PrepareReleaseHandler(group);
3707
3708 auto* leAudioDevice = group->GetFirstDevice();
3709 auto expected_devices_written = 0;
3710 while (leAudioDevice) {
3711 EXPECT_CALL(gatt_queue,
3712 WriteCharacteristic(leAudioDevice->conn_id_,
3713 leAudioDevice->ctp_hdls_.val_hdl, _,
3714 GATT_WRITE_NO_RSP, _, _))
3715 .Times(AtLeast(4));
3716 expected_devices_written++;
3717 leAudioDevice = group->GetNextDevice(leAudioDevice);
3718 }
3719 ASSERT_EQ(expected_devices_written, num_devices);
3720
3721 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3722 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3723 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
3724 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2);
3725 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
3726 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
3727
3728 InjectInitialIdleNotification(group);
3729
3730 EXPECT_CALL(mock_callbacks_,
3731 StatusReportCb(leaudio_group_id,
3732 bluetooth::le_audio::GroupStreamStatus::STREAMING))
3733 .Times(1);
3734
3735 // Start the configuration and stream Media content
3736 LeAudioGroupStateMachine::Get()->StartStream(
3737 group, context_type,
3738 {.sink = types::AudioContexts(context_type),
3739 .source = types::AudioContexts(context_type)});
3740
3741 // Check if group has transitioned to a proper state
3742 ASSERT_EQ(group->GetState(),
3743 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3744
3745 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3746 reset_mock_function_count_map();
3747
3748 // Validate GroupStreamStatus
3749 EXPECT_CALL(
3750 mock_callbacks_,
3751 StatusReportCb(leaudio_group_id,
3752 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3753 EXPECT_CALL(mock_callbacks_,
3754 StatusReportCb(leaudio_group_id,
3755 bluetooth::le_audio::GroupStreamStatus::IDLE));
3756 EXPECT_CALL(mock_callbacks_,
3757 StatusReportCb(leaudio_group_id,
3758 bluetooth::le_audio::GroupStreamStatus::STREAMING))
3759 .Times(0);
3760
3761 // Stop the stream
3762 LeAudioGroupStateMachine::Get()->StopStream(group);
3763
3764 // Check if group has transitioned to a proper state
3765 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
3766 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3767 }
3768
TEST_F(StateMachineTest,testReleaseMultiple_DeviceDisconnectedDuringRelease)3769 TEST_F(StateMachineTest, testReleaseMultiple_DeviceDisconnectedDuringRelease) {
3770 const auto context_type = kContextTypeMedia;
3771 const auto leaudio_group_id = 6;
3772 const auto num_devices = 2;
3773
3774 // Prepare multiple fake connected devices in a group
3775 auto* group =
3776 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3777 ASSERT_EQ(group->Size(), num_devices);
3778
3779 PrepareConfigureCodecHandler(group);
3780 PrepareConfigureQosHandler(group);
3781 PrepareEnableHandler(group);
3782 PrepareDisableHandler(group);
3783
3784 /* Here we inject device disconnection during release */
3785 PrepareReleaseHandler(group, 0, true);
3786
3787 auto* leAudioDevice = group->GetFirstDevice();
3788 auto expected_devices_written = 0;
3789 while (leAudioDevice) {
3790 EXPECT_CALL(gatt_queue,
3791 WriteCharacteristic(leAudioDevice->conn_id_,
3792 leAudioDevice->ctp_hdls_.val_hdl, _,
3793 GATT_WRITE_NO_RSP, _, _))
3794 .Times(AtLeast(4));
3795 expected_devices_written++;
3796 leAudioDevice = group->GetNextDevice(leAudioDevice);
3797 }
3798 ASSERT_EQ(expected_devices_written, num_devices);
3799
3800 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3801 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3802 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
3803 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
3804 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
3805
3806 InjectInitialIdleNotification(group);
3807
3808 EXPECT_CALL(mock_callbacks_,
3809 StatusReportCb(leaudio_group_id,
3810 bluetooth::le_audio::GroupStreamStatus::STREAMING))
3811 .Times(1);
3812
3813 // Start the configuration and stream Media content
3814 LeAudioGroupStateMachine::Get()->StartStream(
3815 group, context_type,
3816 {.sink = types::AudioContexts(context_type),
3817 .source = types::AudioContexts(context_type)});
3818
3819 // Check if group has transitioned to a proper state
3820 ASSERT_EQ(group->GetState(),
3821 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3822
3823 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3824 reset_mock_function_count_map();
3825
3826 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
3827
3828 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
3829 // Validate GroupStreamStatus
3830 EXPECT_CALL(
3831 mock_callbacks_,
3832 StatusReportCb(leaudio_group_id,
3833 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3834 EXPECT_CALL(mock_callbacks_,
3835 StatusReportCb(leaudio_group_id,
3836 bluetooth::le_audio::GroupStreamStatus::IDLE));
3837 EXPECT_CALL(mock_callbacks_,
3838 StatusReportCb(leaudio_group_id,
3839 bluetooth::le_audio::GroupStreamStatus::STREAMING))
3840 .Times(0);
3841
3842 // Stop the stream
3843 LeAudioGroupStateMachine::Get()->StopStream(group);
3844
3845 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
3846
3847 // Check if group has transitioned to a proper state
3848 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
3849 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3850 }
3851
TEST_F(StateMachineTest,testReleaseBidirectional)3852 TEST_F(StateMachineTest, testReleaseBidirectional) {
3853 /* Device is banded headphones with 2x snk + 1x src ase
3854 * (1x bidirectional + 1xunidirectional CIS)
3855 */
3856 additional_snk_ases = 1;
3857 const auto context_type = kContextTypeConversational;
3858 const auto leaudio_group_id = 6;
3859
3860 // Prepare fake connected device group
3861 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
3862
3863 /* Since we prepared device with Conversional context in mind, Sink and Source
3864 * ASEs should have been configured.
3865 */
3866 PrepareConfigureCodecHandler(group, 3);
3867 PrepareConfigureQosHandler(group, 3);
3868 PrepareEnableHandler(group, 3);
3869 PrepareDisableHandler(group, 3);
3870 PrepareReceiverStartReadyHandler(group, 1);
3871 PrepareReleaseHandler(group, 3);
3872
3873 auto* leAudioDevice = group->GetFirstDevice();
3874 EXPECT_CALL(gatt_queue,
3875 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
3876 GATT_WRITE_NO_RSP, _, _))
3877 .Times(AtLeast(4));
3878
3879 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3880 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3881 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
3882 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2);
3883 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
3884 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
3885
3886 InjectInitialIdleNotification(group);
3887
3888 // Start the configuration and stream Media content
3889 LeAudioGroupStateMachine::Get()->StartStream(
3890 group, context_type,
3891 {.sink = types::AudioContexts(context_type),
3892 .source = types::AudioContexts(context_type)});
3893
3894 // Check if group has transitioned to a proper state
3895 ASSERT_EQ(group->GetState(),
3896 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3897
3898 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3899 reset_mock_function_count_map();
3900
3901 // Stop the stream
3902 LeAudioGroupStateMachine::Get()->StopStream(group);
3903
3904 // Check if group has transitioned to a proper state
3905 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
3906 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
3907 reset_mock_function_count_map();
3908 }
3909
TEST_F(StateMachineTest,testDisableAndReleaseBidirectional)3910 TEST_F(StateMachineTest, testDisableAndReleaseBidirectional) {
3911 /* Device is banded headphones with 2x snk + 1x src ase
3912 * (1x bidirectional + 1xunidirectional CIS)
3913 */
3914 additional_snk_ases = 1;
3915 const auto context_type = kContextTypeConversational;
3916 const int leaudio_group_id = 4;
3917
3918 // Prepare fake connected device group
3919 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
3920
3921 /* Since we prepared device with Conversional context in mind, Sink and Source
3922 * ASEs should have been configured.
3923 */
3924 PrepareConfigureCodecHandler(group, 3);
3925 PrepareConfigureQosHandler(group, 3);
3926 PrepareEnableHandler(group, 3);
3927 PrepareDisableHandler(group, 3);
3928 PrepareReceiverStartReadyHandler(group, 1);
3929 PrepareReceiverStopReady(group, 1);
3930 PrepareReleaseHandler(group, 3);
3931
3932 auto* leAudioDevice = group->GetFirstDevice();
3933 EXPECT_CALL(gatt_queue,
3934 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
3935 GATT_WRITE_NO_RSP, _, _))
3936 .Times(AtLeast(4));
3937
3938 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3939 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3940 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
3941 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2);
3942 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
3943 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
3944
3945 // Start the configuration and stream Media content
3946 LeAudioGroupStateMachine::Get()->StartStream(
3947 group, context_type,
3948 {.sink = types::AudioContexts(context_type),
3949 .source = types::AudioContexts(context_type)});
3950
3951 // Suspend the stream
3952 LeAudioGroupStateMachine::Get()->SuspendStream(group);
3953
3954 // Stop the stream
3955 LeAudioGroupStateMachine::Get()->StopStream(group);
3956
3957 // Check if group has transitioned to a proper state
3958 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
3959 }
3960
TEST_F(StateMachineTest,testAseIdAssignmentIdle)3961 TEST_F(StateMachineTest, testAseIdAssignmentIdle) {
3962 const auto context_type = kContextTypeConversational;
3963 const auto leaudio_group_id = 6;
3964 const auto num_devices = 1;
3965
3966 // Prepare multiple fake connected devices in a group
3967 auto* group =
3968 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3969 ASSERT_EQ(group->Size(), num_devices);
3970
3971 // Should not trigger any action on our side
3972 EXPECT_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _)).Times(0);
3973 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0);
3974 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
3975 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
3976 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
3977 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
3978 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
3979
3980 for (auto* device = group->GetFirstDevice(); device != nullptr;
3981 device = group->GetNextDevice(device)) {
3982 for (auto& ase : device->ases_) {
3983 ASSERT_EQ(ase.id, bluetooth::le_audio::types::ase::kAseIdInvalid);
3984 InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle,
3985 nullptr);
3986 ASSERT_EQ(ase.id, ase_id_last_assigned);
3987 }
3988 }
3989 }
3990
TEST_F(StateMachineTest,testAseIdAssignmentCodecConfigured)3991 TEST_F(StateMachineTest, testAseIdAssignmentCodecConfigured) {
3992 const auto context_type = kContextTypeConversational;
3993 const auto leaudio_group_id = 6;
3994 const auto num_devices = 1;
3995
3996 // Prepare multiple fake connected devices in a group
3997 auto* group =
3998 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3999 ASSERT_EQ(group->Size(), num_devices);
4000
4001 // Should not trigger any action on our side
4002 EXPECT_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _)).Times(0);
4003 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0);
4004 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
4005 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
4006 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
4007 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
4008 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
4009
4010 for (auto* device = group->GetFirstDevice(); device != nullptr;
4011 device = group->GetNextDevice(device)) {
4012 for (auto& ase : device->ases_) {
4013 client_parser::ascs::ase_codec_configured_state_params
4014 codec_configured_state_params;
4015
4016 ASSERT_EQ(ase.id, bluetooth::le_audio::types::ase::kAseIdInvalid);
4017 InjectAseStateNotification(&ase, device, group,
4018 ascs::kAseStateCodecConfigured,
4019 &codec_configured_state_params);
4020 ASSERT_EQ(ase.id, ase_id_last_assigned);
4021 }
4022 }
4023 }
4024
TEST_F(StateMachineTest,testAseAutonomousRelease)4025 TEST_F(StateMachineTest, testAseAutonomousRelease) {
4026 /* Device is banded headphones with 2x snk + 1x src ase
4027 * (1x bidirectional + 1xunidirectional CIS)
4028 */
4029 additional_snk_ases = 1;
4030 const auto context_type = kContextTypeConversational;
4031 const int leaudio_group_id = 4;
4032
4033 // Prepare fake connected device group
4034 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
4035
4036 /* Since we prepared device with Conversional context in mind, Sink and Source
4037 * ASEs should have been configured.
4038 */
4039 PrepareConfigureCodecHandler(group, 3);
4040 PrepareConfigureQosHandler(group, 3);
4041 PrepareEnableHandler(group, 3);
4042 PrepareDisableHandler(group, 3);
4043 PrepareReceiverStartReadyHandler(group, 1);
4044 PrepareReceiverStopReady(group, 1);
4045 PrepareReleaseHandler(group, 3);
4046
4047 InjectInitialIdleNotification(group);
4048
4049 // Validate initial GroupStreamStatus
4050 EXPECT_CALL(
4051 mock_callbacks_,
4052 StatusReportCb(leaudio_group_id,
4053 bluetooth::le_audio::GroupStreamStatus::STREAMING));
4054
4055 // Start the configuration and stream Media content
4056 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4057 group, context_type,
4058 {.sink = types::AudioContexts(context_type),
4059 .source = types::AudioContexts(context_type)}));
4060
4061 // Validate new GroupStreamStatus
4062 EXPECT_CALL(mock_callbacks_,
4063 StatusReportCb(leaudio_group_id,
4064 bluetooth::le_audio::GroupStreamStatus::IDLE))
4065 .Times(AtLeast(1));
4066
4067 /* Single disconnect as it is bidirectional Cis*/
4068 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
4069
4070 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
4071 reset_mock_function_count_map();
4072
4073 for (auto* device = group->GetFirstDevice(); device != nullptr;
4074 device = group->GetNextDevice(device)) {
4075 for (auto& ase : device->ases_) {
4076 client_parser::ascs::ase_codec_configured_state_params
4077 codec_configured_state_params;
4078
4079 ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
4080
4081 // Each one does the autonomous release
4082 InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing,
4083 &codec_configured_state_params);
4084 InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle,
4085 &codec_configured_state_params);
4086 }
4087 }
4088
4089 // Verify we've handled the release and updated all states
4090 for (auto* device = group->GetFirstDevice(); device != nullptr;
4091 device = group->GetNextDevice(device)) {
4092 for (auto& ase : device->ases_) {
4093 ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
4094 }
4095 }
4096
4097 ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
4098 }
4099
TEST_F(StateMachineTest,testAseAutonomousRelease2Devices)4100 TEST_F(StateMachineTest, testAseAutonomousRelease2Devices) {
4101 const auto context_type = kContextTypeConversational;
4102 const int leaudio_group_id = 4;
4103 const int num_of_devices = 2;
4104
4105 // Prepare fake connected device group
4106 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type,
4107 num_of_devices);
4108
4109 /* Since we prepared device with Conversional context in mind, Sink and Source
4110 * ASEs should have been configured.
4111 */
4112 PrepareConfigureCodecHandler(group);
4113 PrepareConfigureQosHandler(group);
4114 PrepareEnableHandler(group);
4115 PrepareDisableHandler(group);
4116 PrepareReceiverStartReadyHandler(group);
4117 PrepareReceiverStopReady(group);
4118 PrepareReleaseHandler(group);
4119
4120 InjectInitialIdleNotification(group);
4121
4122 // Validate initial GroupStreamStatus
4123 EXPECT_CALL(
4124 mock_callbacks_,
4125 StatusReportCb(leaudio_group_id,
4126 bluetooth::le_audio::GroupStreamStatus::STREAMING));
4127
4128 // Start the configuration and stream Media content
4129 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4130 group, context_type,
4131 {.sink = types::AudioContexts(context_type),
4132 .source = types::AudioContexts(context_type)}));
4133
4134 // Check streaming will continue
4135 EXPECT_CALL(mock_callbacks_,
4136 StatusReportCb(leaudio_group_id,
4137 bluetooth::le_audio::GroupStreamStatus::IDLE))
4138 .Times(0);
4139
4140 /* Single disconnect as it is bidirectional Cis*/
4141 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
4142
4143 auto device = group->GetFirstDevice();
4144 for (auto& ase : device->ases_) {
4145 client_parser::ascs::ase_codec_configured_state_params
4146 codec_configured_state_params;
4147
4148 ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
4149
4150 // Simulate autonomus release for one device.
4151 InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing,
4152 &codec_configured_state_params);
4153 InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle,
4154 &codec_configured_state_params);
4155 }
4156 }
4157
TEST_F(StateMachineTest,testHandlingAutonomousCodecConfigStateOnConnection)4158 TEST_F(StateMachineTest, testHandlingAutonomousCodecConfigStateOnConnection) {
4159 /* Scenario
4160 * 1. After connection remote device has different ASE configurations
4161 * 2. Try to start stream and make sure it is configured well.
4162 */
4163
4164 const auto context_type = kContextTypeConversational;
4165 const int leaudio_group_id = 4;
4166 const int num_of_devices = 2;
4167
4168 // Prepare fake connected device group
4169 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type,
4170 num_of_devices);
4171
4172 auto* firstDevice = group->GetFirstDevice();
4173 auto* secondDevice = group->GetNextDevice(firstDevice);
4174
4175 /* Since we prepared device with Conversional context in mind, Sink and Source
4176 * ASEs should have been configured.
4177 */
4178 PrepareConfigureCodecHandler(group, 0, true);
4179 PrepareConfigureQosHandler(group);
4180 PrepareEnableHandler(group);
4181 PrepareDisableHandler(group);
4182 PrepareReceiverStartReadyHandler(group);
4183 PrepareReceiverStopReady(group);
4184
4185 /* Number of control point calls
4186 * 1. Codec Config
4187 * 2. QoS Config
4188 * 3. Enable
4189 * 4. Receiver Start Ready
4190 */
4191 EXPECT_CALL(gatt_queue, WriteCharacteristic(firstDevice->conn_id_,
4192 firstDevice->ctp_hdls_.val_hdl, _,
4193 GATT_WRITE_NO_RSP, _, _))
4194 .Times(4);
4195
4196 EXPECT_CALL(gatt_queue, WriteCharacteristic(secondDevice->conn_id_,
4197 secondDevice->ctp_hdls_.val_hdl,
4198 _, GATT_WRITE_NO_RSP, _, _))
4199 .Times(4);
4200
4201 InjectInitialIdleAndConfiguredNotification(group);
4202 // Call it second time to make sure we get into state that current_state_ is
4203 // different then target_state_ even group is not in transition.
4204 InjectInitialIdleAndConfiguredNotification(group);
4205
4206 ASSERT_TRUE(group->GetTargetState() != group->GetState());
4207 ASSERT_FALSE(group->IsInTransition());
4208
4209 // Validate initial GroupStreamStatus
4210 EXPECT_CALL(
4211 mock_callbacks_,
4212 StatusReportCb(leaudio_group_id,
4213 bluetooth::le_audio::GroupStreamStatus::STREAMING));
4214
4215 // Start the configuration and stream Media content
4216 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4217 group, context_type,
4218 {.sink = types::AudioContexts(context_type),
4219 .source = types::AudioContexts(context_type)}));
4220
4221 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
4222 }
4223
TEST_F(StateMachineTest,testHandlingInvalidRemoteAseStateHandling)4224 TEST_F(StateMachineTest, testHandlingInvalidRemoteAseStateHandling) {
4225 /* Scenario
4226 * 1. After connection remote device has different ASE configurations
4227 * 2. Try to start stream and make sure it is configured well.
4228 */
4229
4230 const auto context_type = kContextTypeConversational;
4231 const int leaudio_group_id = 4;
4232 const int num_of_devices = 2;
4233
4234 // Prepare fake connected device group
4235 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type,
4236 num_of_devices);
4237
4238 auto* firstDevice = group->GetFirstDevice();
4239 auto* secondDevice = group->GetNextDevice(firstDevice);
4240
4241 /* Since we prepared device with Conversional context in mind, Sink and Source
4242 * ASEs should have been configured.
4243 */
4244 PrepareConfigureCodecHandler(group, 0, true);
4245 PrepareConfigureQosHandler(group);
4246 PrepareEnableHandler(group);
4247 PrepareDisableHandler(group);
4248 PrepareReceiverStartReadyHandler(group);
4249 PrepareReceiverStopReady(group);
4250
4251 /* Number of control point calls
4252 * 1. Codec Config
4253 * 2. QoS Config
4254 * 3. Enable
4255 * 4. Receiver Start Ready
4256 */
4257 EXPECT_CALL(gatt_queue, WriteCharacteristic(firstDevice->conn_id_,
4258 firstDevice->ctp_hdls_.val_hdl, _,
4259 GATT_WRITE_NO_RSP, _, _))
4260 .Times(4);
4261
4262 EXPECT_CALL(gatt_queue, WriteCharacteristic(secondDevice->conn_id_,
4263 secondDevice->ctp_hdls_.val_hdl,
4264 _, GATT_WRITE_NO_RSP, _, _))
4265 .Times(4);
4266
4267 /* Inject invalid states*/
4268 InjectInitialInvalidNotification(group);
4269
4270 ASSERT_FALSE(group->IsInTransition());
4271
4272 // Validate initial GroupStreamStatus
4273 EXPECT_CALL(
4274 mock_callbacks_,
4275 StatusReportCb(leaudio_group_id,
4276 bluetooth::le_audio::GroupStreamStatus::STREAMING));
4277
4278 // Start the configuration and stream Media content
4279 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4280 group, context_type,
4281 {.sink = types::AudioContexts(context_type),
4282 .source = types::AudioContexts(context_type)}));
4283
4284 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
4285 }
4286
TEST_F(StateMachineTest,testHandlingCachedCodecConfig2Devices)4287 TEST_F(StateMachineTest, testHandlingCachedCodecConfig2Devices) {
4288 const auto context_type = kContextTypeConversational;
4289 const int leaudio_group_id = 4;
4290 const int num_of_devices = 2;
4291
4292 // Prepare fake connected device group
4293 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type,
4294 num_of_devices);
4295
4296 auto* firstDevice = group->GetFirstDevice();
4297 auto* secondDevice = group->GetNextDevice(firstDevice);
4298
4299 /* Since we prepared device with Conversional context in mind, Sink and Source
4300 * ASEs should have been configured.
4301 */
4302 PrepareConfigureCodecHandler(group, 0, true);
4303 PrepareConfigureQosHandler(group);
4304 PrepareEnableHandler(group);
4305 PrepareDisableHandler(group);
4306 PrepareReceiverStartReadyHandler(group);
4307 PrepareReceiverStopReady(group);
4308 PrepareReleaseHandler(group);
4309
4310 stay_in_releasing_state_ = true;
4311
4312 /* Number of control point calls
4313 * 1. Codec Config
4314 * 2. QoS Config
4315 * 3. Enable
4316 * 4. Receiver Start Ready
4317 * 5. Release*/
4318 EXPECT_CALL(gatt_queue, WriteCharacteristic(firstDevice->conn_id_,
4319 firstDevice->ctp_hdls_.val_hdl, _,
4320 GATT_WRITE_NO_RSP, _, _))
4321 .Times(5);
4322
4323 EXPECT_CALL(gatt_queue, WriteCharacteristic(secondDevice->conn_id_,
4324 secondDevice->ctp_hdls_.val_hdl,
4325 _, GATT_WRITE_NO_RSP, _, _))
4326 .Times(5);
4327
4328 InjectInitialIdleNotification(group);
4329
4330 // Validate initial GroupStreamStatus
4331 EXPECT_CALL(
4332 mock_callbacks_,
4333 StatusReportCb(leaudio_group_id,
4334 bluetooth::le_audio::GroupStreamStatus::STREAMING));
4335
4336 // Start the configuration and stream Media content
4337 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4338 group, context_type,
4339 {.sink = types::AudioContexts(context_type),
4340 .source = types::AudioContexts(context_type)}));
4341
4342 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
4343
4344 /* Two disconnect as it is two bidirectional Cises */
4345 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
4346
4347 // Validate initial GroupStreamStatus
4348 EXPECT_CALL(mock_callbacks_,
4349 StatusReportCb(leaudio_group_id,
4350 bluetooth::le_audio::GroupStreamStatus::RELEASING))
4351 .Times(1);
4352 EXPECT_CALL(
4353 mock_callbacks_,
4354 StatusReportCb(
4355 leaudio_group_id,
4356 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS))
4357 .Times(0);
4358
4359 // Stop the stream
4360 LeAudioGroupStateMachine::Get()->StopStream(group);
4361
4362 for (auto& ase : firstDevice->ases_) {
4363 log::debug("{} , {}, {}", firstDevice->address_, ase.id,
4364 bluetooth::common::ToString(ase.state));
4365 ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING);
4366 // Simulate autonomus configured state.
4367 InjectAseStateNotification(&ase, firstDevice, group,
4368 ascs::kAseStateCodecConfigured,
4369 &cached_codec_configuration_map_[ase.id]);
4370 }
4371
4372 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
4373
4374 /* When ALL devices got inactive, we should got the proper group status */
4375 EXPECT_CALL(
4376 mock_callbacks_,
4377 StatusReportCb(
4378 leaudio_group_id,
4379 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS))
4380 .Times(1);
4381 for (auto& ase : secondDevice->ases_) {
4382 log::debug("{} , {}, {}", firstDevice->address_, ase.id,
4383 bluetooth::common::ToString(ase.state));
4384 ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING);
4385 // Simulate autonomus configured state.
4386 InjectAseStateNotification(&ase, secondDevice, group,
4387 ascs::kAseStateCodecConfigured,
4388 &cached_codec_configuration_map_[ase.id]);
4389 }
4390
4391 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
4392 }
4393
TEST_F(StateMachineTest,testStateTransitionTimeoutOnIdleState)4394 TEST_F(StateMachineTest, testStateTransitionTimeoutOnIdleState) {
4395 const auto context_type = kContextTypeRingtone;
4396 const int leaudio_group_id = 4;
4397 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
4398 kLeAudioCodecChannelCountTwoChannel;
4399
4400 // Prepare fake connected device group
4401 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
4402
4403 auto* leAudioDevice = group->GetFirstDevice();
4404 EXPECT_CALL(gatt_queue,
4405 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
4406 GATT_WRITE_NO_RSP, _, _))
4407 .Times(1);
4408
4409 // Start the configuration and stream Media content
4410 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4411 group, context_type,
4412 {.sink = types::AudioContexts(context_type),
4413 .source = types::AudioContexts(context_type)}));
4414
4415 // Disconnect device
4416 // in client.cc before this function is called, state of device is changed.
4417 leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTED);
4418 LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected(
4419 group, leAudioDevice);
4420
4421 // Make sure timeout is cleared
4422 ASSERT_TRUE(fake_osi_alarm_set_on_mloop_.cb == nullptr);
4423 }
4424
TEST_F(StateMachineTest,testStateIdleNotifyAclDisconnectedRemoveCig)4425 TEST_F(StateMachineTest, testStateIdleNotifyAclDisconnectedRemoveCig) {
4426 const auto context_type = kContextTypeRingtone;
4427 const int leaudio_group_id = 4;
4428
4429 // Prepare fake connected device group
4430 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
4431 group->cig.SetState(types::CigState::CREATED);
4432
4433 // Assert current state
4434 ASSERT_TRUE(group->GetState() ==
4435 types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
4436 ASSERT_FALSE(group->IsInTransition());
4437 ASSERT_TRUE(group->cig.GetState() == types::CigState::CREATED);
4438
4439 // Expect RemoveCig to be called
4440 EXPECT_CALL(*mock_iso_manager_, RemoveCig(group->group_id_, _)).Times(1);
4441
4442 // Disconnect device
4443 auto* leAudioDevice = group->GetFirstDevice();
4444 LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected(
4445 group, leAudioDevice);
4446
4447 // Assert Cig state transition to NONE after REMOVING
4448 ASSERT_TRUE(group->cig.GetState() == types::CigState::NONE);
4449 }
4450
TEST_F(StateMachineTest,testStateTransitionTimeout)4451 TEST_F(StateMachineTest, testStateTransitionTimeout) {
4452 const auto context_type = kContextTypeRingtone;
4453 const int leaudio_group_id = 4;
4454 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
4455 kLeAudioCodecChannelCountTwoChannel;
4456
4457 // Prepare fake connected device group
4458 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
4459
4460 /* Since we prepared device with Ringtone context in mind, only one ASE
4461 * should have been configured.
4462 */
4463 PrepareConfigureCodecHandler(group, 1);
4464 PrepareConfigureQosHandler(group, 1);
4465
4466 auto* leAudioDevice = group->GetFirstDevice();
4467 EXPECT_CALL(gatt_queue,
4468 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
4469 GATT_WRITE_NO_RSP, _, _))
4470 .Times(3);
4471
4472 // Start the configuration and stream Media content
4473 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4474 group, context_type,
4475 {.sink = types::AudioContexts(context_type),
4476 .source = types::AudioContexts(context_type)}));
4477
4478 // Check if timeout is fired
4479 EXPECT_CALL(mock_callbacks_, OnStateTransitionTimeout(leaudio_group_id));
4480
4481 // simulate timeout seconds passed, alarm executing
4482 fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
4483 ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));
4484 }
4485
TEST_F(StateMachineTest,testStateTransitionTimeoutAndDisconnectWhenConfigured)4486 TEST_F(StateMachineTest,
4487 testStateTransitionTimeoutAndDisconnectWhenConfigured) {
4488 const auto context_type = kContextTypeMedia;
4489 const int leaudio_group_id = 4;
4490 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
4491 kLeAudioCodecChannelCountTwoChannel;
4492
4493 // Prepare fake connected device group
4494 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
4495
4496 auto* leAudioDevice = group->GetFirstDevice();
4497 EXPECT_CALL(gatt_queue,
4498 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
4499 GATT_WRITE_NO_RSP, _, _))
4500 .Times(1);
4501
4502 InjectInitialConfiguredNotification(group);
4503
4504 group->PrintDebugState();
4505
4506 // Start the configuration and stream Media content
4507 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4508 group, context_type,
4509 {.sink = types::AudioContexts(context_type),
4510 .source = types::AudioContexts(context_type)}));
4511
4512 group->PrintDebugState();
4513
4514 // Check if timeout is fired
4515 EXPECT_CALL(mock_callbacks_, OnStateTransitionTimeout(leaudio_group_id));
4516
4517 // simulate timeout seconds passed, alarm executing
4518 fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
4519 ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));
4520
4521 log::info("OnStateTransitionTimeout");
4522
4523 /* Simulate On State timeout */
4524 group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
4525 group->ClearAllCises();
4526 group->PrintDebugState();
4527
4528 InjectAclDisconnected(group, leAudioDevice);
4529
4530 /* Verify that all ASEs are inactive and reconfiguration flag is cleared.*/
4531 for (const auto& ase : leAudioDevice->ases_) {
4532 ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
4533 ASSERT_EQ(ase.cis_state, types::CisState::IDLE);
4534 ASSERT_EQ(ase.data_path_state, types::DataPathState::IDLE);
4535 ASSERT_EQ(ase.reconfigure, 0);
4536 }
4537 }
4538
TEST_F(StateMachineTest,testStateTransitionTimeoutAndDisconnectWhenQoSConfigured)4539 TEST_F(StateMachineTest,
4540 testStateTransitionTimeoutAndDisconnectWhenQoSConfigured) {
4541 const auto context_type = kContextTypeMedia;
4542 const int leaudio_group_id = 4;
4543 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
4544 kLeAudioCodecChannelCountTwoChannel;
4545
4546 // Prepare fake connected device group
4547 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
4548 PrepareConfigureCodecHandler(group, 1);
4549
4550 auto* leAudioDevice = group->GetFirstDevice();
4551 EXPECT_CALL(gatt_queue,
4552 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
4553 GATT_WRITE_NO_RSP, _, _))
4554 .Times(2);
4555
4556 InjectInitialConfiguredNotification(group);
4557
4558 group->PrintDebugState();
4559
4560 // Start the configuration and stream Media content
4561 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4562 group, context_type,
4563 {.sink = types::AudioContexts(context_type),
4564 .source = types::AudioContexts(context_type)}));
4565
4566 group->PrintDebugState();
4567
4568 // Check if timeout is fired
4569 EXPECT_CALL(mock_callbacks_, OnStateTransitionTimeout(leaudio_group_id));
4570
4571 // simulate timeout seconds passed, alarm executing
4572 fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
4573 ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));
4574
4575 log::info("OnStateTransitionTimeout");
4576
4577 /* Simulate On State timeout */
4578 group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
4579 group->ClearAllCises();
4580 group->PrintDebugState();
4581
4582 InjectAclDisconnected(group, leAudioDevice);
4583
4584 /* Verify that all ASEs are inactive and reconfiguration flag is cleared.*/
4585 for (const auto& ase : leAudioDevice->ases_) {
4586 ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
4587 ASSERT_EQ(ase.cis_state, types::CisState::IDLE);
4588 ASSERT_EQ(ase.data_path_state, types::DataPathState::IDLE);
4589 ASSERT_EQ(ase.reconfigure, 0);
4590 }
4591 }
4592
TEST_F(StateMachineTest,testStateTransitionTimeoutAndDisconnectWhenEnabling)4593 TEST_F(StateMachineTest, testStateTransitionTimeoutAndDisconnectWhenEnabling) {
4594 const auto context_type = kContextTypeMedia;
4595 const int leaudio_group_id = 4;
4596 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
4597 kLeAudioCodecChannelCountTwoChannel;
4598
4599 // Prepare fake connected device group
4600 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
4601 PrepareConfigureCodecHandler(group, 1);
4602 PrepareConfigureQosHandler(group, 1);
4603
4604 auto* leAudioDevice = group->GetFirstDevice();
4605 EXPECT_CALL(gatt_queue,
4606 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
4607 GATT_WRITE_NO_RSP, _, _))
4608 .Times(3);
4609
4610 InjectInitialConfiguredNotification(group);
4611
4612 group->PrintDebugState();
4613
4614 // Start the configuration and stream Media content
4615 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4616 group, context_type,
4617 {.sink = types::AudioContexts(context_type),
4618 .source = types::AudioContexts(context_type)}));
4619
4620 group->PrintDebugState();
4621
4622 // Check if timeout is fired
4623 EXPECT_CALL(mock_callbacks_, OnStateTransitionTimeout(leaudio_group_id));
4624
4625 // simulate timeout seconds passed, alarm executing
4626 fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
4627 ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));
4628
4629 log::info("OnStateTransitionTimeout");
4630
4631 /* Simulate On State timeout */
4632 group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
4633 group->ClearAllCises();
4634 group->PrintDebugState();
4635
4636 InjectAclDisconnected(group, leAudioDevice);
4637
4638 /* Verify that all ASEs are inactive and reconfiguration flag is cleared.*/
4639 for (const auto& ase : leAudioDevice->ases_) {
4640 ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
4641 ASSERT_EQ(ase.cis_state, types::CisState::IDLE);
4642 ASSERT_EQ(ase.data_path_state, types::DataPathState::IDLE);
4643 ASSERT_EQ(ase.reconfigure, 0);
4644 }
4645 }
4646
4647 MATCHER_P(dataPathIsEq, expected, "") { return (arg.data_path_id == expected); }
4648
TEST_F(StateMachineTest,testConfigureDataPathForHost)4649 TEST_F(StateMachineTest, testConfigureDataPathForHost) {
4650 const auto context_type = kContextTypeRingtone;
4651 const int leaudio_group_id = 4;
4652 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
4653 kLeAudioCodecChannelCountTwoChannel;
4654
4655 /* Can be called for every context when fetching the configuration
4656 */
4657 EXPECT_CALL(*mock_codec_manager_, GetCodecConfig(_, _)).Times(AtLeast(1));
4658
4659 // Prepare fake connected device group
4660 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
4661
4662 /* Since we prepared device with Ringtone context in mind, only one ASE
4663 * should have been configured.
4664 */
4665 PrepareConfigureCodecHandler(group, 1);
4666 PrepareConfigureQosHandler(group, 1);
4667 PrepareEnableHandler(group, 1);
4668
4669 EXPECT_CALL(
4670 *mock_iso_manager_,
4671 SetupIsoDataPath(
4672 _, dataPathIsEq(bluetooth::hci::iso_manager::kIsoDataPathHci)))
4673 .Times(1);
4674
4675 InjectInitialIdleNotification(group);
4676
4677 // Start the configuration and stream Media content
4678 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4679 group, context_type,
4680 {.sink = types::AudioContexts(context_type),
4681 .source = types::AudioContexts(context_type)}));
4682 }
4683
TEST_F(StateMachineTestAdsp,testConfigureDataPathForAdsp)4684 TEST_F(StateMachineTestAdsp, testConfigureDataPathForAdsp) {
4685 const auto context_type = kContextTypeRingtone;
4686 const int leaudio_group_id = 4;
4687 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
4688 kLeAudioCodecChannelCountTwoChannel;
4689
4690 /* Can be called for every context when fetching the configuration
4691 */
4692 EXPECT_CALL(*mock_codec_manager_, GetCodecConfig(_, _)).Times(AtLeast(1));
4693
4694 // Prepare fake connected device group
4695 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
4696
4697 /* Since we prepared device with Ringtone context in mind, only one ASE
4698 * should have been configured.
4699 */
4700 PrepareConfigureCodecHandler(group, 1);
4701 PrepareConfigureQosHandler(group, 1);
4702 PrepareEnableHandler(group, 1);
4703
4704 EXPECT_CALL(
4705 *mock_iso_manager_,
4706 SetupIsoDataPath(
4707 _, dataPathIsEq(
4708 bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault)))
4709 .Times(1);
4710
4711 InjectInitialIdleNotification(group);
4712
4713 // Start the configuration and stream Media content
4714 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4715 group, context_type,
4716 {.sink = types::AudioContexts(context_type),
4717 .source = types::AudioContexts(context_type)}));
4718 }
4719
TEST_F(StateMachineTestAdsp,testStreamConfigurationAdspDownMix)4720 TEST_F(StateMachineTestAdsp, testStreamConfigurationAdspDownMix) {
4721 const auto context_type = kContextTypeConversational;
4722 const int leaudio_group_id = 4;
4723 const int num_devices = 2;
4724
4725 // Prepare fake connected device group
4726 auto* group = PrepareSingleTestDeviceGroup(
4727 leaudio_group_id, context_type, num_devices,
4728 types::AudioContexts(kContextTypeConversational));
4729
4730 EXPECT_CALL(
4731 mock_callbacks_,
4732 OnUpdatedCisConfiguration(
4733 group->group_id_, bluetooth::le_audio::types::kLeAudioDirectionSink))
4734 .Times(1);
4735 EXPECT_CALL(mock_callbacks_,
4736 OnUpdatedCisConfiguration(
4737 group->group_id_,
4738 bluetooth::le_audio::types::kLeAudioDirectionSource))
4739 .Times(1);
4740
4741 /* Can be called for every context when fetching the configuration
4742 */
4743 EXPECT_CALL(*mock_codec_manager_, GetCodecConfig(_, _)).Times(AtLeast(1));
4744
4745 PrepareConfigureCodecHandler(group);
4746 PrepareConfigureQosHandler(group);
4747 PrepareEnableHandler(group);
4748 PrepareReceiverStartReadyHandler(group);
4749
4750 InjectInitialIdleNotification(group);
4751
4752 auto* leAudioDevice = group->GetFirstDevice();
4753 InjectAclDisconnected(group, leAudioDevice);
4754
4755 // Start the configuration and stream Media content
4756 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
4757 group, context_type,
4758 {.sink = types::AudioContexts(context_type),
4759 .source = types::AudioContexts(context_type)}));
4760
4761 // Check if group has transitioned to a proper state
4762 ASSERT_EQ(group->GetState(),
4763 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
4764
4765 // Note: The actual channel mixing is verified by the CodecManager unit tests.
4766 }
4767
InjectCisDisconnected(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,uint8_t reason,bool first_cis_disconnect_only=false)4768 static void InjectCisDisconnected(LeAudioDeviceGroup* group,
4769 LeAudioDevice* leAudioDevice, uint8_t reason,
4770 bool first_cis_disconnect_only = false) {
4771 bluetooth::hci::iso_manager::cis_disconnected_evt event;
4772
4773 for (auto const ase : leAudioDevice->ases_) {
4774 if (ase.cis_state != types::CisState::ASSIGNED &&
4775 ase.cis_state != types::CisState::IDLE) {
4776 event.reason = reason;
4777 event.cig_id = group->group_id_;
4778 event.cis_conn_hdl = ase.cis_conn_hdl;
4779 LeAudioGroupStateMachine::Get()->ProcessHciNotifCisDisconnected(
4780 group, leAudioDevice, &event);
4781 if (first_cis_disconnect_only) break;
4782 }
4783 }
4784 }
4785
TEST_F(StateMachineTest,testAttachDeviceToTheStream)4786 TEST_F(StateMachineTest, testAttachDeviceToTheStream) {
4787 const auto context_type = kContextTypeMedia;
4788 const auto leaudio_group_id = 6;
4789 const auto num_devices = 2;
4790
4791 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
4792
4793 // Prepare multiple fake connected devices in a group
4794 auto* group =
4795 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
4796 ASSERT_EQ(group->Size(), num_devices);
4797
4798 PrepareConfigureCodecHandler(group);
4799 PrepareConfigureQosHandler(group);
4800 PrepareEnableHandler(group);
4801 PrepareDisableHandler(group);
4802 PrepareReleaseHandler(group);
4803
4804 auto* leAudioDevice = group->GetFirstDevice();
4805 LeAudioDevice* lastDevice;
4806 LeAudioDevice* fistDevice = leAudioDevice;
4807
4808 auto expected_devices_written = 0;
4809 while (leAudioDevice) {
4810 /* Three Writes:
4811 * 1: Codec Config
4812 * 2: Codec QoS
4813 * 3: Enabling
4814 */
4815 lastDevice = leAudioDevice;
4816 EXPECT_CALL(gatt_queue,
4817 WriteCharacteristic(leAudioDevice->conn_id_,
4818 leAudioDevice->ctp_hdls_.val_hdl, _,
4819 GATT_WRITE_NO_RSP, _, _))
4820 .Times(AtLeast(3));
4821 expected_devices_written++;
4822 leAudioDevice = group->GetNextDevice(leAudioDevice);
4823 }
4824 ASSERT_EQ(expected_devices_written, num_devices);
4825
4826 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
4827 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
4828 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
4829
4830 InjectInitialIdleNotification(group);
4831
4832 // Start the configuration and stream Media content
4833 LeAudioGroupStateMachine::Get()->StartStream(
4834 group, context_type,
4835 {.sink = types::AudioContexts(context_type),
4836 .source = types::AudioContexts(context_type)});
4837
4838 // Check if group has transitioned to a proper state
4839 ASSERT_EQ(group->GetState(),
4840 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
4841 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
4842
4843 // Inject CIS and ACL disconnection of first device
4844 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
4845 InjectAclDisconnected(group, lastDevice);
4846
4847 // Check if group keeps streaming
4848 ASSERT_EQ(group->GetState(),
4849 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
4850
4851 lastDevice->conn_id_ = 3;
4852 lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);
4853
4854 // Make sure ASE with disconnected CIS are not left in STREAMING
4855 ASSERT_EQ(lastDevice->GetFirstAseWithState(
4856 ::bluetooth::le_audio::types::kLeAudioDirectionSink,
4857 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
4858 nullptr);
4859 ASSERT_EQ(lastDevice->GetFirstAseWithState(
4860 ::bluetooth::le_audio::types::kLeAudioDirectionSource,
4861 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
4862 nullptr);
4863
4864 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
4865 lastDevice->ctp_hdls_.val_hdl, _,
4866 GATT_WRITE_NO_RSP, _, _))
4867 .Times(AtLeast(3));
4868
4869 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
4870 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
4871 LeAudioGroupStateMachine::Get()->AttachToStream(
4872 group, lastDevice, {.sink = {media_ccid}, .source = {}});
4873
4874 // Check if group keeps streaming
4875 ASSERT_EQ(group->GetState(),
4876 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
4877
4878 // Verify that the joining device receives the right CCID list
4879 auto lastMeta = lastDevice->GetFirstActiveAse()->metadata;
4880 bool parsedOk = false;
4881 auto ltv = bluetooth::le_audio::types::LeAudioLtvMap::Parse(
4882 lastMeta.data(), lastMeta.size(), parsedOk);
4883 ASSERT_TRUE(parsedOk);
4884
4885 auto ccids =
4886 ltv.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeCcidList);
4887 ASSERT_TRUE(ccids.has_value());
4888 ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
4889
4890 /* Verify that ASE of first device are still good*/
4891 auto ase = fistDevice->GetFirstActiveAse();
4892 ASSERT_NE(ase->qos_config.max_transport_latency, 0);
4893 ASSERT_NE(ase->qos_config.retrans_nb, 0);
4894 }
4895
TEST_F(StateMachineTest,testAttachDeviceToTheStreamV2)4896 TEST_F(StateMachineTest, testAttachDeviceToTheStreamV2) {
4897 const auto context_type = kContextTypeMedia;
4898 const auto leaudio_group_id = 6;
4899 const auto num_devices = 2;
4900
4901 /* Scenario
4902 * 1. Both devices streaming
4903 * 2. One device disconnects
4904 * 3. Audio configuration resume and configuration cache is rebuilt
4905 * 4. Device attached
4906 */
4907 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
4908
4909 // Prepare multiple fake connected devices in a group
4910 auto* group =
4911 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
4912 ASSERT_EQ(group->Size(), num_devices);
4913
4914 PrepareConfigureCodecHandler(group);
4915 PrepareConfigureQosHandler(group);
4916 PrepareEnableHandler(group);
4917 PrepareDisableHandler(group);
4918 PrepareReleaseHandler(group);
4919
4920 auto* leAudioDevice = group->GetFirstDevice();
4921 LeAudioDevice* lastDevice;
4922 LeAudioDevice* fistDevice = leAudioDevice;
4923
4924 auto expected_devices_written = 0;
4925 while (leAudioDevice) {
4926 /* Three Writes:
4927 * 1: Codec Config
4928 * 2: Codec QoS
4929 * 3: Enabling
4930 */
4931 lastDevice = leAudioDevice;
4932 EXPECT_CALL(gatt_queue,
4933 WriteCharacteristic(leAudioDevice->conn_id_,
4934 leAudioDevice->ctp_hdls_.val_hdl, _,
4935 GATT_WRITE_NO_RSP, _, _))
4936 .Times(AtLeast(3));
4937 expected_devices_written++;
4938 leAudioDevice = group->GetNextDevice(leAudioDevice);
4939 }
4940 ASSERT_EQ(expected_devices_written, num_devices);
4941
4942 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
4943 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
4944 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
4945
4946 InjectInitialIdleNotification(group);
4947
4948 // Start the configuration and stream Media content
4949 LeAudioGroupStateMachine::Get()->StartStream(
4950 group, context_type,
4951 {.sink = types::AudioContexts(context_type),
4952 .source = types::AudioContexts(context_type)});
4953
4954 // Check if group has transitioned to a proper state
4955 ASSERT_EQ(group->GetState(),
4956 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
4957 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
4958
4959 // Inject CIS and ACL disconnection of first device
4960 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
4961 InjectAclDisconnected(group, lastDevice);
4962
4963 /* Force update configuration which is what happens when stream stops
4964 * and starts while streaming to single dev. This will rebuild cache,
4965 * which is what we need in this test.
4966 */
4967 group->UpdateAudioSetConfigurationCache(context_type);
4968
4969 // Check if group keeps streaming
4970 ASSERT_EQ(group->GetState(),
4971 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
4972
4973 lastDevice->conn_id_ = 3;
4974 lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);
4975
4976 // Make sure ASE with disconnected CIS are not left in STREAMING
4977 ASSERT_EQ(lastDevice->GetFirstAseWithState(
4978 ::bluetooth::le_audio::types::kLeAudioDirectionSink,
4979 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
4980 nullptr);
4981 ASSERT_EQ(lastDevice->GetFirstAseWithState(
4982 ::bluetooth::le_audio::types::kLeAudioDirectionSource,
4983 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
4984 nullptr);
4985
4986 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
4987 lastDevice->ctp_hdls_.val_hdl, _,
4988 GATT_WRITE_NO_RSP, _, _))
4989 .Times(AtLeast(3));
4990
4991 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
4992 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
4993 LeAudioGroupStateMachine::Get()->AttachToStream(
4994 group, lastDevice, {.sink = {media_ccid}, .source = {}});
4995
4996 // Check if group keeps streaming
4997 ASSERT_EQ(group->GetState(),
4998 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
4999
5000 // Verify that the joining device receives the right CCID list
5001 auto lastMeta = lastDevice->GetFirstActiveAse()->metadata;
5002 bool parsedOk = false;
5003 auto ltv = bluetooth::le_audio::types::LeAudioLtvMap::Parse(
5004 lastMeta.data(), lastMeta.size(), parsedOk);
5005 ASSERT_TRUE(parsedOk);
5006
5007 auto ccids =
5008 ltv.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeCcidList);
5009 ASSERT_TRUE(ccids.has_value());
5010 ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
5011
5012 /* Verify that ASE of first device are still good*/
5013 auto ase = fistDevice->GetFirstActiveAse();
5014 ASSERT_NE(ase->qos_config.max_transport_latency, 0);
5015 ASSERT_NE(ase->qos_config.retrans_nb, 0);
5016 }
5017
TEST_F(StateMachineTest,testAttachDeviceToTheStreamDeviceNoAvailableContext)5018 TEST_F(StateMachineTest, testAttachDeviceToTheStreamDeviceNoAvailableContext) {
5019 const auto context_type = kContextTypeMedia;
5020 const auto leaudio_group_id = 6;
5021 const auto num_devices = 2;
5022
5023 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
5024
5025 // Prepare multiple fake connected devices in a group
5026 auto* group =
5027 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
5028 ASSERT_EQ(group->Size(), num_devices);
5029
5030 PrepareConfigureCodecHandler(group);
5031 PrepareConfigureQosHandler(group);
5032 PrepareEnableHandler(group);
5033 PrepareDisableHandler(group);
5034 PrepareReleaseHandler(group);
5035
5036 auto* leAudioDevice = group->GetFirstDevice();
5037 LeAudioDevice* lastDevice;
5038
5039 auto expected_devices_written = 0;
5040 while (leAudioDevice) {
5041 /* Three Writes:
5042 * 1: Codec Config
5043 * 2: Codec QoS
5044 * 3: Enabling
5045 */
5046 lastDevice = leAudioDevice;
5047 EXPECT_CALL(gatt_queue,
5048 WriteCharacteristic(leAudioDevice->conn_id_,
5049 leAudioDevice->ctp_hdls_.val_hdl, _,
5050 GATT_WRITE_NO_RSP, _, _))
5051 .Times(AtLeast(3));
5052 expected_devices_written++;
5053 leAudioDevice = group->GetNextDevice(leAudioDevice);
5054 }
5055 ASSERT_EQ(expected_devices_written, num_devices);
5056
5057 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5058 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5059 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
5060
5061 InjectInitialIdleNotification(group);
5062
5063 // Start the configuration and stream Media content
5064 LeAudioGroupStateMachine::Get()->StartStream(
5065 group, context_type,
5066 {.sink = types::AudioContexts(context_type),
5067 .source = types::AudioContexts(context_type)});
5068
5069 // Check if group has transitioned to a proper state
5070 ASSERT_EQ(group->GetState(),
5071 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5072 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
5073
5074 // Inject CIS and ACL disconnection of first device
5075 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
5076 InjectAclDisconnected(group, lastDevice);
5077
5078 // Check if group keeps streaming
5079 ASSERT_EQ(group->GetState(),
5080 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5081
5082 // Connect the disconnected device BUT remove MEDIA from available Contex
5083 // Types
5084 lastDevice->conn_id_ = 3;
5085 auto test_context_type = kContextTypeUnspecified | kContextTypeConversational;
5086 lastDevice->SetAvailableContexts(
5087 {.sink = test_context_type, .source = test_context_type});
5088 lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);
5089
5090 // Make sure ASE with disconnected CIS are not left in STREAMING
5091 ASSERT_EQ(lastDevice->GetFirstAseWithState(
5092 ::bluetooth::le_audio::types::kLeAudioDirectionSink,
5093 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
5094 nullptr);
5095 ASSERT_EQ(lastDevice->GetFirstAseWithState(
5096 ::bluetooth::le_audio::types::kLeAudioDirectionSource,
5097 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
5098 nullptr);
5099
5100 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
5101 lastDevice->ctp_hdls_.val_hdl, _,
5102 GATT_WRITE_NO_RSP, _, _))
5103 .Times(AtLeast(0));
5104
5105 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
5106 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
5107 ASSERT_EQ(LeAudioGroupStateMachine::Get()->AttachToStream(
5108 group, lastDevice, {.sink = {media_ccid}, .source = {}}),
5109 false);
5110
5111 ASSERT_EQ(group->GetState(),
5112 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5113 }
5114
TEST_F(StateMachineTest,testAutonomousConfiguredAndAttachToStream)5115 TEST_F(StateMachineTest, testAutonomousConfiguredAndAttachToStream) {
5116 const auto context_type = kContextTypeMedia;
5117 const auto leaudio_group_id = 6;
5118 const auto num_devices = 2;
5119
5120 /* Scenario
5121 * 1. Start streaming
5122 * 2. Stop stream on one device
5123 * 3. Reconnect
5124 * 4. Autonomous Configured state
5125 * 5. Make sure QoS Configure is not send out
5126 * 6. Trigger attach the stream
5127 * 7. Make sure stream is up
5128 */
5129
5130 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
5131
5132 // Prepare multiple fake connected devices in a group
5133 auto* group =
5134 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
5135 ASSERT_EQ(group->Size(), num_devices);
5136
5137 PrepareConfigureCodecHandler(group, 0, true);
5138 PrepareConfigureQosHandler(group);
5139 PrepareEnableHandler(group);
5140 PrepareDisableHandler(group);
5141 PrepareReleaseHandler(group);
5142
5143 auto* leAudioDevice = group->GetFirstDevice();
5144 LeAudioDevice* lastDevice;
5145 LeAudioDevice* fistDevice = leAudioDevice;
5146
5147 auto expected_devices_written = 0;
5148 while (leAudioDevice) {
5149 /* Three Writes:
5150 * 1: Codec Config
5151 * 2: Codec QoS
5152 * 3: Enabling
5153 */
5154 lastDevice = leAudioDevice;
5155 EXPECT_CALL(gatt_queue,
5156 WriteCharacteristic(leAudioDevice->conn_id_,
5157 leAudioDevice->ctp_hdls_.val_hdl, _,
5158 GATT_WRITE_NO_RSP, _, _))
5159 .Times(AtLeast(3));
5160 expected_devices_written++;
5161 leAudioDevice = group->GetNextDevice(leAudioDevice);
5162 }
5163 ASSERT_EQ(expected_devices_written, num_devices);
5164
5165 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5166 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5167 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
5168
5169 InjectInitialIdleNotification(group);
5170
5171 // Start the configuration and stream Media content
5172 LeAudioGroupStateMachine::Get()->StartStream(
5173 group, context_type,
5174 {.sink = types::AudioContexts(context_type),
5175 .source = types::AudioContexts(context_type)});
5176
5177 // Check if group has transitioned to a proper state
5178 ASSERT_EQ(group->GetState(),
5179 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5180 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
5181
5182 // Inject CIS and ACL disconnection of first device
5183 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
5184 InjectAclDisconnected(group, lastDevice);
5185
5186 // Check if group keeps streaming
5187 ASSERT_EQ(group->GetState(),
5188 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5189
5190 /* Set device is getting ready for the connection */
5191 lastDevice->conn_id_ = 3;
5192 lastDevice->SetConnectionState(
5193 DeviceConnectState::CONNECTED_AUTOCONNECT_GETTING_READY);
5194
5195 // Make sure ASE with disconnected CIS are not left in STREAMING
5196 ASSERT_EQ(lastDevice->GetFirstAseWithState(
5197 ::bluetooth::le_audio::types::kLeAudioDirectionSink,
5198 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
5199 nullptr);
5200 ASSERT_EQ(lastDevice->GetFirstAseWithState(
5201 ::bluetooth::le_audio::types::kLeAudioDirectionSource,
5202 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
5203 nullptr);
5204
5205 // Symulate remote autonomous CONFIGURE state
5206 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
5207 lastDevice->ctp_hdls_.val_hdl, _,
5208 GATT_WRITE_NO_RSP, _, _))
5209 .Times(0);
5210
5211 int num_of_notifications = 0;
5212 for (auto& ase : lastDevice->ases_) {
5213 if (ase.id == bluetooth::le_audio::types::ase::kAseIdInvalid) {
5214 continue;
5215 }
5216 log::error("ID : {}, status {}", ase.id,
5217 bluetooth::common::ToString(ase.state));
5218 num_of_notifications++;
5219 InjectAseStateNotification(&ase, lastDevice, group,
5220 ascs::kAseStateCodecConfigured,
5221 &cached_codec_configuration_map_[ase.id]);
5222 break;
5223 }
5224 ASSERT_EQ(num_of_notifications, 1);
5225
5226 testing::Mock::VerifyAndClearExpectations(&gatt_queue);
5227 // Now device is connected. Attach it to the stream
5228
5229 lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);
5230
5231 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
5232 lastDevice->ctp_hdls_.val_hdl, _,
5233 GATT_WRITE_NO_RSP, _, _))
5234 .Times(AtLeast(3));
5235
5236 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5237 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
5238 LeAudioGroupStateMachine::Get()->AttachToStream(
5239 group, lastDevice, {.sink = {media_ccid}, .source = {}});
5240
5241 // Check if group keeps streaming
5242 ASSERT_EQ(group->GetState(),
5243 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5244
5245 // Verify that the joining device receives the right CCID list
5246 auto lastMeta = lastDevice->GetFirstActiveAse()->metadata;
5247 bool parsedOk = false;
5248 auto ltv = bluetooth::le_audio::types::LeAudioLtvMap::Parse(
5249 lastMeta.data(), lastMeta.size(), parsedOk);
5250 ASSERT_TRUE(parsedOk);
5251
5252 auto ccids =
5253 ltv.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeCcidList);
5254 ASSERT_TRUE(ccids.has_value());
5255 ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
5256
5257 /* Verify that ASE of first device are still good*/
5258 auto ase = fistDevice->GetFirstActiveAse();
5259 ASSERT_NE(ase->qos_config.max_transport_latency, 0);
5260 ASSERT_NE(ase->qos_config.retrans_nb, 0);
5261 }
5262
TEST_F(StateMachineTest,testAttachDeviceToTheStream_autonomusQoSConfiguredState)5263 TEST_F(StateMachineTest,
5264 testAttachDeviceToTheStream_autonomusQoSConfiguredState) {
5265 const auto context_type = kContextTypeMedia;
5266 const auto leaudio_group_id = 6;
5267 const auto num_devices = 2;
5268
5269 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
5270
5271 // Prepare multiple fake connected devices in a group
5272 auto* group =
5273 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
5274 ASSERT_EQ(group->Size(), num_devices);
5275
5276 PrepareConfigureCodecHandler(group);
5277 PrepareConfigureQosHandler(group);
5278 PrepareEnableHandler(group);
5279 PrepareDisableHandler(group);
5280 PrepareReleaseHandler(group);
5281
5282 auto* leAudioDevice = group->GetFirstDevice();
5283 LeAudioDevice* lastDevice;
5284 LeAudioDevice* fistDevice = leAudioDevice;
5285
5286 auto expected_devices_written = 0;
5287 while (leAudioDevice) {
5288 /* Three Writes:
5289 * 1: Codec Config
5290 * 2: Codec QoS
5291 * 3: Enabling
5292 */
5293 lastDevice = leAudioDevice;
5294 EXPECT_CALL(gatt_queue,
5295 WriteCharacteristic(leAudioDevice->conn_id_,
5296 leAudioDevice->ctp_hdls_.val_hdl, _,
5297 GATT_WRITE_NO_RSP, _, _))
5298 .Times(AtLeast(3));
5299 expected_devices_written++;
5300 leAudioDevice = group->GetNextDevice(leAudioDevice);
5301 }
5302 ASSERT_EQ(expected_devices_written, num_devices);
5303
5304 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5305 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5306 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
5307
5308 InjectInitialIdleNotification(group);
5309
5310 // Start the configuration and stream Media content
5311 LeAudioGroupStateMachine::Get()->StartStream(
5312 group, context_type,
5313 {.sink = types::AudioContexts(context_type),
5314 .source = types::AudioContexts(context_type)},
5315 {.sink = std::vector<uint8_t>(1, media_ccid),
5316 .source = std::vector<uint8_t>(1, media_ccid)});
5317
5318 // Check if group has transitioned to a proper state
5319 ASSERT_EQ(group->GetState(),
5320 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5321 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
5322
5323 // Inject CIS and ACL disconnection of first device
5324 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
5325
5326 // Check if group keeps streaming
5327 ASSERT_EQ(group->GetState(),
5328 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5329
5330 // Make sure ASE with disconnected CIS are not left in STREAMING
5331 ASSERT_EQ(lastDevice->GetFirstAseWithState(
5332 ::bluetooth::le_audio::types::kLeAudioDirectionSink,
5333 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
5334 nullptr);
5335 ASSERT_EQ(lastDevice->GetFirstAseWithState(
5336 ::bluetooth::le_audio::types::kLeAudioDirectionSource,
5337 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
5338 nullptr);
5339
5340 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
5341 lastDevice->ctp_hdls_.val_hdl, _,
5342 GATT_WRITE_NO_RSP, _, _))
5343 .Times(1);
5344
5345 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5346 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
5347
5348 for (auto& ase : lastDevice->ases_) {
5349 if (cached_remote_qos_configuration_for_ase_.count(&ase) > 0) {
5350 InjectAseStateNotification(
5351 &ase, lastDevice, group, ascs::kAseStateQoSConfigured,
5352 &(cached_remote_qos_configuration_for_ase_[&ase]));
5353 }
5354 }
5355
5356 // Check if group keeps streaming
5357 ASSERT_EQ(group->GetState(),
5358 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5359
5360 // Verify that the joining device receives the right CCID list
5361 auto lastMeta = lastDevice->GetFirstActiveAse()->metadata;
5362 bool parsedOk = false;
5363 auto ltv = bluetooth::le_audio::types::LeAudioLtvMap::Parse(
5364 lastMeta.data(), lastMeta.size(), parsedOk);
5365 ASSERT_TRUE(parsedOk);
5366
5367 auto ccids =
5368 ltv.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeCcidList);
5369 ASSERT_TRUE(ccids.has_value());
5370 ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
5371
5372 /* Verify that ASE of first device are still good*/
5373 auto ase = fistDevice->GetFirstActiveAse();
5374 ASSERT_NE(ase->qos_config.max_transport_latency, 0);
5375 ASSERT_NE(ase->qos_config.retrans_nb, 0);
5376 }
5377
TEST_F(StateMachineTest,testAttachDeviceToTheStreamDoNotAttach)5378 TEST_F(StateMachineTest, testAttachDeviceToTheStreamDoNotAttach) {
5379 const auto context_type = kContextTypeMedia;
5380 const auto leaudio_group_id = 6;
5381 const auto num_devices = 2;
5382
5383 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
5384
5385 // Prepare multiple fake connected devices in a group
5386 auto* group =
5387 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
5388 ASSERT_EQ(group->Size(), num_devices);
5389
5390 PrepareConfigureCodecHandler(group);
5391 PrepareConfigureQosHandler(group);
5392 PrepareEnableHandler(group);
5393
5394 auto* leAudioDevice = group->GetFirstDevice();
5395 LeAudioDevice* lastDevice;
5396
5397 while (leAudioDevice) {
5398 lastDevice = leAudioDevice;
5399 leAudioDevice = group->GetNextDevice(leAudioDevice);
5400 }
5401
5402 InjectInitialIdleNotification(group);
5403
5404 // Inject CIS and ACL disconnection of first device
5405 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
5406 InjectAclDisconnected(group, lastDevice);
5407
5408 // Start the configuration and stream Media content
5409 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5410 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5411 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
5412 LeAudioGroupStateMachine::Get()->StartStream(
5413 group, context_type,
5414 {.sink = types::AudioContexts(context_type),
5415 .source = types::AudioContexts(context_type)});
5416
5417 // Check if group has transitioned to a proper state
5418 ASSERT_EQ(group->GetState(),
5419 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5420 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
5421
5422 // Check if group keeps streaming
5423 ASSERT_EQ(group->GetState(),
5424 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5425
5426 lastDevice->conn_id_ = 3;
5427 lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);
5428
5429 EXPECT_CALL(
5430 mock_callbacks_,
5431 StatusReportCb(leaudio_group_id,
5432 bluetooth::le_audio::GroupStreamStatus::RELEASING));
5433 LeAudioGroupStateMachine::Get()->StopStream(group);
5434 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
5435
5436 ASSERT_FALSE(LeAudioGroupStateMachine::Get()->AttachToStream(
5437 group, lastDevice, {.sink = {}, .source = {}}));
5438 }
5439
TEST_F(StateMachineTest,testReconfigureAfterLateDeviceAttached)5440 TEST_F(StateMachineTest, testReconfigureAfterLateDeviceAttached) {
5441 const auto context_type = kContextTypeMedia;
5442 const auto leaudio_group_id = 6;
5443 const auto num_devices = 2;
5444
5445 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
5446
5447 // Prepare multiple fake connected devices in a group
5448 auto* group =
5449 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
5450 ASSERT_EQ(group->Size(), num_devices);
5451
5452 PrepareConfigureCodecHandler(group, 0, true);
5453 PrepareConfigureQosHandler(group);
5454 PrepareEnableHandler(group);
5455 PrepareDisableHandler(group);
5456 PrepareReleaseHandler(group);
5457
5458 auto* leAudioDevice = group->GetFirstDevice();
5459 LeAudioDevice* lastDevice;
5460 LeAudioDevice* fistDevice = leAudioDevice;
5461
5462 while (leAudioDevice) {
5463 lastDevice = leAudioDevice;
5464 leAudioDevice = group->GetNextDevice(leAudioDevice);
5465 }
5466
5467 InjectInitialIdleNotification(group);
5468
5469 // Inject CIS and ACL disconnection of first device
5470 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
5471 InjectAclDisconnected(group, lastDevice);
5472
5473 /* First device connected. Configure it to stream media */
5474
5475 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5476 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5477 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
5478
5479 types::BidirectionalPair<std::vector<uint8_t>> ccids_list = {
5480 .sink = {media_ccid}, .source = {media_ccid}};
5481
5482 // Start the configuration and stream Media content
5483 LeAudioGroupStateMachine::Get()->StartStream(
5484 group, context_type,
5485 {.sink = types::AudioContexts(context_type),
5486 .source = types::AudioContexts(context_type)},
5487 ccids_list);
5488
5489 // Check if group has transitioned to a proper state
5490 ASSERT_EQ(group->GetState(),
5491 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5492 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
5493
5494 /* Stop the stream and let first device to stay in configured state (caching
5495 * is on)*/
5496 LeAudioGroupStateMachine::Get()->StopStream(group);
5497 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
5498
5499 /* Verify state in the configured state */
5500 ASSERT_EQ(group->GetState(),
5501 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
5502
5503 /* Now when stream is stopped, connect second device. */
5504 lastDevice->conn_id_ = 3;
5505 lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);
5506
5507 group->UpdateAudioContextAvailability();
5508 group->UpdateAudioSetConfigurationCache(context_type);
5509
5510 /* Start stream, make sure 2 devices are started. */
5511
5512 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5513 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5514 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
5515
5516 // Start the configuration and stream Media content
5517 LeAudioGroupStateMachine::Get()->StartStream(
5518 group, context_type,
5519 {.sink = types::AudioContexts(context_type),
5520 .source = types::AudioContexts(context_type)},
5521 ccids_list);
5522
5523 // Check if group keeps streaming
5524 ASSERT_EQ(group->GetState(),
5525 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5526
5527 // Verify that both devicse receives the right CCID list and both are
5528 // streaming
5529 auto ase = lastDevice->GetFirstActiveAse();
5530
5531 // FIXME: No ASE was activated - that's bad
5532 ASSERT_NE(nullptr, ase);
5533 auto lastMeta = ase->metadata;
5534 bool parsedOk = false;
5535 auto ltv = bluetooth::le_audio::types::LeAudioLtvMap::Parse(
5536 lastMeta.data(), lastMeta.size(), parsedOk);
5537 ASSERT_TRUE(parsedOk);
5538
5539 auto ccids =
5540 ltv.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeCcidList);
5541 ASSERT_TRUE(ccids.has_value());
5542 ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
5543
5544 /* Verify that ASE of first device are still good*/
5545 ase = fistDevice->GetFirstActiveAse();
5546 ASSERT_NE(nullptr, ase);
5547 ASSERT_NE(ase->qos_config.max_transport_latency, 0);
5548 ASSERT_NE(ase->qos_config.retrans_nb, 0);
5549 }
5550
TEST_F(StateMachineTest,testReconfigureAfterLateDeviceAttachedConversationalSwb)5551 TEST_F(StateMachineTest,
5552 testReconfigureAfterLateDeviceAttachedConversationalSwb) {
5553 const auto context_type = kContextTypeConversational;
5554 const auto leaudio_group_id = 6;
5555 const auto num_devices = 2;
5556
5557 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
5558
5559 // Prepare multiple fake connected devices in a group
5560 auto* group =
5561 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
5562 ASSERT_EQ(group->Size(), num_devices);
5563
5564 PrepareConfigureCodecHandler(group, 0, true);
5565 PrepareConfigureQosHandler(group);
5566 PrepareEnableHandler(group);
5567 PrepareReceiverStartReadyHandler(group);
5568 PrepareDisableHandler(group);
5569 PrepareReleaseHandler(group);
5570
5571 auto* leAudioDevice = group->GetFirstDevice();
5572 LeAudioDevice* lastDevice;
5573 LeAudioDevice* fistDevice = leAudioDevice;
5574
5575 while (leAudioDevice) {
5576 lastDevice = leAudioDevice;
5577 leAudioDevice = group->GetNextDevice(leAudioDevice);
5578 }
5579
5580 InjectInitialIdleNotification(group);
5581
5582 // Inject CIS and ACL disconnection of first device
5583 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
5584 InjectAclDisconnected(group, lastDevice);
5585
5586 /* First device connected. Configure it to stream media */
5587 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5588 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5589 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
5590
5591 types::BidirectionalPair<std::vector<uint8_t>> ccids_list = {
5592 .sink = {media_ccid}, .source = {media_ccid}};
5593
5594 // Start the configuration and stream Media content
5595 LeAudioGroupStateMachine::Get()->StartStream(
5596 group, context_type,
5597 {.sink = types::AudioContexts(context_type),
5598 .source = types::AudioContexts(context_type)},
5599 ccids_list);
5600
5601 auto current_config = group->GetCachedConfiguration(context_type);
5602 ASSERT_NE(nullptr, current_config.get());
5603 // With a single device there will be no dual bidir SWB but a single bidir SWB
5604 ASSERT_TRUE(
5605 AudioSetConfigurationProvider::Get()->CheckConfigurationIsBiDirSwb(
5606 *current_config.get()));
5607 ASSERT_FALSE(
5608 AudioSetConfigurationProvider::Get()->CheckConfigurationIsDualBiDirSwb(
5609 *current_config.get()));
5610
5611 // Check if group has transitioned to a proper state
5612 ASSERT_EQ(group->GetState(),
5613 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5614 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
5615
5616 /* Stop the stream and let first device to stay in configured state (caching
5617 * is on)*/
5618 LeAudioGroupStateMachine::Get()->StopStream(group);
5619 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
5620
5621 /* Verify state in the configured state */
5622 ASSERT_EQ(group->GetState(),
5623 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
5624
5625 /* Now when stream is stopped, connect second device. */
5626 lastDevice->conn_id_ = 3;
5627 lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);
5628
5629 group->UpdateAudioContextAvailability();
5630 group->UpdateAudioSetConfigurationCache(context_type);
5631
5632 /* Start stream, make sure 2 devices are started. */
5633 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5634 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5635 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4);
5636
5637 // Start the configuration and stream Media content
5638 LeAudioGroupStateMachine::Get()->StartStream(
5639 group, context_type,
5640 {.sink = types::AudioContexts(context_type),
5641 .source = types::AudioContexts(context_type)},
5642 ccids_list);
5643
5644 // Check if group keeps streaming
5645 ASSERT_EQ(group->GetState(),
5646 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5647
5648 // Verify that both devicse receives the right CCID list and both are
5649 // streaming
5650 auto ase = lastDevice->GetFirstActiveAse();
5651
5652 // No ASE was activated - that's bad
5653 ASSERT_NE(nullptr, ase);
5654 auto lastMeta = ase->metadata;
5655 bool parsedOk = false;
5656 auto ltv = bluetooth::le_audio::types::LeAudioLtvMap::Parse(
5657 lastMeta.data(), lastMeta.size(), parsedOk);
5658 ASSERT_TRUE(parsedOk);
5659
5660 auto ccids =
5661 ltv.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeCcidList);
5662 ASSERT_TRUE(ccids.has_value());
5663 ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
5664
5665 /* Verify that ASE of first device are still good*/
5666 ase = fistDevice->GetFirstActiveAse();
5667 ASSERT_NE(nullptr, ase);
5668 ASSERT_NE(ase->qos_config.max_transport_latency, 0);
5669 ASSERT_NE(ase->qos_config.retrans_nb, 0);
5670
5671 // With both devices we should get the dual bidir SWB configuration
5672 current_config = group->GetCachedConfiguration(context_type);
5673 ASSERT_NE(nullptr, current_config.get());
5674 ASSERT_TRUE(
5675 AudioSetConfigurationProvider::Get()->CheckConfigurationIsDualBiDirSwb(
5676 *current_config.get()));
5677 }
5678
TEST_F(StateMachineTestNoSwb,testReconfigureAfterLateDeviceAttachedConversationalNoSwb)5679 TEST_F(StateMachineTestNoSwb,
5680 testReconfigureAfterLateDeviceAttachedConversationalNoSwb) {
5681 const auto context_type = kContextTypeConversational;
5682 const auto leaudio_group_id = 6;
5683 const auto num_devices = 2;
5684
5685 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
5686
5687 // Prepare multiple fake connected devices in a group
5688 auto* group =
5689 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
5690 ASSERT_EQ(group->Size(), num_devices);
5691
5692 PrepareConfigureCodecHandler(group, 0, true);
5693 PrepareConfigureQosHandler(group);
5694 PrepareEnableHandler(group);
5695 PrepareReceiverStartReadyHandler(group);
5696 PrepareDisableHandler(group);
5697 PrepareReleaseHandler(group);
5698
5699 auto* leAudioDevice = group->GetFirstDevice();
5700 LeAudioDevice* lastDevice;
5701 LeAudioDevice* fistDevice = leAudioDevice;
5702
5703 while (leAudioDevice) {
5704 lastDevice = leAudioDevice;
5705 leAudioDevice = group->GetNextDevice(leAudioDevice);
5706 }
5707
5708 InjectInitialIdleNotification(group);
5709
5710 // Inject CIS and ACL disconnection of first device
5711 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
5712 InjectAclDisconnected(group, lastDevice);
5713
5714 /* First device connected. Configure it to stream media */
5715 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5716 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5717 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
5718
5719 types::BidirectionalPair<std::vector<uint8_t>> ccids_list = {
5720 .sink = {media_ccid}, .source = {media_ccid}};
5721
5722 // Start the configuration and stream Media content
5723 LeAudioGroupStateMachine::Get()->StartStream(
5724 group, context_type,
5725 {.sink = types::AudioContexts(context_type),
5726 .source = types::AudioContexts(context_type)},
5727 ccids_list);
5728
5729 auto current_config = group->GetCachedConfiguration(context_type);
5730 ASSERT_NE(nullptr, current_config.get());
5731 // With a single device there shall be no bidir SWB, as we expect the 2nd
5732 // device to join the stream seamlessly while dual bidir SWB is disabled.
5733 ASSERT_FALSE(
5734 AudioSetConfigurationProvider::Get()->CheckConfigurationIsBiDirSwb(
5735 *current_config.get()));
5736 ASSERT_FALSE(
5737 AudioSetConfigurationProvider::Get()->CheckConfigurationIsDualBiDirSwb(
5738 *current_config.get()));
5739
5740 // Check if group has transitioned to a proper state
5741 ASSERT_EQ(group->GetState(),
5742 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5743 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
5744
5745 /* Stop the stream and let first device to stay in configured state (caching
5746 * is on)*/
5747 LeAudioGroupStateMachine::Get()->StopStream(group);
5748 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
5749
5750 /* Verify state in the configured state */
5751 ASSERT_EQ(group->GetState(),
5752 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
5753
5754 /* Now when stream is stopped, connect second device. */
5755 lastDevice->conn_id_ = 3;
5756 lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);
5757
5758 group->UpdateAudioContextAvailability();
5759 group->UpdateAudioSetConfigurationCache(context_type);
5760
5761 /* Start stream, make sure 2 devices are started. */
5762 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5763 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5764 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4);
5765
5766 // Start the configuration and stream Media content
5767 LeAudioGroupStateMachine::Get()->StartStream(
5768 group, context_type,
5769 {.sink = types::AudioContexts(context_type),
5770 .source = types::AudioContexts(context_type)},
5771 ccids_list);
5772
5773 // Check if group keeps streaming
5774 ASSERT_EQ(group->GetState(),
5775 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5776
5777 // Verify that both devicse receives the right CCID list and both are
5778 // streaming
5779 auto ase = lastDevice->GetFirstActiveAse();
5780
5781 // No ASE was activated - that's bad
5782 ASSERT_NE(nullptr, ase);
5783 auto lastMeta = ase->metadata;
5784 bool parsedOk = false;
5785 auto ltv = bluetooth::le_audio::types::LeAudioLtvMap::Parse(
5786 lastMeta.data(), lastMeta.size(), parsedOk);
5787 ASSERT_TRUE(parsedOk);
5788
5789 auto ccids =
5790 ltv.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeCcidList);
5791 ASSERT_TRUE(ccids.has_value());
5792 ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
5793
5794 /* Verify that ASE of first device are still good*/
5795 ase = fistDevice->GetFirstActiveAse();
5796 ASSERT_NE(nullptr, ase);
5797 ASSERT_NE(ase->qos_config.max_transport_latency, 0);
5798 ASSERT_NE(ase->qos_config.retrans_nb, 0);
5799
5800 // With both devices we still should not get the dual bidir SWB configuration
5801 // as it is currently disabled.
5802 current_config = group->GetCachedConfiguration(context_type);
5803 ASSERT_NE(nullptr, current_config.get());
5804 ASSERT_FALSE(
5805 AudioSetConfigurationProvider::Get()->CheckConfigurationIsDualBiDirSwb(
5806 *current_config.get()));
5807 }
5808
TEST_F(StateMachineTest,testStreamToGettingReadyDevice)5809 TEST_F(StateMachineTest, testStreamToGettingReadyDevice) {
5810 const auto context_type = kContextTypeLive;
5811 const auto leaudio_group_id = 666;
5812 const auto num_devices = 2;
5813
5814 ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
5815
5816 // Prepare multiple fake connected devices in a group
5817 auto* group =
5818 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
5819
5820 // Simulate the 2nd device still getting ready
5821 auto* firstDevice = group->GetFirstDevice();
5822 auto* secondDevice = group->GetNextDevice(firstDevice);
5823 secondDevice->SetConnectionState(
5824 DeviceConnectState::CONNECTED_BY_USER_GETTING_READY);
5825
5826 group->UpdateAudioContextAvailability();
5827 group->UpdateAudioSetConfigurationCache(context_type);
5828
5829 ASSERT_EQ(group->Size(), num_devices);
5830 ASSERT_EQ(1, group->NumOfConnected());
5831
5832 PrepareConfigureCodecHandler(group);
5833 PrepareConfigureQosHandler(group);
5834 PrepareEnableHandler(group);
5835 PrepareReceiverStartReadyHandler(group);
5836 PrepareDisableHandler(group);
5837 PrepareReleaseHandler(group);
5838
5839 /* Three Writes:
5840 * 1: Codec Config
5841 * 2: Codec QoS
5842 * 3: Enabling
5843 */
5844 // Expect actions only on the already prepared device
5845 EXPECT_CALL(gatt_queue, WriteCharacteristic(firstDevice->conn_id_,
5846 firstDevice->ctp_hdls_.val_hdl, _,
5847 GATT_WRITE_NO_RSP, _, _))
5848 .Times(AtLeast(3));
5849
5850 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5851 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5852 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
5853
5854 InjectInitialIdleNotification(group);
5855
5856 // Start the configuration and the stream
5857 LeAudioGroupStateMachine::Get()->StartStream(
5858 group, context_type,
5859 {.sink = types::AudioContexts(context_type),
5860 .source = types::AudioContexts(context_type)});
5861
5862 // Check if group has transitioned to a proper state with one device still
5863 // being in the `CONNECTED_BY_USER_GETTING_READY` state
5864 ASSERT_EQ(group->GetState(),
5865 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5866 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
5867 }
5868
TEST_F(StateMachineTest,testAttachDeviceToTheConversationalStream)5869 TEST_F(StateMachineTest, testAttachDeviceToTheConversationalStream) {
5870 const auto context_type = kContextTypeConversational;
5871 const auto leaudio_group_id = 6;
5872 const auto num_devices = 2;
5873
5874 ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
5875
5876 // Prepare multiple fake connected devices in a group
5877 auto* group =
5878 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
5879 ASSERT_EQ(group->Size(), num_devices);
5880
5881 PrepareConfigureCodecHandler(group);
5882 PrepareConfigureQosHandler(group);
5883 PrepareEnableHandler(group);
5884 PrepareReceiverStartReadyHandler(group);
5885 PrepareDisableHandler(group);
5886 PrepareReleaseHandler(group);
5887
5888 auto* leAudioDevice = group->GetFirstDevice();
5889 LeAudioDevice* lastDevice;
5890 LeAudioDevice* firstDevice = leAudioDevice;
5891
5892 auto expected_devices_written = 0;
5893 while (leAudioDevice) {
5894 /* Three Writes:
5895 * 1: Codec Config
5896 * 2: Codec QoS
5897 * 3: Enabling
5898 */
5899 lastDevice = leAudioDevice;
5900 EXPECT_CALL(gatt_queue,
5901 WriteCharacteristic(leAudioDevice->conn_id_,
5902 leAudioDevice->ctp_hdls_.val_hdl, _,
5903 GATT_WRITE_NO_RSP, _, _))
5904 .Times(AtLeast(3));
5905 expected_devices_written++;
5906 leAudioDevice = group->GetNextDevice(leAudioDevice);
5907 }
5908 ASSERT_EQ(expected_devices_written, num_devices);
5909 ASSERT_NE(nullptr, firstDevice);
5910 ASSERT_NE(nullptr, lastDevice);
5911
5912 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
5913 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5914
5915 EXPECT_CALL(*mock_iso_manager_,
5916 SetupIsoDataPath(
5917 _, dataPathDirIsEq(
5918 bluetooth::hci::iso_manager::kIsoDataPathDirectionIn)))
5919 .Times(2);
5920
5921 // Make sure the Out data path is set before we declare that we are ready
5922 {
5923 ::testing::InSequence seq;
5924 EXPECT_CALL(*mock_iso_manager_,
5925 SetupIsoDataPath(
5926 UNIQUE_CIS_CONN_HANDLE(leaudio_group_id, 0),
5927 dataPathDirIsEq(
5928 bluetooth::hci::iso_manager::kIsoDataPathDirectionOut)))
5929 .Times(1);
5930 EXPECT_CALL(ase_ctp_handler,
5931 AseCtpReceiverStartReadyHandler(firstDevice, _, _, _))
5932 .Times(1);
5933 }
5934 {
5935 ::testing::InSequence seq;
5936 EXPECT_CALL(*mock_iso_manager_,
5937 SetupIsoDataPath(
5938 UNIQUE_CIS_CONN_HANDLE(leaudio_group_id, 1),
5939 dataPathDirIsEq(
5940 bluetooth::hci::iso_manager::kIsoDataPathDirectionOut)))
5941 .Times(1);
5942 EXPECT_CALL(ase_ctp_handler,
5943 AseCtpReceiverStartReadyHandler(lastDevice, _, _, _))
5944 .Times(1);
5945 }
5946
5947 InjectInitialIdleNotification(group);
5948
5949 // Start the configuration and stream Conversational content
5950 LeAudioGroupStateMachine::Get()->StartStream(
5951 group, context_type,
5952 {.sink = types::AudioContexts(context_type),
5953 .source = types::AudioContexts(context_type)});
5954
5955 // Check if group has transitioned to a proper state
5956 ASSERT_EQ(group->GetState(),
5957 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5958 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
5959
5960 // Verify data path removal on the second bidirectional CIS
5961 EXPECT_CALL(
5962 *mock_iso_manager_,
5963 RemoveIsoDataPath(
5964 UNIQUE_CIS_CONN_HANDLE(leaudio_group_id, 1),
5965 bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput |
5966 bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput))
5967 .Times(1);
5968
5969 // Inject CIS and ACL disconnection of first device
5970 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
5971 InjectAclDisconnected(group, lastDevice);
5972 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
5973
5974 // Check if group keeps streaming
5975 ASSERT_EQ(group->GetState(),
5976 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
5977
5978 lastDevice->conn_id_ = 3;
5979 lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);
5980
5981 // Make sure ASE with disconnected CIS are not left in STREAMING
5982 ASSERT_EQ(lastDevice->GetFirstAseWithState(
5983 ::bluetooth::le_audio::types::kLeAudioDirectionSink,
5984 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
5985 nullptr);
5986 ASSERT_EQ(lastDevice->GetFirstAseWithState(
5987 ::bluetooth::le_audio::types::kLeAudioDirectionSource,
5988 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
5989 nullptr);
5990
5991 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
5992 lastDevice->ctp_hdls_.val_hdl, _,
5993 GATT_WRITE_NO_RSP, _, _))
5994 .Times(AtLeast(3));
5995
5996 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
5997 EXPECT_CALL(*mock_iso_manager_,
5998 SetupIsoDataPath(
5999 _, dataPathDirIsEq(
6000 bluetooth::hci::iso_manager::kIsoDataPathDirectionIn)))
6001 .Times(1);
6002 // Make sure the Out data path is set before we declare that we are ready
6003 {
6004 ::testing::InSequence seq;
6005 EXPECT_CALL(*mock_iso_manager_,
6006 SetupIsoDataPath(
6007 UNIQUE_CIS_CONN_HANDLE(leaudio_group_id, 1),
6008 dataPathDirIsEq(
6009 bluetooth::hci::iso_manager::kIsoDataPathDirectionOut)))
6010 .Times(1);
6011 EXPECT_CALL(ase_ctp_handler,
6012 AseCtpReceiverStartReadyHandler(lastDevice, _, _, _))
6013 .Times(1);
6014 }
6015
6016 LeAudioGroupStateMachine::Get()->AttachToStream(
6017 group, lastDevice, {.sink = {call_ccid}, .source = {call_ccid}});
6018
6019 // Check if group keeps streaming
6020 ASSERT_EQ(group->GetState(),
6021 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
6022
6023 // Verify that the joining device receives the right CCID list
6024 auto lastMeta = lastDevice->GetFirstActiveAse()->metadata;
6025 bool parsedOk = false;
6026 auto ltv = bluetooth::le_audio::types::LeAudioLtvMap::Parse(
6027 lastMeta.data(), lastMeta.size(), parsedOk);
6028 ASSERT_TRUE(parsedOk);
6029
6030 auto ccids =
6031 ltv.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeCcidList);
6032 ASSERT_TRUE(ccids.has_value());
6033 ASSERT_NE(std::find(ccids->begin(), ccids->end(), call_ccid), ccids->end());
6034
6035 /* Verify that ASE of first device are still good*/
6036 auto ase = firstDevice->GetFirstActiveAse();
6037 ASSERT_NE(ase->qos_config.max_transport_latency, 0);
6038 ASSERT_NE(ase->qos_config.retrans_nb, 0);
6039
6040 // Make sure ASEs with reconnected CIS are in STREAMING state
6041 ASSERT_TRUE(lastDevice->HaveAllActiveAsesSameState(
6042 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING));
6043 }
6044
TEST_F(StateMachineTest,StartStreamAfterConfigure)6045 TEST_F(StateMachineTest, StartStreamAfterConfigure) {
6046 const auto context_type = kContextTypeMedia;
6047 const auto leaudio_group_id = 6;
6048 const auto num_devices = 2;
6049
6050 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
6051
6052 // Prepare multiple fake connected devices in a group
6053 auto* group =
6054 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
6055 ASSERT_EQ(group->Size(), num_devices);
6056
6057 PrepareConfigureCodecHandler(group, 0, true);
6058 PrepareConfigureQosHandler(group);
6059 PrepareEnableHandler(group);
6060 PrepareDisableHandler(group);
6061 PrepareReleaseHandler(group);
6062
6063 InjectInitialIdleNotification(group);
6064
6065 auto* leAudioDevice = group->GetFirstDevice();
6066 auto expected_devices_written = 0;
6067 while (leAudioDevice) {
6068 /* Three Writes:
6069 * 1. Codec configure
6070 * 2: Codec QoS
6071 * 3: Enabling
6072 */
6073 EXPECT_CALL(gatt_queue,
6074 WriteCharacteristic(leAudioDevice->conn_id_,
6075 leAudioDevice->ctp_hdls_.val_hdl, _,
6076 GATT_WRITE_NO_RSP, _, _))
6077 .Times(3);
6078 expected_devices_written++;
6079 leAudioDevice = group->GetNextDevice(leAudioDevice);
6080 }
6081 ASSERT_EQ(expected_devices_written, num_devices);
6082
6083 // Validate GroupStreamStatus
6084 EXPECT_CALL(mock_callbacks_,
6085 StatusReportCb(
6086 leaudio_group_id,
6087 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER));
6088
6089 // Start the configuration and stream Media content
6090 group->SetPendingConfiguration();
6091 LeAudioGroupStateMachine::Get()->ConfigureStream(
6092 group, context_type,
6093 {.sink = types::AudioContexts(context_type),
6094 .source = types::AudioContexts(context_type)});
6095
6096 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6097
6098 group->ClearPendingConfiguration();
6099 // Validate GroupStreamStatus
6100 EXPECT_CALL(
6101 mock_callbacks_,
6102 StatusReportCb(leaudio_group_id,
6103 bluetooth::le_audio::GroupStreamStatus::STREAMING));
6104
6105 // Start the configuration and stream Media content
6106 LeAudioGroupStateMachine::Get()->StartStream(
6107 group, context_type,
6108 {.sink = types::AudioContexts(context_type),
6109 .source = types::AudioContexts(context_type)});
6110
6111 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6112 }
6113
TEST_F(StateMachineTest,StartStreamCachedConfig)6114 TEST_F(StateMachineTest, StartStreamCachedConfig) {
6115 const auto context_type = kContextTypeMedia;
6116 const auto leaudio_group_id = 6;
6117 const auto num_devices = 2;
6118
6119 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
6120
6121 // Prepare multiple fake connected devices in a group
6122 auto* group =
6123 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
6124 ASSERT_EQ(group->Size(), num_devices);
6125
6126 PrepareConfigureCodecHandler(group, 0, true);
6127 PrepareConfigureQosHandler(group);
6128 PrepareEnableHandler(group);
6129 PrepareDisableHandler(group);
6130 PrepareReleaseHandler(group);
6131
6132 InjectInitialIdleNotification(group);
6133
6134 auto* leAudioDevice = group->GetFirstDevice();
6135 auto expected_devices_written = 0;
6136 while (leAudioDevice) {
6137 /* Three Writes:
6138 * 1: Codec config
6139 * 2: Codec QoS (+1 after restart)
6140 * 3: Enabling (+1 after restart)
6141 * 4: Release (1)
6142 */
6143 EXPECT_CALL(gatt_queue,
6144 WriteCharacteristic(leAudioDevice->conn_id_,
6145 leAudioDevice->ctp_hdls_.val_hdl, _,
6146 GATT_WRITE_NO_RSP, _, _))
6147 .Times(6);
6148 expected_devices_written++;
6149 leAudioDevice = group->GetNextDevice(leAudioDevice);
6150 }
6151 ASSERT_EQ(expected_devices_written, num_devices);
6152
6153 // Validate GroupStreamStatus
6154 EXPECT_CALL(
6155 mock_callbacks_,
6156 StatusReportCb(leaudio_group_id,
6157 bluetooth::le_audio::GroupStreamStatus::STREAMING));
6158
6159 // Start the configuration and stream Media content
6160 LeAudioGroupStateMachine::Get()->StartStream(
6161 group, context_type,
6162 {.sink = types::AudioContexts(context_type),
6163 .source = types::AudioContexts(context_type)});
6164
6165 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6166
6167 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6168 reset_mock_function_count_map();
6169
6170 // Validate GroupStreamStatus
6171 EXPECT_CALL(
6172 mock_callbacks_,
6173 StatusReportCb(leaudio_group_id,
6174 bluetooth::le_audio::GroupStreamStatus::RELEASING));
6175
6176 EXPECT_CALL(
6177 mock_callbacks_,
6178 StatusReportCb(
6179 leaudio_group_id,
6180 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
6181 // Start the configuration and stream Media content
6182 LeAudioGroupStateMachine::Get()->StopStream(group);
6183
6184 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6185
6186 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6187 reset_mock_function_count_map();
6188
6189 // Restart stream
6190 EXPECT_CALL(
6191 mock_callbacks_,
6192 StatusReportCb(leaudio_group_id,
6193 bluetooth::le_audio::GroupStreamStatus::STREAMING));
6194
6195 // Start the configuration and stream Media content
6196 LeAudioGroupStateMachine::Get()->StartStream(
6197 group, context_type,
6198 {.sink = types::AudioContexts(context_type),
6199 .source = types::AudioContexts(context_type)});
6200
6201 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6202 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6203 }
6204
TEST_F(StateMachineTest,StartStreamCachedConfigReconfigInvalidBehavior)6205 TEST_F(StateMachineTest, StartStreamCachedConfigReconfigInvalidBehavior) {
6206 const auto context_type = kContextTypeConversational;
6207 const auto leaudio_group_id = 6;
6208 const auto num_devices = 1;
6209 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
6210 kLeAudioCodecChannelCountTwoChannel;
6211
6212 /* Scenario
6213 * 1. Start stream and stop stream so ASEs stays in Configured State
6214 * 2. Reconfigure ASEs localy, so the QoS parameters are zeroed
6215 * 3. Inject one ASE 2 to be in Releasing state
6216 * 4. Start stream and Incject ASE 1 to go into Codec Configured state
6217 * 5. IN such case CIG shall not be created and fallback to Release and
6218 * Configure stream should happen. Before fix CigCreate with invalid
6219 * parameters were called */
6220 ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
6221
6222 // Prepare multiple fake connected devices in a group
6223 auto* group =
6224 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
6225 ASSERT_EQ(group->Size(), num_devices);
6226
6227 PrepareConfigureCodecHandler(group, 0, true);
6228 PrepareConfigureQosHandler(group);
6229 PrepareEnableHandler(group);
6230 PrepareDisableHandler(group);
6231 PrepareReceiverStartReadyHandler(group);
6232 PrepareReleaseHandler(group);
6233
6234 InjectInitialIdleNotification(group);
6235
6236 // Validate GroupStreamStatus
6237 EXPECT_CALL(
6238 mock_callbacks_,
6239 StatusReportCb(leaudio_group_id,
6240 bluetooth::le_audio::GroupStreamStatus::STREAMING));
6241
6242 EXPECT_CALL(*mock_iso_manager_, CreateCig).Times(1);
6243
6244 // Start the configuration and stream call content
6245 LeAudioGroupStateMachine::Get()->StartStream(
6246 group, context_type,
6247 {.sink = types::AudioContexts(context_type),
6248 .source = types::AudioContexts(context_type)});
6249
6250 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6251
6252 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6253 reset_mock_function_count_map();
6254
6255 // Validate GroupStreamStatus
6256 EXPECT_CALL(
6257 mock_callbacks_,
6258 StatusReportCb(leaudio_group_id,
6259 bluetooth::le_audio::GroupStreamStatus::RELEASING));
6260
6261 EXPECT_CALL(
6262 mock_callbacks_,
6263 StatusReportCb(
6264 leaudio_group_id,
6265 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
6266 // Start the configuration and stream Media content
6267 LeAudioGroupStateMachine::Get()->StopStream(group);
6268
6269 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6270 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
6271
6272 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6273 reset_mock_function_count_map();
6274
6275 stop_inject_configured_ase_after_first_ase_configured_ = true;
6276
6277 auto device = group->GetFirstDevice();
6278 int i = 0;
6279 for (auto& ase : device->ases_) {
6280 if (i++ == 0) continue;
6281
6282 // Simulate autonomus release for one ASE
6283 InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing,
6284 nullptr);
6285 }
6286
6287 // Restart stream and expect it will not be created.
6288 EXPECT_CALL(mock_callbacks_,
6289 StatusReportCb(leaudio_group_id,
6290 bluetooth::le_audio::GroupStreamStatus::STREAMING))
6291 .Times(0);
6292 EXPECT_CALL(mock_callbacks_,
6293 StatusReportCb(leaudio_group_id,
6294 bluetooth::le_audio::GroupStreamStatus::RELEASING))
6295 .Times(0);
6296
6297 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0);
6298
6299 // Block the fallback Release which will happen when CreateCig will fail
6300 stay_in_releasing_state_ = true;
6301
6302 // Start the configuration and stream Live content
6303 bool result = LeAudioGroupStateMachine::Get()->StartStream(
6304 group, kContextTypeLive,
6305 {.sink = types::AudioContexts(kContextTypeLive),
6306 .source = types::AudioContexts(kContextTypeLive)});
6307
6308 // Group internally in releasing state. StartStrean should faile.
6309
6310 ASSERT_FALSE(result);
6311
6312 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6313 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
6314 }
6315
TEST_F(StateMachineTest,BoundedHeadphonesConversationalToMediaChannelCount_2)6316 TEST_F(StateMachineTest, BoundedHeadphonesConversationalToMediaChannelCount_2) {
6317 const auto initial_context_type = kContextTypeConversational;
6318 const auto new_context_type = kContextTypeMedia;
6319 const auto leaudio_group_id = 6;
6320 const auto num_devices = 1;
6321 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
6322 kLeAudioCodecChannelCountTwoChannel;
6323
6324 sample_freq_ |= codec_specific::kCapSamplingFrequency48000Hz |
6325 codec_specific::kCapSamplingFrequency32000Hz;
6326 additional_snk_ases = 3;
6327 additional_src_ases = 1;
6328
6329 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
6330 ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
6331
6332 // Prepare multiple fake connected devices in a group
6333 auto* group = PrepareSingleTestDeviceGroup(
6334 leaudio_group_id, initial_context_type, num_devices,
6335 kContextTypeConversational | kContextTypeMedia);
6336 ASSERT_EQ(group->Size(), num_devices);
6337
6338 PrepareConfigureCodecHandler(group, 0, true);
6339 PrepareConfigureQosHandler(group);
6340 PrepareEnableHandler(group);
6341 PrepareDisableHandler(group);
6342 PrepareReleaseHandler(group);
6343 PrepareReceiverStartReadyHandler(group);
6344
6345 InjectInitialIdleNotification(group);
6346
6347 auto* leAudioDevice = group->GetFirstDevice();
6348 auto expected_devices_written = 0;
6349 while (leAudioDevice) {
6350 /* 8 Writes:
6351 * 1: Codec config (+1 after reconfig)
6352 * 2: Codec QoS (+1 after reconfig)
6353 * 3: Enabling (+1 after reconfig)
6354 * 4: ReceiverStartReady (only for conversational)
6355 * 5: Release
6356 */
6357 EXPECT_CALL(gatt_queue,
6358 WriteCharacteristic(leAudioDevice->conn_id_,
6359 leAudioDevice->ctp_hdls_.val_hdl, _,
6360 GATT_WRITE_NO_RSP, _, _))
6361 .Times(8);
6362 expected_devices_written++;
6363 leAudioDevice = group->GetNextDevice(leAudioDevice);
6364 }
6365 ASSERT_EQ(expected_devices_written, num_devices);
6366
6367 // Validate GroupStreamStatus
6368 EXPECT_CALL(
6369 mock_callbacks_,
6370 StatusReportCb(leaudio_group_id,
6371 bluetooth::le_audio::GroupStreamStatus::STREAMING));
6372
6373 // Start the configuration and stream Media content
6374 LeAudioGroupStateMachine::Get()->StartStream(
6375 group, initial_context_type,
6376 {.sink = types::AudioContexts(initial_context_type),
6377 .source = types::AudioContexts(initial_context_type)});
6378
6379 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6380
6381 auto current_config = group->GetCachedConfiguration(initial_context_type);
6382 ASSERT_NE(nullptr, current_config);
6383 ASSERT_EQ(1lu, current_config->confs.sink.size());
6384 ASSERT_EQ(1lu, current_config->confs.source.size());
6385
6386 // Validate GroupStreamStatus
6387 EXPECT_CALL(
6388 mock_callbacks_,
6389 StatusReportCb(leaudio_group_id,
6390 bluetooth::le_audio::GroupStreamStatus::RELEASING));
6391
6392 EXPECT_CALL(
6393 mock_callbacks_,
6394 StatusReportCb(
6395 leaudio_group_id,
6396 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
6397 // Start the configuration and stream Media content
6398 LeAudioGroupStateMachine::Get()->StopStream(group);
6399
6400 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6401
6402 // Restart stream
6403 EXPECT_CALL(
6404 mock_callbacks_,
6405 StatusReportCb(leaudio_group_id,
6406 bluetooth::le_audio::GroupStreamStatus::STREAMING));
6407
6408 // Start the configuration and stream Media content
6409 LeAudioGroupStateMachine::Get()->StartStream(
6410 group, new_context_type,
6411 {.sink = types::AudioContexts(new_context_type),
6412 .source = types::AudioContexts(new_context_type)});
6413
6414 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6415
6416 current_config = group->GetCachedConfiguration(new_context_type);
6417 ASSERT_NE(nullptr, current_config);
6418 ASSERT_EQ(1lu, current_config->confs.sink.size());
6419 ASSERT_EQ(0lu, current_config->confs.source.size());
6420 }
6421
TEST_F(StateMachineTest,BoundedHeadphonesConversationalToMediaChannelCount_1_MonoMic)6422 TEST_F(StateMachineTest,
6423 BoundedHeadphonesConversationalToMediaChannelCount_1_MonoMic) {
6424 const auto initial_context_type = kContextTypeConversational;
6425 const auto new_context_type = kContextTypeMedia;
6426 const auto leaudio_group_id = 6;
6427 const auto num_devices = 1;
6428 // Single audio allocation for the mono source
6429 channel_allocations_source_ =
6430 ::bluetooth::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft;
6431 channel_count_ = kLeAudioCodecChannelCountSingleChannel;
6432
6433 sample_freq_ |= codec_specific::kCapSamplingFrequency48000Hz |
6434 codec_specific::kCapSamplingFrequency32000Hz;
6435 additional_snk_ases = 3;
6436 additional_src_ases = 1;
6437
6438 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
6439 ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
6440
6441 // Prepare one fake connected devices in a group
6442 auto* group = PrepareSingleTestDeviceGroup(
6443 leaudio_group_id, initial_context_type, num_devices,
6444 kContextTypeConversational | kContextTypeMedia);
6445 ASSERT_EQ(group->Size(), num_devices);
6446
6447 // Cannot verify here as we will change the number of ases on reconfigure
6448 PrepareConfigureCodecHandler(group, 0, true);
6449 PrepareConfigureQosHandler(group);
6450 PrepareEnableHandler(group);
6451 PrepareDisableHandler(group);
6452 PrepareReleaseHandler(group);
6453 PrepareReceiverStartReadyHandler(group);
6454
6455 InjectInitialIdleNotification(group);
6456
6457 auto* leAudioDevice = group->GetFirstDevice();
6458 auto expected_devices_written = 0;
6459 while (leAudioDevice) {
6460 /* 8 Writes:
6461 * 1: Codec config (+1 after reconfig)
6462 * 2: Codec QoS (+1 after reconfig)
6463 * 3: Enabling (+1 after reconfig)
6464 * 4: ReceiverStartReady (only for conversational)
6465 * 5: Release
6466 */
6467 EXPECT_CALL(gatt_queue,
6468 WriteCharacteristic(leAudioDevice->conn_id_,
6469 leAudioDevice->ctp_hdls_.val_hdl, _,
6470 GATT_WRITE_NO_RSP, _, _))
6471 .Times(8);
6472 expected_devices_written++;
6473 leAudioDevice = group->GetNextDevice(leAudioDevice);
6474 }
6475 ASSERT_EQ(expected_devices_written, num_devices);
6476
6477 // Validate GroupStreamStatus
6478 EXPECT_CALL(
6479 mock_callbacks_,
6480 StatusReportCb(leaudio_group_id,
6481 bluetooth::le_audio::GroupStreamStatus::STREAMING));
6482
6483 // Start the configuration and stream Media content
6484 LeAudioGroupStateMachine::Get()->StartStream(
6485 group, initial_context_type,
6486 {.sink = types::AudioContexts(initial_context_type),
6487 .source = types::AudioContexts(initial_context_type)});
6488
6489 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6490
6491 auto current_config = group->GetCachedConfiguration(initial_context_type);
6492 ASSERT_NE(nullptr, current_config);
6493 // sink has two locations
6494 ASSERT_EQ(2lu, current_config->confs.sink.size());
6495 // source has a single location
6496 ASSERT_EQ(1lu, current_config->confs.source.size());
6497
6498 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6499 reset_mock_function_count_map();
6500
6501 // Validate GroupStreamStatus
6502 EXPECT_CALL(
6503 mock_callbacks_,
6504 StatusReportCb(leaudio_group_id,
6505 bluetooth::le_audio::GroupStreamStatus::RELEASING));
6506
6507 EXPECT_CALL(
6508 mock_callbacks_,
6509 StatusReportCb(
6510 leaudio_group_id,
6511 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
6512 // Start the configuration and stream Media content
6513 LeAudioGroupStateMachine::Get()->StopStream(group);
6514
6515 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6516 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6517 reset_mock_function_count_map();
6518
6519 // Restart stream
6520 EXPECT_CALL(
6521 mock_callbacks_,
6522 StatusReportCb(leaudio_group_id,
6523 bluetooth::le_audio::GroupStreamStatus::STREAMING));
6524
6525 // Start the configuration and stream Media content
6526 LeAudioGroupStateMachine::Get()->StartStream(
6527 group, new_context_type,
6528 {.sink = types::AudioContexts(new_context_type),
6529 .source = types::AudioContexts(new_context_type)});
6530
6531 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6532 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6533
6534 current_config = group->GetCachedConfiguration(new_context_type);
6535 ASSERT_NE(nullptr, current_config);
6536 ASSERT_EQ(2lu, current_config->confs.sink.size());
6537 ASSERT_EQ(0lu, current_config->confs.source.size());
6538 }
6539
TEST_F(StateMachineTest,DISABLED_BoundedHeadphonesConversationalToMediaChannelCount_1_StereoMic)6540 TEST_F(
6541 StateMachineTest,
6542 DISABLED_BoundedHeadphonesConversationalToMediaChannelCount_1_StereoMic) {
6543 const auto initial_context_type = kContextTypeConversational;
6544 const auto new_context_type = kContextTypeMedia;
6545 const auto leaudio_group_id = 6;
6546 const auto num_devices = 1;
6547 channel_allocations_source_ =
6548 ::bluetooth::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft |
6549 ::bluetooth::le_audio::codec_spec_conf::kLeAudioLocationFrontRight;
6550 channel_count_ = kLeAudioCodecChannelCountSingleChannel;
6551
6552 sample_freq_ |= codec_specific::kCapSamplingFrequency48000Hz |
6553 codec_specific::kCapSamplingFrequency32000Hz;
6554 additional_snk_ases = 3;
6555 additional_src_ases = 1;
6556
6557 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
6558 ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
6559
6560 // Prepare one fake connected devices in a group
6561 auto* group = PrepareSingleTestDeviceGroup(
6562 leaudio_group_id, initial_context_type, num_devices,
6563 kContextTypeConversational | kContextTypeMedia);
6564 ASSERT_EQ(group->Size(), num_devices);
6565
6566 // Cannot verify here as we will change the number of ases on reconfigure
6567 PrepareConfigureCodecHandler(group, 0, true);
6568 PrepareConfigureQosHandler(group);
6569 PrepareEnableHandler(group);
6570 PrepareDisableHandler(group);
6571 PrepareReleaseHandler(group);
6572 PrepareReceiverStartReadyHandler(group);
6573
6574 InjectInitialIdleNotification(group);
6575
6576 auto* leAudioDevice = group->GetFirstDevice();
6577 auto expected_devices_written = 0;
6578 while (leAudioDevice) {
6579 /* 8 Writes:
6580 * 1: Codec config (+1 after reconfig)
6581 * 2: Codec QoS (+1 after reconfig)
6582 * 3: Enabling (+1 after reconfig)
6583 * 4: ReceiverStartReady (only for conversational)
6584 * 5: Release
6585 */
6586 EXPECT_CALL(gatt_queue,
6587 WriteCharacteristic(leAudioDevice->conn_id_,
6588 leAudioDevice->ctp_hdls_.val_hdl, _,
6589 GATT_WRITE_NO_RSP, _, _))
6590 .Times(8);
6591 expected_devices_written++;
6592 leAudioDevice = group->GetNextDevice(leAudioDevice);
6593 }
6594 ASSERT_EQ(expected_devices_written, num_devices);
6595
6596 // Validate GroupStreamStatus
6597 EXPECT_CALL(
6598 mock_callbacks_,
6599 StatusReportCb(leaudio_group_id,
6600 bluetooth::le_audio::GroupStreamStatus::STREAMING));
6601
6602 // Start the configuration and stream Media content
6603 LeAudioGroupStateMachine::Get()->StartStream(
6604 group, initial_context_type,
6605 {.sink = types::AudioContexts(initial_context_type),
6606 .source = types::AudioContexts(initial_context_type)});
6607
6608 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6609
6610 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6611 reset_mock_function_count_map();
6612
6613 auto current_config = group->GetCachedConfiguration(initial_context_type);
6614 ASSERT_NE(nullptr, current_config);
6615 ASSERT_EQ(2lu, current_config->confs.sink.size());
6616 ASSERT_EQ(2lu, current_config->confs.source.size());
6617
6618 // Validate GroupStreamStatus
6619 EXPECT_CALL(
6620 mock_callbacks_,
6621 StatusReportCb(leaudio_group_id,
6622 bluetooth::le_audio::GroupStreamStatus::RELEASING));
6623
6624 EXPECT_CALL(
6625 mock_callbacks_,
6626 StatusReportCb(
6627 leaudio_group_id,
6628 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
6629 // Start the configuration and stream Media content
6630 LeAudioGroupStateMachine::Get()->StopStream(group);
6631
6632 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6633 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6634 reset_mock_function_count_map();
6635
6636 // Restart stream
6637 EXPECT_CALL(
6638 mock_callbacks_,
6639 StatusReportCb(leaudio_group_id,
6640 bluetooth::le_audio::GroupStreamStatus::STREAMING));
6641
6642 // Start the configuration and stream Media content
6643 LeAudioGroupStateMachine::Get()->StartStream(
6644 group, new_context_type,
6645 {.sink = types::AudioContexts(new_context_type),
6646 .source = types::AudioContexts(new_context_type)});
6647
6648 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6649 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6650
6651 current_config = group->GetCachedConfiguration(new_context_type);
6652 ASSERT_NE(nullptr, current_config);
6653 ASSERT_EQ(2lu, current_config->confs.sink.size());
6654 ASSERT_EQ(0lu, current_config->confs.source.size());
6655 }
6656
TEST_F(StateMachineTest,lateCisDisconnectedEvent_DuringReconfiguration)6657 TEST_F(StateMachineTest, lateCisDisconnectedEvent_DuringReconfiguration) {
6658 const auto context_type = kContextTypeMedia;
6659 const auto leaudio_group_id = 6;
6660 const auto num_devices = 1;
6661
6662 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
6663
6664 // Prepare multiple fake connected devices in a group
6665 auto* group =
6666 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
6667 ASSERT_EQ(group->Size(), num_devices);
6668
6669 PrepareConfigureCodecHandler(group, 0, true);
6670 PrepareConfigureQosHandler(group);
6671 PrepareEnableHandler(group);
6672 PrepareDisableHandler(group);
6673 PrepareReleaseHandler(group);
6674
6675 auto* leAudioDevice = group->GetFirstDevice();
6676 auto expected_devices_written = 0;
6677
6678 /* Three Writes:
6679 * 1: Codec Config
6680 * 2: Codec QoS
6681 * 3: Enabling
6682 */
6683 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
6684 leAudioDevice->ctp_hdls_.val_hdl,
6685 _, GATT_WRITE_NO_RSP, _, _))
6686 .Times(AtLeast(3));
6687 expected_devices_written++;
6688
6689 ASSERT_EQ(expected_devices_written, num_devices);
6690
6691 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
6692 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
6693 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
6694
6695 InjectInitialIdleNotification(group);
6696
6697 // Start the configuration and stream Media content
6698 LeAudioGroupStateMachine::Get()->StartStream(
6699 group, context_type,
6700 {.sink = types::AudioContexts(context_type),
6701 .source = types::AudioContexts(context_type)});
6702
6703 // Check if group has transitioned to a proper state
6704 ASSERT_EQ(group->GetState(),
6705 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
6706 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
6707
6708 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6709 reset_mock_function_count_map();
6710
6711 /* Prepare DisconnectCis mock to not symulate CisDisconnection */
6712 ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return());
6713
6714 /* Do reconfiguration */
6715 group->SetPendingConfiguration();
6716
6717 // Validate GroupStreamStatus
6718 EXPECT_CALL(
6719 mock_callbacks_,
6720 StatusReportCb(leaudio_group_id,
6721 bluetooth::le_audio::GroupStreamStatus::RELEASING));
6722
6723 EXPECT_CALL(
6724 mock_callbacks_,
6725 StatusReportCb(
6726 leaudio_group_id,
6727 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS))
6728 .Times(0);
6729 LeAudioGroupStateMachine::Get()->StopStream(group);
6730
6731 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6732
6733 ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
6734
6735 EXPECT_CALL(
6736 mock_callbacks_,
6737 StatusReportCb(
6738 leaudio_group_id,
6739 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
6740
6741 // Inject CIS and ACL disconnection of first device
6742 InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
6743 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6744 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6745 }
6746
TEST_F(StateMachineTest,lateCisDisconnectedEvent_AutonomousConfigured)6747 TEST_F(StateMachineTest, lateCisDisconnectedEvent_AutonomousConfigured) {
6748 const auto context_type = kContextTypeMedia;
6749 const auto leaudio_group_id = 6;
6750 const auto num_devices = 1;
6751
6752 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
6753
6754 // Prepare multiple fake connected devices in a group
6755 auto* group =
6756 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
6757 ASSERT_EQ(group->Size(), num_devices);
6758
6759 PrepareConfigureCodecHandler(group, 0, true);
6760 PrepareConfigureQosHandler(group);
6761 PrepareEnableHandler(group);
6762 PrepareDisableHandler(group);
6763 PrepareReleaseHandler(group);
6764
6765 auto* leAudioDevice = group->GetFirstDevice();
6766 auto expected_devices_written = 0;
6767
6768 /* Three Writes:
6769 * 1: Codec Config
6770 * 2: Codec QoS
6771 * 3: Enabling
6772 */
6773 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
6774 leAudioDevice->ctp_hdls_.val_hdl,
6775 _, GATT_WRITE_NO_RSP, _, _))
6776 .Times(AtLeast(3));
6777 expected_devices_written++;
6778
6779 ASSERT_EQ(expected_devices_written, num_devices);
6780
6781 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
6782 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
6783 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
6784
6785 InjectInitialIdleNotification(group);
6786
6787 // Start the configuration and stream Media content
6788 LeAudioGroupStateMachine::Get()->StartStream(
6789 group, context_type,
6790 {.sink = types::AudioContexts(context_type),
6791 .source = types::AudioContexts(context_type)});
6792
6793 // Check if group has transitioned to a proper state
6794 ASSERT_EQ(group->GetState(),
6795 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
6796 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
6797
6798 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6799 reset_mock_function_count_map();
6800
6801 /* Prepare DisconnectCis mock to not symulate CisDisconnection */
6802 ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return());
6803
6804 // Validate GroupStreamStatus
6805 EXPECT_CALL(
6806 mock_callbacks_,
6807 StatusReportCb(leaudio_group_id,
6808 bluetooth::le_audio::GroupStreamStatus::RELEASING));
6809
6810 EXPECT_CALL(
6811 mock_callbacks_,
6812 StatusReportCb(
6813 leaudio_group_id,
6814 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS))
6815 .Times(0);
6816
6817 // Stop the stream
6818 LeAudioGroupStateMachine::Get()->StopStream(group);
6819
6820 // Check if group has transitioned to a proper state
6821 ASSERT_EQ(group->GetState(),
6822 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
6823
6824 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6825
6826 ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
6827
6828 EXPECT_CALL(
6829 mock_callbacks_,
6830 StatusReportCb(
6831 leaudio_group_id,
6832 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
6833
6834 // Inject CIS and ACL disconnection of first device
6835 InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
6836 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6837 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6838 }
6839
TEST_F(StateMachineTest,lateCisDisconnectedEvent_Idle)6840 TEST_F(StateMachineTest, lateCisDisconnectedEvent_Idle) {
6841 const auto context_type = kContextTypeMedia;
6842 const auto leaudio_group_id = 6;
6843 const auto num_devices = 1;
6844
6845 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
6846
6847 // Prepare multiple fake connected devices in a group
6848 auto* group =
6849 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
6850 ASSERT_EQ(group->Size(), num_devices);
6851
6852 PrepareConfigureCodecHandler(group);
6853 PrepareConfigureQosHandler(group);
6854 PrepareEnableHandler(group);
6855 PrepareDisableHandler(group);
6856 PrepareReleaseHandler(group);
6857
6858 auto* leAudioDevice = group->GetFirstDevice();
6859 auto expected_devices_written = 0;
6860
6861 /* Three Writes:
6862 * 1: Codec Config
6863 * 2: Codec QoS
6864 * 3: Enabling
6865 */
6866 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
6867 leAudioDevice->ctp_hdls_.val_hdl,
6868 _, GATT_WRITE_NO_RSP, _, _))
6869 .Times(AtLeast(3));
6870 expected_devices_written++;
6871
6872 ASSERT_EQ(expected_devices_written, num_devices);
6873
6874 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
6875 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
6876 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
6877
6878 InjectInitialIdleNotification(group);
6879
6880 // Start the configuration and stream Media content
6881 LeAudioGroupStateMachine::Get()->StartStream(
6882 group, context_type,
6883 {.sink = types::AudioContexts(context_type),
6884 .source = types::AudioContexts(context_type)});
6885
6886 // Check if group has transitioned to a proper state
6887 ASSERT_EQ(group->GetState(),
6888 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
6889 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
6890
6891 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6892 reset_mock_function_count_map();
6893 /* Prepare DisconnectCis mock to not symulate CisDisconnection */
6894 ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return());
6895
6896 // Validate GroupStreamStatus
6897 EXPECT_CALL(
6898 mock_callbacks_,
6899 StatusReportCb(leaudio_group_id,
6900 bluetooth::le_audio::GroupStreamStatus::RELEASING));
6901
6902 EXPECT_CALL(mock_callbacks_,
6903 StatusReportCb(leaudio_group_id,
6904 bluetooth::le_audio::GroupStreamStatus::IDLE))
6905 .Times(0);
6906
6907 // Stop the stream
6908 LeAudioGroupStateMachine::Get()->StopStream(group);
6909
6910 // Check if group has transitioned to a proper state
6911 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
6912 ASSERT_EQ(0, get_func_call_count("alarm_cancel"));
6913
6914 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6915
6916 EXPECT_CALL(mock_callbacks_,
6917 StatusReportCb(leaudio_group_id,
6918 bluetooth::le_audio::GroupStreamStatus::IDLE));
6919
6920 // Inject CIS and ACL disconnection of first device
6921 InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
6922 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6923 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6924 }
6925
TEST_F(StateMachineTest,StreamReconfigureAfterCisLostTwoDevices)6926 TEST_F(StateMachineTest, StreamReconfigureAfterCisLostTwoDevices) {
6927 auto context_type = kContextTypeConversational;
6928 const auto leaudio_group_id = 4;
6929 const auto num_devices = 2;
6930
6931 // Prepare multiple fake connected devices in a group
6932 auto* group = PrepareSingleTestDeviceGroup(
6933 leaudio_group_id, context_type, num_devices,
6934 kContextTypeConversational | kContextTypeMedia);
6935 ASSERT_EQ(group->Size(), num_devices);
6936
6937 PrepareConfigureCodecHandler(group);
6938 PrepareConfigureQosHandler(group);
6939 PrepareEnableHandler(group);
6940 PrepareReceiverStartReadyHandler(group);
6941
6942 /* Prepare DisconnectCis mock to not symulate CisDisconnection */
6943 ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return());
6944
6945 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
6946 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
6947 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
6948 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
6949
6950 InjectInitialIdleNotification(group);
6951
6952 auto* leAudioDevice = group->GetFirstDevice();
6953 auto expected_devices_written = 0;
6954 while (leAudioDevice) {
6955 EXPECT_CALL(gatt_queue,
6956 WriteCharacteristic(leAudioDevice->conn_id_,
6957 leAudioDevice->ctp_hdls_.val_hdl, _,
6958 GATT_WRITE_NO_RSP, _, _))
6959 .Times(3);
6960 expected_devices_written++;
6961 leAudioDevice = group->GetNextDevice(leAudioDevice);
6962 }
6963 ASSERT_EQ(expected_devices_written, num_devices);
6964
6965 // Validate GroupStreamStatus
6966 EXPECT_CALL(
6967 mock_callbacks_,
6968 StatusReportCb(leaudio_group_id,
6969 bluetooth::le_audio::GroupStreamStatus::STREAMING));
6970
6971 // Start the configuration and stream Media content
6972 context_type = kContextTypeMedia;
6973 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
6974 group, context_type,
6975 {.sink = types::AudioContexts(context_type),
6976 .source = types::AudioContexts(context_type)}));
6977
6978 // Check if group has transitioned to a proper state
6979 ASSERT_EQ(group->GetState(),
6980 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
6981 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
6982 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
6983 testing::Mock::VerifyAndClearExpectations(&gatt_queue);
6984 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
6985
6986 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
6987 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
6988 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4);
6989 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2);
6990 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
6991
6992 // Device disconnects due to timeout of CIS
6993 leAudioDevice = group->GetFirstDevice();
6994 while (leAudioDevice) {
6995 InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
6996 // Disconnect device
6997 LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected(
6998 group, leAudioDevice);
6999
7000 leAudioDevice = group->GetNextDevice(leAudioDevice);
7001 }
7002
7003 group->ReloadAudioLocations();
7004 group->ReloadAudioDirections();
7005
7006 // Start conversational scenario
7007 leAudioDevice = group->GetFirstDevice();
7008 int device_cnt = num_devices;
7009 while (leAudioDevice) {
7010 leAudioDevice->conn_id_ = device_cnt--;
7011 leAudioDevice->SetConnectionState(DeviceConnectState::CONNECTED);
7012 leAudioDevice = group->GetNextDevice(leAudioDevice);
7013 }
7014
7015 InjectInitialIdleNotification(group);
7016
7017 group->ReloadAudioLocations();
7018 group->ReloadAudioDirections();
7019
7020 leAudioDevice = group->GetFirstDevice();
7021 expected_devices_written = 0;
7022 while (leAudioDevice) {
7023 EXPECT_CALL(gatt_queue,
7024 WriteCharacteristic(leAudioDevice->conn_id_,
7025 leAudioDevice->ctp_hdls_.val_hdl, _,
7026 GATT_WRITE_NO_RSP, _, _))
7027 .Times(4);
7028 expected_devices_written++;
7029 leAudioDevice = group->GetNextDevice(leAudioDevice);
7030 }
7031 ASSERT_EQ(expected_devices_written, num_devices);
7032
7033 // Validate GroupStreamStatus
7034 EXPECT_CALL(
7035 mock_callbacks_,
7036 StatusReportCb(leaudio_group_id,
7037 bluetooth::le_audio::GroupStreamStatus::STREAMING));
7038
7039 // Start the configuration and stream Conversational content
7040 context_type = kContextTypeConversational;
7041 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
7042 group, context_type,
7043 {.sink = types::AudioContexts(context_type),
7044 .source = types::AudioContexts(context_type)}));
7045
7046 // Check if group has transitioned to a proper state
7047 ASSERT_EQ(group->GetState(),
7048 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7049 ASSERT_EQ(2, get_func_call_count("alarm_cancel"));
7050 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7051 testing::Mock::VerifyAndClearExpectations(&gatt_queue);
7052 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
7053 }
7054
TEST_F(StateMachineTest,StreamClearAfterReleaseAndConnectionTimeout)7055 TEST_F(StateMachineTest, StreamClearAfterReleaseAndConnectionTimeout) {
7056 auto context_type = kContextTypeMedia;
7057 const auto leaudio_group_id = 4;
7058 const auto num_devices = 2;
7059
7060 /* Scenario
7061 1. Streaming to 2 device
7062 2. Stream suspend
7063 3. One device got to IDLE
7064 4. Second device Connection Timeout
7065 */
7066
7067 // Prepare multiple fake connected devices in a group
7068 auto* group = PrepareSingleTestDeviceGroup(
7069 leaudio_group_id, context_type, num_devices,
7070 kContextTypeConversational | kContextTypeMedia);
7071 ASSERT_EQ(group->Size(), num_devices);
7072
7073 PrepareConfigureCodecHandler(group);
7074 PrepareConfigureQosHandler(group);
7075 PrepareEnableHandler(group);
7076
7077 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
7078 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
7079 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
7080 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2);
7081 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
7082 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
7083
7084 InjectInitialIdleNotification(group);
7085
7086 auto* leAudioDevice = group->GetFirstDevice();
7087 auto* firstDevice = leAudioDevice;
7088 auto* lastDevice = leAudioDevice;
7089
7090 while (leAudioDevice) {
7091 lastDevice = leAudioDevice;
7092 leAudioDevice = group->GetNextDevice(leAudioDevice);
7093 }
7094
7095 // Validate GroupStreamStatus
7096 EXPECT_CALL(
7097 mock_callbacks_,
7098 StatusReportCb(leaudio_group_id,
7099 bluetooth::le_audio::GroupStreamStatus::STREAMING));
7100
7101 // Start the configuration and stream Media content
7102 context_type = kContextTypeMedia;
7103 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
7104 group, context_type,
7105 {.sink = types::AudioContexts(context_type),
7106 .source = types::AudioContexts(context_type)}));
7107
7108 // Check if group has transitioned to a proper state
7109 ASSERT_EQ(group->GetState(),
7110 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7111 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
7112 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
7113
7114 EXPECT_CALL(
7115 mock_callbacks_,
7116 StatusReportCb(leaudio_group_id,
7117 bluetooth::le_audio::GroupStreamStatus::RELEASING));
7118 EXPECT_CALL(mock_callbacks_,
7119 StatusReportCb(leaudio_group_id,
7120 bluetooth::le_audio::GroupStreamStatus::IDLE));
7121
7122 /* Prepare release handler only for first device. */
7123 PrepareReleaseHandler(group, 0, false, firstDevice);
7124 LeAudioGroupStateMachine::Get()->StopStream(group);
7125
7126 /* Second device will disconnect because of timeout. Do not bother
7127 * with remove data path response from the controller. In test we are doing it
7128 * in a test thread which breaks things. */
7129 ON_CALL(*mock_iso_manager_, RemoveIsoDataPath).WillByDefault(Return());
7130 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
7131 InjectAclDisconnected(group, lastDevice);
7132
7133 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
7134 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7135 }
7136
TEST_F(StateMachineTest,VerifyThereIsNoDoubleDataPathRemoval)7137 TEST_F(StateMachineTest, VerifyThereIsNoDoubleDataPathRemoval) {
7138 auto context_type = kContextTypeConversational;
7139 const auto leaudio_group_id = 4;
7140 const auto num_devices = 1;
7141
7142 /* Symulate banded headphonse */
7143 channel_count_ = kLeAudioCodecChannelCountSingleChannel |
7144 kLeAudioCodecChannelCountTwoChannel;
7145
7146 /* Scenario
7147 1. Phone call to 1 device
7148 2. Stop the stream
7149 3. Get both ASE sink and Source to releasing
7150 4. Verify only 1 RemoveDataPath is called
7151 */
7152
7153 // Prepare multiple fake connected devices in a group
7154 auto* group = PrepareSingleTestDeviceGroup(
7155 leaudio_group_id, context_type, num_devices,
7156 kContextTypeConversational | kContextTypeMedia);
7157 ASSERT_EQ(group->Size(), num_devices);
7158
7159 PrepareConfigureCodecHandler(group);
7160 PrepareConfigureQosHandler(group);
7161 PrepareEnableHandler(group);
7162 PrepareReleaseHandler(group);
7163 PrepareReceiverStartReadyHandler(group);
7164
7165 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
7166 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
7167 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
7168 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1);
7169
7170 /*Test ends before full clean*/
7171 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
7172 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
7173
7174 InjectInitialIdleNotification(group);
7175
7176 // Validate GroupStreamStatus
7177 EXPECT_CALL(
7178 mock_callbacks_,
7179 StatusReportCb(leaudio_group_id,
7180 bluetooth::le_audio::GroupStreamStatus::STREAMING));
7181
7182 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
7183 group, context_type,
7184 {.sink = types::AudioContexts(context_type),
7185 .source = types::AudioContexts(context_type)}));
7186
7187 // Check if group has transitioned to a proper state
7188 ASSERT_EQ(group->GetState(),
7189 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7190 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
7191 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
7192
7193 EXPECT_CALL(
7194 mock_callbacks_,
7195 StatusReportCb(leaudio_group_id,
7196 bluetooth::le_audio::GroupStreamStatus::RELEASING));
7197
7198 /* Do not trigger any action on removeIsoData path.*/
7199 ON_CALL(*mock_iso_manager_, RemoveIsoDataPath).WillByDefault(Return());
7200
7201 LeAudioGroupStateMachine::Get()->StopStream(group);
7202
7203 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
7204 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7205 }
7206
TEST_F(StateMachineTest,StreamStartWithDifferentContextFromConfiguredState)7207 TEST_F(StateMachineTest, StreamStartWithDifferentContextFromConfiguredState) {
7208 auto context_type = kContextTypeConversational;
7209 const auto leaudio_group_id = 6;
7210 const auto num_devices = 2;
7211
7212 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
7213
7214 // Prepare multiple fake connected devices in a group
7215 auto* group = PrepareSingleTestDeviceGroup(
7216 leaudio_group_id, context_type, num_devices,
7217 kContextTypeConversational | kContextTypeMedia);
7218 ASSERT_EQ(group->Size(), num_devices);
7219
7220 PrepareConfigureCodecHandler(group, 0, true);
7221 PrepareConfigureQosHandler(group);
7222 PrepareEnableHandler(group);
7223 PrepareDisableHandler(group);
7224 PrepareReleaseHandler(group);
7225 PrepareReceiverStartReadyHandler(group);
7226
7227 InjectInitialIdleNotification(group);
7228
7229 auto* leAudioDevice = group->GetFirstDevice();
7230 auto expected_devices_written = 0;
7231 while (leAudioDevice) {
7232 /* Three Writes:
7233 * 1. Codec configure
7234 * 2: Codec QoS
7235 * 3: Enabling
7236 */
7237 EXPECT_CALL(gatt_queue,
7238 WriteCharacteristic(leAudioDevice->conn_id_,
7239 leAudioDevice->ctp_hdls_.val_hdl, _,
7240 GATT_WRITE_NO_RSP, _, _))
7241 .Times(4);
7242 expected_devices_written++;
7243 leAudioDevice = group->GetNextDevice(leAudioDevice);
7244 }
7245 ASSERT_EQ(expected_devices_written, num_devices);
7246
7247 // Validate GroupStreamStatus
7248 EXPECT_CALL(mock_callbacks_,
7249 StatusReportCb(
7250 leaudio_group_id,
7251 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER));
7252
7253 // Start the configuration and stream Media content
7254 group->SetPendingConfiguration();
7255 LeAudioGroupStateMachine::Get()->ConfigureStream(
7256 group, context_type,
7257 {.sink = types::AudioContexts(context_type),
7258 .source = types::AudioContexts(context_type)});
7259
7260 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
7261
7262 group->ClearPendingConfiguration();
7263 // Validate GroupStreamStatus
7264 EXPECT_CALL(
7265 mock_callbacks_,
7266 StatusReportCb(leaudio_group_id,
7267 bluetooth::le_audio::GroupStreamStatus::STREAMING));
7268
7269 context_type = kContextTypeMedia;
7270 // Start the configuration and stream Media content
7271 LeAudioGroupStateMachine::Get()->StartStream(
7272 group, context_type,
7273 {.sink = types::AudioContexts(context_type),
7274 .source = types::AudioContexts(context_type)});
7275
7276 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
7277 }
7278
TEST_F(StateMachineTest,StreamStartWithSameContextFromConfiguredStateButNewMetadata)7279 TEST_F(StateMachineTest,
7280 StreamStartWithSameContextFromConfiguredStateButNewMetadata) {
7281 auto context_type = kContextTypeConversational;
7282 const auto leaudio_group_id = 6;
7283 const auto num_devices = 2;
7284
7285 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
7286
7287 // Prepare multiple fake connected devices in a group
7288 auto* group = PrepareSingleTestDeviceGroup(
7289 leaudio_group_id, context_type, num_devices,
7290 kContextTypeConversational | kContextTypeLive);
7291 ASSERT_EQ(group->Size(), num_devices);
7292
7293 PrepareConfigureCodecHandler(group, 0, true);
7294 PrepareConfigureQosHandler(group);
7295 PrepareEnableHandler(group);
7296 PrepareDisableHandler(group);
7297 PrepareReleaseHandler(group);
7298 PrepareReceiverStartReadyHandler(group);
7299
7300 InjectInitialIdleNotification(group);
7301
7302 auto* leAudioDevice = group->GetFirstDevice();
7303 LeAudioDevice* firstActiveDevice = leAudioDevice;
7304 auto expected_devices_written = 0;
7305 while (leAudioDevice) {
7306 /* Three Writes:
7307 * 1. Codec configure
7308 * 2: Codec QoS
7309 * 3: Enabling
7310 */
7311 EXPECT_CALL(gatt_queue,
7312 WriteCharacteristic(leAudioDevice->conn_id_,
7313 leAudioDevice->ctp_hdls_.val_hdl, _,
7314 GATT_WRITE_NO_RSP, _, _))
7315 .Times(4);
7316 expected_devices_written++;
7317 leAudioDevice = group->GetNextDevice(leAudioDevice);
7318 }
7319 ASSERT_EQ(expected_devices_written, num_devices);
7320
7321 // Validate GroupStreamStatus
7322 EXPECT_CALL(mock_callbacks_,
7323 StatusReportCb(
7324 leaudio_group_id,
7325 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER));
7326
7327 // Start the configuration and stream Media content
7328 group->SetPendingConfiguration();
7329 LeAudioGroupStateMachine::Get()->ConfigureStream(
7330 group, context_type,
7331 {.sink = types::AudioContexts(context_type),
7332 .source = types::AudioContexts(context_type)});
7333
7334 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
7335
7336 group->ClearPendingConfiguration();
7337 // Validate GroupStreamStatus
7338 EXPECT_CALL(
7339 mock_callbacks_,
7340 StatusReportCb(leaudio_group_id,
7341 bluetooth::le_audio::GroupStreamStatus::STREAMING));
7342
7343 auto metadata_context_type = kContextTypeLive;
7344 types::BidirectionalPair<std::vector<uint8_t>> ccid_lists = {
7345 .sink = {media_ccid}, .source = {media_ccid}};
7346
7347 // Start the configuration and stream Media content
7348 LeAudioGroupStateMachine::Get()->StartStream(
7349 group, context_type,
7350 {.sink = types::AudioContexts(metadata_context_type),
7351 .source = types::AudioContexts(metadata_context_type)},
7352 ccid_lists);
7353
7354 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
7355
7356 // Verify that the joining device receives the right CCID list
7357 auto lastMeta = firstActiveDevice->GetFirstActiveAse()->metadata;
7358 bool parsedOk = false;
7359 auto ltv = bluetooth::le_audio::types::LeAudioLtvMap::Parse(
7360 lastMeta.data(), lastMeta.size(), parsedOk);
7361 ASSERT_TRUE(parsedOk);
7362
7363 auto ccids =
7364 ltv.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeCcidList);
7365 ASSERT_TRUE(ccids.has_value());
7366 ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
7367 }
7368
TEST_F(StateMachineTest,testAttachDeviceToTheStreamCisFailure)7369 TEST_F(StateMachineTest, testAttachDeviceToTheStreamCisFailure) {
7370 const auto context_type = kContextTypeMedia;
7371 const auto leaudio_group_id = 6;
7372 const auto num_devices = 2;
7373
7374 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
7375
7376 // Prepare multiple fake connected devices in a group
7377 auto* group =
7378 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
7379 ASSERT_EQ(group->Size(), num_devices);
7380
7381 PrepareConfigureCodecHandler(group);
7382 PrepareConfigureQosHandler(group);
7383 PrepareEnableHandler(group);
7384 PrepareDisableHandler(group);
7385 PrepareReleaseHandler(group);
7386
7387 auto* leAudioDevice = group->GetFirstDevice();
7388 LeAudioDevice* lastDevice;
7389 LeAudioDevice* fistDevice = leAudioDevice;
7390
7391 auto expected_devices_written = 0;
7392 while (leAudioDevice) {
7393 /* Three Writes:
7394 * 1: Codec Config
7395 * 2: Codec QoS
7396 * 3: Enabling
7397 */
7398 lastDevice = leAudioDevice;
7399 EXPECT_CALL(gatt_queue,
7400 WriteCharacteristic(leAudioDevice->conn_id_,
7401 leAudioDevice->ctp_hdls_.val_hdl, _,
7402 GATT_WRITE_NO_RSP, _, _))
7403 .Times(AtLeast(3));
7404 expected_devices_written++;
7405 leAudioDevice = group->GetNextDevice(leAudioDevice);
7406 }
7407 ASSERT_EQ(expected_devices_written, num_devices);
7408
7409 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
7410 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
7411 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
7412
7413 InjectInitialIdleNotification(group);
7414
7415 // Start the configuration and stream Media content
7416 LeAudioGroupStateMachine::Get()->StartStream(
7417 group, context_type,
7418 {.sink = types::AudioContexts(context_type),
7419 .source = types::AudioContexts(context_type)});
7420
7421 // Check if group has transitioned to a proper state
7422 ASSERT_EQ(group->GetState(),
7423 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7424 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7425
7426 // Inject CIS and ACL disconnection of first device
7427 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
7428 InjectAclDisconnected(group, lastDevice);
7429
7430 // Check if group keeps streaming
7431 ASSERT_EQ(group->GetState(),
7432 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7433
7434 lastDevice->conn_id_ = 3;
7435 lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);
7436
7437 // Make sure ASE with disconnected CIS are not left in STREAMING
7438 ASSERT_EQ(lastDevice->GetFirstAseWithState(
7439 ::bluetooth::le_audio::types::kLeAudioDirectionSink,
7440 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
7441 nullptr);
7442 ASSERT_EQ(lastDevice->GetFirstAseWithState(
7443 ::bluetooth::le_audio::types::kLeAudioDirectionSource,
7444 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
7445 nullptr);
7446
7447 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
7448 lastDevice->ctp_hdls_.val_hdl, _,
7449 GATT_WRITE_NO_RSP, _, _))
7450 .Times(AtLeast(3));
7451
7452 do_not_send_cis_establish_event_ = true;
7453
7454 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
7455 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
7456 LeAudioGroupStateMachine::Get()->AttachToStream(
7457 group, lastDevice, {.sink = {media_ccid}, .source = {}});
7458
7459 // Check if group keeps streaming
7460 ASSERT_EQ(group->GetState(),
7461 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7462
7463 // Verify that the joining device receives the right CCID list
7464 auto lastMeta = lastDevice->GetFirstActiveAse()->metadata;
7465 bool parsedOk = false;
7466 auto ltv = bluetooth::le_audio::types::LeAudioLtvMap::Parse(
7467 lastMeta.data(), lastMeta.size(), parsedOk);
7468 ASSERT_TRUE(parsedOk);
7469
7470 auto ccids =
7471 ltv.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeCcidList);
7472 ASSERT_TRUE(ccids.has_value());
7473 ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
7474
7475 /* Verify that ASE of first device are still good*/
7476 auto ase = fistDevice->GetFirstActiveAse();
7477 ASSERT_NE(ase->qos_config.max_transport_latency, 0);
7478 ASSERT_NE(ase->qos_config.retrans_nb, 0);
7479 }
7480
TEST_F(StateMachineTest,testAttachDeviceWhileSecondDeviceDisconnects)7481 TEST_F(StateMachineTest, testAttachDeviceWhileSecondDeviceDisconnects) {
7482 const auto context_type = kContextTypeMedia;
7483 const auto leaudio_group_id = 6;
7484 const auto num_devices = 2;
7485
7486 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
7487
7488 // Prepare multiple fake connected devices in a group
7489 auto* group =
7490 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
7491 ASSERT_EQ(group->Size(), num_devices);
7492
7493 PrepareConfigureCodecHandler(group);
7494 PrepareConfigureQosHandler(group);
7495 PrepareEnableHandler(group);
7496 PrepareDisableHandler(group);
7497 PrepareReleaseHandler(group);
7498
7499 auto* leAudioDevice = group->GetFirstDevice();
7500 LeAudioDevice* lastDevice;
7501 LeAudioDevice* firstDevice = leAudioDevice;
7502
7503 auto expected_devices_written = 0;
7504 while (leAudioDevice) {
7505 /* Three Writes:
7506 * 1: Codec Config
7507 * 2: Codec QoS
7508 * 3: Enable
7509 */
7510 lastDevice = leAudioDevice;
7511 EXPECT_CALL(gatt_queue,
7512 WriteCharacteristic(leAudioDevice->conn_id_,
7513 leAudioDevice->ctp_hdls_.val_hdl, _,
7514 GATT_WRITE_NO_RSP, _, _))
7515 .Times(AtLeast(3));
7516 expected_devices_written++;
7517 leAudioDevice = group->GetNextDevice(leAudioDevice);
7518 }
7519 ASSERT_EQ(expected_devices_written, num_devices);
7520
7521 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
7522 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
7523 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
7524
7525 InjectInitialIdleNotification(group);
7526
7527 // Start the configuration and stream Media content
7528 LeAudioGroupStateMachine::Get()->StartStream(
7529 group, context_type,
7530 {.sink = types::AudioContexts(context_type),
7531 .source = types::AudioContexts(context_type)});
7532
7533 // Check if group has transitioned to a proper state
7534 ASSERT_EQ(group->GetState(),
7535 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7536 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7537
7538 // Inject CIS and ACL disconnection of first device
7539 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
7540 InjectAclDisconnected(group, lastDevice);
7541
7542 log::info(" Device B - Disconnected ");
7543
7544 // Check if group keeps streaming
7545 ASSERT_EQ(group->GetState(),
7546 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7547
7548 // Set second device is connected now.
7549 lastDevice->conn_id_ = 3;
7550 lastDevice->SetConnectionState(DeviceConnectState::CONNECTED);
7551
7552 // Make sure ASE with disconnected CIS are not left in STREAMING
7553 ASSERT_EQ(lastDevice->GetFirstAseWithState(
7554 ::bluetooth::le_audio::types::kLeAudioDirectionSink,
7555 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
7556 nullptr);
7557 ASSERT_EQ(lastDevice->GetFirstAseWithState(
7558 ::bluetooth::le_audio::types::kLeAudioDirectionSource,
7559 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
7560 nullptr);
7561
7562 // Expect just Codec Configure on ASCS Control Point
7563 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
7564 lastDevice->ctp_hdls_.val_hdl, _,
7565 GATT_WRITE_NO_RSP, _, _))
7566 .Times(AtLeast(1));
7567
7568 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
7569 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
7570
7571 // Remove Configuration incjection but cache configuration for future
7572 // injection
7573 PrepareConfigureCodecHandler(group, 0, true, false);
7574
7575 log::info("Device B - Attaching to the stream");
7576
7577 LeAudioGroupStateMachine::Get()->AttachToStream(
7578 group, lastDevice, {.sink = {media_ccid}, .source = {}});
7579
7580 // Check if group keeps streaming
7581 ASSERT_EQ(group->GetState(),
7582 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7583
7584 /* Verify that ASE of first device are still good*/
7585 auto ase = firstDevice->GetFirstActiveAse();
7586 ASSERT_NE(ase->qos_config.max_transport_latency, 0);
7587 ASSERT_NE(ase->qos_config.retrans_nb, 0);
7588
7589 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7590 testing::Mock::VerifyAndClearExpectations(&gatt_queue);
7591
7592 log::info(
7593 "Device A is disconnecting while Device B is attaching to the stream");
7594
7595 InjectCisDisconnected(group, firstDevice, HCI_ERR_CONNECTION_TOUT);
7596 InjectReleasingAndIdleState(group, firstDevice);
7597
7598 // Check if group keeps streaming
7599 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
7600 ASSERT_EQ(group->GetTargetState(),
7601 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7602
7603 ASSERT_EQ(group->cig.GetState(), types::CigState::CREATED);
7604
7605 log::info("Device B continues configuration and streaming");
7606
7607 // Expect QoS config and Enable on ASCS Control Point
7608 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
7609 lastDevice->ctp_hdls_.val_hdl, _,
7610 GATT_WRITE_NO_RSP, _, _))
7611 .Times(AtLeast(2));
7612
7613 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
7614 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
7615
7616 InjectCachedConfiguratuibForActiveAses(group, lastDevice);
7617
7618 // Check if group keeps streaming
7619 ASSERT_EQ(group->GetState(),
7620 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7621
7622 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7623 testing::Mock::VerifyAndClearExpectations(&gatt_queue);
7624 }
7625
TEST_F(StateMachineTest,testAclDropWithoutApriorCisDisconnection)7626 TEST_F(StateMachineTest, testAclDropWithoutApriorCisDisconnection) {
7627 const auto context_type = kContextTypeMedia;
7628 const auto leaudio_group_id = 6;
7629 const auto num_devices = 2;
7630
7631 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
7632
7633 // Prepare multiple fake connected devices in a group
7634 auto* group =
7635 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
7636 ASSERT_EQ(group->Size(), num_devices);
7637
7638 PrepareConfigureCodecHandler(group);
7639 PrepareConfigureQosHandler(group);
7640 PrepareEnableHandler(group);
7641 PrepareDisableHandler(group);
7642 PrepareReleaseHandler(group);
7643
7644 auto* leAudioDevice = group->GetFirstDevice();
7645 LeAudioDevice* firstDevice = leAudioDevice;
7646 LeAudioDevice* lastDevice = leAudioDevice;
7647
7648 auto expected_devices_written = 0;
7649 while (leAudioDevice) {
7650 /* Three Writes:
7651 * 1: Codec Config
7652 * 2: Codec QoS
7653 * 3: Enabling
7654 */
7655 lastDevice = leAudioDevice;
7656 EXPECT_CALL(gatt_queue,
7657 WriteCharacteristic(leAudioDevice->conn_id_,
7658 leAudioDevice->ctp_hdls_.val_hdl, _,
7659 GATT_WRITE_NO_RSP, _, _))
7660 .Times(AtLeast(3));
7661 expected_devices_written++;
7662 leAudioDevice = group->GetNextDevice(leAudioDevice);
7663 }
7664 ASSERT_EQ(expected_devices_written, num_devices);
7665
7666 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
7667 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
7668 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
7669
7670 InjectInitialIdleNotification(group);
7671
7672 // Start the configuration and stream Media content
7673 LeAudioGroupStateMachine::Get()->StartStream(
7674 group, context_type,
7675 {.sink = types::AudioContexts(context_type),
7676 .source = types::AudioContexts(context_type)});
7677
7678 // Check if group has transitioned to a proper state
7679 ASSERT_EQ(group->GetState(),
7680 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7681 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7682
7683 /* Separate CIS for dual CIS device is treated as sink device */
7684 ASSERT_EQ(group->stream_conf.stream_params.sink.num_of_devices, 2);
7685 ASSERT_EQ(group->stream_conf.stream_params.sink.num_of_channels, 2);
7686
7687 // Inject CIS and ACL disconnection of first device
7688 InjectAclDisconnected(group, firstDevice);
7689
7690 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
7691 InjectAclDisconnected(group, lastDevice);
7692
7693 ASSERT_EQ(group->stream_conf.stream_params.sink.num_of_devices, 0);
7694 ASSERT_EQ(group->stream_conf.stream_params.sink.num_of_channels, 0);
7695 }
7696
TEST_F(StateMachineTest,testAutonomousDisableTimeout)7697 TEST_F(StateMachineTest, testAutonomousDisableTimeout) {
7698 const auto context_type = kContextTypeConversational;
7699 const auto leaudio_group_id = 6;
7700 const auto num_devices = 2;
7701
7702 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
7703
7704 // Prepare multiple fake connected devices in a group
7705 auto* group =
7706 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
7707 ASSERT_EQ(group->Size(), num_devices);
7708
7709 PrepareConfigureCodecHandler(group);
7710 PrepareConfigureQosHandler(group);
7711 PrepareEnableHandler(group);
7712 PrepareDisableHandler(group);
7713 PrepareReleaseHandler(group);
7714 PrepareReceiverStartReadyHandler(group);
7715
7716 auto* leAudioDevice = group->GetFirstDevice();
7717 LeAudioDevice* lastDevice;
7718 // LeAudioDevice* fistDevice = leAudioDevice;
7719
7720 auto expected_devices_written = 0;
7721 while (leAudioDevice) {
7722 /* Three Writes:
7723 * 1: Codec Config
7724 * 2: Codec QoS
7725 * 3: Enabling
7726 */
7727 lastDevice = leAudioDevice;
7728 EXPECT_CALL(gatt_queue,
7729 WriteCharacteristic(leAudioDevice->conn_id_,
7730 leAudioDevice->ctp_hdls_.val_hdl, _,
7731 GATT_WRITE_NO_RSP, _, _))
7732 .Times(AtLeast(3));
7733 expected_devices_written++;
7734 leAudioDevice = group->GetNextDevice(leAudioDevice);
7735 }
7736 ASSERT_EQ(expected_devices_written, num_devices);
7737
7738 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
7739 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
7740 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4);
7741
7742 InjectInitialIdleNotification(group);
7743
7744 // Start the configuration and stream Conversational content
7745 LeAudioGroupStateMachine::Get()->StartStream(
7746 group, context_type,
7747 {.sink = types::AudioContexts(context_type),
7748 .source = types::AudioContexts(context_type)});
7749
7750 /* First timer started for transition to streaming state */
7751 ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));
7752
7753 // Check if group has transitioned to a proper state
7754 ASSERT_EQ(group->GetState(),
7755 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7756
7757 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7758
7759 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1);
7760
7761 /* First timer finished when group achieves streaming state */
7762 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
7763
7764 /* Remote initiates autonomous Disable operation */
7765 auto ase = lastDevice->GetFirstActiveAseByDirection(
7766 ::bluetooth::le_audio::types::kLeAudioDirectionSink);
7767
7768 InjectAseStateNotification(ase, lastDevice, group,
7769 ascs::kAseStateQoSConfigured,
7770 &cached_qos_configuration_map_[ase->id]);
7771
7772 /* Second timer started for autonomous transition to disabled state */
7773 ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop"));
7774
7775 // Inject CIS disconnection of first device
7776 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
7777
7778 // Check if timeout is fired
7779 EXPECT_CALL(mock_callbacks_,
7780 OnDeviceAutonomousStateTransitionTimeout(lastDevice));
7781
7782 fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
7783 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7784 }
7785
TEST_F(StateMachineTest,testAutonomousDisableSuccess)7786 TEST_F(StateMachineTest, testAutonomousDisableSuccess) {
7787 const auto context_type = kContextTypeConversational;
7788 const auto leaudio_group_id = 6;
7789 const auto num_devices = 2;
7790
7791 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
7792
7793 // Prepare multiple fake connected devices in a group
7794 auto* group =
7795 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
7796 ASSERT_EQ(group->Size(), num_devices);
7797
7798 PrepareConfigureCodecHandler(group);
7799 PrepareConfigureQosHandler(group);
7800 PrepareEnableHandler(group);
7801 PrepareDisableHandler(group);
7802 PrepareReleaseHandler(group);
7803 PrepareReceiverStartReadyHandler(group);
7804
7805 auto* leAudioDevice = group->GetFirstDevice();
7806 LeAudioDevice* lastDevice;
7807
7808 auto expected_devices_written = 0;
7809 while (leAudioDevice) {
7810 /* Three Writes:
7811 * 1: Codec Config
7812 * 2: Codec QoS
7813 * 3: Enabling
7814 */
7815 lastDevice = leAudioDevice;
7816 EXPECT_CALL(gatt_queue,
7817 WriteCharacteristic(leAudioDevice->conn_id_,
7818 leAudioDevice->ctp_hdls_.val_hdl, _,
7819 GATT_WRITE_NO_RSP, _, _))
7820 .Times(AtLeast(3));
7821 expected_devices_written++;
7822 leAudioDevice = group->GetNextDevice(leAudioDevice);
7823 }
7824 ASSERT_EQ(expected_devices_written, num_devices);
7825
7826 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
7827 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
7828 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4);
7829
7830 InjectInitialIdleNotification(group);
7831
7832 // Start the configuration and stream Conversational content
7833 LeAudioGroupStateMachine::Get()->StartStream(
7834 group, context_type,
7835 {.sink = types::AudioContexts(context_type),
7836 .source = types::AudioContexts(context_type)});
7837
7838 /* First timer started for transition to streaming state */
7839 ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));
7840
7841 // Check if group has transitioned to a proper state
7842 ASSERT_EQ(group->GetState(),
7843 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7844
7845 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7846
7847 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1);
7848
7849 /* Remote initiates autonomous Disable operation */
7850 auto ase_sink = lastDevice->GetFirstActiveAseByDirection(
7851 ::bluetooth::le_audio::types::kLeAudioDirectionSink);
7852
7853 InjectAseStateNotification(ase_sink, lastDevice, group,
7854 ascs::kAseStateQoSConfigured,
7855 &cached_qos_configuration_map_[ase_sink->id]);
7856
7857 /* Check if autonomous operation timer is not canceled */
7858 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
7859 /* Second timer started for autonomous transition to disabled state */
7860 ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop"));
7861
7862 auto ase_source = lastDevice->GetFirstActiveAseByDirection(
7863 ::bluetooth::le_audio::types::kLeAudioDirectionSource);
7864
7865 client_parser::ascs::ase_transient_state_params disabling_params = {
7866 .metadata = {}};
7867 InjectAseStateNotification(ase_source, lastDevice, group,
7868 ascs::kAseStateDisabling, &disabling_params);
7869 InjectAseStateNotification(ase_source, lastDevice, group,
7870 ascs::kAseStateQoSConfigured,
7871 &cached_qos_configuration_map_[ase_source->id]);
7872
7873 /* Inject CIS disconnection of first device, disconenct only first CIS because
7874 * while processing first disconnection test will try to bring up this ASEs
7875 * to STREAMING state and connect CISes again.
7876 */
7877 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT, true);
7878 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7879
7880 /* Check if autonomous operation timer is freed */
7881 ASSERT_EQ(1, get_func_call_count("alarm_free"));
7882 }
7883
TEST_F(StateMachineTest,testAutonomousDisableCancelOnDisconnect)7884 TEST_F(StateMachineTest, testAutonomousDisableCancelOnDisconnect) {
7885 const auto context_type = kContextTypeConversational;
7886 const auto leaudio_group_id = 6;
7887 const auto num_devices = 2;
7888
7889 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
7890
7891 // Prepare multiple fake connected devices in a group
7892 auto* group =
7893 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
7894 ASSERT_EQ(group->Size(), num_devices);
7895
7896 PrepareConfigureCodecHandler(group);
7897 PrepareConfigureQosHandler(group);
7898 PrepareEnableHandler(group);
7899 PrepareDisableHandler(group);
7900 PrepareReleaseHandler(group);
7901 PrepareReceiverStartReadyHandler(group);
7902
7903 auto* leAudioDevice = group->GetFirstDevice();
7904 LeAudioDevice* lastDevice;
7905
7906 auto expected_devices_written = 0;
7907 while (leAudioDevice) {
7908 /* Three Writes:
7909 * 1: Codec Config
7910 * 2: Codec QoS
7911 * 3: Enabling
7912 */
7913 lastDevice = leAudioDevice;
7914 EXPECT_CALL(gatt_queue,
7915 WriteCharacteristic(leAudioDevice->conn_id_,
7916 leAudioDevice->ctp_hdls_.val_hdl, _,
7917 GATT_WRITE_NO_RSP, _, _))
7918 .Times(AtLeast(3));
7919 expected_devices_written++;
7920 leAudioDevice = group->GetNextDevice(leAudioDevice);
7921 }
7922 ASSERT_EQ(expected_devices_written, num_devices);
7923
7924 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
7925 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
7926 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4);
7927
7928 InjectInitialIdleNotification(group);
7929
7930 // Start the configuration and stream Conversational content
7931 LeAudioGroupStateMachine::Get()->StartStream(
7932 group, context_type,
7933 {.sink = types::AudioContexts(context_type),
7934 .source = types::AudioContexts(context_type)});
7935
7936 /* First timer started for transition to streaming state */
7937 ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));
7938
7939 // Check if group has transitioned to a proper state
7940 ASSERT_EQ(group->GetState(),
7941 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
7942 testing::Mock::VerifyAndClearExpectations(mock_iso_manager_);
7943
7944 /* First timer finished when group achieves streaming state */
7945 ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
7946
7947 /* Remote initiates autonomous Disable operation */
7948 auto ase = lastDevice->GetFirstActiveAseByDirection(
7949 ::bluetooth::le_audio::types::kLeAudioDirectionSink);
7950
7951 InjectAseStateNotification(ase, lastDevice, group,
7952 ascs::kAseStateQoSConfigured,
7953 &cached_qos_configuration_map_[ase->id]);
7954
7955 /* Second timer started for autonomous transition to disabled state */
7956 ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop"));
7957
7958 // Inject ACL disconnection of first device
7959 InjectAclDisconnected(group, lastDevice);
7960
7961 /* Check if autonomous operation timer is freed on ASEs deactivation */
7962 ASSERT_EQ(2, get_func_call_count("alarm_free"));
7963 }
7964
7965 } // namespace internal
7966 } // namespace bluetooth::le_audio
7967