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