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