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 <gmock/gmock.h>
21 #include <gtest/gtest.h>
22
23 #include <functional>
24
25 #include "bta/le_audio/content_control_id_keeper.h"
26 #include "bta_gatt_api_mock.h"
27 #include "bta_gatt_queue_mock.h"
28 #include "btm_api_mock.h"
29 #include "client_parser.h"
30 #include "fake_osi.h"
31 #include "gd/common/init_flags.h"
32 #include "le_audio_set_configuration_provider.h"
33 #include "mock_codec_manager.h"
34 #include "mock_controller.h"
35 #include "mock_csis_client.h"
36 #include "mock_iso_manager.h"
37 #include "types/bt_transport.h"
38
39 using ::le_audio::DeviceConnectState;
40 using ::le_audio::codec_spec_caps::kLeAudioCodecLC3ChannelCountSingleChannel;
41 using ::le_audio::codec_spec_caps::kLeAudioCodecLC3ChannelCountTwoChannel;
42 using ::le_audio::types::LeAudioContextType;
43 using ::testing::_;
44 using ::testing::AnyNumber;
45 using ::testing::AtLeast;
46 using ::testing::DoAll;
47 using ::testing::Invoke;
48 using ::testing::NiceMock;
49 using ::testing::Return;
50 using ::testing::SaveArg;
51 using ::testing::Test;
52
53 std::map<std::string, int> mock_function_count_map;
54 extern struct fake_osi_alarm_set_on_mloop fake_osi_alarm_set_on_mloop_;
55
56 void osi_property_set_bool(const char* key, bool value);
57 static const char* test_flags[] = {
58 "INIT_logging_debug_enabled_for_all=true",
59 nullptr,
60 };
61
62 constexpr uint8_t media_ccid = 0xC0;
63 constexpr auto media_context =
64 static_cast<std::underlying_type<LeAudioContextType>::type>(
65 LeAudioContextType::MEDIA);
66
67 constexpr uint8_t call_ccid = 0xD0;
68 constexpr auto call_context =
69 static_cast<std::underlying_type<LeAudioContextType>::type>(
70 LeAudioContextType::CONVERSATIONAL);
71
72 namespace le_audio {
73 namespace internal {
74
75 // Just some arbitrary initial handles - it has no real meaning
76 #define ATTR_HANDLE_ASCS_POOL_START (0x0000 | 32)
77 #define ATTR_HANDLE_PACS_POOL_START (0xFF00 | 64)
78
79 constexpr LeAudioContextType kContextTypeUnspecified =
80 static_cast<LeAudioContextType>(0x0001);
81 constexpr LeAudioContextType kContextTypeConversational =
82 static_cast<LeAudioContextType>(0x0002);
83 constexpr LeAudioContextType kContextTypeMedia =
84 static_cast<LeAudioContextType>(0x0004);
85 constexpr LeAudioContextType kContextTypeSoundEffects =
86 static_cast<LeAudioContextType>(0x0080);
87 constexpr LeAudioContextType kContextTypeRingtone =
88 static_cast<LeAudioContextType>(0x0200);
89
90 namespace codec_specific {
91
92 constexpr uint8_t kLc3CodingFormat = 0x06;
93
94 // Reference Codec Capabilities values to test against
95 constexpr uint8_t kCapTypeSupportedSamplingFrequencies = 0x01;
96 constexpr uint8_t kCapTypeSupportedFrameDurations = 0x02;
97 constexpr uint8_t kCapTypeAudioChannelCount = 0x03;
98 constexpr uint8_t kCapTypeSupportedOctetsPerCodecFrame = 0x04;
99 // constexpr uint8_t kCapTypeSupportedLc3CodecFramesPerSdu = 0x05;
100
101 // constexpr uint8_t kCapSamplingFrequency8000Hz = 0x0001;
102 // constexpr uint8_t kCapSamplingFrequency11025Hz = 0x0002;
103 constexpr uint8_t kCapSamplingFrequency16000Hz = 0x0004;
104 // constexpr uint8_t kCapSamplingFrequency22050Hz = 0x0008;
105 // constexpr uint8_t kCapSamplingFrequency24000Hz = 0x0010;
106 constexpr uint8_t kCapSamplingFrequency32000Hz = 0x0020;
107 // constexpr uint8_t kCapSamplingFrequency44100Hz = 0x0040;
108 constexpr uint8_t kCapSamplingFrequency48000Hz = 0x0080;
109 // constexpr uint8_t kCapSamplingFrequency88200Hz = 0x0100;
110 // constexpr uint8_t kCapSamplingFrequency96000Hz = 0x0200;
111 // constexpr uint8_t kCapSamplingFrequency176400Hz = 0x0400;
112 // constexpr uint8_t kCapSamplingFrequency192000Hz = 0x0800;
113 // constexpr uint8_t kCapSamplingFrequency384000Hz = 0x1000;
114
115 constexpr uint8_t kCapFrameDuration7p5ms = 0x01;
116 constexpr uint8_t kCapFrameDuration10ms = 0x02;
117 // constexpr uint8_t kCapFrameDuration7p5msPreferred = 0x10;
118 constexpr uint8_t kCapFrameDuration10msPreferred = 0x20;
119 } // namespace codec_specific
120
121 namespace ascs {
122 constexpr uint8_t kAseStateIdle = 0x00;
123 constexpr uint8_t kAseStateCodecConfigured = 0x01;
124 constexpr uint8_t kAseStateQoSConfigured = 0x02;
125 constexpr uint8_t kAseStateEnabling = 0x03;
126 constexpr uint8_t kAseStateStreaming = 0x04;
127 constexpr uint8_t kAseStateDisabling = 0x05;
128 constexpr uint8_t kAseStateReleasing = 0x06;
129
130 // constexpr uint8_t kAseParamDirectionServerIsAudioSink = 0x01;
131 // constexpr uint8_t kAseParamDirectionServerIsAudioSource = 0x02;
132
133 constexpr uint8_t kAseParamFramingUnframedSupported = 0x00;
134 // constexpr uint8_t kAseParamFramingUnframedNotSupported = 0x01;
135
136 // constexpr uint8_t kAseParamPreferredPhy1M = 0x01;
137 // constexpr uint8_t kAseParamPreferredPhy2M = 0x02;
138 // constexpr uint8_t kAseParamPreferredPhyCoded = 0x04;
139
140 constexpr uint8_t kAseCtpOpcodeConfigureCodec = 0x01;
141 constexpr uint8_t kAseCtpOpcodeConfigureQos = 0x02;
142 constexpr uint8_t kAseCtpOpcodeEnable = 0x03;
143 constexpr uint8_t kAseCtpOpcodeReceiverStartReady = 0x04;
144 constexpr uint8_t kAseCtpOpcodeDisable = 0x05;
145 constexpr uint8_t kAseCtpOpcodeReceiverStopReady = 0x06;
146 // constexpr uint8_t kAseCtpOpcodeUpdateMetadata = 0x07;
147 constexpr uint8_t kAseCtpOpcodeRelease = 0x08;
148 constexpr uint8_t kAseCtpOpcodeMaxVal = kAseCtpOpcodeRelease;
149
150 } // namespace ascs
151
GetTestAddress(uint8_t index)152 static RawAddress GetTestAddress(uint8_t index) {
153 return {{0xC0, 0xDE, 0xC0, 0xDE, 0x00, index}};
154 }
155
156 class MockLeAudioGroupStateMachineCallbacks
157 : public LeAudioGroupStateMachine::Callbacks {
158 public:
159 MockLeAudioGroupStateMachineCallbacks() = default;
160 MockLeAudioGroupStateMachineCallbacks(
161 const MockLeAudioGroupStateMachineCallbacks&) = delete;
162 MockLeAudioGroupStateMachineCallbacks& operator=(
163 const MockLeAudioGroupStateMachineCallbacks&) = delete;
164
165 ~MockLeAudioGroupStateMachineCallbacks() override = default;
166 MOCK_METHOD((void), StatusReportCb,
167 (int group_id, bluetooth::le_audio::GroupStreamStatus status),
168 (override));
169 MOCK_METHOD((void), OnStateTransitionTimeout, (int group_id), (override));
170 };
171
172 class StateMachineTest : public Test {
173 protected:
174 uint8_t ase_id_last_assigned = types::ase::kAseIdInvalid;
175 uint8_t additional_snk_ases = 0;
176 uint8_t additional_src_ases = 0;
177 uint8_t channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel;
178 uint16_t sample_freq_ = codec_specific::kCapSamplingFrequency16000Hz;
179
SetUp()180 void SetUp() override {
181 bluetooth::common::InitFlags::Load(test_flags);
182 mock_function_count_map.clear();
183 controller::SetMockControllerInterface(&mock_controller_);
184 bluetooth::manager::SetMockBtmInterface(&btm_interface);
185 gatt::SetMockBtaGattInterface(&gatt_interface);
186 gatt::SetMockBtaGattQueue(&gatt_queue);
187
188 ::le_audio::AudioSetConfigurationProvider::Initialize();
189 LeAudioGroupStateMachine::Initialize(&mock_callbacks_);
190
191 ContentControlIdKeeper::GetInstance()->Start();
192
193 MockCsisClient::SetMockInstanceForTesting(&mock_csis_client_module_);
194 ON_CALL(mock_csis_client_module_, Get())
195 .WillByDefault(Return(&mock_csis_client_module_));
196 ON_CALL(mock_csis_client_module_, IsCsisClientRunning())
197 .WillByDefault(Return(true));
198 ON_CALL(mock_csis_client_module_, GetDeviceList(_))
199 .WillByDefault(Invoke([this](int group_id) { return addresses_; }));
200 ON_CALL(mock_csis_client_module_, GetDesiredSize(_))
201 .WillByDefault(
202 Invoke([this](int group_id) { return (int)(addresses_.size()); }));
203
204 // Support 2M Phy
205 ON_CALL(mock_controller_, SupportsBle2mPhy()).WillByDefault(Return(true));
206 ON_CALL(btm_interface, IsPhy2mSupported(_, _)).WillByDefault(Return(true));
207 ON_CALL(btm_interface, GetHCIConnHandle(_, _))
208 .WillByDefault(
209 Invoke([](RawAddress const& remote_bda, tBT_TRANSPORT transport) {
210 return remote_bda.IsEmpty()
211 ? HCI_INVALID_HANDLE
212 : ((uint16_t)(remote_bda.address[0] ^
213 remote_bda.address[1] ^
214 remote_bda.address[2]))
215 << 8 |
216 (remote_bda.address[3] ^ remote_bda.address[4] ^
217 remote_bda.address[5]);
218 }));
219
220 ON_CALL(gatt_queue, WriteCharacteristic(_, _, _, GATT_WRITE_NO_RSP, _, _))
221 .WillByDefault(Invoke([this](uint16_t conn_id, uint16_t handle,
222 std::vector<uint8_t> value,
223 tGATT_WRITE_TYPE write_type,
224 GATT_WRITE_OP_CB cb, void* cb_data) {
225 for (auto& dev : le_audio_devices_) {
226 if (dev->conn_id_ == conn_id) {
227 // Control point write handler
228 if (dev->ctp_hdls_.val_hdl == handle) {
229 HandleCtpOperation(dev.get(), value, cb, cb_data);
230 }
231 break;
232 }
233 }
234 }));
235
236 ConfigureIsoManagerMock();
237 ConfigCodecManagerMock();
238 }
239
HandleCtpOperation(LeAudioDevice * device,std::vector<uint8_t> value,GATT_WRITE_OP_CB cb,void * cb_data)240 void HandleCtpOperation(LeAudioDevice* device, std::vector<uint8_t> value,
241 GATT_WRITE_OP_CB cb, void* cb_data) {
242 auto opcode = value[0];
243
244 // Verify against valid opcode range
245 ASSERT_LT(opcode, ascs::kAseCtpOpcodeMaxVal + 1);
246 ASSERT_NE(opcode, 0);
247
248 if (ase_ctp_handlers[opcode])
249 ase_ctp_handlers[opcode](device, std::move(value), cb, cb_data);
250 }
251
252 /* Helper function to make a deterministic (and unique on the entire device)
253 * connection handle for a given cis.
254 */
255 #define UNIQUE_CIS_CONN_HANDLE(cig_id, cis_index) (cig_id << 8 | cis_index)
256
ConfigureIsoManagerMock()257 void ConfigureIsoManagerMock() {
258 iso_manager_ = bluetooth::hci::IsoManager::GetInstance();
259 ASSERT_NE(iso_manager_, nullptr);
260 iso_manager_->Start();
261
262 mock_iso_manager_ = MockIsoManager::GetInstance();
263 ASSERT_NE(mock_iso_manager_, nullptr);
264
265 ON_CALL(*mock_iso_manager_, CreateCig)
266 .WillByDefault(
267 [this](uint8_t cig_id,
268 bluetooth::hci::iso_manager::cig_create_params p) {
269 DLOG(INFO) << "CreateCig";
270
271 auto& group = le_audio_device_groups_[cig_id];
272 if (group) {
273 std::vector<uint16_t> conn_handles;
274 // Fake connection ID for each cis in a request
275 for (auto i = 0u; i < p.cis_cfgs.size(); ++i) {
276 conn_handles.push_back(UNIQUE_CIS_CONN_HANDLE(cig_id, i));
277 }
278 auto status = HCI_SUCCESS;
279 if (group_create_command_disallowed_) {
280 group_create_command_disallowed_ = false;
281 status = HCI_ERR_COMMAND_DISALLOWED;
282 }
283
284 LeAudioGroupStateMachine::Get()->ProcessHciNotifOnCigCreate(
285 group.get(), status, cig_id, conn_handles);
286 }
287 });
288
289 ON_CALL(*mock_iso_manager_, RemoveCig)
290 .WillByDefault([this](uint8_t cig_id, bool force) {
291 DLOG(INFO) << "CreateRemove";
292
293 auto& group = le_audio_device_groups_[cig_id];
294 if (group) {
295 // Fake connection ID for each cis in a request
296 LeAudioGroupStateMachine::Get()->ProcessHciNotifOnCigRemove(
297 0, group.get());
298 }
299 });
300
301 ON_CALL(*mock_iso_manager_, SetupIsoDataPath)
302 .WillByDefault([this](uint16_t conn_handle,
303 bluetooth::hci::iso_manager::iso_data_path_params
304 p) {
305 DLOG(INFO) << "SetupIsoDataPath";
306
307 auto dev_it =
308 std::find_if(le_audio_devices_.begin(), le_audio_devices_.end(),
309 [&conn_handle](auto& dev) {
310 auto ases = dev->GetAsesByCisConnHdl(conn_handle);
311 return (ases.sink || ases.source);
312 });
313 if (dev_it == le_audio_devices_.end()) {
314 DLOG(ERROR) << "Device not found";
315 return;
316 }
317
318 for (auto& kv_pair : le_audio_device_groups_) {
319 auto& group = kv_pair.second;
320 if (group->IsDeviceInTheGroup(dev_it->get())) {
321 LeAudioGroupStateMachine::Get()->ProcessHciNotifSetupIsoDataPath(
322 group.get(), dev_it->get(), 0, conn_handle);
323 return;
324 }
325 }
326 });
327
328 ON_CALL(*mock_iso_manager_, RemoveIsoDataPath)
329 .WillByDefault([this](uint16_t conn_handle, uint8_t iso_direction) {
330 DLOG(INFO) << "RemoveIsoDataPath";
331
332 auto dev_it =
333 std::find_if(le_audio_devices_.begin(), le_audio_devices_.end(),
334 [&conn_handle](auto& dev) {
335 auto ases = dev->GetAsesByCisConnHdl(conn_handle);
336 return (ases.sink || ases.source);
337 });
338 if (dev_it == le_audio_devices_.end()) {
339 DLOG(ERROR) << "Device not found";
340 return;
341 }
342
343 for (auto& kv_pair : le_audio_device_groups_) {
344 auto& group = kv_pair.second;
345 if (group->IsDeviceInTheGroup(dev_it->get())) {
346 LeAudioGroupStateMachine::Get()->ProcessHciNotifRemoveIsoDataPath(
347 group.get(), dev_it->get(), 0, conn_handle);
348 return;
349 }
350 }
351 });
352
353 ON_CALL(*mock_iso_manager_, EstablishCis)
354 .WillByDefault([this](bluetooth::hci::iso_manager::cis_establish_params
355 conn_params) {
356 DLOG(INFO) << "EstablishCis";
357
358 for (auto& pair : conn_params.conn_pairs) {
359 auto dev_it = std::find_if(
360 le_audio_devices_.begin(), le_audio_devices_.end(),
361 [&pair](auto& dev) {
362 auto ases = dev->GetAsesByCisConnHdl(pair.cis_conn_handle);
363 return (ases.sink || ases.source);
364 });
365 if (dev_it == le_audio_devices_.end()) {
366 DLOG(ERROR) << "Device not found";
367 return;
368 }
369
370 for (auto& kv_pair : le_audio_device_groups_) {
371 auto& group = kv_pair.second;
372 if (group->IsDeviceInTheGroup(dev_it->get())) {
373 bluetooth::hci::iso_manager::cis_establish_cmpl_evt evt;
374
375 // Fill proper values if needed
376 evt.status = 0x00;
377 evt.cig_id = group->group_id_;
378 evt.cis_conn_hdl = pair.cis_conn_handle;
379 evt.cig_sync_delay = 0;
380 evt.cis_sync_delay = 0;
381 evt.trans_lat_mtos = 0;
382 evt.trans_lat_stom = 0;
383 evt.phy_mtos = 0;
384 evt.phy_stom = 0;
385 evt.nse = 0;
386 evt.bn_mtos = 0;
387 evt.bn_stom = 0;
388 evt.ft_mtos = 0;
389 evt.ft_stom = 0;
390 evt.max_pdu_mtos = 0;
391 evt.max_pdu_stom = 0;
392 evt.iso_itv = 0;
393
394 LeAudioGroupStateMachine::Get()->ProcessHciNotifCisEstablished(
395 group.get(), dev_it->get(), &evt);
396 break;
397 }
398 }
399 }
400 });
401
402 ON_CALL(*mock_iso_manager_, DisconnectCis)
403 .WillByDefault([this](uint16_t cis_handle, uint8_t reason) {
404 DLOG(INFO) << "DisconnectCis";
405
406 auto dev_it =
407 std::find_if(le_audio_devices_.begin(), le_audio_devices_.end(),
408 [&cis_handle](auto& dev) {
409 auto ases = dev->GetAsesByCisConnHdl(cis_handle);
410 return (ases.sink || ases.source);
411 });
412 if (dev_it == le_audio_devices_.end()) {
413 DLOG(ERROR) << "Device not found";
414 return;
415 }
416
417 // When we disconnect the remote with HCI_ERR_PEER_USER, we
418 // should be getting HCI_ERR_CONN_CAUSE_LOCAL_HOST from HCI.
419 if (reason == HCI_ERR_PEER_USER) {
420 reason = HCI_ERR_CONN_CAUSE_LOCAL_HOST;
421 }
422
423 for (auto& kv_pair : le_audio_device_groups_) {
424 auto& group = kv_pair.second;
425 if (group->IsDeviceInTheGroup(dev_it->get())) {
426 bluetooth::hci::iso_manager::cis_disconnected_evt evt{
427 .reason = reason,
428 .cig_id = static_cast<uint8_t>(group->group_id_),
429 .cis_conn_hdl = cis_handle,
430 };
431 LeAudioGroupStateMachine::Get()->ProcessHciNotifCisDisconnected(
432 group.get(), dev_it->get(), &evt);
433 return;
434 }
435 }
436 });
437 }
438
ConfigCodecManagerMock()439 void ConfigCodecManagerMock() {
440 codec_manager_ = le_audio::CodecManager::GetInstance();
441 ASSERT_NE(codec_manager_, nullptr);
442 std::vector<bluetooth::le_audio::btle_audio_codec_config_t>
443 mock_offloading_preference(0);
444 codec_manager_->Start(mock_offloading_preference);
445 mock_codec_manager_ = MockCodecManager::GetInstance();
446 ASSERT_NE(mock_codec_manager_, nullptr);
447 ON_CALL(*mock_codec_manager_, GetCodecLocation())
448 .WillByDefault(Return(types::CodecLocation::HOST));
449 }
450
TearDown()451 void TearDown() override {
452 /* Clear the alarm on tear down in case test case ends when the
453 * alarm is scheduled
454 */
455 alarm_cancel(nullptr);
456
457 iso_manager_->Stop();
458 mock_iso_manager_ = nullptr;
459 codec_manager_->Stop();
460 mock_codec_manager_ = nullptr;
461
462 gatt::SetMockBtaGattQueue(nullptr);
463 gatt::SetMockBtaGattInterface(nullptr);
464 bluetooth::manager::SetMockBtmInterface(nullptr);
465 controller::SetMockControllerInterface(nullptr);
466
467 for (auto i = 0u; i <= ascs::kAseCtpOpcodeMaxVal; ++i)
468 ase_ctp_handlers[i] = nullptr;
469
470 le_audio_devices_.clear();
471 addresses_.clear();
472 cached_codec_configuration_map_.clear();
473 cached_ase_to_cis_id_map_.clear();
474 LeAudioGroupStateMachine::Cleanup();
475 ::le_audio::AudioSetConfigurationProvider::Cleanup();
476 }
477
PrepareConnectedDevice(uint8_t id,DeviceConnectState initial_connect_state,uint8_t num_ase_snk,uint8_t num_ase_src)478 std::shared_ptr<LeAudioDevice> PrepareConnectedDevice(
479 uint8_t id, DeviceConnectState initial_connect_state, uint8_t num_ase_snk,
480 uint8_t num_ase_src) {
481 auto leAudioDevice = std::make_shared<LeAudioDevice>(GetTestAddress(id),
482 initial_connect_state);
483 leAudioDevice->conn_id_ = id;
484 leAudioDevice->SetConnectionState(DeviceConnectState::CONNECTED);
485
486 uint16_t attr_handle = ATTR_HANDLE_ASCS_POOL_START;
487 leAudioDevice->snk_audio_locations_hdls_.val_hdl = attr_handle++;
488 leAudioDevice->snk_audio_locations_hdls_.ccc_hdl = attr_handle++;
489 leAudioDevice->src_audio_locations_hdls_.val_hdl = attr_handle++;
490 leAudioDevice->src_audio_locations_hdls_.ccc_hdl = attr_handle++;
491 leAudioDevice->audio_avail_hdls_.val_hdl = attr_handle++;
492 leAudioDevice->audio_avail_hdls_.ccc_hdl = attr_handle++;
493 leAudioDevice->audio_supp_cont_hdls_.val_hdl = attr_handle++;
494 leAudioDevice->audio_supp_cont_hdls_.ccc_hdl = attr_handle++;
495 leAudioDevice->ctp_hdls_.val_hdl = attr_handle++;
496 leAudioDevice->ctp_hdls_.ccc_hdl = attr_handle++;
497
498 // Add some Sink ASEs
499 while (num_ase_snk) {
500 types::ase ase(0, 0, 0x01);
501 ase.hdls.val_hdl = attr_handle++;
502 ase.hdls.ccc_hdl = attr_handle++;
503
504 leAudioDevice->ases_.emplace_back(std::move(ase));
505 num_ase_snk--;
506 }
507
508 // Add some Source ASEs
509 while (num_ase_src) {
510 types::ase ase(0, 0, 0x02);
511 ase.hdls.val_hdl = attr_handle++;
512 ase.hdls.ccc_hdl = attr_handle++;
513
514 leAudioDevice->ases_.emplace_back(std::move(ase));
515 num_ase_src--;
516 }
517
518 le_audio_devices_.push_back(leAudioDevice);
519 addresses_.push_back(leAudioDevice->address_);
520
521 return std::move(leAudioDevice);
522 }
523
GroupTheDevice(int group_id,const std::shared_ptr<LeAudioDevice> & leAudioDevice)524 LeAudioDeviceGroup* GroupTheDevice(
525 int group_id, const std::shared_ptr<LeAudioDevice>& leAudioDevice) {
526 if (le_audio_device_groups_.count(group_id) == 0) {
527 le_audio_device_groups_[group_id] =
528 std::make_unique<LeAudioDeviceGroup>(group_id);
529 }
530
531 auto& group = le_audio_device_groups_[group_id];
532
533 group->AddNode(leAudioDevice);
534 if (group->IsEmpty()) return nullptr;
535
536 return &(*group);
537 }
538
InjectAseStateNotification(types::ase * ase,LeAudioDevice * device,LeAudioDeviceGroup * group,uint8_t new_state,void * new_state_params)539 void InjectAseStateNotification(types::ase* ase, LeAudioDevice* device,
540 LeAudioDeviceGroup* group, uint8_t new_state,
541 void* new_state_params) {
542 // Prepare additional params
543 switch (new_state) {
544 case ascs::kAseStateCodecConfigured: {
545 client_parser::ascs::ase_codec_configured_state_params* conf =
546 static_cast<
547 client_parser::ascs::ase_codec_configured_state_params*>(
548 new_state_params);
549 std::vector<uint8_t> notif_value(25 + conf->codec_spec_conf.size());
550 auto* p = notif_value.data();
551
552 UINT8_TO_STREAM(p, ase->id == types::ase::kAseIdInvalid
553 ? ++ase_id_last_assigned
554 : ase->id);
555 UINT8_TO_STREAM(p, new_state);
556
557 UINT8_TO_STREAM(p, conf->framing);
558 UINT8_TO_STREAM(p, conf->preferred_phy);
559 UINT8_TO_STREAM(p, conf->preferred_retrans_nb);
560 UINT16_TO_STREAM(p, conf->max_transport_latency);
561 UINT24_TO_STREAM(p, conf->pres_delay_min);
562 UINT24_TO_STREAM(p, conf->pres_delay_max);
563 UINT24_TO_STREAM(p, conf->preferred_pres_delay_min);
564 UINT24_TO_STREAM(p, conf->preferred_pres_delay_max);
565
566 // CodecID:
567 UINT8_TO_STREAM(p, conf->codec_id.coding_format);
568 UINT16_TO_STREAM(p, conf->codec_id.vendor_company_id);
569 UINT16_TO_STREAM(p, conf->codec_id.vendor_codec_id);
570
571 // Codec Spec. Conf. Length and Data
572 UINT8_TO_STREAM(p, conf->codec_spec_conf.size());
573 memcpy(p, conf->codec_spec_conf.data(), conf->codec_spec_conf.size());
574
575 LeAudioGroupStateMachine::Get()->ProcessGattNotifEvent(
576 notif_value.data(), notif_value.size(), ase, device, group);
577 } break;
578
579 case ascs::kAseStateQoSConfigured: {
580 client_parser::ascs::ase_qos_configured_state_params* conf =
581 static_cast<client_parser::ascs::ase_qos_configured_state_params*>(
582 new_state_params);
583 std::vector<uint8_t> notif_value(17);
584 auto* p = notif_value.data();
585
586 // Prepare header
587 UINT8_TO_STREAM(p, ase->id);
588 UINT8_TO_STREAM(p, new_state);
589
590 UINT8_TO_STREAM(p, conf->cig_id);
591 UINT8_TO_STREAM(p, conf->cis_id);
592 UINT24_TO_STREAM(p, conf->sdu_interval);
593 UINT8_TO_STREAM(p, conf->framing);
594 UINT8_TO_STREAM(p, conf->phy);
595 UINT16_TO_STREAM(p, conf->max_sdu);
596 UINT8_TO_STREAM(p, conf->retrans_nb);
597 UINT16_TO_STREAM(p, conf->max_transport_latency);
598 UINT24_TO_STREAM(p, conf->pres_delay);
599
600 LeAudioGroupStateMachine::Get()->ProcessGattNotifEvent(
601 notif_value.data(), notif_value.size(), ase, device, group);
602 } break;
603
604 case ascs::kAseStateEnabling:
605 // fall-through
606 case ascs::kAseStateStreaming:
607 // fall-through
608 case ascs::kAseStateDisabling: {
609 client_parser::ascs::ase_transient_state_params* params =
610 static_cast<client_parser::ascs::ase_transient_state_params*>(
611 new_state_params);
612 std::vector<uint8_t> notif_value(5 + params->metadata.size());
613 auto* p = notif_value.data();
614
615 // Prepare header
616 UINT8_TO_STREAM(p, ase->id);
617 UINT8_TO_STREAM(p, new_state);
618
619 UINT8_TO_STREAM(p, group->group_id_);
620 UINT8_TO_STREAM(p, ase->cis_id);
621 UINT8_TO_STREAM(p, params->metadata.size());
622 memcpy(p, params->metadata.data(), params->metadata.size());
623
624 LeAudioGroupStateMachine::Get()->ProcessGattNotifEvent(
625 notif_value.data(), notif_value.size(), ase, device, group);
626 } break;
627
628 case ascs::kAseStateReleasing:
629 // fall-through
630 case ascs::kAseStateIdle: {
631 std::vector<uint8_t> notif_value(2);
632 auto* p = notif_value.data();
633
634 // Prepare header
635 UINT8_TO_STREAM(p, ase->id == types::ase::kAseIdInvalid
636 ? ++ase_id_last_assigned
637 : ase->id);
638 UINT8_TO_STREAM(p, new_state);
639
640 LeAudioGroupStateMachine::Get()->ProcessGattNotifEvent(
641 notif_value.data(), notif_value.size(), ase, device, group);
642 } break;
643
644 default:
645 break;
646 };
647 }
648
InsertPacRecord(std::vector<types::acs_ac_record> & recs,uint16_t sampling_frequencies_bitfield,uint8_t supported_frame_durations_bitfield,uint8_t audio_channel_count_bitfield,uint16_t supported_octets_per_codec_frame_min,uint16_t supported_octets_per_codec_frame_max,uint8_t coding_format=codec_specific::kLc3CodingFormat,uint16_t vendor_company_id=0x0000,uint16_t vendor_codec_id=0x0000,std::vector<uint8_t> metadata={})649 static void InsertPacRecord(
650 std::vector<types::acs_ac_record>& recs,
651 uint16_t sampling_frequencies_bitfield,
652 uint8_t supported_frame_durations_bitfield,
653 uint8_t audio_channel_count_bitfield,
654 uint16_t supported_octets_per_codec_frame_min,
655 uint16_t supported_octets_per_codec_frame_max,
656 uint8_t coding_format = codec_specific::kLc3CodingFormat,
657 uint16_t vendor_company_id = 0x0000, uint16_t vendor_codec_id = 0x0000,
658 std::vector<uint8_t> metadata = {}) {
659 recs.push_back({
660 .codec_id =
661 {
662 .coding_format = coding_format,
663 .vendor_company_id = vendor_company_id,
664 .vendor_codec_id = vendor_codec_id,
665 },
666 .codec_spec_caps = types::LeAudioLtvMap({
667 {codec_specific::kCapTypeSupportedSamplingFrequencies,
668 {(uint8_t)(sampling_frequencies_bitfield),
669 (uint8_t)(sampling_frequencies_bitfield >> 8)}},
670 {codec_specific::kCapTypeSupportedFrameDurations,
671 {supported_frame_durations_bitfield}},
672 {codec_specific::kCapTypeAudioChannelCount,
673 {audio_channel_count_bitfield}},
674 {codec_specific::kCapTypeSupportedOctetsPerCodecFrame,
675 {
676 // Min
677 (uint8_t)(supported_octets_per_codec_frame_min),
678 (uint8_t)(supported_octets_per_codec_frame_min >> 8),
679 // Max
680 (uint8_t)(supported_octets_per_codec_frame_max),
681 (uint8_t)(supported_octets_per_codec_frame_max >> 8),
682 }},
683 }),
684 .metadata = std::move(metadata),
685 });
686 }
687
InjectInitialIdleNotification(LeAudioDeviceGroup * group)688 void InjectInitialIdleNotification(LeAudioDeviceGroup* group) {
689 for (auto* device = group->GetFirstDevice(); device != nullptr;
690 device = group->GetNextDevice(device)) {
691 for (auto& ase : device->ases_) {
692 InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle,
693 nullptr);
694 }
695 }
696 }
697
MultipleTestDevicePrepare(int leaudio_group_id,LeAudioContextType context_type,uint16_t device_cnt,types::AudioContexts update_contexts,bool insert_default_pac_records=true)698 void MultipleTestDevicePrepare(int leaudio_group_id,
699 LeAudioContextType context_type,
700 uint16_t device_cnt,
701 types::AudioContexts update_contexts,
702 bool insert_default_pac_records = true) {
703 // Prepare fake connected device group
704 DeviceConnectState initial_connect_state =
705 DeviceConnectState::CONNECTING_BY_USER;
706 int total_devices = device_cnt;
707 le_audio::LeAudioDeviceGroup* group = nullptr;
708
709 uint8_t num_ase_snk;
710 uint8_t num_ase_src;
711 switch (context_type) {
712 case kContextTypeRingtone:
713 num_ase_snk = 1 + additional_snk_ases;
714 num_ase_src = 0 + additional_src_ases;
715 break;
716
717 case kContextTypeMedia:
718 num_ase_snk = 2 + additional_snk_ases;
719 num_ase_src = 0 + additional_src_ases;
720 break;
721
722 case kContextTypeConversational:
723 num_ase_snk = 1 + additional_snk_ases;
724 num_ase_src = 1 + additional_src_ases;
725 break;
726
727 default:
728 ASSERT_TRUE(false);
729 }
730
731 while (device_cnt) {
732 auto leAudioDevice = PrepareConnectedDevice(
733 device_cnt--, initial_connect_state, num_ase_snk, num_ase_src);
734
735 if (insert_default_pac_records) {
736 uint16_t attr_handle = ATTR_HANDLE_PACS_POOL_START;
737
738 /* As per spec, unspecified shall be supported */
739 auto snk_context_type = kContextTypeUnspecified | update_contexts;
740 auto src_context_type = kContextTypeUnspecified | update_contexts;
741
742 // Prepare Sink Published Audio Capability records
743 if ((kContextTypeRingtone | kContextTypeMedia |
744 kContextTypeConversational)
745 .test(context_type)) {
746 // Set target ASE configurations
747 std::vector<types::acs_ac_record> pac_recs;
748
749 InsertPacRecord(pac_recs, sample_freq_,
750 codec_specific::kCapFrameDuration10ms |
751 codec_specific::kCapFrameDuration7p5ms |
752 codec_specific::kCapFrameDuration10msPreferred,
753 channel_count_, 30, 120);
754
755 types::hdl_pair handle_pair;
756 handle_pair.val_hdl = attr_handle++;
757 handle_pair.ccc_hdl = attr_handle++;
758
759 leAudioDevice->snk_pacs_.emplace_back(
760 std::make_tuple(std::move(handle_pair), pac_recs));
761
762 snk_context_type.set(static_cast<LeAudioContextType>(context_type));
763 leAudioDevice->snk_audio_locations_ =
764 ::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft |
765 ::le_audio::codec_spec_conf::kLeAudioLocationFrontRight;
766 }
767
768 // Prepare Source Published Audio Capability records
769 if (context_type == kContextTypeConversational) {
770 // Set target ASE configurations
771 std::vector<types::acs_ac_record> pac_recs;
772
773 InsertPacRecord(pac_recs,
774 codec_specific::kCapSamplingFrequency16000Hz,
775 codec_specific::kCapFrameDuration10ms |
776 codec_specific::kCapFrameDuration7p5ms |
777 codec_specific::kCapFrameDuration10msPreferred,
778 0b00000001, 30, 120);
779
780 types::hdl_pair handle_pair;
781 handle_pair.val_hdl = attr_handle++;
782 handle_pair.ccc_hdl = attr_handle++;
783
784 leAudioDevice->src_pacs_.emplace_back(
785 std::make_tuple(std::move(handle_pair), pac_recs));
786 src_context_type.set(
787 static_cast<LeAudioContextType>(kContextTypeConversational));
788
789 leAudioDevice->src_audio_locations_ =
790 ::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft |
791 ::le_audio::codec_spec_conf::kLeAudioLocationFrontRight;
792 }
793
794 leAudioDevice->SetSupportedContexts(snk_context_type, src_context_type);
795 leAudioDevice->SetAvailableContexts(snk_context_type, src_context_type);
796 }
797
798 group = GroupTheDevice(leaudio_group_id, std::move(leAudioDevice));
799 /* Set the location and direction to the group (done in client.cc)*/
800 group->ReloadAudioLocations();
801 group->ReloadAudioDirections();
802 }
803
804 /* Stimulate update of available context map */
805 auto types_set = update_contexts.any() ? context_type | update_contexts
806 : types::AudioContexts(context_type);
807 group->UpdateAudioContextTypeAvailability(types_set);
808
809 ASSERT_NE(group, nullptr);
810 ASSERT_EQ(group->Size(), total_devices);
811 }
812
PrepareSingleTestDeviceGroup(int leaudio_group_id,LeAudioContextType context_type,uint16_t device_cnt=1,types::AudioContexts update_contexts=types::AudioContexts ())813 LeAudioDeviceGroup* PrepareSingleTestDeviceGroup(
814 int leaudio_group_id, LeAudioContextType context_type,
815 uint16_t device_cnt = 1,
816 types::AudioContexts update_contexts = types::AudioContexts()) {
817 MultipleTestDevicePrepare(leaudio_group_id, context_type, device_cnt,
818 update_contexts);
819 return le_audio_device_groups_.count(leaudio_group_id)
820 ? le_audio_device_groups_[leaudio_group_id].get()
821 : nullptr;
822 }
823
PrepareConfigureCodecHandler(LeAudioDeviceGroup * group,int verify_ase_count=0,bool caching=false)824 void PrepareConfigureCodecHandler(LeAudioDeviceGroup* group,
825 int verify_ase_count = 0,
826 bool caching = false) {
827 ase_ctp_handlers[ascs::kAseCtpOpcodeConfigureCodec] =
828 [group, verify_ase_count, caching, this](
829 LeAudioDevice* device, std::vector<uint8_t> value,
830 GATT_WRITE_OP_CB cb, void* cb_data) {
831 auto num_ase = value[1];
832
833 // Verify ase count if needed
834 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
835
836 // Inject Configured ASE state notification for each requested ASE
837 auto* ase_p = &value[2];
838 for (auto i = 0u; i < num_ase; ++i) {
839 client_parser::ascs::ase_codec_configured_state_params
840 codec_configured_state_params;
841
842 /* Check if this is a valid ASE ID */
843 auto ase_id = *ase_p++;
844 auto it = std::find_if(
845 device->ases_.begin(), device->ases_.end(),
846 [ase_id](auto& ase) { return (ase.id == ase_id); });
847 ASSERT_NE(it, device->ases_.end());
848 const auto ase = &(*it);
849
850 // Skip target latency param
851 ase_p++;
852
853 codec_configured_state_params.preferred_phy = *ase_p++;
854 codec_configured_state_params.codec_id.coding_format = ase_p[0];
855 codec_configured_state_params.codec_id.vendor_company_id =
856 (uint16_t)(ase_p[1] << 8 | ase_p[2]),
857 codec_configured_state_params.codec_id.vendor_codec_id =
858 (uint16_t)(ase_p[3] << 8 | ase_p[4]),
859 ase_p += 5;
860
861 auto codec_spec_param_len = *ase_p++;
862 auto num_handled_bytes = ase_p - value.data();
863 codec_configured_state_params.codec_spec_conf =
864 std::vector<uint8_t>(
865 value.begin() + num_handled_bytes,
866 value.begin() + num_handled_bytes + codec_spec_param_len);
867 ase_p += codec_spec_param_len;
868
869 // Some initial QoS settings
870 codec_configured_state_params.framing =
871 ascs::kAseParamFramingUnframedSupported;
872 codec_configured_state_params.preferred_retrans_nb = 0x04;
873 codec_configured_state_params.max_transport_latency = 0x0010;
874 codec_configured_state_params.pres_delay_min = 0xABABAB;
875 codec_configured_state_params.pres_delay_max = 0xCDCDCD;
876 codec_configured_state_params.preferred_pres_delay_min =
877 types::kPresDelayNoPreference;
878 codec_configured_state_params.preferred_pres_delay_max =
879 types::kPresDelayNoPreference;
880
881 if (caching) {
882 cached_codec_configuration_map_[ase_id] =
883 codec_configured_state_params;
884 }
885 InjectAseStateNotification(ase, device, group,
886 ascs::kAseStateCodecConfigured,
887 &codec_configured_state_params);
888 }
889 };
890 }
891
PrepareConfigureQosHandler(LeAudioDeviceGroup * group,int verify_ase_count=0,bool caching=false)892 void PrepareConfigureQosHandler(LeAudioDeviceGroup* group,
893 int verify_ase_count = 0,
894 bool caching = false) {
895 ase_ctp_handlers[ascs::kAseCtpOpcodeConfigureQos] =
896 [group, verify_ase_count, caching, this](
897 LeAudioDevice* device, std::vector<uint8_t> value,
898 GATT_WRITE_OP_CB cb, void* cb_data) {
899 auto num_ase = value[1];
900
901 // Verify ase count if needed
902 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
903
904 // Inject Configured QoS state notification for each requested ASE
905 auto* ase_p = &value[2];
906 for (auto i = 0u; i < num_ase; ++i) {
907 client_parser::ascs::ase_qos_configured_state_params
908 qos_configured_state_params;
909
910 /* Check if this is a valid ASE ID */
911 auto ase_id = *ase_p++;
912 auto it = std::find_if(
913 device->ases_.begin(), device->ases_.end(),
914 [ase_id](auto& ase) { return (ase.id == ase_id); });
915 ASSERT_NE(it, device->ases_.end());
916 const auto ase = &(*it);
917
918 qos_configured_state_params.cig_id = *ase_p++;
919 qos_configured_state_params.cis_id = *ase_p++;
920
921 qos_configured_state_params.sdu_interval =
922 (uint32_t)((ase_p[0] << 16) | (ase_p[1] << 8) | ase_p[2]);
923 ase_p += 3;
924
925 qos_configured_state_params.framing = *ase_p++;
926 qos_configured_state_params.phy = *ase_p++;
927 qos_configured_state_params.max_sdu =
928 (uint16_t)((ase_p[0] << 8) | ase_p[1]);
929 ase_p += 2;
930
931 qos_configured_state_params.retrans_nb = *ase_p++;
932 qos_configured_state_params.max_transport_latency =
933 (uint16_t)((ase_p[0] << 8) | ase_p[1]);
934 ase_p += 2;
935
936 qos_configured_state_params.pres_delay =
937 (uint16_t)((ase_p[0] << 16) | (ase_p[1] << 8) | ase_p[2]);
938 ase_p += 3;
939
940 if (caching) {
941 LOG(INFO) << __func__ << " Device: " << device->address_;
942 if (cached_ase_to_cis_id_map_.count(device->address_) > 0) {
943 auto ase_list = cached_ase_to_cis_id_map_.at(device->address_);
944 if (ase_list.count(ase_id) > 0) {
945 auto cis_id = ase_list.at(ase_id);
946 ASSERT_EQ(cis_id, qos_configured_state_params.cis_id);
947 } else {
948 ase_list[ase_id] = qos_configured_state_params.cis_id;
949 }
950 } else {
951 std::map<int, int> ase_map;
952 ase_map[ase_id] = qos_configured_state_params.cis_id;
953
954 cached_ase_to_cis_id_map_[device->address_] = ase_map;
955 }
956 }
957
958 InjectAseStateNotification(ase, device, group,
959 ascs::kAseStateQoSConfigured,
960 &qos_configured_state_params);
961 }
962 };
963 }
964
PrepareEnableHandler(LeAudioDeviceGroup * group,int verify_ase_count=0,bool inject_enabling=true)965 void PrepareEnableHandler(LeAudioDeviceGroup* group, int verify_ase_count = 0,
966 bool inject_enabling = true) {
967 ase_ctp_handlers[ascs::kAseCtpOpcodeEnable] =
968 [group, verify_ase_count, inject_enabling, this](
969 LeAudioDevice* device, std::vector<uint8_t> value,
970 GATT_WRITE_OP_CB cb, void* cb_data) {
971 auto num_ase = value[1];
972
973 // Verify ase count if needed
974 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
975
976 // Inject Streaming ASE state notification for each requested ASE
977 auto* ase_p = &value[2];
978 for (auto i = 0u; i < num_ase; ++i) {
979 /* Check if this is a valid ASE ID */
980 auto ase_id = *ase_p++;
981 auto it = std::find_if(
982 device->ases_.begin(), device->ases_.end(),
983 [ase_id](auto& ase) { return (ase.id == ase_id); });
984 ASSERT_NE(it, device->ases_.end());
985 const auto ase = &(*it);
986
987 auto meta_len = *ase_p++;
988 auto num_handled_bytes = ase_p - value.data();
989 ase_p += meta_len;
990
991 client_parser::ascs::ase_transient_state_params enable_params = {
992 .metadata = std::vector<uint8_t>(
993 value.begin() + num_handled_bytes,
994 value.begin() + num_handled_bytes + meta_len)};
995
996 // Server does the 'ReceiverStartReady' on its own - goes to
997 // Streaming, when in Sink role
998 if (ase->direction & le_audio::types::kLeAudioDirectionSink) {
999 if (inject_enabling)
1000 InjectAseStateNotification(ase, device, group,
1001 ascs::kAseStateEnabling,
1002 &enable_params);
1003 InjectAseStateNotification(
1004 ase, device, group, ascs::kAseStateStreaming, &enable_params);
1005 } else {
1006 InjectAseStateNotification(
1007 ase, device, group, ascs::kAseStateEnabling, &enable_params);
1008 }
1009 }
1010 };
1011 }
1012
PrepareDisableHandler(LeAudioDeviceGroup * group,int verify_ase_count=0)1013 void PrepareDisableHandler(LeAudioDeviceGroup* group,
1014 int verify_ase_count = 0) {
1015 ase_ctp_handlers[ascs::kAseCtpOpcodeDisable] =
1016 [group, verify_ase_count, this](LeAudioDevice* device,
1017 std::vector<uint8_t> value,
1018 GATT_WRITE_OP_CB cb, void* cb_data) {
1019 auto num_ase = value[1];
1020
1021 // Verify ase count if needed
1022 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
1023 ASSERT_EQ(value.size(), 2ul + num_ase);
1024
1025 // Inject Disabling & QoS Conf. ASE state notification for each ASE
1026 auto* ase_p = &value[2];
1027 for (auto i = 0u; i < num_ase; ++i) {
1028 /* Check if this is a valid ASE ID */
1029 auto ase_id = *ase_p++;
1030 auto it = std::find_if(
1031 device->ases_.begin(), device->ases_.end(),
1032 [ase_id](auto& ase) { return (ase.id == ase_id); });
1033 ASSERT_NE(it, device->ases_.end());
1034 const auto ase = &(*it);
1035
1036 // The Disabling state is present for Source ASE
1037 if (ase->direction & le_audio::types::kLeAudioDirectionSource) {
1038 client_parser::ascs::ase_transient_state_params disabling_params =
1039 {.metadata = {}};
1040 InjectAseStateNotification(ase, device, group,
1041 ascs::kAseStateDisabling,
1042 &disabling_params);
1043 }
1044
1045 // Server does the 'ReceiverStopReady' on its own - goes to
1046 // Streaming, when in Sink role
1047 if (ase->direction & le_audio::types::kLeAudioDirectionSink) {
1048 // FIXME: For now our fake peer does not remember qos params
1049 client_parser::ascs::ase_qos_configured_state_params
1050 qos_configured_state_params;
1051 InjectAseStateNotification(ase, device, group,
1052 ascs::kAseStateQoSConfigured,
1053 &qos_configured_state_params);
1054 }
1055 }
1056 };
1057 }
1058
PrepareReceiverStartReady(LeAudioDeviceGroup * group,int verify_ase_count=0)1059 void PrepareReceiverStartReady(LeAudioDeviceGroup* group,
1060 int verify_ase_count = 0) {
1061 ase_ctp_handlers[ascs::kAseCtpOpcodeReceiverStartReady] =
1062 [group, verify_ase_count, this](LeAudioDevice* device,
1063 std::vector<uint8_t> value,
1064 GATT_WRITE_OP_CB cb, void* cb_data) {
1065 auto num_ase = value[1];
1066
1067 // Verify ase count if needed
1068 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
1069
1070 // Inject Streaming ASE state notification for each Source ASE
1071 auto* ase_p = &value[2];
1072 for (auto i = 0u; i < num_ase; ++i) {
1073 /* Check if this is a valid ASE ID */
1074 auto ase_id = *ase_p++;
1075 auto it = std::find_if(
1076 device->ases_.begin(), device->ases_.end(),
1077 [ase_id](auto& ase) { return (ase.id == ase_id); });
1078 ASSERT_NE(it, device->ases_.end());
1079
1080 // Once we did the 'ReceiverStartReady' the server goes to
1081 // Streaming, when in Source role
1082 auto meta_len = *ase_p++;
1083 auto num_handled_bytes = ase_p - value.data();
1084 ase_p += num_handled_bytes;
1085
1086 const auto& ase = &(*it);
1087 client_parser::ascs::ase_transient_state_params enable_params = {
1088 .metadata = std::vector<uint8_t>(
1089 value.begin() + num_handled_bytes,
1090 value.begin() + num_handled_bytes + meta_len)};
1091 InjectAseStateNotification(
1092 ase, device, group, ascs::kAseStateStreaming, &enable_params);
1093 }
1094 };
1095 }
1096
PrepareReceiverStopReady(LeAudioDeviceGroup * group,int verify_ase_count=0)1097 void PrepareReceiverStopReady(LeAudioDeviceGroup* group,
1098 int verify_ase_count = 0) {
1099 ase_ctp_handlers[ascs::kAseCtpOpcodeReceiverStopReady] =
1100 [group, verify_ase_count, this](LeAudioDevice* device,
1101 std::vector<uint8_t> value,
1102 GATT_WRITE_OP_CB cb, void* cb_data) {
1103 auto num_ase = value[1];
1104
1105 // Verify ase count if needed
1106 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
1107
1108 // Inject QoS configured ASE state notification for each Source ASE
1109 auto* ase_p = &value[2];
1110 for (auto i = 0u; i < num_ase; ++i) {
1111 /* Check if this is a valid ASE ID */
1112 auto ase_id = *ase_p++;
1113 auto it = std::find_if(
1114 device->ases_.begin(), device->ases_.end(),
1115 [ase_id](auto& ase) { return (ase.id == ase_id); });
1116 ASSERT_NE(it, device->ases_.end());
1117
1118 const auto& ase = &(*it);
1119
1120 // FIXME: For now our fake peer does not remember qos params
1121 client_parser::ascs::ase_qos_configured_state_params
1122 qos_configured_state_params;
1123 InjectAseStateNotification(ase, device, group,
1124 ascs::kAseStateQoSConfigured,
1125 &qos_configured_state_params);
1126 }
1127 };
1128 }
1129
PrepareReleaseHandler(LeAudioDeviceGroup * group,int verify_ase_count=0)1130 void PrepareReleaseHandler(LeAudioDeviceGroup* group,
1131 int verify_ase_count = 0) {
1132 ase_ctp_handlers[ascs::kAseCtpOpcodeRelease] =
1133 [group, verify_ase_count, this](LeAudioDevice* device,
1134 std::vector<uint8_t> value,
1135 GATT_WRITE_OP_CB cb, void* cb_data) {
1136 auto num_ase = value[1];
1137
1138 // Verify ase count if needed
1139 if (verify_ase_count) ASSERT_EQ(verify_ase_count, num_ase);
1140 ASSERT_EQ(value.size(), 2ul + num_ase);
1141
1142 // Inject Releasing & Idle ASE state notification for each ASE
1143 auto* ase_p = &value[2];
1144 for (auto i = 0u; i < num_ase; ++i) {
1145 /* Check if this is a valid ASE ID */
1146 auto ase_id = *ase_p++;
1147 auto it = std::find_if(
1148 device->ases_.begin(), device->ases_.end(),
1149 [ase_id](auto& ase) { return (ase.id == ase_id); });
1150 ASSERT_NE(it, device->ases_.end());
1151 const auto ase = &(*it);
1152
1153 InjectAseStateNotification(ase, device, group,
1154 ascs::kAseStateReleasing, nullptr);
1155
1156 /* Check if codec configuration is cached */
1157 if (cached_codec_configuration_map_.count(ase_id) > 0) {
1158 InjectAseStateNotification(
1159 ase, device, group, ascs::kAseStateCodecConfigured,
1160 &cached_codec_configuration_map_[ase_id]);
1161 } else {
1162 // Release - no caching
1163 InjectAseStateNotification(ase, device, group,
1164 ascs::kAseStateIdle, nullptr);
1165 }
1166 }
1167 };
1168 }
1169
1170 MockCsisClient mock_csis_client_module_;
1171 NiceMock<controller::MockControllerInterface> mock_controller_;
1172 NiceMock<bluetooth::manager::MockBtmInterface> btm_interface;
1173 gatt::MockBtaGattInterface gatt_interface;
1174 gatt::MockBtaGattQueue gatt_queue;
1175
1176 bluetooth::hci::IsoManager* iso_manager_;
1177 MockIsoManager* mock_iso_manager_;
1178 le_audio::CodecManager* codec_manager_;
1179 MockCodecManager* mock_codec_manager_;
1180
1181 std::function<void(LeAudioDevice* device, std::vector<uint8_t> value,
1182 GATT_WRITE_OP_CB cb, void* cb_data)>
1183 ase_ctp_handlers[ascs::kAseCtpOpcodeMaxVal + 1] = {nullptr};
1184 std::map<int, client_parser::ascs::ase_codec_configured_state_params>
1185 cached_codec_configuration_map_;
1186
1187 std::map<RawAddress, std::map<int, int>> cached_ase_to_cis_id_map_;
1188
1189 MockLeAudioGroupStateMachineCallbacks mock_callbacks_;
1190 std::vector<std::shared_ptr<LeAudioDevice>> le_audio_devices_;
1191 std::vector<RawAddress> addresses_;
1192 std::map<uint8_t, std::unique_ptr<LeAudioDeviceGroup>>
1193 le_audio_device_groups_;
1194 bool group_create_command_disallowed_ = false;
1195 };
1196
TEST_F(StateMachineTest,testInit)1197 TEST_F(StateMachineTest, testInit) {
1198 ASSERT_NE(LeAudioGroupStateMachine::Get(), nullptr);
1199 }
1200
TEST_F(StateMachineTest,testCleanup)1201 TEST_F(StateMachineTest, testCleanup) {
1202 ASSERT_NE(LeAudioGroupStateMachine::Get(), nullptr);
1203 LeAudioGroupStateMachine::Cleanup();
1204 EXPECT_DEATH(LeAudioGroupStateMachine::Get(), "");
1205 }
1206
TEST_F(StateMachineTest,testConfigureCodecSingle)1207 TEST_F(StateMachineTest, testConfigureCodecSingle) {
1208 /* Device is banded headphones with 1x snk + 0x src ase
1209 * (1xunidirectional CIS) with channel count 2 (for stereo
1210 */
1211 const auto context_type = kContextTypeRingtone;
1212 const int leaudio_group_id = 2;
1213 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
1214 kLeAudioCodecLC3ChannelCountTwoChannel;
1215
1216 // Prepare fake connected device group
1217 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
1218
1219 /* Since we prepared device with Ringtone context in mind, only one ASE
1220 * should have been configured.
1221 */
1222 auto* leAudioDevice = group->GetFirstDevice();
1223 PrepareConfigureCodecHandler(group, 1);
1224
1225 /* Start the configuration and stream Media content.
1226 * Expect 1 time for the Codec Config call only. */
1227 EXPECT_CALL(gatt_queue,
1228 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
1229 GATT_WRITE_NO_RSP, _, _))
1230 .Times(1);
1231
1232 /* Do nothing on the CigCreate, so the state machine stays in the configure
1233 * state */
1234 ON_CALL(*mock_iso_manager_, CreateCig).WillByDefault(Return());
1235 EXPECT_CALL(*mock_iso_manager_, CreateCig).Times(1);
1236
1237 InjectInitialIdleNotification(group);
1238
1239 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1240 group, static_cast<LeAudioContextType>(context_type),
1241 types::AudioContexts(context_type)));
1242
1243 // Check if group has transitioned to a proper state
1244 ASSERT_EQ(group->GetState(),
1245 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
1246
1247 /* Cancel is called when group goes to streaming. */
1248 ASSERT_EQ(0, mock_function_count_map["alarm_cancel"]);
1249 }
1250
TEST_F(StateMachineTest,testConfigureCodecMulti)1251 TEST_F(StateMachineTest, testConfigureCodecMulti) {
1252 const auto context_type = kContextTypeMedia;
1253 const auto leaudio_group_id = 2;
1254 const auto num_devices = 2;
1255
1256 // Prepare multiple fake connected devices in a group
1257 auto* group =
1258 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
1259 ASSERT_EQ(group->Size(), num_devices);
1260
1261 PrepareConfigureCodecHandler(group);
1262
1263 auto expected_devices_written = 0;
1264 auto* leAudioDevice = group->GetFirstDevice();
1265 while (leAudioDevice) {
1266 EXPECT_CALL(gatt_queue,
1267 WriteCharacteristic(leAudioDevice->conn_id_,
1268 leAudioDevice->ctp_hdls_.val_hdl, _,
1269 GATT_WRITE_NO_RSP, _, _))
1270 .Times(AtLeast(1));
1271 expected_devices_written++;
1272 leAudioDevice = group->GetNextDevice(leAudioDevice);
1273 }
1274 ASSERT_EQ(expected_devices_written, num_devices);
1275
1276 InjectInitialIdleNotification(group);
1277
1278 /* Do nothing on the CigCreate, so the state machine stays in the configure
1279 * state */
1280 ON_CALL(*mock_iso_manager_, CreateCig).WillByDefault(Return());
1281 EXPECT_CALL(*mock_iso_manager_, CreateCig).Times(1);
1282
1283 // Start the configuration and stream the content
1284 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1285 group, static_cast<LeAudioContextType>(context_type),
1286 types::AudioContexts(context_type)));
1287
1288 // Check if group has transitioned to a proper state
1289 ASSERT_EQ(group->GetState(),
1290 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
1291
1292 /* Cancel is called when group goes to streaming. */
1293 ASSERT_EQ(0, mock_function_count_map["alarm_cancel"]);
1294 }
1295
TEST_F(StateMachineTest,testConfigureQosSingle)1296 TEST_F(StateMachineTest, testConfigureQosSingle) {
1297 /* Device is banded headphones with 2x snk + 1x src ase
1298 * (1x bidirectional + 1xunidirectional CIS)
1299 */
1300 additional_snk_ases = 1;
1301 additional_src_ases = 1;
1302 const auto context_type = kContextTypeRingtone;
1303 const int leaudio_group_id = 3;
1304
1305 // Prepare fake connected device group
1306 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
1307
1308 /* Since we prepared device with Ringtone context in mind, only one ASE
1309 * should have been configured.
1310 */
1311 auto* leAudioDevice = group->GetFirstDevice();
1312 PrepareConfigureCodecHandler(group, 2);
1313 PrepareConfigureQosHandler(group, 2);
1314
1315 // Start the configuration and stream Media content
1316 EXPECT_CALL(gatt_queue,
1317 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
1318 GATT_WRITE_NO_RSP, _, _))
1319 .Times(3);
1320
1321 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1322 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
1323 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
1324 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1325 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1326 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1327
1328 InjectInitialIdleNotification(group);
1329
1330 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1331 group, context_type, types::AudioContexts(context_type)));
1332
1333 // Check if group has transitioned to a proper state
1334 ASSERT_EQ(group->GetState(),
1335 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
1336
1337 ASSERT_EQ(0, mock_function_count_map["alarm_cancel"]);
1338 }
1339
TEST_F(StateMachineTest,testConfigureQosSingleRecoverCig)1340 TEST_F(StateMachineTest, testConfigureQosSingleRecoverCig) {
1341 /* Device is banded headphones with 2x snk + 1x src ase
1342 * (1x bidirectional + 1xunidirectional CIS)
1343 */
1344 additional_snk_ases = 1;
1345 additional_src_ases = 1;
1346 const auto context_type = kContextTypeRingtone;
1347 const int leaudio_group_id = 3;
1348
1349 /* Assume that on previous BT OFF CIG was not removed */
1350 group_create_command_disallowed_ = true;
1351
1352 // Prepare fake connected device group
1353 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
1354
1355 /* Since we prepared device with Ringtone context in mind, only one ASE
1356 * should have been configured.
1357 */
1358 auto* leAudioDevice = group->GetFirstDevice();
1359 PrepareConfigureCodecHandler(group, 2);
1360 PrepareConfigureQosHandler(group, 2);
1361
1362 // Start the configuration and stream Media content
1363 EXPECT_CALL(gatt_queue,
1364 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
1365 GATT_WRITE_NO_RSP, _, _))
1366 .Times(3);
1367
1368 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2);
1369 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
1370 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
1371 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
1372 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1373 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1374
1375 InjectInitialIdleNotification(group);
1376
1377 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1378 group, static_cast<LeAudioContextType>(context_type),
1379 types::AudioContexts(context_type)));
1380
1381 // Check if group has transitioned to a proper state
1382 ASSERT_EQ(group->GetState(),
1383 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
1384 ASSERT_EQ(0, mock_function_count_map["alarm_cancel"]);
1385 }
1386
TEST_F(StateMachineTest,testConfigureQosMultiple)1387 TEST_F(StateMachineTest, testConfigureQosMultiple) {
1388 const auto context_type = kContextTypeMedia;
1389 const auto leaudio_group_id = 3;
1390 const auto num_devices = 2;
1391
1392 // Prepare multiple fake connected devices in a group
1393 auto* group =
1394 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
1395 ASSERT_EQ(group->Size(), num_devices);
1396
1397 PrepareConfigureCodecHandler(group);
1398 PrepareConfigureQosHandler(group);
1399
1400 auto* leAudioDevice = group->GetFirstDevice();
1401 auto expected_devices_written = 0;
1402 while (leAudioDevice) {
1403 EXPECT_CALL(gatt_queue,
1404 WriteCharacteristic(leAudioDevice->conn_id_,
1405 leAudioDevice->ctp_hdls_.val_hdl, _,
1406 GATT_WRITE_NO_RSP, _, _))
1407 .Times(AtLeast(2));
1408 expected_devices_written++;
1409 leAudioDevice = group->GetNextDevice(leAudioDevice);
1410 }
1411 ASSERT_EQ(expected_devices_written, num_devices);
1412
1413 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1414 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
1415 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
1416 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1417 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1418 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1419
1420 InjectInitialIdleNotification(group);
1421
1422 // Start the configuration and stream Media content
1423 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1424 group, static_cast<LeAudioContextType>(context_type),
1425 types::AudioContexts(context_type)));
1426
1427 // Check if group has transitioned to a proper state
1428 ASSERT_EQ(group->GetState(),
1429 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
1430 ASSERT_EQ(0, mock_function_count_map["alarm_cancel"]);
1431 }
1432
TEST_F(StateMachineTest,testStreamSingle)1433 TEST_F(StateMachineTest, testStreamSingle) {
1434 /* Device is banded headphones with 1x snk + 0x src ase
1435 * (1xunidirectional CIS) with channel count 2 (for stereo
1436 */
1437 const auto context_type = kContextTypeRingtone;
1438 const int leaudio_group_id = 4;
1439 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
1440 kLeAudioCodecLC3ChannelCountTwoChannel;
1441
1442 // Prepare fake connected device group
1443 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
1444
1445 /* Ringtone with channel count 1 for single device and 1 ASE sink will
1446 * end up with 1 Sink ASE being configured.
1447 */
1448 PrepareConfigureCodecHandler(group, 1);
1449 PrepareConfigureQosHandler(group, 1);
1450 PrepareEnableHandler(group, 1);
1451
1452 auto* leAudioDevice = group->GetFirstDevice();
1453 EXPECT_CALL(gatt_queue,
1454 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
1455 GATT_WRITE_NO_RSP, _, _))
1456 .Times(3);
1457
1458 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1459 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
1460 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
1461 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1462 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1463 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1464
1465 InjectInitialIdleNotification(group);
1466
1467 // Validate GroupStreamStatus
1468 EXPECT_CALL(
1469 mock_callbacks_,
1470 StatusReportCb(leaudio_group_id,
1471 bluetooth::le_audio::GroupStreamStatus::STREAMING));
1472
1473 // Start the configuration and stream Media content
1474 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1475 group, static_cast<LeAudioContextType>(context_type),
1476 types::AudioContexts(context_type)));
1477
1478 // Check if group has transitioned to a proper state
1479 ASSERT_EQ(group->GetState(),
1480 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
1481 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
1482 }
1483
TEST_F(StateMachineTest,testStreamSkipEnablingSink)1484 TEST_F(StateMachineTest, testStreamSkipEnablingSink) {
1485 /* Device is banded headphones with 2x snk + none src ase
1486 * (2x unidirectional CIS)
1487 */
1488 const auto context_type = kContextTypeMedia;
1489 const int leaudio_group_id = 4;
1490
1491 // Prepare fake connected device group
1492 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
1493
1494 /* For Media context type with channel count 1 and two ASEs,
1495 * there should have be 2 Ases configured configured.
1496 */
1497 PrepareConfigureCodecHandler(group, 2);
1498 PrepareConfigureQosHandler(group, 2);
1499 PrepareEnableHandler(group, 2, false);
1500
1501 auto* leAudioDevice = group->GetFirstDevice();
1502 EXPECT_CALL(gatt_queue,
1503 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
1504 GATT_WRITE_NO_RSP, _, _))
1505 .Times(3);
1506
1507 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1508 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
1509 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
1510 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1511 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1512 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1513
1514 InjectInitialIdleNotification(group);
1515
1516 // Validate GroupStreamStatus
1517 EXPECT_CALL(
1518 mock_callbacks_,
1519 StatusReportCb(leaudio_group_id,
1520 bluetooth::le_audio::GroupStreamStatus::STREAMING));
1521
1522 // Start the configuration and stream Media content
1523 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1524 group, static_cast<LeAudioContextType>(context_type),
1525 types::AudioContexts(context_type)));
1526
1527 // Check if group has transitioned to a proper state
1528 ASSERT_EQ(group->GetState(),
1529 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
1530
1531 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
1532 }
1533
TEST_F(StateMachineTest,testStreamSkipEnablingSinkSource)1534 TEST_F(StateMachineTest, testStreamSkipEnablingSinkSource) {
1535 /* Device is banded headphones with 2x snk + 1x src ase
1536 * (1x bidirectional CIS)
1537 */
1538 const auto context_type = kContextTypeConversational;
1539 const int leaudio_group_id = 4;
1540
1541 additional_snk_ases = 1;
1542
1543 // Prepare fake connected device group
1544 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
1545
1546 /* Since we prepared device with Conversional context in mind,
1547 * 2 Sink ASEs and 1 Source ASE should have been configured.
1548 */
1549 PrepareConfigureCodecHandler(group, 3);
1550 PrepareConfigureQosHandler(group, 3);
1551 PrepareEnableHandler(group, 3, false);
1552 PrepareReceiverStartReady(group, 1);
1553
1554 auto* leAudioDevice = group->GetFirstDevice();
1555 EXPECT_CALL(gatt_queue,
1556 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
1557 GATT_WRITE_NO_RSP, _, _))
1558 .Times(4);
1559
1560 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1561 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
1562 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
1563 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1564 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1565 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1566
1567 InjectInitialIdleNotification(group);
1568
1569 // Validate GroupStreamStatus
1570 EXPECT_CALL(
1571 mock_callbacks_,
1572 StatusReportCb(leaudio_group_id,
1573 bluetooth::le_audio::GroupStreamStatus::STREAMING));
1574
1575 // Start the configuration and stream Media content
1576 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1577 group, static_cast<LeAudioContextType>(context_type),
1578 types::AudioContexts(context_type)));
1579
1580 // Check if group has transitioned to a proper state
1581 ASSERT_EQ(group->GetState(),
1582 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
1583 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
1584 }
1585
TEST_F(StateMachineTest,testStreamMultipleConversational)1586 TEST_F(StateMachineTest, testStreamMultipleConversational) {
1587 const auto context_type = kContextTypeConversational;
1588 const auto leaudio_group_id = 4;
1589 const auto num_devices = 2;
1590
1591 // Prepare multiple fake connected devices in a group
1592 auto* group =
1593 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
1594 ASSERT_EQ(group->Size(), num_devices);
1595
1596 PrepareConfigureCodecHandler(group);
1597 PrepareConfigureQosHandler(group);
1598 PrepareEnableHandler(group);
1599 PrepareReceiverStartReady(group);
1600
1601 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1602 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1));
1603 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4);
1604 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1605 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1606 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1607
1608 InjectInitialIdleNotification(group);
1609
1610 auto* leAudioDevice = group->GetFirstDevice();
1611 auto expected_devices_written = 0;
1612 while (leAudioDevice) {
1613 EXPECT_CALL(gatt_queue,
1614 WriteCharacteristic(leAudioDevice->conn_id_,
1615 leAudioDevice->ctp_hdls_.val_hdl, _,
1616 GATT_WRITE_NO_RSP, _, _))
1617 .Times(4);
1618 expected_devices_written++;
1619 leAudioDevice = group->GetNextDevice(leAudioDevice);
1620 }
1621 ASSERT_EQ(expected_devices_written, num_devices);
1622
1623 // Validate GroupStreamStatus
1624 EXPECT_CALL(
1625 mock_callbacks_,
1626 StatusReportCb(leaudio_group_id,
1627 bluetooth::le_audio::GroupStreamStatus::STREAMING));
1628
1629 // Start the configuration and stream Media content
1630 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1631 group, static_cast<LeAudioContextType>(context_type),
1632 types::AudioContexts(context_type)));
1633
1634 // Check if group has transitioned to a proper state
1635 ASSERT_EQ(group->GetState(),
1636 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
1637 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
1638 }
1639
TEST_F(StateMachineTest,testStreamMultiple)1640 TEST_F(StateMachineTest, testStreamMultiple) {
1641 const auto context_type = kContextTypeMedia;
1642 const auto leaudio_group_id = 4;
1643 const auto num_devices = 2;
1644
1645 // Prepare multiple fake connected devices in a group
1646 auto* group =
1647 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
1648 ASSERT_EQ(group->Size(), num_devices);
1649
1650 PrepareConfigureCodecHandler(group);
1651 PrepareConfigureQosHandler(group);
1652 PrepareEnableHandler(group);
1653
1654 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1655 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1));
1656 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
1657 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1658 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1659 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1660
1661 InjectInitialIdleNotification(group);
1662
1663 auto* leAudioDevice = group->GetFirstDevice();
1664 auto expected_devices_written = 0;
1665 while (leAudioDevice) {
1666 EXPECT_CALL(gatt_queue,
1667 WriteCharacteristic(leAudioDevice->conn_id_,
1668 leAudioDevice->ctp_hdls_.val_hdl, _,
1669 GATT_WRITE_NO_RSP, _, _))
1670 .Times(AtLeast(3));
1671 expected_devices_written++;
1672 leAudioDevice = group->GetNextDevice(leAudioDevice);
1673 }
1674 ASSERT_EQ(expected_devices_written, num_devices);
1675
1676 // Validate GroupStreamStatus
1677 EXPECT_CALL(
1678 mock_callbacks_,
1679 StatusReportCb(leaudio_group_id,
1680 bluetooth::le_audio::GroupStreamStatus::STREAMING));
1681
1682 // Start the configuration and stream Media content
1683 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1684 group, static_cast<LeAudioContextType>(context_type),
1685 types::AudioContexts(context_type)));
1686
1687 // Check if group has transitioned to a proper state
1688 ASSERT_EQ(group->GetState(),
1689 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
1690 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
1691 }
1692
TEST_F(StateMachineTest,testUpdateMetadataMultiple)1693 TEST_F(StateMachineTest, testUpdateMetadataMultiple) {
1694 const auto context_type = kContextTypeMedia;
1695 const auto leaudio_group_id = 4;
1696 const auto num_devices = 2;
1697
1698 // Prepare multiple fake connected devices in a group
1699 auto* group =
1700 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
1701 ASSERT_EQ(group->Size(), num_devices);
1702
1703 PrepareConfigureCodecHandler(group);
1704 PrepareConfigureQosHandler(group);
1705 PrepareEnableHandler(group);
1706
1707 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1708 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1));
1709 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
1710 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
1711 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
1712 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1713
1714 InjectInitialIdleNotification(group);
1715
1716 auto* leAudioDevice = group->GetFirstDevice();
1717 auto expected_devices_written = 0;
1718 while (leAudioDevice) {
1719 EXPECT_CALL(gatt_queue,
1720 WriteCharacteristic(leAudioDevice->conn_id_,
1721 leAudioDevice->ctp_hdls_.val_hdl, _,
1722 GATT_WRITE_NO_RSP, _, _))
1723 .Times(AtLeast(3));
1724 expected_devices_written++;
1725 leAudioDevice = group->GetNextDevice(leAudioDevice);
1726 }
1727 ASSERT_EQ(expected_devices_written, num_devices);
1728
1729 // Validate GroupStreamStatus
1730 EXPECT_CALL(
1731 mock_callbacks_,
1732 StatusReportCb(leaudio_group_id,
1733 bluetooth::le_audio::GroupStreamStatus::STREAMING));
1734
1735 // Start the configuration and stream Media content
1736 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1737 group, static_cast<LeAudioContextType>(context_type),
1738 types::AudioContexts(context_type)));
1739
1740 testing::Mock::VerifyAndClearExpectations(&gatt_queue);
1741
1742 // Check if group has transitioned to a proper state
1743 ASSERT_EQ(group->GetState(),
1744 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
1745
1746 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
1747 mock_function_count_map["alarm_cancel"] = 0;
1748
1749 // Make sure all devices get the metadata update
1750 leAudioDevice = group->GetFirstDevice();
1751 expected_devices_written = 0;
1752 while (leAudioDevice) {
1753 EXPECT_CALL(gatt_queue,
1754 WriteCharacteristic(leAudioDevice->conn_id_,
1755 leAudioDevice->ctp_hdls_.val_hdl, _,
1756 GATT_WRITE_NO_RSP, _, _))
1757 .Times(1);
1758 expected_devices_written++;
1759 leAudioDevice = group->GetNextDevice(leAudioDevice);
1760 }
1761 ASSERT_EQ(expected_devices_written, num_devices);
1762
1763 const auto metadata_context_type =
1764 kContextTypeMedia | kContextTypeSoundEffects;
1765 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
1766 group, static_cast<LeAudioContextType>(context_type),
1767 metadata_context_type));
1768
1769 /* This is just update metadata - watchdog is not used */
1770 ASSERT_EQ(0, mock_function_count_map["alarm_cancel"]);
1771 }
1772
TEST_F(StateMachineTest,testDisableSingle)1773 TEST_F(StateMachineTest, testDisableSingle) {
1774 /* Device is banded headphones with 2x snk + 0x src ase
1775 * (2xunidirectional CIS)
1776 */
1777 additional_snk_ases = 1;
1778 const auto context_type = kContextTypeRingtone;
1779 const int leaudio_group_id = 4;
1780
1781 // Prepare fake connected device group
1782 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
1783
1784 /* Ringtone context plus additional ASE with channel count 1
1785 * gives us 2 ASE which should have been configured.
1786 */
1787 PrepareConfigureCodecHandler(group, 2);
1788 PrepareConfigureQosHandler(group, 2);
1789 PrepareEnableHandler(group, 2);
1790 PrepareDisableHandler(group, 2);
1791
1792 auto* leAudioDevice = group->GetFirstDevice();
1793 EXPECT_CALL(gatt_queue,
1794 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
1795 GATT_WRITE_NO_RSP, _, _))
1796 .Times(4);
1797
1798 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1799 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
1800 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
1801 EXPECT_CALL(
1802 *mock_iso_manager_,
1803 RemoveIsoDataPath(
1804 _, bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput))
1805 .Times(2);
1806 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
1807 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1808
1809 InjectInitialIdleNotification(group);
1810
1811 EXPECT_CALL(
1812 mock_callbacks_,
1813 StatusReportCb(leaudio_group_id,
1814 bluetooth::le_audio::GroupStreamStatus::STREAMING));
1815
1816 // Start the configuration and stream Media content
1817 LeAudioGroupStateMachine::Get()->StartStream(
1818 group, static_cast<LeAudioContextType>(context_type),
1819 types::AudioContexts(context_type));
1820
1821 // Check if group has transitioned to a proper state
1822 ASSERT_EQ(group->GetState(),
1823 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
1824
1825 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
1826 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
1827 mock_function_count_map["alarm_cancel"] = 0;
1828
1829 // Validate GroupStreamStatus
1830 EXPECT_CALL(
1831 mock_callbacks_,
1832 StatusReportCb(leaudio_group_id,
1833 bluetooth::le_audio::GroupStreamStatus::SUSPENDING));
1834 EXPECT_CALL(
1835 mock_callbacks_,
1836 StatusReportCb(leaudio_group_id,
1837 bluetooth::le_audio::GroupStreamStatus::SUSPENDED));
1838
1839 // Suspend the stream
1840 LeAudioGroupStateMachine::Get()->SuspendStream(group);
1841
1842 // Check if group has transition to a proper state
1843 ASSERT_EQ(group->GetState(),
1844 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
1845
1846 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
1847 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
1848 }
1849
TEST_F(StateMachineTest,testDisableMultiple)1850 TEST_F(StateMachineTest, testDisableMultiple) {
1851 const auto context_type = kContextTypeMedia;
1852 const auto leaudio_group_id = 4;
1853 const auto num_devices = 2;
1854
1855 // Prepare multiple fake connected devices in a group
1856 auto* group =
1857 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
1858 ASSERT_EQ(group->Size(), num_devices);
1859
1860 PrepareConfigureCodecHandler(group);
1861 PrepareConfigureQosHandler(group);
1862 PrepareEnableHandler(group);
1863 PrepareDisableHandler(group);
1864
1865 auto* leAudioDevice = group->GetFirstDevice();
1866 auto expected_devices_written = 0;
1867 while (leAudioDevice) {
1868 EXPECT_CALL(gatt_queue,
1869 WriteCharacteristic(leAudioDevice->conn_id_,
1870 leAudioDevice->ctp_hdls_.val_hdl, _,
1871 GATT_WRITE_NO_RSP, _, _))
1872 .Times(AtLeast(4));
1873 expected_devices_written++;
1874 leAudioDevice = group->GetNextDevice(leAudioDevice);
1875 }
1876 ASSERT_EQ(expected_devices_written, num_devices);
1877
1878 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1879 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
1880 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
1881 EXPECT_CALL(
1882 *mock_iso_manager_,
1883 RemoveIsoDataPath(
1884 _, bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput))
1885 .Times(2);
1886 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
1887 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1888
1889 InjectInitialIdleNotification(group);
1890
1891 // Start the configuration and stream Media content
1892 LeAudioGroupStateMachine::Get()->StartStream(
1893 group, static_cast<LeAudioContextType>(context_type),
1894 types::AudioContexts(context_type));
1895
1896 // Check if group has transitioned to a proper state
1897 ASSERT_EQ(group->GetState(),
1898 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
1899 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
1900 mock_function_count_map["alarm_cancel"] = 0;
1901
1902 // Validate GroupStreamStatus
1903 EXPECT_CALL(
1904 mock_callbacks_,
1905 StatusReportCb(leaudio_group_id,
1906 bluetooth::le_audio::GroupStreamStatus::SUSPENDING));
1907 EXPECT_CALL(
1908 mock_callbacks_,
1909 StatusReportCb(leaudio_group_id,
1910 bluetooth::le_audio::GroupStreamStatus::SUSPENDED));
1911
1912 // Suspend the stream
1913 LeAudioGroupStateMachine::Get()->SuspendStream(group);
1914
1915 // Check if group has transitioned to a proper state
1916 ASSERT_EQ(group->GetState(),
1917 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
1918 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
1919 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
1920 }
1921
TEST_F(StateMachineTest,testDisableBidirectional)1922 TEST_F(StateMachineTest, testDisableBidirectional) {
1923 /* Device is banded headphones with 2x snk + 1x src ase
1924 * (1x bidirectional + 1xunidirectional CIS)
1925 */
1926 additional_snk_ases = 1;
1927 const auto context_type = kContextTypeConversational;
1928 const int leaudio_group_id = 4;
1929
1930 // Prepare fake connected device group
1931 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
1932
1933 /* Since we prepared device with Conversional context in mind, Sink and Source
1934 * ASEs should have been configured.
1935 */
1936 PrepareConfigureCodecHandler(group, 3);
1937 PrepareConfigureQosHandler(group, 3);
1938 PrepareEnableHandler(group, 3);
1939 PrepareDisableHandler(group, 3);
1940 PrepareReceiverStartReady(group, 1);
1941 PrepareReceiverStopReady(group, 1);
1942
1943 auto* leAudioDevice = group->GetFirstDevice();
1944 EXPECT_CALL(gatt_queue,
1945 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
1946 GATT_WRITE_NO_RSP, _, _))
1947 .Times(AtLeast(4));
1948
1949 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
1950 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
1951 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
1952 bool removed_bidirectional = false;
1953 bool removed_unidirectional = false;
1954
1955 /* Check data path removal */
1956 ON_CALL(*mock_iso_manager_, RemoveIsoDataPath)
1957 .WillByDefault(Invoke([&removed_bidirectional, &removed_unidirectional,
1958 this](uint16_t conn_handle,
1959 uint8_t data_path_dir) {
1960 /* Set flags for verification */
1961 if (data_path_dir ==
1962 (bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput |
1963 bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput)) {
1964 removed_bidirectional = true;
1965 } else if (data_path_dir == bluetooth::hci::iso_manager::
1966 kRemoveIsoDataPathDirectionInput) {
1967 removed_unidirectional = true;
1968 }
1969
1970 /* Copied from default handler of RemoveIsoDataPath*/
1971 auto dev_it =
1972 std::find_if(le_audio_devices_.begin(), le_audio_devices_.end(),
1973 [&conn_handle](auto& dev) {
1974 auto ases = dev->GetAsesByCisConnHdl(conn_handle);
1975 return (ases.sink || ases.source);
1976 });
1977 if (dev_it == le_audio_devices_.end()) {
1978 return;
1979 }
1980
1981 for (auto& kv_pair : le_audio_device_groups_) {
1982 auto& group = kv_pair.second;
1983 if (group->IsDeviceInTheGroup(dev_it->get())) {
1984 LeAudioGroupStateMachine::Get()->ProcessHciNotifRemoveIsoDataPath(
1985 group.get(), dev_it->get(), 0, conn_handle);
1986 return;
1987 }
1988 }
1989 /* End of copy */
1990 }));
1991
1992 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
1993 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
1994
1995 // Start the configuration and stream Media content
1996 LeAudioGroupStateMachine::Get()->StartStream(
1997 group, static_cast<LeAudioContextType>(context_type),
1998 types::AudioContexts(context_type));
1999
2000 // Check if group has transitioned to a proper state
2001 ASSERT_EQ(group->GetState(),
2002 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2003
2004 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2005 mock_function_count_map["alarm_cancel"] = 0;
2006
2007 // Validate GroupStreamStatus
2008 EXPECT_CALL(
2009 mock_callbacks_,
2010 StatusReportCb(leaudio_group_id,
2011 bluetooth::le_audio::GroupStreamStatus::SUSPENDING));
2012 EXPECT_CALL(
2013 mock_callbacks_,
2014 StatusReportCb(leaudio_group_id,
2015 bluetooth::le_audio::GroupStreamStatus::SUSPENDED));
2016
2017 // Suspend the stream
2018 LeAudioGroupStateMachine::Get()->SuspendStream(group);
2019
2020 // Check if group has transitioned to a proper state
2021 ASSERT_EQ(group->GetState(),
2022 types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
2023 ASSERT_EQ(removed_bidirectional, true);
2024 ASSERT_EQ(removed_unidirectional, true);
2025
2026 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
2027 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2028 }
2029
TEST_F(StateMachineTest,testReleaseSingle)2030 TEST_F(StateMachineTest, testReleaseSingle) {
2031 /* Device is banded headphones with 1x snk + 0x src ase
2032 * (1xunidirectional CIS) with channel count 2 (for stereo)
2033 */
2034 const auto context_type = kContextTypeRingtone;
2035 const int leaudio_group_id = 4;
2036 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
2037 kLeAudioCodecLC3ChannelCountTwoChannel;
2038
2039 // Prepare fake connected device group
2040 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2041
2042 /* Since we prepared device with Ringtone context in mind, only one ASE
2043 * should have been configured.
2044 */
2045 PrepareConfigureCodecHandler(group, 1);
2046 PrepareConfigureQosHandler(group, 1);
2047 PrepareEnableHandler(group, 1);
2048 PrepareDisableHandler(group, 1);
2049 PrepareReleaseHandler(group, 1);
2050
2051 auto* leAudioDevice = group->GetFirstDevice();
2052 EXPECT_CALL(gatt_queue,
2053 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2054 GATT_WRITE_NO_RSP, _, _))
2055 .Times(4);
2056
2057 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2058 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
2059 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
2060 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1);
2061 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
2062 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2063
2064 InjectInitialIdleNotification(group);
2065
2066 // Start the configuration and stream Media content
2067 LeAudioGroupStateMachine::Get()->StartStream(
2068 group, static_cast<LeAudioContextType>(context_type),
2069 types::AudioContexts(context_type));
2070
2071 // Check if group has transitioned to a proper state
2072 ASSERT_EQ(group->GetState(),
2073 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2074 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2075 mock_function_count_map["alarm_cancel"] = 0;
2076 // Validate GroupStreamStatus
2077 EXPECT_CALL(
2078 mock_callbacks_,
2079 StatusReportCb(leaudio_group_id,
2080 bluetooth::le_audio::GroupStreamStatus::RELEASING));
2081 EXPECT_CALL(mock_callbacks_,
2082 StatusReportCb(leaudio_group_id,
2083 bluetooth::le_audio::GroupStreamStatus::IDLE));
2084
2085 // Stop the stream
2086 LeAudioGroupStateMachine::Get()->StopStream(group);
2087
2088 // Check if group has transitioned to a proper state
2089 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2090 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2091 }
2092
TEST_F(StateMachineTest,testReleaseCachingSingle)2093 TEST_F(StateMachineTest, testReleaseCachingSingle) {
2094 /* Device is banded headphones with 1x snk + 0x src ase
2095 * (1xunidirectional CIS)
2096 */
2097 const auto context_type = kContextTypeRingtone;
2098 const int leaudio_group_id = 4;
2099 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
2100 kLeAudioCodecLC3ChannelCountTwoChannel;
2101
2102 // Prepare fake connected device group
2103 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2104
2105 /* Since we prepared device with Ringtone context in mind, only one ASE
2106 * should have been configured.
2107 */
2108 PrepareConfigureCodecHandler(group, 1, true);
2109 PrepareConfigureQosHandler(group, 1);
2110 PrepareEnableHandler(group, 1);
2111 PrepareDisableHandler(group, 1);
2112 PrepareReleaseHandler(group, 1);
2113
2114 auto* leAudioDevice = group->GetFirstDevice();
2115 EXPECT_CALL(gatt_queue,
2116 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2117 GATT_WRITE_NO_RSP, _, _))
2118 .Times(4);
2119
2120 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2121 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
2122 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
2123 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1);
2124 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
2125 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2126
2127 InjectInitialIdleNotification(group);
2128
2129 // Validate GroupStreamStatus
2130 EXPECT_CALL(
2131 mock_callbacks_,
2132 StatusReportCb(leaudio_group_id,
2133 bluetooth::le_audio::GroupStreamStatus::RELEASING));
2134
2135 EXPECT_CALL(
2136 mock_callbacks_,
2137 StatusReportCb(
2138 leaudio_group_id,
2139 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
2140 EXPECT_CALL(
2141 mock_callbacks_,
2142 StatusReportCb(leaudio_group_id,
2143 bluetooth::le_audio::GroupStreamStatus::STREAMING));
2144
2145 // Start the configuration and stream Media content
2146 LeAudioGroupStateMachine::Get()->StartStream(
2147 group, static_cast<LeAudioContextType>(context_type),
2148 types::AudioContexts(context_type));
2149
2150 // Check if group has transitioned to a proper state
2151 ASSERT_EQ(group->GetState(),
2152 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2153
2154 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2155 mock_function_count_map["alarm_cancel"] = 0;
2156
2157 // Stop the stream
2158 LeAudioGroupStateMachine::Get()->StopStream(group);
2159
2160 // Check if group has transitioned to a proper state
2161 ASSERT_EQ(group->GetState(),
2162 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
2163
2164 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2165 }
2166
TEST_F(StateMachineTest,testStreamCaching_NoReconfigurationNeeded_SingleDevice)2167 TEST_F(StateMachineTest,
2168 testStreamCaching_NoReconfigurationNeeded_SingleDevice) {
2169 const auto context_type = kContextTypeRingtone;
2170 const int leaudio_group_id = 4;
2171 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
2172 kLeAudioCodecLC3ChannelCountTwoChannel;
2173
2174 additional_snk_ases = 2;
2175 // Prepare fake connected device group
2176 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2177
2178 /* Since we prepared device with Ringtone context in mind and with no Source
2179 * ASEs, therefor only one ASE should have been configured.
2180 */
2181 PrepareConfigureCodecHandler(group, 1, true);
2182 PrepareConfigureQosHandler(group, 1, true);
2183 PrepareEnableHandler(group, 1);
2184 PrepareDisableHandler(group, 1);
2185 PrepareReleaseHandler(group, 1);
2186
2187 /* Ctp messages we expect:
2188 * 1. Codec Config
2189 * 2. QoS Config
2190 * 3. Enable
2191 * 4. Release
2192 * 5. QoS Config (because device stays in Configured state)
2193 * 6. Enable
2194 */
2195 auto* leAudioDevice = group->GetFirstDevice();
2196 EXPECT_CALL(gatt_queue,
2197 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2198 GATT_WRITE_NO_RSP, _, _))
2199 .Times(6);
2200
2201 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2);
2202 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2);
2203 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
2204 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(1);
2205 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
2206 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2207
2208 InjectInitialIdleNotification(group);
2209
2210 // Validate GroupStreamStatus
2211 EXPECT_CALL(
2212 mock_callbacks_,
2213 StatusReportCb(leaudio_group_id,
2214 bluetooth::le_audio::GroupStreamStatus::RELEASING));
2215
2216 EXPECT_CALL(
2217 mock_callbacks_,
2218 StatusReportCb(
2219 leaudio_group_id,
2220 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
2221
2222 EXPECT_CALL(mock_callbacks_,
2223 StatusReportCb(leaudio_group_id,
2224 bluetooth::le_audio::GroupStreamStatus::STREAMING))
2225 .Times(2);
2226
2227 // Start the configuration and stream Ringtone content
2228 LeAudioGroupStateMachine::Get()->StartStream(
2229 group, static_cast<LeAudioContextType>(context_type),
2230 types::AudioContexts(context_type));
2231
2232 // Check if group has transitioned to a proper state
2233 ASSERT_EQ(group->GetState(),
2234 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2235
2236 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2237 mock_function_count_map["alarm_cancel"] = 0;
2238
2239 // Stop the stream
2240 LeAudioGroupStateMachine::Get()->StopStream(group);
2241
2242 // Check if group has transitioned to a proper state
2243 ASSERT_EQ(group->GetState(),
2244 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
2245
2246 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2247 mock_function_count_map["alarm_cancel"] = 0;
2248
2249 // Start the configuration and stream Media content
2250 LeAudioGroupStateMachine::Get()->StartStream(
2251 group, static_cast<LeAudioContextType>(context_type),
2252 types::AudioContexts(context_type));
2253
2254 // Check if group has transitioned to a proper state
2255 ASSERT_EQ(group->GetState(),
2256 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2257
2258 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2259 mock_function_count_map["alarm_cancel"] = 0;
2260 }
2261
TEST_F(StateMachineTest,test_StreamCaching_ReconfigureForContextChange_SingleDevice)2262 TEST_F(StateMachineTest,
2263 test_StreamCaching_ReconfigureForContextChange_SingleDevice) {
2264 auto context_type = kContextTypeConversational;
2265 const int leaudio_group_id = 4;
2266 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
2267 kLeAudioCodecLC3ChannelCountTwoChannel;
2268
2269 additional_snk_ases = 2;
2270 /* Prepare fake connected device group with update of Media and Conversational
2271 * contexts
2272 */
2273 auto* group = PrepareSingleTestDeviceGroup(
2274 leaudio_group_id, context_type, 1,
2275 kContextTypeConversational | kContextTypeMedia);
2276
2277 /* Don't validate ASE here, as after reconfiguration different ASE number
2278 * will be used.
2279 * For the first configuration (CONVERSTATIONAL) there will be 2 ASEs (Sink
2280 * and Source) After reconfiguration (MEDIA) there will be single ASE.
2281 */
2282 PrepareConfigureCodecHandler(group, 0, true);
2283 PrepareConfigureQosHandler(group, 0, true);
2284 PrepareEnableHandler(group);
2285 PrepareReceiverStartReady(group);
2286 PrepareReleaseHandler(group);
2287
2288 /* Ctp messages we expect:
2289 * 1. Codec Config
2290 * 2. QoS Config
2291 * 3. Enable
2292 * 4. Release
2293 * 5. Codec Config
2294 * 6. QoS Config
2295 * 7. Enable
2296 */
2297 auto* leAudioDevice = group->GetFirstDevice();
2298 EXPECT_CALL(gatt_queue,
2299 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2300 GATT_WRITE_NO_RSP, _, _))
2301 .Times(8);
2302
2303 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2);
2304 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2);
2305
2306 /* 2 times for first configuration (1 Sink, 1 Source), 1 time for second
2307 * configuration (1 Sink)*/
2308 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
2309
2310 uint8_t value =
2311 bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput |
2312 bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput;
2313 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, value)).Times(1);
2314 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
2315 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2316
2317 InjectInitialIdleNotification(group);
2318
2319 // Validate GroupStreamStatus
2320 EXPECT_CALL(
2321 mock_callbacks_,
2322 StatusReportCb(leaudio_group_id,
2323 bluetooth::le_audio::GroupStreamStatus::RELEASING));
2324
2325 EXPECT_CALL(
2326 mock_callbacks_,
2327 StatusReportCb(
2328 leaudio_group_id,
2329 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
2330
2331 EXPECT_CALL(mock_callbacks_,
2332 StatusReportCb(leaudio_group_id,
2333 bluetooth::le_audio::GroupStreamStatus::STREAMING))
2334 .Times(2);
2335
2336 // Start the configuration and stream Conversational content
2337 LeAudioGroupStateMachine::Get()->StartStream(
2338 group, static_cast<LeAudioContextType>(context_type),
2339 types::AudioContexts(context_type));
2340
2341 // Check if group has transitioned to a proper state
2342 ASSERT_EQ(group->GetState(),
2343 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2344
2345 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2346 mock_function_count_map["alarm_cancel"] = 0;
2347
2348 // Stop the stream
2349 LeAudioGroupStateMachine::Get()->StopStream(group);
2350
2351 // Check if group has transitioned to a proper state
2352 ASSERT_EQ(group->GetState(),
2353 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
2354
2355 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2356 mock_function_count_map["alarm_cancel"] = 0;
2357
2358 // Start the configuration and stream Media content
2359 context_type = kContextTypeMedia;
2360 LeAudioGroupStateMachine::Get()->StartStream(
2361 group, static_cast<LeAudioContextType>(context_type),
2362 types::AudioContexts(context_type));
2363
2364 // Check if group has transitioned to a proper state
2365 ASSERT_EQ(group->GetState(),
2366 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2367 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2368 }
2369
TEST_F(StateMachineTest,testReleaseMultiple)2370 TEST_F(StateMachineTest, testReleaseMultiple) {
2371 const auto context_type = kContextTypeMedia;
2372 const auto leaudio_group_id = 6;
2373 const auto num_devices = 2;
2374
2375 // Prepare multiple fake connected devices in a group
2376 auto* group =
2377 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
2378 ASSERT_EQ(group->Size(), num_devices);
2379
2380 PrepareConfigureCodecHandler(group);
2381 PrepareConfigureQosHandler(group);
2382 PrepareEnableHandler(group);
2383 PrepareDisableHandler(group);
2384 PrepareReleaseHandler(group);
2385
2386 auto* leAudioDevice = group->GetFirstDevice();
2387 auto expected_devices_written = 0;
2388 while (leAudioDevice) {
2389 EXPECT_CALL(gatt_queue,
2390 WriteCharacteristic(leAudioDevice->conn_id_,
2391 leAudioDevice->ctp_hdls_.val_hdl, _,
2392 GATT_WRITE_NO_RSP, _, _))
2393 .Times(AtLeast(4));
2394 expected_devices_written++;
2395 leAudioDevice = group->GetNextDevice(leAudioDevice);
2396 }
2397 ASSERT_EQ(expected_devices_written, num_devices);
2398
2399 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2400 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
2401 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
2402 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2);
2403 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
2404 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2405
2406 InjectInitialIdleNotification(group);
2407
2408 // Start the configuration and stream Media content
2409 LeAudioGroupStateMachine::Get()->StartStream(
2410 group, static_cast<LeAudioContextType>(context_type),
2411 types::AudioContexts(context_type));
2412
2413 // Check if group has transitioned to a proper state
2414 ASSERT_EQ(group->GetState(),
2415 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2416
2417 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2418 mock_function_count_map["alarm_cancel"] = 0;
2419
2420 // Validate GroupStreamStatus
2421 EXPECT_CALL(
2422 mock_callbacks_,
2423 StatusReportCb(leaudio_group_id,
2424 bluetooth::le_audio::GroupStreamStatus::RELEASING));
2425 EXPECT_CALL(mock_callbacks_,
2426 StatusReportCb(leaudio_group_id,
2427 bluetooth::le_audio::GroupStreamStatus::IDLE));
2428
2429 // Stop the stream
2430 LeAudioGroupStateMachine::Get()->StopStream(group);
2431
2432 // Check if group has transitioned to a proper state
2433 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2434 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2435 }
2436
TEST_F(StateMachineTest,testReleaseBidirectional)2437 TEST_F(StateMachineTest, testReleaseBidirectional) {
2438 /* Device is banded headphones with 2x snk + 1x src ase
2439 * (1x bidirectional + 1xunidirectional CIS)
2440 */
2441 additional_snk_ases = 1;
2442 const auto context_type = kContextTypeConversational;
2443 const auto leaudio_group_id = 6;
2444
2445 // Prepare fake connected device group
2446 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2447
2448 /* Since we prepared device with Conversional context in mind, Sink and Source
2449 * ASEs should have been configured.
2450 */
2451 PrepareConfigureCodecHandler(group, 3);
2452 PrepareConfigureQosHandler(group, 3);
2453 PrepareEnableHandler(group, 3);
2454 PrepareDisableHandler(group, 3);
2455 PrepareReceiverStartReady(group, 1);
2456 PrepareReleaseHandler(group, 3);
2457
2458 auto* leAudioDevice = group->GetFirstDevice();
2459 EXPECT_CALL(gatt_queue,
2460 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2461 GATT_WRITE_NO_RSP, _, _))
2462 .Times(AtLeast(4));
2463
2464 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2465 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
2466 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
2467 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2);
2468 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
2469 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2470
2471 InjectInitialIdleNotification(group);
2472
2473 // Start the configuration and stream Media content
2474 LeAudioGroupStateMachine::Get()->StartStream(
2475 group, static_cast<LeAudioContextType>(context_type),
2476 types::AudioContexts(context_type));
2477
2478 // Check if group has transitioned to a proper state
2479 ASSERT_EQ(group->GetState(),
2480 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2481
2482 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2483 mock_function_count_map["alarm_cancel"] = 0;
2484
2485 // Stop the stream
2486 LeAudioGroupStateMachine::Get()->StopStream(group);
2487
2488 // Check if group has transitioned to a proper state
2489 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2490 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2491 mock_function_count_map["alarm_cancel"] = 0;
2492 }
2493
TEST_F(StateMachineTest,testDisableAndReleaseBidirectional)2494 TEST_F(StateMachineTest, testDisableAndReleaseBidirectional) {
2495 /* Device is banded headphones with 2x snk + 1x src ase
2496 * (1x bidirectional + 1xunidirectional CIS)
2497 */
2498 additional_snk_ases = 1;
2499 const auto context_type = kContextTypeConversational;
2500 const int leaudio_group_id = 4;
2501
2502 // Prepare fake connected device group
2503 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2504
2505 /* Since we prepared device with Conversional context in mind, Sink and Source
2506 * ASEs should have been configured.
2507 */
2508 PrepareConfigureCodecHandler(group, 3);
2509 PrepareConfigureQosHandler(group, 3);
2510 PrepareEnableHandler(group, 3);
2511 PrepareDisableHandler(group, 3);
2512 PrepareReceiverStartReady(group, 1);
2513 PrepareReceiverStopReady(group, 1);
2514 PrepareReleaseHandler(group, 3);
2515
2516 auto* leAudioDevice = group->GetFirstDevice();
2517 EXPECT_CALL(gatt_queue,
2518 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2519 GATT_WRITE_NO_RSP, _, _))
2520 .Times(AtLeast(4));
2521
2522 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
2523 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
2524 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(3);
2525 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(2);
2526 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
2527 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
2528
2529 // Start the configuration and stream Media content
2530 LeAudioGroupStateMachine::Get()->StartStream(
2531 group, static_cast<LeAudioContextType>(context_type),
2532 types::AudioContexts(context_type));
2533
2534 // Suspend the stream
2535 LeAudioGroupStateMachine::Get()->SuspendStream(group);
2536
2537 // Stop the stream
2538 LeAudioGroupStateMachine::Get()->StopStream(group);
2539
2540 // Check if group has transitioned to a proper state
2541 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2542 }
2543
TEST_F(StateMachineTest,testAseIdAssignmentIdle)2544 TEST_F(StateMachineTest, testAseIdAssignmentIdle) {
2545 const auto context_type = kContextTypeConversational;
2546 const auto leaudio_group_id = 6;
2547 const auto num_devices = 1;
2548
2549 // Prepare multiple fake connected devices in a group
2550 auto* group =
2551 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
2552 ASSERT_EQ(group->Size(), num_devices);
2553
2554 // Should not trigger any action on our side
2555 EXPECT_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _)).Times(0);
2556 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0);
2557 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
2558 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
2559 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2560 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2561 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
2562
2563 for (auto* device = group->GetFirstDevice(); device != nullptr;
2564 device = group->GetNextDevice(device)) {
2565 for (auto& ase : device->ases_) {
2566 ASSERT_EQ(ase.id, le_audio::types::ase::kAseIdInvalid);
2567 InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle,
2568 nullptr);
2569 ASSERT_EQ(ase.id, ase_id_last_assigned);
2570 }
2571 }
2572 }
2573
TEST_F(StateMachineTest,testAseIdAssignmentCodecConfigured)2574 TEST_F(StateMachineTest, testAseIdAssignmentCodecConfigured) {
2575 const auto context_type = kContextTypeConversational;
2576 const auto leaudio_group_id = 6;
2577 const auto num_devices = 1;
2578
2579 // Prepare multiple fake connected devices in a group
2580 auto* group =
2581 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
2582 ASSERT_EQ(group->Size(), num_devices);
2583
2584 // Should not trigger any action on our side
2585 EXPECT_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _)).Times(0);
2586 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0);
2587 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0);
2588 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0);
2589 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
2590 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
2591 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0);
2592
2593 for (auto* device = group->GetFirstDevice(); device != nullptr;
2594 device = group->GetNextDevice(device)) {
2595 for (auto& ase : device->ases_) {
2596 client_parser::ascs::ase_codec_configured_state_params
2597 codec_configured_state_params;
2598
2599 ASSERT_EQ(ase.id, le_audio::types::ase::kAseIdInvalid);
2600 InjectAseStateNotification(&ase, device, group,
2601 ascs::kAseStateCodecConfigured,
2602 &codec_configured_state_params);
2603 ASSERT_EQ(ase.id, ase_id_last_assigned);
2604 }
2605 }
2606 }
2607
TEST_F(StateMachineTest,testAseAutonomousRelease)2608 TEST_F(StateMachineTest, testAseAutonomousRelease) {
2609 /* Device is banded headphones with 2x snk + 1x src ase
2610 * (1x bidirectional + 1xunidirectional CIS)
2611 */
2612 additional_snk_ases = 1;
2613 const auto context_type = kContextTypeConversational;
2614 const int leaudio_group_id = 4;
2615
2616 // Prepare fake connected device group
2617 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2618
2619 /* Since we prepared device with Conversional context in mind, Sink and Source
2620 * ASEs should have been configured.
2621 */
2622 PrepareConfigureCodecHandler(group, 3);
2623 PrepareConfigureQosHandler(group, 3);
2624 PrepareEnableHandler(group, 3);
2625 PrepareDisableHandler(group, 3);
2626 PrepareReceiverStartReady(group, 1);
2627 PrepareReceiverStopReady(group, 1);
2628 PrepareReleaseHandler(group, 3);
2629
2630 InjectInitialIdleNotification(group);
2631
2632 // Validate initial GroupStreamStatus
2633 EXPECT_CALL(
2634 mock_callbacks_,
2635 StatusReportCb(leaudio_group_id,
2636 bluetooth::le_audio::GroupStreamStatus::STREAMING));
2637
2638 // Start the configuration and stream Media content
2639 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2640 group, static_cast<LeAudioContextType>(context_type),
2641 types::AudioContexts(context_type)));
2642
2643 // Validate new GroupStreamStatus
2644 EXPECT_CALL(mock_callbacks_,
2645 StatusReportCb(leaudio_group_id,
2646 bluetooth::le_audio::GroupStreamStatus::IDLE))
2647 .Times(AtLeast(1));
2648
2649 /* Single disconnect as it is bidirectional Cis*/
2650 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2);
2651
2652 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
2653 mock_function_count_map["alarm_cancel"] = 0;
2654
2655 for (auto* device = group->GetFirstDevice(); device != nullptr;
2656 device = group->GetNextDevice(device)) {
2657 for (auto& ase : device->ases_) {
2658 client_parser::ascs::ase_codec_configured_state_params
2659 codec_configured_state_params;
2660
2661 ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2662
2663 // Each one does the autonomous release
2664 InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing,
2665 &codec_configured_state_params);
2666 InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle,
2667 &codec_configured_state_params);
2668 }
2669 }
2670
2671 // Verify we've handled the release and updated all states
2672 for (auto* device = group->GetFirstDevice(); device != nullptr;
2673 device = group->GetNextDevice(device)) {
2674 for (auto& ase : device->ases_) {
2675 ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2676 }
2677 }
2678
2679 ASSERT_EQ(0, mock_function_count_map["alarm_cancel"]);
2680 }
2681
TEST_F(StateMachineTest,testAseAutonomousRelease2Devices)2682 TEST_F(StateMachineTest, testAseAutonomousRelease2Devices) {
2683 const auto context_type = kContextTypeConversational;
2684 const int leaudio_group_id = 4;
2685 const int num_of_devices = 2;
2686
2687 // Prepare fake connected device group
2688 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type,
2689 num_of_devices);
2690
2691 /* Since we prepared device with Conversional context in mind, Sink and Source
2692 * ASEs should have been configured.
2693 */
2694 PrepareConfigureCodecHandler(group);
2695 PrepareConfigureQosHandler(group);
2696 PrepareEnableHandler(group);
2697 PrepareDisableHandler(group);
2698 PrepareReceiverStartReady(group);
2699 PrepareReceiverStopReady(group);
2700 PrepareReleaseHandler(group);
2701
2702 InjectInitialIdleNotification(group);
2703
2704 // Validate initial GroupStreamStatus
2705 EXPECT_CALL(
2706 mock_callbacks_,
2707 StatusReportCb(leaudio_group_id,
2708 bluetooth::le_audio::GroupStreamStatus::STREAMING));
2709
2710 // Start the configuration and stream Media content
2711 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2712 group, static_cast<LeAudioContextType>(context_type),
2713 types::AudioContexts(context_type)));
2714
2715 // Check streaming will continue
2716 EXPECT_CALL(mock_callbacks_,
2717 StatusReportCb(leaudio_group_id,
2718 bluetooth::le_audio::GroupStreamStatus::IDLE))
2719 .Times(0);
2720
2721 /* Single disconnect as it is bidirectional Cis*/
2722 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(1);
2723
2724 auto device = group->GetFirstDevice();
2725 for (auto& ase : device->ases_) {
2726 client_parser::ascs::ase_codec_configured_state_params
2727 codec_configured_state_params;
2728
2729 ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2730
2731 // Simulate autonomus release for one device.
2732 InjectAseStateNotification(&ase, device, group, ascs::kAseStateReleasing,
2733 &codec_configured_state_params);
2734 InjectAseStateNotification(&ase, device, group, ascs::kAseStateIdle,
2735 &codec_configured_state_params);
2736 }
2737 }
2738
TEST_F(StateMachineTest,testStateTransitionTimeoutOnIdleState)2739 TEST_F(StateMachineTest, testStateTransitionTimeoutOnIdleState) {
2740 const auto context_type = kContextTypeRingtone;
2741 const int leaudio_group_id = 4;
2742 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
2743 kLeAudioCodecLC3ChannelCountTwoChannel;
2744
2745 // Prepare fake connected device group
2746 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2747
2748 auto* leAudioDevice = group->GetFirstDevice();
2749 EXPECT_CALL(gatt_queue,
2750 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2751 GATT_WRITE_NO_RSP, _, _))
2752 .Times(1);
2753
2754 // Start the configuration and stream Media content
2755 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2756 group, static_cast<LeAudioContextType>(context_type),
2757 types::AudioContexts(context_type)));
2758
2759 // Disconnect device
2760 LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected(
2761 group, leAudioDevice);
2762
2763 // Make sure timeout is cleared
2764 ASSERT_TRUE(fake_osi_alarm_set_on_mloop_.cb == nullptr);
2765 }
2766
TEST_F(StateMachineTest,testStateTransitionTimeout)2767 TEST_F(StateMachineTest, testStateTransitionTimeout) {
2768 const auto context_type = kContextTypeRingtone;
2769 const int leaudio_group_id = 4;
2770 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
2771 kLeAudioCodecLC3ChannelCountTwoChannel;
2772
2773 // Prepare fake connected device group
2774 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2775
2776 /* Since we prepared device with Ringtone context in mind, only one ASE
2777 * should have been configured.
2778 */
2779 PrepareConfigureCodecHandler(group, 1);
2780 PrepareConfigureQosHandler(group, 1);
2781
2782 auto* leAudioDevice = group->GetFirstDevice();
2783 EXPECT_CALL(gatt_queue,
2784 WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _,
2785 GATT_WRITE_NO_RSP, _, _))
2786 .Times(3);
2787
2788 // Start the configuration and stream Media content
2789 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2790 group, static_cast<LeAudioContextType>(context_type),
2791 types::AudioContexts(context_type)));
2792
2793 // Check if timeout is fired
2794 EXPECT_CALL(mock_callbacks_, OnStateTransitionTimeout(leaudio_group_id));
2795
2796 // simulate timeout seconds passed, alarm executing
2797 fake_osi_alarm_set_on_mloop_.cb(fake_osi_alarm_set_on_mloop_.data);
2798 ASSERT_EQ(1, mock_function_count_map["alarm_set_on_mloop"]);
2799 }
2800
2801 MATCHER_P(dataPathIsEq, expected, "") { return (arg.data_path_id == expected); }
2802
TEST_F(StateMachineTest,testConfigureDataPathForHost)2803 TEST_F(StateMachineTest, testConfigureDataPathForHost) {
2804 const auto context_type = kContextTypeRingtone;
2805 const int leaudio_group_id = 4;
2806 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
2807 kLeAudioCodecLC3ChannelCountTwoChannel;
2808
2809 /* Should be called 3 times because
2810 * 1 - calling GetConfigurations just after connection
2811 * (UpdateAudioContextTypeAvailability)
2812 * 2 - when doing configuration of the context type
2813 * 3 - AddCisToStreamConfiguration -> CreateStreamVectorForOffloader
2814 * 4 - Data Path
2815 */
2816 EXPECT_CALL(*mock_codec_manager_, GetCodecLocation())
2817 .Times(4)
2818 .WillRepeatedly(Return(types::CodecLocation::HOST));
2819
2820 // Prepare fake connected device group
2821 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2822
2823 /* Since we prepared device with Ringtone context in mind, only one ASE
2824 * should have been configured.
2825 */
2826 PrepareConfigureCodecHandler(group, 1);
2827 PrepareConfigureQosHandler(group, 1);
2828 PrepareEnableHandler(group, 1);
2829
2830 EXPECT_CALL(
2831 *mock_iso_manager_,
2832 SetupIsoDataPath(
2833 _, dataPathIsEq(bluetooth::hci::iso_manager::kIsoDataPathHci)))
2834 .Times(1);
2835
2836 InjectInitialIdleNotification(group);
2837
2838 // Start the configuration and stream Media content
2839 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2840 group, static_cast<LeAudioContextType>(context_type),
2841 types::AudioContexts(context_type)));
2842 }
TEST_F(StateMachineTest,testConfigureDataPathForAdsp)2843 TEST_F(StateMachineTest, testConfigureDataPathForAdsp) {
2844 const auto context_type = kContextTypeRingtone;
2845 const int leaudio_group_id = 4;
2846 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
2847 kLeAudioCodecLC3ChannelCountTwoChannel;
2848
2849 /* Should be called 3 times because
2850 * 1 - calling GetConfigurations just after connection
2851 * (UpdateAudioContextTypeAvailability)
2852 * 2 - when doing configuration of the context type
2853 * 3 - AddCisToStreamConfiguration -> CreateStreamVectorForOffloader
2854 * 4 - data path
2855 */
2856 EXPECT_CALL(*mock_codec_manager_, GetCodecLocation())
2857 .Times(4)
2858 .WillRepeatedly(Return(types::CodecLocation::ADSP));
2859
2860 // Prepare fake connected device group
2861 auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type);
2862
2863 /* Since we prepared device with Ringtone context in mind, only one ASE
2864 * should have been configured.
2865 */
2866 PrepareConfigureCodecHandler(group, 1);
2867 PrepareConfigureQosHandler(group, 1);
2868 PrepareEnableHandler(group, 1);
2869
2870 EXPECT_CALL(
2871 *mock_iso_manager_,
2872 SetupIsoDataPath(
2873 _, dataPathIsEq(
2874 bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault)))
2875 .Times(1);
2876
2877 InjectInitialIdleNotification(group);
2878
2879 // Start the configuration and stream Media content
2880 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2881 group, static_cast<LeAudioContextType>(context_type),
2882 types::AudioContexts(context_type)));
2883 }
2884
InjectAclDisconnected(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)2885 static void InjectAclDisconnected(LeAudioDeviceGroup* group,
2886 LeAudioDevice* leAudioDevice) {
2887 LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected(
2888 group, leAudioDevice);
2889 }
2890
TEST_F(StateMachineTest,testStreamConfigurationAdspDownMix)2891 TEST_F(StateMachineTest, testStreamConfigurationAdspDownMix) {
2892 const auto context_type = kContextTypeConversational;
2893 const int leaudio_group_id = 4;
2894 const int num_devices = 2;
2895
2896 // Prepare fake connected device group
2897 auto* group = PrepareSingleTestDeviceGroup(
2898 leaudio_group_id, context_type, num_devices,
2899 types::AudioContexts(kContextTypeConversational));
2900
2901 /* Should be called 5 times because
2902 * 1 - calling GetConfigurations just after connection
2903 * (UpdateAudioContextTypeAvailability),
2904 * 2 - when doing configuration of the context type
2905 * 3 - AddCisToStreamConfiguration -> CreateStreamVectorForOffloader (sink)
2906 * 4 - AddCisToStreamConfiguration -> CreateStreamVectorForOffloader (source)
2907 * 5,6 - Data Path
2908 */
2909 EXPECT_CALL(*mock_codec_manager_, GetCodecLocation())
2910 .Times(6)
2911 .WillRepeatedly(Return(types::CodecLocation::ADSP));
2912
2913 PrepareConfigureCodecHandler(group);
2914 PrepareConfigureQosHandler(group);
2915 PrepareEnableHandler(group);
2916 PrepareReceiverStartReady(group);
2917
2918 InjectInitialIdleNotification(group);
2919
2920 auto* leAudioDevice = group->GetFirstDevice();
2921 InjectAclDisconnected(group, leAudioDevice);
2922
2923 // Start the configuration and stream Media content
2924 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
2925 group, static_cast<LeAudioContextType>(context_type),
2926 types::AudioContexts(context_type)));
2927
2928 ASSERT_EQ(
2929 static_cast<int>(
2930 group->stream_conf.sink_offloader_streams_target_allocation.size()),
2931 2);
2932 ASSERT_EQ(
2933 static_cast<int>(
2934 group->stream_conf.source_offloader_streams_target_allocation.size()),
2935 2);
2936
2937 ASSERT_EQ(
2938 static_cast<int>(
2939 group->stream_conf.sink_offloader_streams_current_allocation.size()),
2940 2);
2941 ASSERT_EQ(
2942 static_cast<int>(group->stream_conf
2943 .source_offloader_streams_current_allocation.size()),
2944 2);
2945
2946 // Check if group has transitioned to a proper state
2947 ASSERT_EQ(group->GetState(),
2948 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2949
2950 uint32_t allocation = 0;
2951 for (const auto& s :
2952 group->stream_conf.sink_offloader_streams_target_allocation) {
2953 allocation |= s.second;
2954 ASSERT_FALSE(allocation == 0);
2955 }
2956 ASSERT_TRUE(allocation == codec_spec_conf::kLeAudioLocationStereo);
2957
2958 allocation = 0;
2959 for (const auto& s :
2960 group->stream_conf.source_offloader_streams_target_allocation) {
2961 allocation |= s.second;
2962 ASSERT_FALSE(allocation == 0);
2963 }
2964 ASSERT_TRUE(allocation == codec_spec_conf::kLeAudioLocationStereo);
2965
2966 for (const auto& s :
2967 group->stream_conf.sink_offloader_streams_current_allocation) {
2968 ASSERT_TRUE((s.second == 0) ||
2969 (s.second == codec_spec_conf::kLeAudioLocationStereo));
2970 }
2971
2972 for (const auto& s :
2973 group->stream_conf.source_offloader_streams_current_allocation) {
2974 ASSERT_TRUE((s.second == 0) ||
2975 (s.second == codec_spec_conf::kLeAudioLocationStereo));
2976 }
2977 }
2978
InjectCisDisconnected(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,uint8_t reason)2979 static void InjectCisDisconnected(LeAudioDeviceGroup* group,
2980 LeAudioDevice* leAudioDevice,
2981 uint8_t reason) {
2982 bluetooth::hci::iso_manager::cis_disconnected_evt event;
2983
2984 for (auto const ase : leAudioDevice->ases_) {
2985 if (ase.data_path_state != types::AudioStreamDataPathState::CIS_ASSIGNED &&
2986 ase.data_path_state != types::AudioStreamDataPathState::IDLE) {
2987 event.reason = reason;
2988 event.cig_id = group->group_id_;
2989 event.cis_conn_hdl = ase.cis_conn_hdl;
2990 LeAudioGroupStateMachine::Get()->ProcessHciNotifCisDisconnected(
2991 group, leAudioDevice, &event);
2992 }
2993 }
2994 }
2995
TEST_F(StateMachineTest,testAttachDeviceToTheStream)2996 TEST_F(StateMachineTest, testAttachDeviceToTheStream) {
2997 const auto context_type = kContextTypeMedia;
2998 const auto leaudio_group_id = 6;
2999 const auto num_devices = 2;
3000
3001 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
3002
3003 // Prepare multiple fake connected devices in a group
3004 auto* group =
3005 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3006 ASSERT_EQ(group->Size(), num_devices);
3007
3008 PrepareConfigureCodecHandler(group);
3009 PrepareConfigureQosHandler(group);
3010 PrepareEnableHandler(group);
3011 PrepareDisableHandler(group);
3012 PrepareReleaseHandler(group);
3013
3014 auto* leAudioDevice = group->GetFirstDevice();
3015 LeAudioDevice* lastDevice;
3016 LeAudioDevice* fistDevice = leAudioDevice;
3017
3018 auto expected_devices_written = 0;
3019 while (leAudioDevice) {
3020 /* Three Writes:
3021 * 1: Codec Config
3022 * 2: Codec QoS
3023 * 3: Enabling
3024 */
3025 lastDevice = leAudioDevice;
3026 EXPECT_CALL(gatt_queue,
3027 WriteCharacteristic(leAudioDevice->conn_id_,
3028 leAudioDevice->ctp_hdls_.val_hdl, _,
3029 GATT_WRITE_NO_RSP, _, _))
3030 .Times(AtLeast(3));
3031 expected_devices_written++;
3032 leAudioDevice = group->GetNextDevice(leAudioDevice);
3033 }
3034 ASSERT_EQ(expected_devices_written, num_devices);
3035
3036 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3037 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3038 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
3039
3040 InjectInitialIdleNotification(group);
3041
3042 // Start the configuration and stream Media content
3043 LeAudioGroupStateMachine::Get()->StartStream(
3044 group, static_cast<LeAudioContextType>(context_type),
3045 types::AudioContexts(context_type));
3046
3047 // Check if group has transitioned to a proper state
3048 ASSERT_EQ(group->GetState(),
3049 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3050 testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
3051
3052 // Inject CIS and ACL disconnection of first device
3053 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
3054 InjectAclDisconnected(group, lastDevice);
3055
3056 // Check if group keeps streaming
3057 ASSERT_EQ(group->GetState(),
3058 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3059
3060 lastDevice->conn_id_ = 3;
3061 group->UpdateAudioContextTypeAvailability();
3062
3063 // Make sure ASE with disconnected CIS are not left in STREAMING
3064 ASSERT_EQ(lastDevice->GetFirstAseWithState(
3065 ::le_audio::types::kLeAudioDirectionSink,
3066 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
3067 nullptr);
3068 ASSERT_EQ(lastDevice->GetFirstAseWithState(
3069 ::le_audio::types::kLeAudioDirectionSource,
3070 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
3071 nullptr);
3072
3073 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
3074 lastDevice->ctp_hdls_.val_hdl, _,
3075 GATT_WRITE_NO_RSP, _, _))
3076 .Times(AtLeast(3));
3077
3078 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3079 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1);
3080 LeAudioGroupStateMachine::Get()->AttachToStream(group, lastDevice);
3081
3082 // Check if group keeps streaming
3083 ASSERT_EQ(group->GetState(),
3084 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3085
3086 // Verify that the joining device receives the right CCID list
3087 auto lastMeta = lastDevice->GetFirstActiveAse()->metadata;
3088 bool parsedOk = false;
3089 auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(),
3090 lastMeta.size(), parsedOk);
3091 ASSERT_TRUE(parsedOk);
3092
3093 auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList);
3094 ASSERT_TRUE(ccids.has_value());
3095 ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end());
3096
3097 /* Verify that ASE of first device are still good*/
3098 auto ase = fistDevice->GetFirstActiveAse();
3099 ASSERT_NE(ase->max_transport_latency, 0);
3100 ASSERT_NE(ase->retrans_nb, 0);
3101 }
3102
TEST_F(StateMachineTest,testAttachDeviceToTheConversationalStream)3103 TEST_F(StateMachineTest, testAttachDeviceToTheConversationalStream) {
3104 const auto context_type = kContextTypeConversational;
3105 const auto leaudio_group_id = 6;
3106 const auto num_devices = 2;
3107
3108 ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
3109
3110 // Prepare multiple fake connected devices in a group
3111 auto* group =
3112 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3113 ASSERT_EQ(group->Size(), num_devices);
3114
3115 PrepareConfigureCodecHandler(group);
3116 PrepareConfigureQosHandler(group);
3117 PrepareEnableHandler(group);
3118 PrepareReceiverStartReady(group);
3119 PrepareDisableHandler(group);
3120 PrepareReleaseHandler(group);
3121
3122 auto* leAudioDevice = group->GetFirstDevice();
3123 LeAudioDevice* lastDevice;
3124 LeAudioDevice* fistDevice = leAudioDevice;
3125
3126 auto expected_devices_written = 0;
3127 while (leAudioDevice) {
3128 /* Three Writes:
3129 * 1: Codec Config
3130 * 2: Codec QoS
3131 * 3: Enabling
3132 */
3133 lastDevice = leAudioDevice;
3134 EXPECT_CALL(gatt_queue,
3135 WriteCharacteristic(leAudioDevice->conn_id_,
3136 leAudioDevice->ctp_hdls_.val_hdl, _,
3137 GATT_WRITE_NO_RSP, _, _))
3138 .Times(AtLeast(3));
3139 expected_devices_written++;
3140 leAudioDevice = group->GetNextDevice(leAudioDevice);
3141 }
3142 ASSERT_EQ(expected_devices_written, num_devices);
3143
3144 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3145 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3146 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4);
3147
3148 InjectInitialIdleNotification(group);
3149
3150 // Start the configuration and stream Conversational content
3151 LeAudioGroupStateMachine::Get()->StartStream(
3152 group, static_cast<LeAudioContextType>(context_type),
3153 types::AudioContexts(context_type));
3154
3155 // Check if group has transitioned to a proper state
3156 ASSERT_EQ(group->GetState(),
3157 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3158 testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
3159
3160 // Inject CIS and ACL disconnection of first device
3161 InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
3162 InjectAclDisconnected(group, lastDevice);
3163
3164 // Check if group keeps streaming
3165 ASSERT_EQ(group->GetState(),
3166 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3167
3168 lastDevice->conn_id_ = 3;
3169 group->UpdateAudioContextTypeAvailability();
3170
3171 // Make sure ASE with disconnected CIS are not left in STREAMING
3172 ASSERT_EQ(lastDevice->GetFirstAseWithState(
3173 ::le_audio::types::kLeAudioDirectionSink,
3174 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
3175 nullptr);
3176 ASSERT_EQ(lastDevice->GetFirstAseWithState(
3177 ::le_audio::types::kLeAudioDirectionSource,
3178 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
3179 nullptr);
3180
3181 EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
3182 lastDevice->ctp_hdls_.val_hdl, _,
3183 GATT_WRITE_NO_RSP, _, _))
3184 .Times(AtLeast(3));
3185
3186 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3187 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
3188 LeAudioGroupStateMachine::Get()->AttachToStream(group, lastDevice);
3189
3190 // Check if group keeps streaming
3191 ASSERT_EQ(group->GetState(),
3192 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3193
3194 // Verify that the joining device receives the right CCID list
3195 auto lastMeta = lastDevice->GetFirstActiveAse()->metadata;
3196 bool parsedOk = false;
3197 auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(),
3198 lastMeta.size(), parsedOk);
3199 ASSERT_TRUE(parsedOk);
3200
3201 auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList);
3202 ASSERT_TRUE(ccids.has_value());
3203 ASSERT_NE(std::find(ccids->begin(), ccids->end(), call_ccid), ccids->end());
3204
3205 /* Verify that ASE of first device are still good*/
3206 auto ase = fistDevice->GetFirstActiveAse();
3207 ASSERT_NE(ase->max_transport_latency, 0);
3208 ASSERT_NE(ase->retrans_nb, 0);
3209
3210 // Make sure ASEs with reconnected CIS are in STREAMING state
3211 ASSERT_TRUE(lastDevice->HaveAllActiveAsesSameState(
3212 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING));
3213 }
3214
TEST_F(StateMachineTest,StartStreamAfterConfigure)3215 TEST_F(StateMachineTest, StartStreamAfterConfigure) {
3216 const auto context_type = kContextTypeMedia;
3217 const auto leaudio_group_id = 6;
3218 const auto num_devices = 2;
3219
3220 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
3221
3222 // Prepare multiple fake connected devices in a group
3223 auto* group =
3224 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3225 ASSERT_EQ(group->Size(), num_devices);
3226
3227 PrepareConfigureCodecHandler(group, 0, true);
3228 PrepareConfigureQosHandler(group);
3229 PrepareEnableHandler(group);
3230 PrepareDisableHandler(group);
3231 PrepareReleaseHandler(group);
3232
3233 InjectInitialIdleNotification(group);
3234
3235 auto* leAudioDevice = group->GetFirstDevice();
3236 auto expected_devices_written = 0;
3237 while (leAudioDevice) {
3238 /* Three Writes:
3239 * 1. Codec configure
3240 * 2: Codec QoS
3241 * 3: Enabling
3242 */
3243 EXPECT_CALL(gatt_queue,
3244 WriteCharacteristic(leAudioDevice->conn_id_,
3245 leAudioDevice->ctp_hdls_.val_hdl, _,
3246 GATT_WRITE_NO_RSP, _, _))
3247 .Times(3);
3248 expected_devices_written++;
3249 leAudioDevice = group->GetNextDevice(leAudioDevice);
3250 }
3251 ASSERT_EQ(expected_devices_written, num_devices);
3252
3253 // Validate GroupStreamStatus
3254 EXPECT_CALL(mock_callbacks_,
3255 StatusReportCb(
3256 leaudio_group_id,
3257 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER));
3258
3259 // Start the configuration and stream Media content
3260 group->SetPendingConfiguration();
3261 LeAudioGroupStateMachine::Get()->ConfigureStream(
3262 group, context_type, types::AudioContexts(context_type));
3263
3264 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3265
3266 group->ClearPendingConfiguration();
3267 // Validate GroupStreamStatus
3268 EXPECT_CALL(
3269 mock_callbacks_,
3270 StatusReportCb(leaudio_group_id,
3271 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3272
3273 // Start the configuration and stream Media content
3274 LeAudioGroupStateMachine::Get()->StartStream(
3275 group, context_type, types::AudioContexts(context_type));
3276
3277 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3278 }
3279
TEST_F(StateMachineTest,StartStreamCachedConfig)3280 TEST_F(StateMachineTest, StartStreamCachedConfig) {
3281 const auto context_type = kContextTypeMedia;
3282 const auto leaudio_group_id = 6;
3283 const auto num_devices = 2;
3284
3285 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
3286
3287 // Prepare multiple fake connected devices in a group
3288 auto* group =
3289 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3290 ASSERT_EQ(group->Size(), num_devices);
3291
3292 PrepareConfigureCodecHandler(group, 0, true);
3293 PrepareConfigureQosHandler(group);
3294 PrepareEnableHandler(group);
3295 PrepareDisableHandler(group);
3296 PrepareReleaseHandler(group);
3297
3298 InjectInitialIdleNotification(group);
3299
3300 auto* leAudioDevice = group->GetFirstDevice();
3301 auto expected_devices_written = 0;
3302 while (leAudioDevice) {
3303 /* Three Writes:
3304 * 1: Codec config
3305 * 2: Codec QoS (+1 after restart)
3306 * 3: Enabling (+1 after restart)
3307 * 4: Release (1)
3308 */
3309 EXPECT_CALL(gatt_queue,
3310 WriteCharacteristic(leAudioDevice->conn_id_,
3311 leAudioDevice->ctp_hdls_.val_hdl, _,
3312 GATT_WRITE_NO_RSP, _, _))
3313 .Times(6);
3314 expected_devices_written++;
3315 leAudioDevice = group->GetNextDevice(leAudioDevice);
3316 }
3317 ASSERT_EQ(expected_devices_written, num_devices);
3318
3319 // Validate GroupStreamStatus
3320 EXPECT_CALL(
3321 mock_callbacks_,
3322 StatusReportCb(leaudio_group_id,
3323 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3324
3325 // Start the configuration and stream Media content
3326 LeAudioGroupStateMachine::Get()->StartStream(
3327 group, context_type, types::AudioContexts(context_type));
3328
3329 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3330
3331 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3332 mock_function_count_map["alarm_cancel"] = 0;
3333
3334 // Validate GroupStreamStatus
3335 EXPECT_CALL(
3336 mock_callbacks_,
3337 StatusReportCb(leaudio_group_id,
3338 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3339
3340 EXPECT_CALL(
3341 mock_callbacks_,
3342 StatusReportCb(
3343 leaudio_group_id,
3344 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
3345 // Start the configuration and stream Media content
3346 LeAudioGroupStateMachine::Get()->StopStream(group);
3347
3348 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3349
3350 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3351 mock_function_count_map["alarm_cancel"] = 0;
3352
3353 // Restart stream
3354 EXPECT_CALL(
3355 mock_callbacks_,
3356 StatusReportCb(leaudio_group_id,
3357 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3358
3359 // Start the configuration and stream Media content
3360 LeAudioGroupStateMachine::Get()->StartStream(
3361 group, context_type, types::AudioContexts(context_type));
3362
3363 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3364 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3365 }
3366
TEST_F(StateMachineTest,BoundedHeadphonesConversationalToMediaChannelCount_2)3367 TEST_F(StateMachineTest, BoundedHeadphonesConversationalToMediaChannelCount_2) {
3368 const auto initial_context_type = kContextTypeConversational;
3369 const auto new_context_type = kContextTypeMedia;
3370 const auto leaudio_group_id = 6;
3371 const auto num_devices = 1;
3372 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel |
3373 kLeAudioCodecLC3ChannelCountTwoChannel;
3374
3375 sample_freq_ |= codec_specific::kCapSamplingFrequency48000Hz |
3376 codec_specific::kCapSamplingFrequency32000Hz;
3377 additional_snk_ases = 3;
3378 additional_src_ases = 1;
3379
3380 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
3381 ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
3382
3383 // Prepare multiple fake connected devices in a group
3384 auto* group = PrepareSingleTestDeviceGroup(
3385 leaudio_group_id, initial_context_type, num_devices,
3386 kContextTypeConversational | kContextTypeMedia);
3387 ASSERT_EQ(group->Size(), num_devices);
3388
3389 PrepareConfigureCodecHandler(group, 0, true);
3390 PrepareConfigureQosHandler(group);
3391 PrepareEnableHandler(group);
3392 PrepareDisableHandler(group);
3393 PrepareReleaseHandler(group);
3394 PrepareReceiverStartReady(group);
3395
3396 InjectInitialIdleNotification(group);
3397
3398 auto* leAudioDevice = group->GetFirstDevice();
3399 auto expected_devices_written = 0;
3400 while (leAudioDevice) {
3401 /* 8 Writes:
3402 * 1: Codec config (+1 after reconfig)
3403 * 2: Codec QoS (+1 after reconfig)
3404 * 3: Enabling (+1 after reconfig)
3405 * 4: ReceiverStartReady (only for conversational)
3406 * 5: Release
3407 */
3408 EXPECT_CALL(gatt_queue,
3409 WriteCharacteristic(leAudioDevice->conn_id_,
3410 leAudioDevice->ctp_hdls_.val_hdl, _,
3411 GATT_WRITE_NO_RSP, _, _))
3412 .Times(8);
3413 expected_devices_written++;
3414 leAudioDevice = group->GetNextDevice(leAudioDevice);
3415 }
3416 ASSERT_EQ(expected_devices_written, num_devices);
3417
3418 // Validate GroupStreamStatus
3419 EXPECT_CALL(
3420 mock_callbacks_,
3421 StatusReportCb(leaudio_group_id,
3422 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3423
3424 // Start the configuration and stream Media content
3425 LeAudioGroupStateMachine::Get()->StartStream(
3426 group, initial_context_type, types::AudioContexts(initial_context_type));
3427
3428 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3429
3430 // Validate GroupStreamStatus
3431 EXPECT_CALL(
3432 mock_callbacks_,
3433 StatusReportCb(leaudio_group_id,
3434 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3435
3436 EXPECT_CALL(
3437 mock_callbacks_,
3438 StatusReportCb(
3439 leaudio_group_id,
3440 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
3441 // Start the configuration and stream Media content
3442 LeAudioGroupStateMachine::Get()->StopStream(group);
3443
3444 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3445
3446 // Restart stream
3447 EXPECT_CALL(
3448 mock_callbacks_,
3449 StatusReportCb(leaudio_group_id,
3450 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3451
3452 // Start the configuration and stream Media content
3453 LeAudioGroupStateMachine::Get()->StartStream(
3454 group, new_context_type, types::AudioContexts(new_context_type));
3455
3456 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3457 }
3458
TEST_F(StateMachineTest,BoundedHeadphonesConversationalToMediaChannelCount_1)3459 TEST_F(StateMachineTest, BoundedHeadphonesConversationalToMediaChannelCount_1) {
3460 const auto initial_context_type = kContextTypeConversational;
3461 const auto new_context_type = kContextTypeMedia;
3462 const auto leaudio_group_id = 6;
3463 const auto num_devices = 1;
3464 channel_count_ = kLeAudioCodecLC3ChannelCountSingleChannel;
3465
3466 sample_freq_ |= codec_specific::kCapSamplingFrequency48000Hz |
3467 codec_specific::kCapSamplingFrequency32000Hz;
3468 additional_snk_ases = 3;
3469 additional_src_ases = 1;
3470
3471 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
3472 ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
3473
3474 // Prepare one fake connected devices in a group
3475 auto* group = PrepareSingleTestDeviceGroup(
3476 leaudio_group_id, initial_context_type, num_devices,
3477 kContextTypeConversational | kContextTypeMedia);
3478 ASSERT_EQ(group->Size(), num_devices);
3479
3480 // Cannot verify here as we will change the number of ases on reconfigure
3481 PrepareConfigureCodecHandler(group, 0, true);
3482 PrepareConfigureQosHandler(group);
3483 PrepareEnableHandler(group);
3484 PrepareDisableHandler(group);
3485 PrepareReleaseHandler(group);
3486 PrepareReceiverStartReady(group);
3487
3488 InjectInitialIdleNotification(group);
3489
3490 auto* leAudioDevice = group->GetFirstDevice();
3491 auto expected_devices_written = 0;
3492 while (leAudioDevice) {
3493 /* 8 Writes:
3494 * 1: Codec config (+1 after reconfig)
3495 * 2: Codec QoS (+1 after reconfig)
3496 * 3: Enabling (+1 after reconfig)
3497 * 4: ReceiverStartReady (only for conversational)
3498 * 5: Release
3499 */
3500 EXPECT_CALL(gatt_queue,
3501 WriteCharacteristic(leAudioDevice->conn_id_,
3502 leAudioDevice->ctp_hdls_.val_hdl, _,
3503 GATT_WRITE_NO_RSP, _, _))
3504 .Times(8);
3505 expected_devices_written++;
3506 leAudioDevice = group->GetNextDevice(leAudioDevice);
3507 }
3508 ASSERT_EQ(expected_devices_written, num_devices);
3509
3510 // Validate GroupStreamStatus
3511 EXPECT_CALL(
3512 mock_callbacks_,
3513 StatusReportCb(leaudio_group_id,
3514 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3515
3516 // Start the configuration and stream Media content
3517 LeAudioGroupStateMachine::Get()->StartStream(
3518 group, initial_context_type, types::AudioContexts(initial_context_type));
3519
3520 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3521
3522 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3523 mock_function_count_map["alarm_cancel"] = 0;
3524
3525 // Validate GroupStreamStatus
3526 EXPECT_CALL(
3527 mock_callbacks_,
3528 StatusReportCb(leaudio_group_id,
3529 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3530
3531 EXPECT_CALL(
3532 mock_callbacks_,
3533 StatusReportCb(
3534 leaudio_group_id,
3535 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
3536 // Start the configuration and stream Media content
3537 LeAudioGroupStateMachine::Get()->StopStream(group);
3538
3539 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3540 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3541 mock_function_count_map["alarm_cancel"] = 0;
3542
3543 // Restart stream
3544 EXPECT_CALL(
3545 mock_callbacks_,
3546 StatusReportCb(leaudio_group_id,
3547 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3548
3549 // Start the configuration and stream Media content
3550 LeAudioGroupStateMachine::Get()->StartStream(
3551 group, new_context_type, types::AudioContexts(new_context_type));
3552
3553 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3554 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3555 }
3556
TEST_F(StateMachineTest,lateCisDisconnectedEvent_ConfiguredByUser)3557 TEST_F(StateMachineTest, lateCisDisconnectedEvent_ConfiguredByUser) {
3558 const auto context_type = kContextTypeMedia;
3559 const auto leaudio_group_id = 6;
3560 const auto num_devices = 1;
3561
3562 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
3563
3564 // Prepare multiple fake connected devices in a group
3565 auto* group =
3566 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3567 ASSERT_EQ(group->Size(), num_devices);
3568
3569 PrepareConfigureCodecHandler(group, 0, true);
3570 PrepareConfigureQosHandler(group);
3571 PrepareEnableHandler(group);
3572 PrepareDisableHandler(group);
3573 PrepareReleaseHandler(group);
3574
3575 auto* leAudioDevice = group->GetFirstDevice();
3576 auto expected_devices_written = 0;
3577
3578 /* Three Writes:
3579 * 1: Codec Config
3580 * 2: Codec QoS
3581 * 3: Enabling
3582 */
3583 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
3584 leAudioDevice->ctp_hdls_.val_hdl,
3585 _, GATT_WRITE_NO_RSP, _, _))
3586 .Times(AtLeast(3));
3587 expected_devices_written++;
3588
3589 ASSERT_EQ(expected_devices_written, num_devices);
3590
3591 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3592 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3593 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
3594
3595 InjectInitialIdleNotification(group);
3596
3597 // Start the configuration and stream Media content
3598 LeAudioGroupStateMachine::Get()->StartStream(
3599 group, static_cast<LeAudioContextType>(context_type),
3600 types::AudioContexts(context_type));
3601
3602 // Check if group has transitioned to a proper state
3603 ASSERT_EQ(group->GetState(),
3604 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3605 testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
3606
3607 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3608 mock_function_count_map["alarm_cancel"] = 0;
3609
3610 /* Prepare DisconnectCis mock to not symulate CisDisconnection */
3611 ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return());
3612
3613 /* Do reconfiguration */
3614 group->SetPendingConfiguration();
3615
3616 // Validate GroupStreamStatus
3617 EXPECT_CALL(
3618 mock_callbacks_,
3619 StatusReportCb(leaudio_group_id,
3620 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3621
3622 EXPECT_CALL(mock_callbacks_,
3623 StatusReportCb(
3624 leaudio_group_id,
3625 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER))
3626 .Times(0);
3627 LeAudioGroupStateMachine::Get()->StopStream(group);
3628
3629 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3630
3631 ASSERT_EQ(0, mock_function_count_map["alarm_cancel"]);
3632
3633 EXPECT_CALL(mock_callbacks_,
3634 StatusReportCb(
3635 leaudio_group_id,
3636 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_BY_USER));
3637
3638 // Inject CIS and ACL disconnection of first device
3639 InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
3640 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3641 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3642 }
3643
TEST_F(StateMachineTest,lateCisDisconnectedEvent_AutonomousConfigured)3644 TEST_F(StateMachineTest, lateCisDisconnectedEvent_AutonomousConfigured) {
3645 const auto context_type = kContextTypeMedia;
3646 const auto leaudio_group_id = 6;
3647 const auto num_devices = 1;
3648
3649 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
3650
3651 // Prepare multiple fake connected devices in a group
3652 auto* group =
3653 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3654 ASSERT_EQ(group->Size(), num_devices);
3655
3656 PrepareConfigureCodecHandler(group, 0, true);
3657 PrepareConfigureQosHandler(group);
3658 PrepareEnableHandler(group);
3659 PrepareDisableHandler(group);
3660 PrepareReleaseHandler(group);
3661
3662 auto* leAudioDevice = group->GetFirstDevice();
3663 auto expected_devices_written = 0;
3664
3665 /* Three Writes:
3666 * 1: Codec Config
3667 * 2: Codec QoS
3668 * 3: Enabling
3669 */
3670 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
3671 leAudioDevice->ctp_hdls_.val_hdl,
3672 _, GATT_WRITE_NO_RSP, _, _))
3673 .Times(AtLeast(3));
3674 expected_devices_written++;
3675
3676 ASSERT_EQ(expected_devices_written, num_devices);
3677
3678 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3679 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3680 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
3681
3682 InjectInitialIdleNotification(group);
3683
3684 // Start the configuration and stream Media content
3685 LeAudioGroupStateMachine::Get()->StartStream(
3686 group, static_cast<LeAudioContextType>(context_type),
3687 types::AudioContexts(context_type));
3688
3689 // Check if group has transitioned to a proper state
3690 ASSERT_EQ(group->GetState(),
3691 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3692 testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
3693
3694 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3695 mock_function_count_map["alarm_cancel"] = 0;
3696
3697 /* Prepare DisconnectCis mock to not symulate CisDisconnection */
3698 ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return());
3699
3700 // Validate GroupStreamStatus
3701 EXPECT_CALL(
3702 mock_callbacks_,
3703 StatusReportCb(leaudio_group_id,
3704 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3705
3706 EXPECT_CALL(
3707 mock_callbacks_,
3708 StatusReportCb(
3709 leaudio_group_id,
3710 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS))
3711 .Times(0);
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(),
3718 types::AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
3719
3720 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3721
3722 ASSERT_EQ(0, mock_function_count_map["alarm_cancel"]);
3723
3724 EXPECT_CALL(
3725 mock_callbacks_,
3726 StatusReportCb(
3727 leaudio_group_id,
3728 bluetooth::le_audio::GroupStreamStatus::CONFIGURED_AUTONOMOUS));
3729
3730 // Inject CIS and ACL disconnection of first device
3731 InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
3732 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3733 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3734 }
3735
TEST_F(StateMachineTest,lateCisDisconnectedEvent_Idle)3736 TEST_F(StateMachineTest, lateCisDisconnectedEvent_Idle) {
3737 const auto context_type = kContextTypeMedia;
3738 const auto leaudio_group_id = 6;
3739 const auto num_devices = 1;
3740
3741 ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid);
3742
3743 // Prepare multiple fake connected devices in a group
3744 auto* group =
3745 PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
3746 ASSERT_EQ(group->Size(), num_devices);
3747
3748 PrepareConfigureCodecHandler(group);
3749 PrepareConfigureQosHandler(group);
3750 PrepareEnableHandler(group);
3751 PrepareDisableHandler(group);
3752 PrepareReleaseHandler(group);
3753
3754 auto* leAudioDevice = group->GetFirstDevice();
3755 auto expected_devices_written = 0;
3756
3757 /* Three Writes:
3758 * 1: Codec Config
3759 * 2: Codec QoS
3760 * 3: Enabling
3761 */
3762 EXPECT_CALL(gatt_queue, WriteCharacteristic(leAudioDevice->conn_id_,
3763 leAudioDevice->ctp_hdls_.val_hdl,
3764 _, GATT_WRITE_NO_RSP, _, _))
3765 .Times(AtLeast(3));
3766 expected_devices_written++;
3767
3768 ASSERT_EQ(expected_devices_written, num_devices);
3769
3770 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
3771 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
3772 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
3773
3774 InjectInitialIdleNotification(group);
3775
3776 // Start the configuration and stream Media content
3777 LeAudioGroupStateMachine::Get()->StartStream(
3778 group, static_cast<LeAudioContextType>(context_type),
3779 types::AudioContexts(context_type));
3780
3781 // Check if group has transitioned to a proper state
3782 ASSERT_EQ(group->GetState(),
3783 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3784 testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
3785
3786 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3787 mock_function_count_map["alarm_cancel"] = 0;
3788 /* Prepare DisconnectCis mock to not symulate CisDisconnection */
3789 ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return());
3790
3791 // Validate GroupStreamStatus
3792 EXPECT_CALL(
3793 mock_callbacks_,
3794 StatusReportCb(leaudio_group_id,
3795 bluetooth::le_audio::GroupStreamStatus::RELEASING));
3796
3797 EXPECT_CALL(mock_callbacks_,
3798 StatusReportCb(leaudio_group_id,
3799 bluetooth::le_audio::GroupStreamStatus::IDLE))
3800 .Times(0);
3801
3802 // Stop the stream
3803 LeAudioGroupStateMachine::Get()->StopStream(group);
3804
3805 // Check if group has transitioned to a proper state
3806 ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
3807 ASSERT_EQ(0, mock_function_count_map["alarm_cancel"]);
3808
3809 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3810
3811 EXPECT_CALL(mock_callbacks_,
3812 StatusReportCb(leaudio_group_id,
3813 bluetooth::le_audio::GroupStreamStatus::IDLE));
3814
3815 // Inject CIS and ACL disconnection of first device
3816 InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
3817 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3818 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3819 }
3820
TEST_F(StateMachineTest,StreamReconfigureAfterCisLostTwoDevices)3821 TEST_F(StateMachineTest, StreamReconfigureAfterCisLostTwoDevices) {
3822 auto context_type = kContextTypeConversational;
3823 const auto leaudio_group_id = 4;
3824 const auto num_devices = 2;
3825
3826 // Prepare multiple fake connected devices in a group
3827 auto* group = PrepareSingleTestDeviceGroup(
3828 leaudio_group_id, context_type, num_devices,
3829 kContextTypeConversational | kContextTypeMedia);
3830 ASSERT_EQ(group->Size(), num_devices);
3831
3832 PrepareConfigureCodecHandler(group);
3833 PrepareConfigureQosHandler(group);
3834 PrepareEnableHandler(group);
3835 PrepareReceiverStartReady(group);
3836
3837 /* Prepare DisconnectCis mock to not symulate CisDisconnection */
3838 ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return());
3839
3840 EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2);
3841 EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2);
3842 EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(6);
3843 EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
3844 EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
3845 EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
3846
3847 InjectInitialIdleNotification(group);
3848
3849 auto* leAudioDevice = group->GetFirstDevice();
3850 auto expected_devices_written = 0;
3851 while (leAudioDevice) {
3852 EXPECT_CALL(gatt_queue,
3853 WriteCharacteristic(leAudioDevice->conn_id_,
3854 leAudioDevice->ctp_hdls_.val_hdl, _,
3855 GATT_WRITE_NO_RSP, _, _))
3856 .Times(3);
3857 expected_devices_written++;
3858 leAudioDevice = group->GetNextDevice(leAudioDevice);
3859 }
3860 ASSERT_EQ(expected_devices_written, num_devices);
3861
3862 // Validate GroupStreamStatus
3863 EXPECT_CALL(
3864 mock_callbacks_,
3865 StatusReportCb(leaudio_group_id,
3866 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3867
3868 // Start the configuration and stream Media content
3869 context_type = kContextTypeMedia;
3870 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
3871 group, static_cast<LeAudioContextType>(context_type),
3872 types::AudioContexts(context_type)));
3873
3874 // Check if group has transitioned to a proper state
3875 ASSERT_EQ(group->GetState(),
3876 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3877 ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
3878 testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
3879 testing::Mock::VerifyAndClearExpectations(&gatt_queue);
3880 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3881
3882 // Device disconnects due to timeout of CIS
3883 leAudioDevice = group->GetFirstDevice();
3884 while (leAudioDevice) {
3885 InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
3886 // Disconnect device
3887 LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected(
3888 group, leAudioDevice);
3889
3890 leAudioDevice = group->GetNextDevice(leAudioDevice);
3891 }
3892
3893 LOG(INFO) << "GK A1";
3894 group->ReloadAudioLocations();
3895 group->ReloadAudioDirections();
3896 group->UpdateAudioContextTypeAvailability();
3897
3898 // Start conversational scenario
3899 leAudioDevice = group->GetFirstDevice();
3900 int device_cnt = num_devices;
3901 while (leAudioDevice) {
3902 LOG(INFO) << "GK A11";
3903 leAudioDevice->conn_id_ = device_cnt--;
3904 leAudioDevice->SetConnectionState(DeviceConnectState::CONNECTED);
3905 leAudioDevice = group->GetNextDevice(leAudioDevice);
3906 }
3907
3908 LOG(INFO) << "GK A2";
3909 InjectInitialIdleNotification(group);
3910
3911 group->ReloadAudioLocations();
3912 group->ReloadAudioDirections();
3913 group->UpdateAudioContextTypeAvailability(kContextTypeConversational |
3914 kContextTypeMedia);
3915
3916 leAudioDevice = group->GetFirstDevice();
3917 expected_devices_written = 0;
3918 while (leAudioDevice) {
3919 EXPECT_CALL(gatt_queue,
3920 WriteCharacteristic(leAudioDevice->conn_id_,
3921 leAudioDevice->ctp_hdls_.val_hdl, _,
3922 GATT_WRITE_NO_RSP, _, _))
3923 .Times(4);
3924 expected_devices_written++;
3925 leAudioDevice = group->GetNextDevice(leAudioDevice);
3926 }
3927 ASSERT_EQ(expected_devices_written, num_devices);
3928
3929 // Validate GroupStreamStatus
3930 EXPECT_CALL(
3931 mock_callbacks_,
3932 StatusReportCb(leaudio_group_id,
3933 bluetooth::le_audio::GroupStreamStatus::STREAMING));
3934
3935 // Start the configuration and stream Conversational content
3936 context_type = kContextTypeConversational;
3937 ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
3938 group, static_cast<LeAudioContextType>(context_type),
3939 types::AudioContexts(context_type)));
3940
3941 // Check if group has transitioned to a proper state
3942 ASSERT_EQ(group->GetState(),
3943 types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
3944 ASSERT_EQ(2, mock_function_count_map["alarm_cancel"]);
3945 testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
3946 testing::Mock::VerifyAndClearExpectations(&gatt_queue);
3947 testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
3948 }
3949
3950 } // namespace internal
3951 } // namespace le_audio
3952