• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <base/functional/bind.h>
21 #include <base/functional/callback.h>
22 #include <base/strings/string_number_conversions.h>
23 #include <bluetooth/log.h>
24 #include <com_android_bluetooth_flags.h>
25 
26 #include <algorithm>
27 #include <cstddef>
28 #include <cstdint>
29 #include <memory>
30 #include <sstream>
31 #include <string>
32 #include <utility>
33 #include <vector>
34 
35 #include "bta_gatt_queue.h"
36 #include "btm_iso_api.h"
37 #include "btm_iso_api_types.h"
38 #include "client_parser.h"
39 #include "common/strings.h"
40 #include "device_groups.h"
41 #include "devices.h"
42 #include "gatt_api.h"
43 #include "hardware/bt_le_audio.h"
44 #include "hci/hci_packets.h"
45 #include "hci_error_code.h"
46 #include "hcimsgs.h"
47 #include "internal_include/bt_trace.h"
48 #include "le_audio_health_status.h"
49 #include "le_audio_log_history.h"
50 #include "le_audio_types.h"
51 #include "osi/include/alarm.h"
52 #include "osi/include/osi.h"
53 #include "osi/include/properties.h"
54 #include "stack/include/btm_client_interface.h"
55 #include "types/bt_transport.h"
56 #include "types/raw_address.h"
57 
58 #ifdef TARGET_FLOSS
59 #include <audio_hal_interface/audio_linux.h>
60 #else
61 #include <hardware/audio.h>
62 #endif  // TARGET_FLOSS
63 
64 // clang-format off
65 /* ASCS state machine 1.0
66  *
67  * State machine manages group of ASEs to make transition from one state to
68  * another according to specification and keeping involved necessary externals
69  * like: ISO, CIG, ISO data path, audio path form/to upper layer.
70  *
71  * GroupStream (API): GroupStream method of this le audio implementation class
72  *                    object should allow transition from Idle (No Caching),
73  *                    Codec Configured (Caching after release) state to
74  *                    Streaming for all ASEs in group within time limit. Time
75  *                    limit should keep safe whole state machine from being
76  *                    stucked in any in-middle state, which is not a destination
77  *                    state.
78  *
79  *                    TODO Second functionality of streaming should be switch
80  *                    context which will base on previous state, context type.
81  *
82  * GroupStop (API): GroupStop method of this le audio implementation class
83  *                  object should allow safe transition from any state to Idle
84  *                  or Codec Configured (if caching supported).
85  *
86  * ╔══════════════════╦═════════════════════════════╦══════════════╦══════════════════╦══════╗
87  * ║  Current State   ║ ASE Control Point Operation ║    Result    ║    Next State    ║ Note ║
88  * ╠══════════════════╬═════════════════════════════╬══════════════╬══════════════════╬══════╣
89  * ║ Idle             ║ Config Codec                ║ Success      ║ Codec Configured ║  +   ║
90  * ║ Codec Configured ║ Config Codec                ║ Success      ║ Codec Configured ║  -   ║
91  * ║ Codec Configured ║ Release                     ║ Success      ║ Releasing        ║  +   ║
92  * ║ Codec Configured ║ Config QoS                  ║ Success      ║ QoS Configured   ║  +   ║
93  * ║ QoS Configured   ║ Config Codec                ║ Success      ║ Codec Configured ║  -   ║
94  * ║ QoS Configured   ║ Config QoS                  ║ Success      ║ QoS Configured   ║  -   ║
95  * ║ QoS Configured   ║ Release                     ║ Success      ║ Releasing        ║  +   ║
96  * ║ QoS Configured   ║ Enable                      ║ Success      ║ Enabling         ║  +   ║
97  * ║ Enabling         ║ Release                     ║ Success      ║ Releasing        ║  +   ║
98  * ║ Enabling         ║ Update Metadata             ║ Success      ║ Enabling         ║  -   ║
99  * ║ Enabling         ║ Disable                     ║ Success      ║ Disabling        ║  -   ║
100  * ║ Enabling         ║ Receiver Start Ready        ║ Success      ║ Streaming        ║  +   ║
101  * ║ Streaming        ║ Update Metadata             ║ Success      ║ Streaming        ║  -   ║
102  * ║ Streaming        ║ Disable                     ║ Success      ║ Disabling        ║  +   ║
103  * ║ Streaming        ║ Release                     ║ Success      ║ Releasing        ║  +   ║
104  * ║ Disabling        ║ Receiver Stop Ready         ║ Success      ║ QoS Configured   ║  +   ║
105  * ║ Disabling        ║ Release                     ║ Success      ║ Releasing        ║  +   ║
106  * ║ Releasing        ║ Released (no caching)       ║ Success      ║ Idle             ║  +   ║
107  * ║ Releasing        ║ Released (caching)          ║ Success      ║ Codec Configured ║  -   ║
108  * ╚══════════════════╩═════════════════════════════╩══════════════╩══════════════════╩══════╝
109  *
110  * + - supported transition
111  * - - not supported
112  */
113 // clang-format on
114 
115 using bluetooth::common::ToString;
116 using bluetooth::hci::IsoManager;
117 using bluetooth::le_audio::GroupStreamStatus;
118 using bluetooth::le_audio::LeAudioDevice;
119 using bluetooth::le_audio::LeAudioDeviceGroup;
120 using bluetooth::le_audio::LeAudioGroupStateMachine;
121 
122 using bluetooth::hci::ErrorCode;
123 using bluetooth::hci::ErrorCodeText;
124 using bluetooth::le_audio::DsaMode;
125 using bluetooth::le_audio::DsaModes;
126 using bluetooth::le_audio::types::ase;
127 using bluetooth::le_audio::types::AseState;
128 using bluetooth::le_audio::types::AudioContexts;
129 using bluetooth::le_audio::types::BidirectionalPair;
130 using bluetooth::le_audio::types::CigState;
131 using bluetooth::le_audio::types::CisState;
132 using bluetooth::le_audio::types::DataPathState;
133 using bluetooth::le_audio::types::LeAudioContextType;
134 using bluetooth::le_audio::types::LeAudioLtvMap;
135 
136 namespace {
137 
138 using namespace bluetooth;
139 
140 constexpr int linkQualityCheckInterval = 4000;
141 constexpr int kAutonomousTransitionTimeoutMs = 5000;
142 constexpr int kNumberOfCisRetries = 2;
143 
link_quality_cb(void * data)144 static void link_quality_cb(void* data) {
145   // very ugly, but we need to pass just two bytes
146   uint16_t cis_conn_handle = *((uint16_t*)data);
147 
148   IsoManager::GetInstance()->ReadIsoLinkQuality(cis_conn_handle);
149 }
150 
151 class LeAudioGroupStateMachineImpl;
152 LeAudioGroupStateMachineImpl* instance;
153 
154 class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
155 public:
LeAudioGroupStateMachineImpl(Callbacks * state_machine_callbacks)156   LeAudioGroupStateMachineImpl(Callbacks* state_machine_callbacks)
157       : state_machine_callbacks_(state_machine_callbacks),
158         watchdog_(alarm_new("LeAudioStateMachineTimer")) {
159     log_history_ = LeAudioLogHistory::Get();
160   }
161 
~LeAudioGroupStateMachineImpl()162   ~LeAudioGroupStateMachineImpl() {
163     alarm_free(watchdog_);
164     watchdog_ = nullptr;
165     log_history_->Cleanup();
166     log_history_ = nullptr;
167   }
168 
AttachToStream(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,BidirectionalPair<std::vector<uint8_t>> ccids)169   bool AttachToStream(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
170                       BidirectionalPair<std::vector<uint8_t>> ccids) override {
171     log::info("group id: {} device: {}", group->group_id_, leAudioDevice->address_);
172 
173     /* This function is used to attach the device to the stream.
174      * Limitation here is that device should be previously in the streaming
175      * group and just got reconnected.
176      */
177     if (group->GetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING ||
178         group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
179       log::error("Group {} is not streaming or is in transition, state: {}, target state: {}",
180                  group->group_id_, ToString(group->GetState()), ToString(group->GetTargetState()));
181       return false;
182     }
183 
184     /* This is cautious - mostly needed for unit test only */
185     auto group_metadata_contexts = get_bidirectional(group->GetMetadataContexts());
186     auto device_available_contexts = leAudioDevice->GetAvailableContexts();
187     if (!group_metadata_contexts.test_any(device_available_contexts)) {
188       log::info("{} does is not have required context type", leAudioDevice->address_);
189       return false;
190     }
191 
192     /* If remote device is in QoS state, go to enabling state. */
193     if (leAudioDevice->HaveActiveAse() &&
194         leAudioDevice->HaveAllActiveAsesSameState(
195                 AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED)) {
196       log::info("{} in QoS state, proceed to Enable state", leAudioDevice->address_);
197       PrepareAndSendEnable(leAudioDevice);
198       return true;
199     }
200 
201     /* Invalidate configuration to make sure it is chosen properly when new
202      * member connects
203      */
204     group->InvalidateCachedConfigurations();
205 
206     if (!group->Configure(group->GetConfigurationContextType(), group->GetMetadataContexts(),
207                           ccids)) {
208       log::error("failed to set ASE configuration");
209       return false;
210     }
211 
212     PrepareAndSendCodecConfigure(group, leAudioDevice);
213     return true;
214   }
215 
StartStream(LeAudioDeviceGroup * group,LeAudioContextType context_type,const BidirectionalPair<AudioContexts> & metadata_context_types,BidirectionalPair<std::vector<uint8_t>> ccid_lists)216   bool StartStream(LeAudioDeviceGroup* group, LeAudioContextType context_type,
217                    const BidirectionalPair<AudioContexts>& metadata_context_types,
218                    BidirectionalPair<std::vector<uint8_t>> ccid_lists) override {
219     log::info("current state: {}", ToString(group->GetState()));
220 
221     switch (group->GetState()) {
222       case AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED:
223         if (group->IsConfiguredForContext(context_type)) {
224           if (group->Activate(context_type, metadata_context_types, ccid_lists)) {
225             SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
226 
227             if (CigCreate(group)) {
228               return true;
229             }
230           }
231           log::info("Could not activate device, try to configure it again");
232         }
233 
234         /* Deactivate previousely activated ASEs in case if there were just a
235          * reconfiguration (group target state as CODEC CONFIGURED) and no
236          * deactivation. Currently activated ASEs cannot be used for different
237          * context.
238          */
239         group->Deactivate();
240 
241         /* We are going to reconfigure whole group. Clear Cises.*/
242         ReleaseCisIds(group);
243 
244         /* If configuration is needed */
245         [[fallthrough]];
246 
247       case AseState::BTA_LE_AUDIO_ASE_STATE_IDLE:
248         if (!group->Configure(context_type, metadata_context_types, ccid_lists)) {
249           log::error("failed to set ASE configuration");
250           return false;
251         }
252 
253         group->cig.GenerateCisIds(context_type);
254         /* All ASEs should aim to achieve target state */
255         SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
256         if (!PrepareAndSendCodecConfigToTheGroup(group)) {
257           group->PrintDebugState();
258           ClearGroup(group, true);
259         }
260         break;
261 
262       case AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED: {
263         LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice();
264         if (!leAudioDevice) {
265           group->PrintDebugState();
266           log::error("group_id: {} has no active devices", group->group_id_);
267           return false;
268         }
269 
270         if (!group->IsConfiguredForContext(context_type)) {
271           if (group->GetConfigurationContextType() == context_type) {
272             log::info(
273                     "Looks like another device connected in the meantime to group_id: {}, try to "
274                     "reconfigure.",
275                     group->group_id_);
276             if (group->Configure(context_type, metadata_context_types, ccid_lists)) {
277               return PrepareAndSendCodecConfigToTheGroup(group);
278             }
279           }
280           log::error("Trying to start stream not configured for the context {} in group_id: {} ",
281                      ToString(context_type), group->group_id_);
282           group->PrintDebugState();
283           StopStream(group);
284           return false;
285         }
286 
287         // Even stream is already configured for the context, update the metadata.
288         group->SetMetadataContexts(metadata_context_types);
289 
290         /* All ASEs should aim to achieve target state */
291         SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
292         PrepareAndSendEnableToTheGroup(group);
293         break;
294       }
295 
296       case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING: {
297         /* This case just updates the metadata for the stream, in case
298          * stream configuration is satisfied. We can do that already for
299          * all the devices in a group, without any state transitions.
300          */
301         if (!group->IsMetadataChanged(metadata_context_types, ccid_lists)) {
302           return true;
303         }
304 
305         group->SetMetadataContexts(metadata_context_types);
306 
307         LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice();
308         if (!leAudioDevice) {
309           log::error("group has no active devices");
310           return false;
311         }
312 
313         while (leAudioDevice) {
314           PrepareAndSendUpdateMetadata(group, leAudioDevice, metadata_context_types, ccid_lists);
315           leAudioDevice = group->GetNextActiveDevice(leAudioDevice);
316         }
317         break;
318       }
319 
320       default:
321         log::error("Unable to transit from {}", ToString(group->GetState()));
322         return false;
323     }
324 
325     return true;
326   }
327 
ConfigureStream(LeAudioDeviceGroup * group,LeAudioContextType context_type,const BidirectionalPair<AudioContexts> & metadata_context_types,BidirectionalPair<std::vector<uint8_t>> ccid_lists,bool configure_qos)328   bool ConfigureStream(LeAudioDeviceGroup* group, LeAudioContextType context_type,
329                        const BidirectionalPair<AudioContexts>& metadata_context_types,
330                        BidirectionalPair<std::vector<uint8_t>> ccid_lists,
331                        bool configure_qos) override {
332     if (group->GetState() > AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) {
333       log::error("Stream should be stopped or in configured stream. Current state: {}",
334                  ToString(group->GetState()));
335       return false;
336     }
337 
338     if (configure_qos) {
339       if (group->IsConfiguredForContext(context_type)) {
340         if (group->Activate(context_type, metadata_context_types, ccid_lists)) {
341           SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
342           if (CigCreate(group)) {
343             return true;
344           }
345         }
346       }
347       log::info("Could not activate device, try to configure it again");
348     }
349 
350     group->Deactivate();
351     ReleaseCisIds(group);
352 
353     if (!group->Configure(context_type, metadata_context_types, ccid_lists)) {
354       log::error("Could not configure ASEs for group {} content type {}", group->group_id_,
355                  int(context_type));
356 
357       return false;
358     }
359 
360     group->cig.GenerateCisIds(context_type);
361     if (configure_qos) {
362       SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
363     } else {
364       SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
365     }
366     return PrepareAndSendCodecConfigToTheGroup(group);
367   }
368 
SuspendStream(LeAudioDeviceGroup * group)369   void SuspendStream(LeAudioDeviceGroup* group) override {
370     /* All ASEs should aim to achieve target state */
371     SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
372     auto status = PrepareAndSendDisableToTheGroup(group);
373     state_machine_callbacks_->StatusReportCb(group->group_id_, status);
374   }
375 
StopStream(LeAudioDeviceGroup * group)376   void StopStream(LeAudioDeviceGroup* group) override {
377     if (group->IsReleasingOrIdle()) {
378       log::info("group: {} in_transition: {}, current_state {}", group->group_id_,
379                 group->IsInTransition(), ToString(group->GetState()));
380       return;
381     }
382 
383     /* All Ases should aim to achieve target state */
384     SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
385 
386     auto status = PrepareAndSendReleaseToTheGroup(group);
387     state_machine_callbacks_->StatusReportCb(group->group_id_, status);
388   }
389 
notifyLeAudioHealth(LeAudioDeviceGroup * group,bluetooth::le_audio::LeAudioHealthGroupStatType stat)390   void notifyLeAudioHealth(LeAudioDeviceGroup* group,
391                            bluetooth::le_audio::LeAudioHealthGroupStatType stat) {
392     auto leAudioHealthStatus = bluetooth::le_audio::LeAudioHealthStatus::Get();
393     if (leAudioHealthStatus) {
394       leAudioHealthStatus->AddStatisticForGroup(group, stat);
395     }
396   }
397 
ProcessGattCtpNotification(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,uint8_t * value,uint16_t len)398   void ProcessGattCtpNotification(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
399                                   uint8_t* value, uint16_t len) {
400     auto ntf = std::make_unique<struct bluetooth::le_audio::client_parser::ascs::ctp_ntf>();
401 
402     bool valid_notification = ParseAseCtpNotification(*ntf, len, value);
403     if (group == nullptr) {
404       log::warn("Notification received to invalid group");
405       return;
406     }
407 
408     /* State machine looks on ASE state and base on it take decisions.
409      * If ASE state is not achieve on time, timeout is reported and upper
410      * layer mostlikely drops ACL considers that remote is in bad state.
411      * However, it might happen that remote device rejects ASE configuration for
412      * some reason and ASCS specification defines tones of different reasons.
413      * Maybe in the future we will be able to handle all of them but for now it
414      * seems to be important to allow remote device to reject ASE configuration
415      * when stream is creating. e.g. Allow remote to reject Enable on unwanted
416      * context type.
417      */
418 
419     auto target_state = group->GetTargetState();
420     auto current_state = group->GetState();
421     auto in_transition = group->IsInTransition();
422     if (!in_transition || target_state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
423       log::debug(
424               "Not interested in ctp result for group {} inTransition: {} , targetState: {}, "
425               "currentState: {}",
426               group->group_id_, in_transition, ToString(target_state), ToString(current_state));
427       return;
428     }
429 
430     if (!valid_notification) {
431       /* Do nothing, just allow guard timer to fire */
432       log::error("Invalid CTP notification for group {}", group->group_id_);
433       return;
434     }
435 
436     for (auto& entry : ntf->entries) {
437       // release ASEs on device which did not accept control point command
438       if (entry.response_code !=
439           bluetooth::le_audio::client_parser::ascs::kCtpResponseCodeSuccess) {
440         if (ntf->op == bluetooth::le_audio::client_parser::ascs::kCtpOpcodeRelease) {
441           log::warn(
442                   "Release failed for {}, ase: {}, last_ase_ctp_command_sent: {:#x}, error: {:#x}, "
443                   "reason: {:#x}, let "
444                   "watchdog to fire",
445                   leAudioDevice->address_, entry.ase_id, leAudioDevice->last_ase_ctp_command_sent,
446                   entry.response_code, entry.reason);
447           return;
448         }
449 
450         auto release_sent_to_remote = PrepareAndSendRelease(leAudioDevice);
451         auto active_devices = group->GetNumOfActiveDevices();
452 
453         int releasing_devices = 0;
454         for (auto dev = group->GetFirstActiveDevice(); dev; dev = group->GetNextActiveDevice(dev)) {
455           if (dev->last_ase_ctp_command_sent ==
456               bluetooth::le_audio::client_parser::ascs::kCtpOpcodeRelease) {
457             releasing_devices++;
458           }
459         }
460 
461         log::error(
462                 "Releasing ASE due to control point error for {}, ase: {}, opcode: {:#x}, "
463                 "last_ase_ctp_command_sent: {:#x}, error: "
464                 "{:#x}, reason: {:#x}. release_sent_to_remote: {}, active_devices: {}, "
465                 "releasing_devices: {}",
466                 leAudioDevice->address_, entry.ase_id, ntf->op,
467                 leAudioDevice->last_ase_ctp_command_sent, entry.response_code, entry.reason,
468                 release_sent_to_remote, active_devices, releasing_devices);
469 
470         // If there is no active devices it means, the whole set got released
471         if (releasing_devices == 0 && active_devices == 0) {
472           /* No remote communication expected */
473           ClearGroup(group, true);
474           notifyLeAudioHealth(
475                   group,
476                   bluetooth::le_audio::LeAudioHealthGroupStatType::STREAM_CREATE_SIGNALING_FAILED);
477         } else if (active_devices != 0 && releasing_devices == active_devices) {
478           group->SetTargetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
479           state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::RELEASING);
480           notifyLeAudioHealth(
481                   group,
482                   bluetooth::le_audio::LeAudioHealthGroupStatType::STREAM_CREATE_SIGNALING_FAILED);
483         }
484         return;
485       }
486     }
487 
488     log::debug("Ctp result OK for group {} inTransition: {} , targetState: {}, currentState: {}",
489                group->group_id_, in_transition, ToString(target_state), ToString(current_state));
490   }
491 
ProcessGattNotifEvent(uint8_t * value,uint16_t len,struct ase * ase,LeAudioDevice * leAudioDevice,LeAudioDeviceGroup * group)492   void ProcessGattNotifEvent(uint8_t* value, uint16_t len, struct ase* ase,
493                              LeAudioDevice* leAudioDevice, LeAudioDeviceGroup* group) override {
494     struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr arh;
495 
496     ParseAseStatusHeader(arh, len, value);
497 
498     if (ase->id == 0x00) {
499       /* Initial state of Ase - update id */
500       log::info(", discovered ase id: {}", arh.id);
501       ase->id = arh.id;
502     }
503 
504     auto state = static_cast<AseState>(arh.state);
505 
506     log::info("{} , ASE id: {}, state changed {} -> {}", leAudioDevice->address_, ase->id,
507               ToString(ase->state), ToString(state));
508 
509     log_history_->AddLogHistory(kLogAseStateNotif, leAudioDevice->group_id_,
510                                 leAudioDevice->address_,
511                                 "ASE_ID " + std::to_string(arh.id) + ": " + ToString(state),
512                                 "curr: " + ToString(ase->state));
513 
514     switch (state) {
515       case AseState::BTA_LE_AUDIO_ASE_STATE_IDLE:
516         AseStateMachineProcessIdle(arh, ase, group, leAudioDevice);
517         break;
518       case AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED:
519         AseStateMachineProcessCodecConfigured(
520                 arh, ase, value + bluetooth::le_audio::client_parser::ascs::kAseRspHdrMinLen,
521                 len - bluetooth::le_audio::client_parser::ascs::kAseRspHdrMinLen, group,
522                 leAudioDevice);
523         break;
524       case AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED:
525         AseStateMachineProcessQosConfigured(arh, ase, group, leAudioDevice);
526         break;
527       case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING:
528         AseStateMachineProcessEnabling(arh, ase, group, leAudioDevice);
529         break;
530       case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING:
531         AseStateMachineProcessStreaming(
532                 arh, ase, value + bluetooth::le_audio::client_parser::ascs::kAseRspHdrMinLen,
533                 len - bluetooth::le_audio::client_parser::ascs::kAseRspHdrMinLen, group,
534                 leAudioDevice);
535         break;
536       case AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING:
537         AseStateMachineProcessDisabling(arh, ase, group, leAudioDevice);
538         break;
539       case AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING:
540         AseStateMachineProcessReleasing(arh, ase, group, leAudioDevice);
541         break;
542       default:
543         log::error("Wrong AES status: {}", static_cast<int>(arh.state));
544         StopStream(group);
545         break;
546     }
547   }
548 
ProcessHciNotifOnCigCreate(LeAudioDeviceGroup * group,uint8_t status,uint8_t,std::vector<uint16_t> conn_handles)549   void ProcessHciNotifOnCigCreate(LeAudioDeviceGroup* group, uint8_t status, uint8_t /*cig_id*/,
550                                   std::vector<uint16_t> conn_handles) override {
551     /* TODO: What if not all cises will be configured ?
552      * conn_handle.size() != active ases in group
553      */
554 
555     if (!group) {
556       log::error(", group is null");
557       return;
558     }
559 
560     log_history_->AddLogHistory(kLogHciEvent, group->group_id_, RawAddress::kEmpty,
561                                 kLogCisCreateOp + "STATUS=" + loghex(status));
562 
563     if (status != HCI_SUCCESS) {
564       if (status == HCI_ERR_COMMAND_DISALLOWED) {
565         /*
566          * We are here, because stack has no chance to remove CIG when it was
567          * shut during streaming. In the same time, controller probably was not
568          * Reseted, which creates the issue. Lets remove CIG and try to create
569          * it again.
570          */
571         group->cig.SetState(CigState::RECOVERING);
572         IsoManager::GetInstance()->RemoveCig(group->group_id_, true);
573         return;
574       }
575 
576       group->cig.SetState(CigState::NONE);
577       log::error(", failed to create CIG, reason: 0x{:02x}, new cig state: {}", status,
578                  ToString(group->cig.GetState()));
579       StopStream(group);
580       return;
581     }
582 
583     log::assert_that(group->cig.GetState() == CigState::CREATING,
584                      "Unexpected CIG creation group id: {}, cig state: {}", group->group_id_,
585                      ToString(group->cig.GetState()));
586 
587     group->cig.SetState(CigState::CREATED);
588     log::info("Group: {}, id: {} cig state: {}, number of cis handles: {}", std::format_ptr(group),
589               group->group_id_, ToString(group->cig.GetState()),
590               static_cast<int>(conn_handles.size()));
591 
592     if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING &&
593         group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
594       /* Group is not going to stream. It happen while CIG was creating.
595        * Remove CIG in such a case
596        */
597       log::warn("group_id {} is not going to stream anymore. Remove CIG.", group->group_id_);
598       group->PrintDebugState();
599       RemoveCigForGroup(group);
600       return;
601     }
602 
603     /* Assign all connection handles to CIS ids of the CIG */
604     group->cig.AssignCisConnHandles(conn_handles);
605 
606     /* Assign all connection handles to multiple device ASEs */
607     group->AssignCisConnHandlesToAses();
608 
609     PrepareAndSendQoSToTheGroup(group);
610   }
611 
FreeLinkQualityReports(LeAudioDevice * leAudioDevice)612   void FreeLinkQualityReports(LeAudioDevice* leAudioDevice) {
613     if (leAudioDevice->link_quality_timer == nullptr) {
614       return;
615     }
616 
617     alarm_free(leAudioDevice->link_quality_timer);
618     leAudioDevice->link_quality_timer = nullptr;
619   }
620 
ProcessHciNotifyOnCigRemoveRecovering(uint8_t status,LeAudioDeviceGroup * group)621   void ProcessHciNotifyOnCigRemoveRecovering(uint8_t status, LeAudioDeviceGroup* group) {
622     group->cig.SetState(CigState::NONE);
623 
624     log_history_->AddLogHistory(kLogHciEvent, group->group_id_, RawAddress::kEmpty,
625                                 kLogCigRemoveOp + " STATUS=" + loghex(status));
626     if (status != HCI_SUCCESS) {
627       log::error(
628               "Could not recover from the COMMAND DISALLOAD on CigCreate. Status "
629               "on CIG remove is 0x{:02x}",
630               status);
631       StopStream(group);
632       return;
633     }
634     log::info("Succeed on CIG Recover - back to creating CIG");
635     if (!CigCreate(group)) {
636       log::error("Could not create CIG. Stop the stream for group {}", group->group_id_);
637       StopStream(group);
638     }
639   }
640 
ProcessHciNotifOnCigRemove(uint8_t status,LeAudioDeviceGroup * group)641   void ProcessHciNotifOnCigRemove(uint8_t status, LeAudioDeviceGroup* group) override {
642     if (group->cig.GetState() == CigState::RECOVERING) {
643       ProcessHciNotifyOnCigRemoveRecovering(status, group);
644       return;
645     }
646 
647     log_history_->AddLogHistory(kLogHciEvent, group->group_id_, RawAddress::kEmpty,
648                                 kLogCigRemoveOp + " STATUS=" + loghex(status));
649 
650     if (status != HCI_SUCCESS) {
651       group->cig.SetState(CigState::CREATED);
652       log::error("failed to remove cig, id: {}, status 0x{:02x}, new cig state: {}",
653                  group->group_id_, status, ToString(group->cig.GetState()));
654       return;
655     }
656 
657     log::assert_that(group->cig.GetState() == CigState::REMOVING,
658                      "Unexpected CIG remove group id: {}, cig state {}", group->group_id_,
659                      ToString(group->cig.GetState()));
660 
661     group->cig.SetState(CigState::NONE);
662 
663     LeAudioDevice* leAudioDevice = group->GetFirstDevice();
664     if (!leAudioDevice) {
665       return;
666     }
667 
668     do {
669       FreeLinkQualityReports(leAudioDevice);
670 
671       for (auto& ase : leAudioDevice->ases_) {
672         ase.cis_state = CisState::IDLE;
673         ase.data_path_state = DataPathState::IDLE;
674       }
675     } while ((leAudioDevice = group->GetNextDevice(leAudioDevice)));
676   }
677 
ProcessHciNotifSetupIsoDataPath(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,uint8_t status,uint16_t conn_handle)678   void ProcessHciNotifSetupIsoDataPath(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
679                                        uint8_t status, uint16_t conn_handle) override {
680     log_history_->AddLogHistory(
681             kLogHciEvent, group->group_id_, leAudioDevice->address_,
682             kLogSetDataPathOp + "cis_h:" + loghex(conn_handle) + " STATUS=" + loghex(status));
683 
684     /* Find ASE and later update state for the given cis.*/
685     auto ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState(CisState::CONNECTED,
686                                                                      DataPathState::CONFIGURING);
687 
688     if (status) {
689       log::error("Failed to setup data path for {}, cis handle: {:#x}, error: {:#x}",
690                  leAudioDevice->address_, conn_handle, status);
691       if (ase && ase->cis_conn_hdl == conn_handle) {
692         ase->data_path_state = DataPathState::IDLE;
693       }
694       StopStream(group);
695 
696       return;
697     }
698 
699     if (group->dsa_.active &&
700         (group->dsa_.mode == DsaMode::ISO_SW || group->dsa_.mode == DsaMode::ISO_HW) &&
701         leAudioDevice->GetDsaDataPathState() == DataPathState::CONFIGURING) {
702       log::info("Datapath configured for headtracking");
703       leAudioDevice->SetDsaDataPathState(DataPathState::CONFIGURED);
704       return;
705     }
706 
707     if (!ase || ase->cis_conn_hdl != conn_handle) {
708       log::error("Cannot find ase by handle {}", conn_handle);
709       return;
710     }
711 
712     ase->data_path_state = DataPathState::CONFIGURED;
713 
714     if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
715       log::warn("Group {} is not targeting streaming state any more", group->group_id_);
716       return;
717     }
718 
719     AddCisToStreamConfiguration(group, leAudioDevice, ase);
720 
721     if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING &&
722         !group->GetFirstActiveDeviceByCisAndDataPathState(CisState::CONNECTED,
723                                                           DataPathState::IDLE)) {
724       /* No more transition for group. Here we are for the late join device
725        * scenario */
726       cancel_watchdog_if_needed(group->group_id_);
727     }
728 
729     if (group->GetNotifyStreamingWhenCisesAreReadyFlag() && group->IsGroupStreamReady()) {
730       group->SetNotifyStreamingWhenCisesAreReadyFlag(false);
731       log::info("Ready to notify Group Streaming.");
732       cancel_watchdog_if_needed(group->group_id_);
733       if (group->GetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
734         group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
735       }
736       state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::STREAMING);
737     };
738   }
739 
ProcessHciNotifRemoveIsoDataPath(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,uint8_t status,uint16_t conn_hdl)740   void ProcessHciNotifRemoveIsoDataPath(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
741                                         uint8_t status, uint16_t conn_hdl) override {
742     log_history_->AddLogHistory(kLogHciEvent, group->group_id_, leAudioDevice->address_,
743                                 kLogRemoveDataPathOp + "STATUS=" + loghex(status));
744 
745     if (status != HCI_SUCCESS) {
746       log::error("failed to remove ISO data path, reason: 0x{:0x} - continuing stream closing",
747                  status);
748       /* Just continue - disconnecting CIS removes data path as well.*/
749     }
750 
751     bool do_disconnect = false;
752 
753     auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(conn_hdl);
754     if (ases_pair.sink && (ases_pair.sink->data_path_state == DataPathState::REMOVING)) {
755       ases_pair.sink->data_path_state = DataPathState::IDLE;
756 
757       if (ases_pair.sink->cis_state == CisState::CONNECTED) {
758         ases_pair.sink->cis_state = CisState::DISCONNECTING;
759         do_disconnect = true;
760       }
761     }
762 
763     if (ases_pair.source && (ases_pair.source->data_path_state == DataPathState::REMOVING)) {
764       ases_pair.source->data_path_state = DataPathState::IDLE;
765 
766       if (ases_pair.source->cis_state == CisState::CONNECTED) {
767         ases_pair.source->cis_state = CisState::DISCONNECTING;
768         do_disconnect = true;
769       }
770     } else {
771       if (group->dsa_.active && leAudioDevice->GetDsaDataPathState() == DataPathState::REMOVING) {
772         log::info("DSA data path removed");
773         leAudioDevice->SetDsaDataPathState(DataPathState::IDLE);
774         leAudioDevice->SetDsaCisHandle(LE_AUDIO_INVALID_CIS_HANDLE);
775       }
776     }
777 
778     if (do_disconnect) {
779       group->RemoveCisFromStreamIfNeeded(leAudioDevice, conn_hdl);
780       IsoManager::GetInstance()->DisconnectCis(conn_hdl, HCI_ERR_PEER_USER);
781 
782       log_history_->AddLogHistory(kLogStateMachineTag, group->group_id_, leAudioDevice->address_,
783                                   kLogCisDisconnectOp + "cis_h:" + loghex(conn_hdl));
784     }
785   }
786 
ProcessHciNotifIsoLinkQualityRead(LeAudioDeviceGroup *,LeAudioDevice *,uint8_t conn_handle,uint32_t txUnackedPackets,uint32_t txFlushedPackets,uint32_t txLastSubeventPackets,uint32_t retransmittedPackets,uint32_t crcErrorPackets,uint32_t rxUnreceivedPackets,uint32_t duplicatePackets)787   void ProcessHciNotifIsoLinkQualityRead(LeAudioDeviceGroup* /*group*/,
788                                          LeAudioDevice* /*leAudioDevice*/, uint8_t conn_handle,
789                                          uint32_t txUnackedPackets, uint32_t txFlushedPackets,
790                                          uint32_t txLastSubeventPackets,
791                                          uint32_t retransmittedPackets, uint32_t crcErrorPackets,
792                                          uint32_t rxUnreceivedPackets, uint32_t duplicatePackets) {
793     log::info(
794             "conn_handle: 0x{:x}, txUnackedPackets: 0x{:x}, txFlushedPackets: "
795             "0x{:x}, txLastSubeventPackets: 0x{:x}, retransmittedPackets: 0x{:x}, "
796             "crcErrorPackets: 0x{:x}, rxUnreceivedPackets: 0x{:x}, "
797             "duplicatePackets: 0x{:x}",
798             conn_handle, txUnackedPackets, txFlushedPackets, txLastSubeventPackets,
799             retransmittedPackets, crcErrorPackets, rxUnreceivedPackets, duplicatePackets);
800   }
801 
ReleaseCisIds(LeAudioDeviceGroup * group)802   void ReleaseCisIds(LeAudioDeviceGroup* group) {
803     if (group == nullptr) {
804       log::debug("Group is null.");
805       return;
806     }
807     log::debug("Releasing CIS is for group {}", group->group_id_);
808 
809     LeAudioDevice* leAudioDevice = group->GetFirstDevice();
810     while (leAudioDevice != nullptr) {
811       for (auto& ase : leAudioDevice->ases_) {
812         ase.cis_id = bluetooth::le_audio::kInvalidCisId;
813         ase.cis_conn_hdl = bluetooth::le_audio::kInvalidCisConnHandle;
814       }
815       leAudioDevice = group->GetNextDevice(leAudioDevice);
816     }
817 
818     group->ClearAllCises();
819   }
820 
SendStreamingStatusCbIfNeeded(LeAudioDeviceGroup * group)821   void SendStreamingStatusCbIfNeeded(LeAudioDeviceGroup* group) {
822     /* This function should be called when some of the set members got disconnected but there are
823      * still other CISes connected. When state machine is in STREAMING state, status will be sent up
824      * to the user, so it can update encoder or offloader.
825      */
826     log::info("group_id: {}", group->group_id_);
827     if (group->HaveAllCisesDisconnected()) {
828       log::info("All cises disconnected;");
829       return;
830     }
831 
832     if ((group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) &&
833         (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)) {
834       state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::STREAMING);
835     } else {
836       log::warn("group_id {} not in streaming, CISes are still there", group->group_id_);
837       group->PrintDebugState();
838     }
839   }
840 
RemoveCigForGroup(LeAudioDeviceGroup * group)841   void RemoveCigForGroup(LeAudioDeviceGroup* group) {
842     log::debug("Group: {}, id: {} cig state: {}", std::format_ptr(group), group->group_id_,
843                ToString(group->cig.GetState()));
844     if (group->cig.GetState() != CigState::CREATED) {
845       log::warn("Group: {}, id: {} cig state: {} cannot be removed", std::format_ptr(group),
846                 group->group_id_, ToString(group->cig.GetState()));
847       return;
848     }
849 
850     group->cig.SetState(CigState::REMOVING);
851     IsoManager::GetInstance()->RemoveCig(group->group_id_);
852     log::debug("Group: {}, id: {} cig state: {}", std::format_ptr(group), group->group_id_,
853                ToString(group->cig.GetState()));
854     log_history_->AddLogHistory(kLogStateMachineTag, group->group_id_, RawAddress::kEmpty,
855                                 kLogCigRemoveOp);
856   }
857 
ProcessHciNotifAclDisconnected(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)858   void ProcessHciNotifAclDisconnected(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
859     FreeLinkQualityReports(leAudioDevice);
860     if (!group) {
861       log::error("group is null for device: {} group_id: {}", leAudioDevice->address_,
862                  leAudioDevice->group_id_);
863       /* mark ASEs as not used. */
864       leAudioDevice->DeactivateAllAses();
865       return;
866     }
867 
868     /* It is possible that ACL disconnection came before CIS disconnect event */
869     for (auto& ase : leAudioDevice->ases_) {
870       if (ase.data_path_state == DataPathState::CONFIGURED ||
871           ase.data_path_state == DataPathState::CONFIGURING) {
872         RemoveDataPathByCisHandle(leAudioDevice, ase.cis_conn_hdl);
873       }
874       group->RemoveCisFromStreamIfNeeded(leAudioDevice, ase.cis_conn_hdl);
875     }
876 
877     /* mark ASEs as not used. */
878     leAudioDevice->DeactivateAllAses();
879 
880     /* Update the current group audio context availability which could change
881      * due to disconnected group member.
882      */
883     group->ReloadAudioLocations();
884     group->ReloadAudioDirections();
885     group->InvalidateCachedConfigurations();
886     group->InvalidateGroupStrategy();
887 
888     /* If group is in Idle and not transitioning, update the current group
889      * audio context availability which could change due to disconnected group
890      * member.
891      */
892     if ((group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) && !group->IsInTransition()) {
893       log::info("group: {} is in IDLE", group->group_id_);
894 
895       /* When OnLeAudioDeviceSetStateTimeout happens, group will transition
896        * to IDLE, and after that an ACL disconnect will be triggered. We need
897        * to check if CIG is created and if it is, remove it so it can be created
898        * again after reconnect. Otherwise we will get Command Disallowed on CIG
899        * Create when starting stream.
900        */
901       if (group->cig.GetState() == CigState::CREATED) {
902         log::info("CIG is in CREATED state so removing CIG for Group {}", group->group_id_);
903         RemoveCigForGroup(group);
904       }
905       return;
906     }
907 
908     log::debug("device: {}, group connected: {}, all active ase disconnected:: {}",
909                leAudioDevice->address_, group->IsAnyDeviceConnected(),
910                group->HaveAllCisesDisconnected());
911 
912     if (group->IsAnyDeviceConnected()) {
913       /*
914        * ACL of one of the device has been dropped. If number of CISes has
915        * changed notify upper layer so the CodecManager can be updated with CIS
916        * information.
917        */
918       if (!group->HaveAllCisesDisconnected()) {
919         /* some CISes are connected */
920         SendStreamingStatusCbIfNeeded(group);
921         return;
922       }
923 
924       if (!group->IsInTransitionTo(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE)) {
925         /* do nothing if not transitioning to IDLE */
926         return;
927       }
928     }
929 
930     /* Group is not connected and all the CISes are down.
931      * Clean states and destroy HCI group
932      */
933     log::debug("Clearing inactive group");
934     ClearGroup(group, true);
935   }
936 
cancel_watchdog_if_needed(int group_id)937   void cancel_watchdog_if_needed(int group_id) {
938     if (alarm_is_scheduled(watchdog_)) {
939       log_history_->AddLogHistory(kLogStateMachineTag, group_id, RawAddress::kEmpty,
940                                   "WATCHDOG STOPPED");
941       alarm_cancel(watchdog_);
942     }
943   }
944 
applyDsaDataPath(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,uint16_t conn_hdl)945   void applyDsaDataPath(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
946                         uint16_t conn_hdl) {
947     if (!group->dsa_.active) {
948       log::info("DSA mode not used");
949       return;
950     }
951 
952     DsaModes dsa_modes = leAudioDevice->GetDsaModes();
953     if (dsa_modes.empty()) {
954       log::warn("DSA mode not supported by this LE Audio device: {}", leAudioDevice->address_);
955       group->dsa_.active = false;
956       return;
957     }
958 
959     if (std::find(dsa_modes.begin(), dsa_modes.end(), DsaMode::ISO_SW) == dsa_modes.end() &&
960         std::find(dsa_modes.begin(), dsa_modes.end(), DsaMode::ISO_HW) == dsa_modes.end()) {
961       log::warn("DSA mode not supported by this LE Audio device: {}", leAudioDevice->address_);
962       group->dsa_.active = false;
963       return;
964     }
965 
966     uint8_t data_path_id = bluetooth::hci::iso_manager::kIsoDataPathHci;
967     bluetooth::le_audio::types::LeAudioCodecId codec = {
968             .coding_format = bluetooth::hci::kIsoCodingFormatTransparent,
969             .vendor_company_id = 0x0000,
970             .vendor_codec_id = 0x0000};
971     log::info("DSA mode used: {}", static_cast<int>(group->dsa_.mode));
972     switch (group->dsa_.mode) {
973       case DsaMode::ISO_HW:
974         data_path_id = bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault;
975         if (!com::android::bluetooth::flags::dsa_hw_transparent_codec()) {
976           codec = bluetooth::le_audio::types::kLeAudioCodecHeadtracking;
977         }
978         break;
979       case DsaMode::ISO_SW:
980         data_path_id = bluetooth::hci::iso_manager::kIsoDataPathHci;
981         codec = bluetooth::le_audio::types::kLeAudioCodecHeadtracking;
982         break;
983       default:
984         log::warn("Unexpected DsaMode: {}", static_cast<int>(group->dsa_.mode));
985         group->dsa_.active = false;
986         return;
987     }
988 
989     leAudioDevice->SetDsaDataPathState(DataPathState::CONFIGURING);
990     leAudioDevice->SetDsaCisHandle(conn_hdl);
991 
992     log::verbose("DSA mode supported on this LE Audio device: {}, apply data path: {}",
993                  leAudioDevice->address_, data_path_id);
994 
995     LeAudioLogHistory::Get()->AddLogHistory(
996             kLogStateMachineTag, group->group_id_, RawAddress::kEmpty,
997             kLogSetDataPathOp + "cis_h:" + loghex(conn_hdl),
998             "direction: " + loghex(bluetooth::hci::iso_manager::kIsoDataPathDirectionOut));
999 
1000     bluetooth::hci::iso_manager::iso_data_path_params param = {
1001             .data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionOut,
1002             .data_path_id = data_path_id,
1003             .codec_id_format = codec.coding_format,
1004             .codec_id_company = codec.vendor_company_id,
1005             .codec_id_vendor = codec.vendor_codec_id,
1006             .controller_delay = 0x00000000,
1007             .codec_conf = std::vector<uint8_t>(),
1008     };
1009     IsoManager::GetInstance()->SetupIsoDataPath(conn_hdl, std::move(param));
1010   }
1011 
ProcessHciNotifCisEstablished(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,const bluetooth::hci::iso_manager::cis_establish_cmpl_evt * event)1012   void ProcessHciNotifCisEstablished(
1013           LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
1014           const bluetooth::hci::iso_manager::cis_establish_cmpl_evt* event) override {
1015     auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(event->cis_conn_hdl);
1016 
1017     log_history_->AddLogHistory(kLogHciEvent, group->group_id_, leAudioDevice->address_,
1018                                 kLogCisEstablishedOp + "cis_h:" + loghex(event->cis_conn_hdl) +
1019                                         " STATUS=" + loghex(event->status));
1020 
1021     if (event->status != HCI_SUCCESS) {
1022       log::warn("{}: failed to create CIS 0x{:04x}, status: {} (0x{:02x})", leAudioDevice->address_,
1023                 event->cis_conn_hdl, ErrorCodeText((ErrorCode)event->status), event->status);
1024 
1025       if (event->status == HCI_ERR_CANCELLED_BY_LOCAL_HOST) {
1026         log::info("{} CIS creation aborted by us, waiting for disconnection complete",
1027                   leAudioDevice->address_);
1028         return;
1029       }
1030 
1031       if (ases_pair.sink) {
1032         ases_pair.sink->cis_state = CisState::ASSIGNED;
1033       }
1034       if (ases_pair.source) {
1035         ases_pair.source->cis_state = CisState::ASSIGNED;
1036       }
1037 
1038       if (event->status == HCI_ERR_CONN_FAILED_ESTABLISHMENT &&
1039           ((leAudioDevice->cis_failed_to_be_established_retry_cnt_++) < kNumberOfCisRetries) &&
1040           (CisCreateForDevice(group, leAudioDevice))) {
1041         log::info("Retrying ({}) to create CIS for {}",
1042                   leAudioDevice->cis_failed_to_be_established_retry_cnt_, leAudioDevice->address_);
1043         return;
1044       }
1045 
1046       if (event->status == HCI_ERR_UNSUPPORTED_REM_FEATURE &&
1047           group->asymmetric_phy_for_unidirectional_cis_supported == true &&
1048           group->GetSduInterval(bluetooth::le_audio::types::kLeAudioDirectionSource) == 0) {
1049         log::info(
1050                 "Remote device may not support asymmetric phy for CIS, retry "
1051                 "symmetric setting again");
1052         group->asymmetric_phy_for_unidirectional_cis_supported = false;
1053       }
1054 
1055       log::error("CIS creation failed {} times, stopping the stream",
1056                  leAudioDevice->cis_failed_to_be_established_retry_cnt_);
1057       leAudioDevice->cis_failed_to_be_established_retry_cnt_ = 0;
1058 
1059       /* CIS establishment failed. Remove CIG if no other CIS is already created
1060        * or pending. If CIS is established, this will be handled in disconnected
1061        * complete event
1062        */
1063       if (group->HaveAllCisesDisconnected()) {
1064         RemoveCigForGroup(group);
1065       }
1066 
1067       StopStream(group);
1068       return;
1069     }
1070 
1071     if (leAudioDevice->cis_failed_to_be_established_retry_cnt_ > 0) {
1072       /* Reset retry counter */
1073       leAudioDevice->cis_failed_to_be_established_retry_cnt_ = 0;
1074     }
1075 
1076     bool is_cis_connecting =
1077             (ases_pair.sink && ases_pair.sink->cis_state == CisState::CONNECTING) ||
1078             (ases_pair.source && ases_pair.source->cis_state == CisState::CONNECTING);
1079 
1080     if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING ||
1081         !is_cis_connecting) {
1082       bool is_cis_disconnecting =
1083               (ases_pair.sink && ases_pair.sink->cis_state == CisState::DISCONNECTING) ||
1084               (ases_pair.source && ases_pair.source->cis_state == CisState::DISCONNECTING);
1085       if (is_cis_disconnecting) {
1086         /* We are in the process of CIS disconnection while the Established event came.
1087          * The Disconnection Complete shall come right after.
1088          */
1089         log::info("{} got CIS is in disconnecting state", leAudioDevice->address_);
1090       } else {
1091         log::error("Unintended CIS establishment event came for group id: {}", group->group_id_);
1092         StopStream(group);
1093       }
1094 
1095       return;
1096     }
1097 
1098     if (ases_pair.sink) {
1099       ases_pair.sink->cis_state = CisState::CONNECTED;
1100     }
1101     if (ases_pair.source) {
1102       ases_pair.source->cis_state = CisState::CONNECTED;
1103     }
1104 
1105     if (ases_pair.sink && (ases_pair.sink->data_path_state == DataPathState::IDLE)) {
1106       PrepareDataPath(group->group_id_, ases_pair.sink);
1107     }
1108 
1109     if (ases_pair.source && (ases_pair.source->data_path_state == DataPathState::IDLE)) {
1110       PrepareDataPath(group->group_id_, ases_pair.source);
1111     } else {
1112       applyDsaDataPath(group, leAudioDevice, event->cis_conn_hdl);
1113     }
1114 
1115     if (osi_property_get_bool("persist.bluetooth.iso_link_quality_report", false)) {
1116       leAudioDevice->link_quality_timer = alarm_new_periodic("le_audio_cis_link_quality");
1117       leAudioDevice->link_quality_timer_data = event->cis_conn_hdl;
1118       alarm_set_on_mloop(leAudioDevice->link_quality_timer, linkQualityCheckInterval,
1119                          link_quality_cb, &leAudioDevice->link_quality_timer_data);
1120     }
1121 
1122     if (!leAudioDevice->HaveAllActiveAsesCisEst()) {
1123       /* More cis established events has to come */
1124       return;
1125     }
1126 
1127     if (!leAudioDevice->IsReadyToCreateStream()) {
1128       /* Device still remains in ready to create stream state. It means that
1129        * more enabling status notifications has to come. This may only happen
1130        * for reconnection scenario for bi-directional CIS.
1131        */
1132       return;
1133     }
1134 
1135     /* All CISes created. Send start ready for source ASE before we can go
1136      * to streaming state.
1137      */
1138     struct ase* ase = leAudioDevice->GetFirstActiveAse();
1139     log::assert_that(ase != nullptr,
1140                      "shouldn't be called without an active ASE, device {}, "
1141                      "group id: {}, cis handle 0x{:04x}",
1142                      leAudioDevice->address_, event->cig_id, event->cis_conn_hdl);
1143 
1144     PrepareAndSendReceiverStartReady(leAudioDevice, ase);
1145   }
1146 
WriteToControlPoint(LeAudioDevice * leAudioDevice,std::vector<uint8_t> value)1147   static void WriteToControlPoint(LeAudioDevice* leAudioDevice, std::vector<uint8_t> value) {
1148     tGATT_WRITE_TYPE write_type = GATT_WRITE_NO_RSP;
1149 
1150     if (value.size() > (leAudioDevice->mtu_ - 3)) {
1151       log::warn("{}, using long write procedure ({} > {})", leAudioDevice->address_, value.size(),
1152                 leAudioDevice->mtu_ - 3);
1153 
1154       /* Note, that this type is actually LONG WRITE.
1155        * Meaning all the Prepare Writes plus Execute is handled in the stack
1156        */
1157       write_type = GATT_WRITE;
1158     }
1159 
1160     BtaGattQueue::WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl,
1161                                       value, write_type, NULL, NULL);
1162   }
1163 
RemoveDataPathByCisHandle(LeAudioDevice * leAudioDevice,uint16_t cis_conn_hdl)1164   static void RemoveDataPathByCisHandle(LeAudioDevice* leAudioDevice, uint16_t cis_conn_hdl) {
1165     auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(cis_conn_hdl);
1166     uint8_t value = 0;
1167 
1168     if (ases_pair.sink && (ases_pair.sink->data_path_state == DataPathState::CONFIGURED ||
1169                            ases_pair.sink->data_path_state == DataPathState::CONFIGURING)) {
1170       value |= bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionInput;
1171       ases_pair.sink->data_path_state = DataPathState::REMOVING;
1172     }
1173 
1174     if (ases_pair.source && (ases_pair.source->data_path_state == DataPathState::CONFIGURED ||
1175                              ases_pair.source->data_path_state == DataPathState::CONFIGURING)) {
1176       value |= bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput;
1177       ases_pair.source->data_path_state = DataPathState::REMOVING;
1178     } else {
1179       if (leAudioDevice->GetDsaDataPathState() == DataPathState::CONFIGURED ||
1180           leAudioDevice->GetDsaDataPathState() == DataPathState::CONFIGURING) {
1181         value |= bluetooth::hci::iso_manager::kRemoveIsoDataPathDirectionOutput;
1182         leAudioDevice->SetDsaDataPathState(DataPathState::REMOVING);
1183       }
1184     }
1185 
1186     if (value == 0) {
1187       log::info("Data path was not set. Nothing to do here.");
1188       return;
1189     }
1190 
1191     IsoManager::GetInstance()->RemoveIsoDataPath(cis_conn_hdl, value);
1192 
1193     LeAudioLogHistory::Get()->AddLogHistory(
1194             kLogStateMachineTag, leAudioDevice->group_id_, leAudioDevice->address_,
1195             kLogRemoveDataPathOp + " cis_h:" + loghex(cis_conn_hdl));
1196   }
1197 
ProcessHciNotifCisDisconnected(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,const bluetooth::hci::iso_manager::cis_disconnected_evt * event)1198   void ProcessHciNotifCisDisconnected(
1199           LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
1200           const bluetooth::hci::iso_manager::cis_disconnected_evt* event) override {
1201     /* Reset the disconnected CIS states */
1202 
1203     FreeLinkQualityReports(leAudioDevice);
1204 
1205     auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(event->cis_conn_hdl);
1206 
1207     log_history_->AddLogHistory(kLogHciEvent, group->group_id_, leAudioDevice->address_,
1208                                 kLogCisDisconnectedOp + "cis_h:" + loghex(event->cis_conn_hdl) +
1209                                         " REASON=" + loghex(event->reason));
1210 
1211     if (ases_pair.sink) {
1212       ases_pair.sink->cis_state = CisState::ASSIGNED;
1213     }
1214     if (ases_pair.source) {
1215       ases_pair.source->cis_state = CisState::ASSIGNED;
1216     }
1217 
1218     RemoveDataPathByCisHandle(leAudioDevice, event->cis_conn_hdl);
1219 
1220     /* If this is peer disconnecting CIS, make sure to clear data path */
1221     if (event->reason != HCI_ERR_CONN_CAUSE_LOCAL_HOST) {
1222       // Make sure we won't stay in STREAMING state
1223       if (ases_pair.sink && ases_pair.sink->state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
1224         SetAseState(leAudioDevice, ases_pair.sink, AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
1225       }
1226       if (ases_pair.source &&
1227           ases_pair.source->state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
1228         SetAseState(leAudioDevice, ases_pair.source,
1229                     AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
1230       }
1231     }
1232 
1233     group->RemoveCisFromStreamIfNeeded(leAudioDevice, event->cis_conn_hdl);
1234 
1235     auto target_state = group->GetTargetState();
1236     log::info(" group id {}, state {}, target state {}", group->group_id_,
1237               bluetooth::common::ToString(group->GetState()),
1238               bluetooth::common::ToString(target_state));
1239 
1240     switch (target_state) {
1241       case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING: {
1242         /* Something wrong happen when streaming or when creating stream.
1243          * If there is other device connected and streaming, just leave it as it
1244          * is, otherwise stop the stream.
1245          */
1246         if (!group->HaveAllCisesDisconnected()) {
1247           /* There is ASE streaming for some device. Continue streaming. */
1248           SendStreamingStatusCbIfNeeded(group);
1249           log::warn("Group member disconnected during streaming. Cis handle 0x{:04x}",
1250                     event->cis_conn_hdl);
1251           return;
1252         }
1253 
1254         /* CISes are disconnected, but it could be a case here, that there is
1255          * another set member trying to get STREAMING state. Can happen when
1256          * while streaming user switch buds. In such a case, lets try to allow
1257          * that device to continue
1258          */
1259 
1260         LeAudioDevice* attaching_device = getDeviceTryingToAttachTheStream(group);
1261         if (attaching_device != nullptr) {
1262           /* There is a device willitng to stream. Let's wait for it to start
1263            * streaming */
1264           auto active_ase = attaching_device->GetFirstActiveAse();
1265           group->SetState(active_ase->state);
1266 
1267           /* this is just to start timer */
1268           group->SetTargetState(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
1269           log::info(
1270                   "{} is still attaching to stream while other members got "
1271                   "disconnected from the group_id: {}",
1272                   attaching_device->address_, group->group_id_);
1273           return;
1274         }
1275 
1276         log::info("Lost all members from the group {}", group->group_id_);
1277         group->cig.cises.clear();
1278         RemoveCigForGroup(group);
1279 
1280         group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
1281         group->SetTargetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
1282         /* If there is no more ase to stream. Notify it is in IDLE. */
1283         state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::IDLE);
1284         return;
1285       }
1286 
1287       case AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED:
1288         /* Intentional group disconnect has finished, but the last CIS in the
1289          * event came after the ASE notification.
1290          * If group is already suspended and all CIS are disconnected, we can
1291          * report SUSPENDED state.
1292          */
1293         if ((group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) &&
1294             group->HaveAllCisesDisconnected()) {
1295           /* No more transition for group */
1296           cancel_watchdog_if_needed(group->group_id_);
1297 
1298           state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::SUSPENDED);
1299           return;
1300         }
1301         break;
1302       case AseState::BTA_LE_AUDIO_ASE_STATE_IDLE:
1303       case AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED: {
1304         /* Those two are used when closing the stream and CIS disconnection is
1305          * expected */
1306         if (!group->HaveAllCisesDisconnected()) {
1307           log::debug("Still waiting for all CISes being disconnected for group:{}",
1308                      group->group_id_);
1309           return;
1310         }
1311 
1312         auto current_group_state = group->GetState();
1313         log::info("group {} current state: {}, target state: {}", group->group_id_,
1314                   bluetooth::common::ToString(current_group_state),
1315                   bluetooth::common::ToString(target_state));
1316         /* It might happen that controller notified about CIS disconnection
1317          * later, after ASE state already changed.
1318          * In such an event, there is need to notify upper layer about state
1319          * from here.
1320          */
1321         if (current_group_state == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {
1322           cancel_watchdog_if_needed(group->group_id_);
1323           log::info("Cises disconnected for group {}, we are good in Idle state.",
1324                     group->group_id_);
1325           ReleaseCisIds(group);
1326           state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::IDLE);
1327         } else if (current_group_state == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) {
1328           cancel_watchdog_if_needed(group->group_id_);
1329           auto reconfig = group->IsPendingConfiguration();
1330           log::info(
1331                   "Cises disconnected for group: {}, we are good in Configured "
1332                   "state, reconfig={}.",
1333                   group->group_id_, reconfig);
1334 
1335           /* This is Autonomous change if both, target and current state
1336            * is CODEC_CONFIGURED
1337            */
1338           if (target_state == current_group_state) {
1339             state_machine_callbacks_->StatusReportCb(group->group_id_,
1340                                                      GroupStreamStatus::CONFIGURED_AUTONOMOUS);
1341           }
1342         }
1343         RemoveCigForGroup(group);
1344       } break;
1345       default:
1346         break;
1347     }
1348 
1349     /* We should send Receiver Stop Ready when acting as a source */
1350     if (ases_pair.source && ases_pair.source->state == AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING) {
1351       leAudioDevice->last_ase_ctp_command_sent =
1352               bluetooth::le_audio::client_parser::ascs::kCtpOpcodeReceiverStopReady;
1353 
1354       std::vector<uint8_t> ids = {ases_pair.source->id};
1355       std::vector<uint8_t> value;
1356 
1357       bluetooth::le_audio::client_parser::ascs::PrepareAseCtpAudioReceiverStopReady(ids, value);
1358       WriteToControlPoint(leAudioDevice, value);
1359 
1360       log_history_->AddLogHistory(
1361               kLogControlPointCmd, leAudioDevice->group_id_, leAudioDevice->address_,
1362               kLogAseStopReadyOp + "ASE_ID " + std::to_string(ases_pair.source->id));
1363     }
1364 
1365     /* Tear down CIS's data paths within the group */
1366     struct ase* ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState(
1367             CisState::CONNECTED, DataPathState::CONFIGURED);
1368     if (!ase) {
1369       leAudioDevice = group->GetNextActiveDevice(leAudioDevice);
1370       /* No more ASEs to disconnect their CISes */
1371       if (!leAudioDevice) {
1372         return;
1373       }
1374 
1375       ase = leAudioDevice->GetFirstActiveAse();
1376     }
1377 
1378     log::assert_that(ase, "shouldn't be called without an active ASE");
1379     if (ase->data_path_state == DataPathState::CONFIGURED) {
1380       RemoveDataPathByCisHandle(leAudioDevice, ase->cis_conn_hdl);
1381     }
1382   }
1383 
1384 private:
1385   static constexpr uint64_t kStateTransitionTimeoutMs = 3500;
1386   static constexpr char kStateTransitionTimeoutMsProp[] =
1387           "persist.bluetooth.leaudio.device.set.state.timeoutms";
1388   Callbacks* state_machine_callbacks_;
1389   alarm_t* watchdog_;
1390   LeAudioLogHistory* log_history_;
1391 
1392   /* This callback is called on timeout during transition to target state */
OnStateTransitionTimeout(int group_id)1393   void OnStateTransitionTimeout(int group_id) {
1394     log_history_->AddLogHistory(kLogStateMachineTag, group_id, RawAddress::kEmpty,
1395                                 "WATCHDOG FIRED");
1396     state_machine_callbacks_->OnStateTransitionTimeout(group_id);
1397   }
1398 
SetTargetState(LeAudioDeviceGroup * group,AseState state)1399   void SetTargetState(LeAudioDeviceGroup* group, AseState state) {
1400     auto current_state = ToString(group->GetTargetState());
1401     auto new_state = ToString(state);
1402 
1403     log::debug("Watchdog watch started for group={} transition from {} to {}", group->group_id_,
1404                current_state, new_state);
1405 
1406     group->SetTargetState(state);
1407 
1408     /* Group should tie in time to get requested status */
1409     uint64_t timeoutMs = kStateTransitionTimeoutMs;
1410     timeoutMs = osi_property_get_int32(kStateTransitionTimeoutMsProp, timeoutMs);
1411 
1412     cancel_watchdog_if_needed(group->group_id_);
1413 
1414     alarm_set_on_mloop(
1415             watchdog_, timeoutMs,
1416             [](void* data) {
1417               if (instance) {
1418                 instance->OnStateTransitionTimeout(PTR_TO_INT(data));
1419               }
1420             },
1421             INT_TO_PTR(group->group_id_));
1422 
1423     log_history_->AddLogHistory(kLogStateMachineTag, group->group_id_, RawAddress::kEmpty,
1424                                 "WATCHDOG STARTED");
1425   }
1426 
AddCisToStreamConfiguration(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,const struct ase * ase)1427   void AddCisToStreamConfiguration(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
1428                                    const struct ase* ase) {
1429     group->stream_conf.codec_id = ase->codec_config.id;
1430 
1431     auto cis_conn_hdl = ase->cis_conn_hdl;
1432     auto& params = group->stream_conf.stream_params.get(ase->direction);
1433     log::info("Adding cis handle 0x{:04x} ({}) to stream list", cis_conn_hdl,
1434               ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSink ? "sink"
1435                                                                                   : "source");
1436 
1437     auto iter = std::find_if(
1438             params.stream_config.stream_map.begin(), params.stream_config.stream_map.end(),
1439             [cis_conn_hdl](auto& info) { return cis_conn_hdl == info.stream_handle; });
1440     log::assert_that(iter == params.stream_config.stream_map.end(),
1441                      "Stream is already there 0x{:04x}", cis_conn_hdl);
1442 
1443     params.num_of_devices++;
1444     params.num_of_channels += ase->codec_config.channel_count_per_iso_stream;
1445 
1446     auto ase_audio_channel_allocation = ase->codec_config.GetAudioChannelAllocation();
1447     params.audio_channel_allocation |= ase_audio_channel_allocation;
1448 
1449     params.stream_config.bits_per_sample = ase->codec_config.GetBitsPerSample();
1450 
1451     auto address_with_type = leAudioDevice->GetAddressWithType();
1452     auto info = ::bluetooth::le_audio::stream_map_info(ase->cis_conn_hdl,
1453                                                        ase_audio_channel_allocation, true);
1454     info.codec_config = ase->codec_config;
1455     info.target_latency = ase->target_latency;
1456     info.target_phy = ase->qos_config.phy;
1457     info.metadata = ase->metadata;
1458     info.address = address_with_type.bda;
1459     info.address_type = address_with_type.type;
1460     params.stream_config.stream_map.push_back(info);
1461 
1462     // Note that for the vendor codec some of the parameters will be missing
1463     auto core_config = ase->codec_config.params.GetAsCoreCodecConfig();
1464     if (params.stream_config.sampling_frequency_hz == 0) {
1465       params.stream_config.sampling_frequency_hz = core_config.GetSamplingFrequencyHz();
1466     } else {
1467       log::assert_that(
1468               params.stream_config.sampling_frequency_hz == core_config.GetSamplingFrequencyHz(),
1469               "sample freq mismatch: {}!={}", params.stream_config.sampling_frequency_hz,
1470               core_config.GetSamplingFrequencyHz());
1471     }
1472 
1473     if (params.stream_config.octets_per_codec_frame == 0) {
1474       params.stream_config.octets_per_codec_frame = *core_config.octets_per_codec_frame;
1475     } else {
1476       log::assert_that(
1477               params.stream_config.octets_per_codec_frame == *core_config.octets_per_codec_frame,
1478               "octets per frame mismatch: {}!={}", params.stream_config.octets_per_codec_frame,
1479               *core_config.octets_per_codec_frame);
1480     }
1481 
1482     if (params.stream_config.codec_frames_blocks_per_sdu == 0) {
1483       params.stream_config.codec_frames_blocks_per_sdu = *core_config.codec_frames_blocks_per_sdu;
1484     } else {
1485       log::assert_that(params.stream_config.codec_frames_blocks_per_sdu ==
1486                                *core_config.codec_frames_blocks_per_sdu,
1487                        "codec_frames_blocks_per_sdu: {}!={}",
1488                        params.stream_config.codec_frames_blocks_per_sdu,
1489                        *core_config.codec_frames_blocks_per_sdu);
1490     }
1491 
1492     if (params.stream_config.frame_duration_us == 0) {
1493       params.stream_config.frame_duration_us = core_config.GetFrameDurationUs();
1494     } else {
1495       log::assert_that(params.stream_config.frame_duration_us == core_config.GetFrameDurationUs(),
1496                        "frame_duration_us: {}!={}", params.stream_config.frame_duration_us,
1497                        core_config.GetFrameDurationUs());
1498     }
1499 
1500     params.stream_config.peer_delay_ms = group->GetRemoteDelay(ase->direction);
1501 
1502     log::info(
1503             "Added {} Stream Configuration. CIS Connection Handle: {}, Audio "
1504             "Channel Allocation: {}, Number Of Devices: {}, Number Of Channels: {}",
1505             (ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSink ? "Sink"
1506                                                                                  : "Source"),
1507             cis_conn_hdl, ase_audio_channel_allocation, params.num_of_devices,
1508             params.num_of_channels);
1509 
1510     /* Update CodecManager stream configuration */
1511     state_machine_callbacks_->OnUpdatedCisConfiguration(group->group_id_, ase->direction);
1512   }
1513 
isIntervalAndLatencyProperlySet(uint32_t sdu_interval_us,uint16_t max_latency_ms)1514   static bool isIntervalAndLatencyProperlySet(uint32_t sdu_interval_us, uint16_t max_latency_ms) {
1515     log::verbose("sdu_interval_us: {}, max_latency_ms: {}", sdu_interval_us, max_latency_ms);
1516 
1517     if (sdu_interval_us == 0) {
1518       return max_latency_ms == bluetooth::le_audio::types::kMaxTransportLatencyMin;
1519     }
1520     return (1000 * max_latency_ms) >= sdu_interval_us;
1521   }
1522 
ApplyDsaParams(LeAudioDeviceGroup * group,bluetooth::hci::iso_manager::cig_create_params & param)1523   void ApplyDsaParams(LeAudioDeviceGroup* group,
1524                       bluetooth::hci::iso_manager::cig_create_params& param) {
1525     log::info("DSA mode selected: {}", (int)group->dsa_.mode);
1526     group->dsa_.active = false;
1527 
1528     /* Unidirectional streaming */
1529     if (param.sdu_itv_stom == 0) {
1530       log::info("Media streaming, apply DSA parameters");
1531 
1532       switch (group->dsa_.mode) {
1533         case DsaMode::ISO_HW:
1534         case DsaMode::ISO_SW: {
1535           auto& cis_cfgs = param.cis_cfgs;
1536           auto it = cis_cfgs.begin();
1537 
1538           for (auto dsa_modes : group->GetAllowedDsaModesList()) {
1539             if (!dsa_modes.empty() && it != cis_cfgs.end()) {
1540               if (std::find(dsa_modes.begin(), dsa_modes.end(), group->dsa_.mode) !=
1541                   dsa_modes.end()) {
1542                 log::info("Device found with support for selected DsaMode");
1543 
1544                 group->dsa_.active = true;
1545 
1546                 param.sdu_itv_stom = bluetooth::le_audio::types::kLeAudioHeadtrackerSduItv;
1547                 param.max_trans_lat_stom =
1548                         bluetooth::le_audio::types::kLeAudioHeadtrackerMaxTransLat;
1549                 it->max_sdu_size_stom = bluetooth::le_audio::types::kLeAudioHeadtrackerMaxSduSize;
1550 
1551                 // Early draft of DSA 2.0 spec mentioned allocating 15 bytes for headtracker data
1552                 if (!group->DsaReducedSduSizeSupported()) {
1553                   log::verbose("Device does not support reduced headtracker SDU");
1554                   it->max_sdu_size_stom = 15;
1555                 }
1556 
1557                 it->rtn_stom = bluetooth::le_audio::types::kLeAudioHeadtrackerRtn;
1558 
1559                 it++;
1560               }
1561             }
1562           }
1563         } break;
1564 
1565         case DsaMode::ACL:
1566           /* Todo: Prioritize the ACL */
1567           break;
1568 
1569         case DsaMode::DISABLED:
1570         default:
1571           /* No need to change ISO parameters */
1572           break;
1573       }
1574     } else {
1575       log::debug("Bidirection streaming, ignore DSA mode");
1576     }
1577   }
1578 
CigCreate(LeAudioDeviceGroup * group)1579   bool CigCreate(LeAudioDeviceGroup* group) {
1580     uint32_t sdu_interval_mtos, sdu_interval_stom;
1581     uint16_t max_trans_lat_mtos, max_trans_lat_stom;
1582     uint8_t packing, framing, sca;
1583     std::vector<EXT_CIS_CFG> cis_cfgs;
1584 
1585     log::debug("Group: {}, id: {} cig state: {}", std::format_ptr(group), group->group_id_,
1586                ToString(group->cig.GetState()));
1587 
1588     if (group->cig.GetState() != CigState::NONE) {
1589       log::warn("Group {}, id: {} has invalid cig state: {}", std::format_ptr(group),
1590                 group->group_id_, ToString(group->cig.GetState()));
1591       return false;
1592     }
1593 
1594     sdu_interval_mtos = group->GetSduInterval(bluetooth::le_audio::types::kLeAudioDirectionSink);
1595     sdu_interval_stom = group->GetSduInterval(bluetooth::le_audio::types::kLeAudioDirectionSource);
1596     sca = group->GetSCA();
1597     packing = group->GetPacking();
1598     framing = group->GetFraming();
1599     max_trans_lat_mtos = group->GetMaxTransportLatencyMtos();
1600     max_trans_lat_stom = group->GetMaxTransportLatencyStom();
1601 
1602     uint16_t max_sdu_size_mtos = 0;
1603     uint16_t max_sdu_size_stom = 0;
1604     uint8_t phy_mtos = group->GetPhyBitmask(bluetooth::le_audio::types::kLeAudioDirectionSink);
1605     uint8_t phy_stom = group->GetPhyBitmask(bluetooth::le_audio::types::kLeAudioDirectionSource);
1606 
1607     if (!isIntervalAndLatencyProperlySet(sdu_interval_mtos, max_trans_lat_mtos) ||
1608         !isIntervalAndLatencyProperlySet(sdu_interval_stom, max_trans_lat_stom)) {
1609       log::error("Latency and interval not properly set");
1610       group->PrintDebugState();
1611       return false;
1612     }
1613 
1614     // Use 1M Phy for the ACK packet from remote device to phone for better
1615     // sensitivity
1616     if (group->asymmetric_phy_for_unidirectional_cis_supported && sdu_interval_stom == 0 &&
1617         (phy_stom & bluetooth::hci::kIsoCigPhy1M) != 0) {
1618       log::info("Use asymmetric PHY for unidirectional CIS");
1619       phy_stom = bluetooth::hci::kIsoCigPhy1M;
1620     }
1621 
1622     uint8_t rtn_mtos = 0;
1623     uint8_t rtn_stom = 0;
1624 
1625     /* Currently assumed Sink/Source configuration is same across cis types.
1626      * If a cis in cises_ is currently associated with active device/ASE(s),
1627      * use the Sink/Source configuration for the same.
1628      * If a cis in cises_ is not currently associated with active device/ASE(s),
1629      * use the Sink/Source configuration for the cis in cises_
1630      * associated with a active device/ASE(s). When the same cis is associated
1631      * later, with active device/ASE(s), check if current configuration is
1632      * supported or not, if not, reconfigure CIG.
1633      */
1634     for (struct bluetooth::le_audio::types::cis& cis : group->cig.cises) {
1635       uint16_t max_sdu_size_mtos_temp =
1636               group->GetMaxSduSize(bluetooth::le_audio::types::kLeAudioDirectionSink, cis.id);
1637       uint16_t max_sdu_size_stom_temp =
1638               group->GetMaxSduSize(bluetooth::le_audio::types::kLeAudioDirectionSource, cis.id);
1639       uint8_t rtn_mtos_temp =
1640               group->GetRtn(bluetooth::le_audio::types::kLeAudioDirectionSink, cis.id);
1641       uint8_t rtn_stom_temp =
1642               group->GetRtn(bluetooth::le_audio::types::kLeAudioDirectionSource, cis.id);
1643 
1644       max_sdu_size_mtos = max_sdu_size_mtos_temp ? max_sdu_size_mtos_temp : max_sdu_size_mtos;
1645       max_sdu_size_stom = max_sdu_size_stom_temp ? max_sdu_size_stom_temp : max_sdu_size_stom;
1646       rtn_mtos = rtn_mtos_temp ? rtn_mtos_temp : rtn_mtos;
1647       rtn_stom = rtn_stom_temp ? rtn_stom_temp : rtn_stom;
1648     }
1649 
1650     for (struct bluetooth::le_audio::types::cis& cis : group->cig.cises) {
1651       EXT_CIS_CFG cis_cfg = {};
1652 
1653       cis_cfg.cis_id = cis.id;
1654       cis_cfg.phy_mtos = phy_mtos;
1655       cis_cfg.phy_stom = phy_stom;
1656       if (cis.type == bluetooth::le_audio::types::CisType::CIS_TYPE_BIDIRECTIONAL) {
1657         cis_cfg.max_sdu_size_mtos = max_sdu_size_mtos;
1658         cis_cfg.rtn_mtos = rtn_mtos;
1659         cis_cfg.max_sdu_size_stom = max_sdu_size_stom;
1660         cis_cfg.rtn_stom = rtn_stom;
1661         cis_cfgs.push_back(cis_cfg);
1662       } else if (cis.type == bluetooth::le_audio::types::CisType::CIS_TYPE_UNIDIRECTIONAL_SINK) {
1663         cis_cfg.max_sdu_size_mtos = max_sdu_size_mtos;
1664         cis_cfg.rtn_mtos = rtn_mtos;
1665         cis_cfg.max_sdu_size_stom = 0;
1666         cis_cfg.rtn_stom = 0;
1667         cis_cfgs.push_back(cis_cfg);
1668       } else {
1669         cis_cfg.max_sdu_size_mtos = 0;
1670         cis_cfg.rtn_mtos = 0;
1671         cis_cfg.max_sdu_size_stom = max_sdu_size_stom;
1672         cis_cfg.rtn_stom = rtn_stom;
1673         cis_cfgs.push_back(cis_cfg);
1674       }
1675     }
1676 
1677     if ((sdu_interval_mtos == 0 && sdu_interval_stom == 0) ||
1678         (max_trans_lat_mtos == bluetooth::le_audio::types::kMaxTransportLatencyMin &&
1679          max_trans_lat_stom == bluetooth::le_audio::types::kMaxTransportLatencyMin) ||
1680         (max_sdu_size_mtos == 0 && max_sdu_size_stom == 0)) {
1681       log::error("Trying to create invalid group");
1682       group->PrintDebugState();
1683       return false;
1684     }
1685 
1686     bluetooth::hci::iso_manager::cig_create_params param = {
1687             .sdu_itv_mtos = sdu_interval_mtos,
1688             .sdu_itv_stom = sdu_interval_stom,
1689             .sca = sca,
1690             .packing = packing,
1691             .framing = framing,
1692             .max_trans_lat_stom = max_trans_lat_stom,
1693             .max_trans_lat_mtos = max_trans_lat_mtos,
1694             .cis_cfgs = std::move(cis_cfgs),
1695     };
1696 
1697     ApplyDsaParams(group, param);
1698 
1699     log_history_->AddLogHistory(kLogStateMachineTag, group->group_id_, RawAddress::kEmpty,
1700                                 kLogCigCreateOp + "#CIS: " + std::to_string(param.cis_cfgs.size()));
1701 
1702     group->cig.SetState(CigState::CREATING);
1703     IsoManager::GetInstance()->CreateCig(group->group_id_, std::move(param));
1704     log::debug("Group: {}, id: {} cig state: {}", std::format_ptr(group), group->group_id_,
1705                ToString(group->cig.GetState()));
1706     return true;
1707   }
1708 
CisCreateForDevice(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)1709   static bool CisCreateForDevice(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
1710     std::vector<EXT_CIS_CREATE_CFG> conn_pairs;
1711     struct ase* ase = leAudioDevice->GetFirstActiveAse();
1712 
1713     /* Make sure CIG is there */
1714     if (group->cig.GetState() != CigState::CREATED) {
1715       log::error("CIG is not created for group_id {}", group->group_id_);
1716       group->PrintDebugState();
1717       return false;
1718     }
1719 
1720     std::stringstream extra_stream;
1721     do {
1722       /* First in ase pair is Sink, second Source */
1723       auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(ase->cis_conn_hdl);
1724 
1725       /* Already in pending state - bi-directional CIS or seconde CIS to same
1726        * device */
1727       if (ase->cis_state == CisState::CONNECTING || ase->cis_state == CisState::CONNECTED) {
1728         continue;
1729       }
1730 
1731       if (ases_pair.sink) {
1732         ases_pair.sink->cis_state = CisState::CONNECTING;
1733       }
1734       if (ases_pair.source) {
1735         ases_pair.source->cis_state = CisState::CONNECTING;
1736       }
1737 
1738       uint16_t acl_handle = get_btm_client_interface().peer.BTM_GetHCIConnHandle(
1739               leAudioDevice->address_, BT_TRANSPORT_LE);
1740       conn_pairs.push_back({.cis_conn_handle = ase->cis_conn_hdl, .acl_conn_handle = acl_handle});
1741       log::info("cis handle: 0x{:04x}, acl handle: 0x{:04x}", ase->cis_conn_hdl, acl_handle);
1742       extra_stream << "cis_h:" << loghex(ase->cis_conn_hdl) << " acl_h:" << loghex(acl_handle)
1743                    << ";;";
1744     } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
1745 
1746     LeAudioLogHistory::Get()->AddLogHistory(
1747             kLogStateMachineTag, leAudioDevice->group_id_, RawAddress::kEmpty,
1748             kLogCisCreateOp + "#CIS: " + std::to_string(conn_pairs.size()), extra_stream.str());
1749 
1750     IsoManager::GetInstance()->EstablishCis({.conn_pairs = std::move(conn_pairs)});
1751 
1752     return true;
1753   }
1754 
CisCreate(LeAudioDeviceGroup * group)1755   static bool CisCreate(LeAudioDeviceGroup* group) {
1756     LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice();
1757     struct ase* ase;
1758     std::vector<EXT_CIS_CREATE_CFG> conn_pairs;
1759 
1760     log::assert_that(leAudioDevice, "Shouldn't be called without an active device.");
1761 
1762     /* Make sure CIG is there */
1763     if (group->cig.GetState() != CigState::CREATED) {
1764       log::error("CIG is not created for group_id {}", group->group_id_);
1765       group->PrintDebugState();
1766       return false;
1767     }
1768 
1769     do {
1770       ase = leAudioDevice->GetFirstActiveAse();
1771       log::assert_that(ase, "shouldn't be called without an active ASE");
1772       do {
1773         /* First is ase pair is Sink, second Source */
1774         auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(ase->cis_conn_hdl);
1775 
1776         /* Already in pending state - bi-directional CIS */
1777         if (ase->cis_state == CisState::CONNECTING) {
1778           continue;
1779         }
1780 
1781         if (ases_pair.sink) {
1782           ases_pair.sink->cis_state = CisState::CONNECTING;
1783         }
1784         if (ases_pair.source) {
1785           ases_pair.source->cis_state = CisState::CONNECTING;
1786         }
1787 
1788         uint16_t acl_handle = get_btm_client_interface().peer.BTM_GetHCIConnHandle(
1789                 leAudioDevice->address_, BT_TRANSPORT_LE);
1790         conn_pairs.push_back({.cis_conn_handle = ase->cis_conn_hdl, .acl_conn_handle = acl_handle});
1791         log::debug("cis handle: {} acl handle : 0x{:x}", ase->cis_conn_hdl, acl_handle);
1792       } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
1793     } while ((leAudioDevice = group->GetNextActiveDevice(leAudioDevice)));
1794 
1795     IsoManager::GetInstance()->EstablishCis({.conn_pairs = std::move(conn_pairs)});
1796 
1797     return true;
1798   }
1799 
PrepareDataPath(int group_id,struct ase * ase)1800   static void PrepareDataPath(int group_id, struct ase* ase) {
1801     bluetooth::hci::iso_manager::iso_data_path_params param = {
1802             .data_path_dir = ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSink
1803                                      ? bluetooth::hci::iso_manager::kIsoDataPathDirectionIn
1804                                      : bluetooth::hci::iso_manager::kIsoDataPathDirectionOut,
1805             .data_path_id = ase->data_path_configuration.dataPathId,
1806             .codec_id_format = ase->data_path_configuration.isoDataPathConfig.codecId.coding_format,
1807             .codec_id_company =
1808                     ase->data_path_configuration.isoDataPathConfig.codecId.vendor_company_id,
1809             .codec_id_vendor =
1810                     ase->data_path_configuration.isoDataPathConfig.codecId.vendor_codec_id,
1811             .controller_delay = ase->data_path_configuration.isoDataPathConfig.controllerDelayUs,
1812             .codec_conf = ase->data_path_configuration.isoDataPathConfig.configuration,
1813     };
1814 
1815     LeAudioLogHistory::Get()->AddLogHistory(
1816             kLogStateMachineTag, group_id, RawAddress::kEmpty,
1817             kLogSetDataPathOp + "cis_h:" + loghex(ase->cis_conn_hdl),
1818             "direction: " + loghex(param.data_path_dir) + ", codecId: " +
1819                     ToString(ase->data_path_configuration.isoDataPathConfig.codecId));
1820 
1821     ase->data_path_state = DataPathState::CONFIGURING;
1822     IsoManager::GetInstance()->SetupIsoDataPath(ase->cis_conn_hdl, std::move(param));
1823   }
1824 
ReleaseDataPath(LeAudioDeviceGroup * group)1825   static void ReleaseDataPath(LeAudioDeviceGroup* group) {
1826     LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice();
1827     log::assert_that(leAudioDevice, "Shouldn't be called without an active device.");
1828 
1829     auto ase = leAudioDevice->GetFirstActiveAseByCisAndDataPathState(CisState::CONNECTED,
1830                                                                      DataPathState::CONFIGURED);
1831     log::assert_that(ase, "Shouldn't be called without an active ASE.");
1832     RemoveDataPathByCisHandle(leAudioDevice, ase->cis_conn_hdl);
1833   }
1834 
SetAseState(LeAudioDevice * leAudioDevice,struct ase * ase,AseState state)1835   void SetAseState(LeAudioDevice* leAudioDevice, struct ase* ase, AseState state) {
1836     log::info("{} ({}), ase_id: {}, {} -> {}", leAudioDevice->address_, leAudioDevice->group_id_,
1837               ase->id, ToString(ase->state), ToString(state));
1838 
1839     log_history_->AddLogHistory(kLogStateMachineTag, leAudioDevice->group_id_,
1840                                 leAudioDevice->address_,
1841                                 "ASE_ID " + std::to_string(ase->id) + ": " + kLogStateChangedOp,
1842                                 ToString(ase->state) + "->" + ToString(state));
1843 
1844     ase->state = state;
1845   }
1846 
getDeviceTryingToAttachTheStream(LeAudioDeviceGroup * group)1847   LeAudioDevice* getDeviceTryingToAttachTheStream(LeAudioDeviceGroup* group) {
1848     /* Device which is attaching the stream is just an active device not in
1849      * STREAMING state and NOT in  the RELEASING state.
1850      * The precondition is, that TargetState is Streaming
1851      */
1852 
1853     log::debug("group_id: {}, targetState: {}", group->group_id_,
1854                ToString(group->GetTargetState()));
1855 
1856     if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
1857       return nullptr;
1858     }
1859 
1860     for (auto dev = group->GetFirstActiveDevice(); dev != nullptr;
1861          dev = group->GetNextActiveDevice(dev)) {
1862       if (!dev->HaveAllActiveAsesSameState(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) &&
1863           !dev->HaveAnyReleasingAse()) {
1864         log::debug("Attaching device {} to group_id: {}", dev->address_, group->group_id_);
1865         return dev;
1866       }
1867     }
1868     return nullptr;
1869   }
1870 
AseStateMachineProcessIdle(struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr &,struct ase * ase,LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)1871   void AseStateMachineProcessIdle(
1872           struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr& /*arh*/, struct ase* ase,
1873           LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
1874     switch (ase->state) {
1875       case AseState::BTA_LE_AUDIO_ASE_STATE_IDLE:
1876       case AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED:
1877         break;
1878       case AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING: {
1879         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
1880         ase->active = false;
1881         ase->configured_for_context_type =
1882                 bluetooth::le_audio::types::LeAudioContextType::UNINITIALIZED;
1883 
1884         if (!leAudioDevice->HaveAllActiveAsesSameState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE)) {
1885           /* More ASEs notification from this device has to come for this group
1886            */
1887           log::debug("Wait for more ASE to configure for device {}", leAudioDevice->address_);
1888           return;
1889         }
1890 
1891         if (!group->HaveAllActiveDevicesAsesTheSameState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE)) {
1892           log::debug("Waiting for more devices to get into idle state");
1893           return;
1894         }
1895 
1896         /* Last node is in releasing state*/
1897         group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
1898         group->PrintDebugState();
1899 
1900         /* If all CISes are disconnected, notify upper layer about IDLE state,
1901          * otherwise wait for */
1902         if (!group->HaveAllCisesDisconnected() ||
1903             getDeviceTryingToAttachTheStream(group) != nullptr) {
1904           log::warn("Not all CISes removed before going to IDLE for group {}, waiting...",
1905                     group->group_id_);
1906           group->PrintDebugState();
1907           return;
1908         }
1909 
1910         cancel_watchdog_if_needed(group->group_id_);
1911         ReleaseCisIds(group);
1912         state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::IDLE);
1913 
1914         break;
1915       }
1916       case AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED:
1917       case AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING:
1918         log::error("Ignore invalid attempt of state transition from  {} to {}, {}, ase_id: {}",
1919                    ToString(ase->state), ToString(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE),
1920                    leAudioDevice->address_, ase->id);
1921         group->PrintDebugState();
1922         break;
1923       case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING:
1924       case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING:
1925         log::error("Invalid state transition from {} to {}, {}, ase_id: {}. Stopping the stream.",
1926                    ToString(ase->state), ToString(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE),
1927                    leAudioDevice->address_, ase->id);
1928         group->PrintDebugState();
1929         StopStream(group);
1930         break;
1931     }
1932   }
1933 
PrepareAndSendQoSToTheGroup(LeAudioDeviceGroup * group)1934   void PrepareAndSendQoSToTheGroup(LeAudioDeviceGroup* group) {
1935     LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice();
1936     if (!leAudioDevice) {
1937       log::error("No active device for the group");
1938       group->PrintDebugState();
1939       ClearGroup(group, true);
1940       return;
1941     }
1942 
1943     for (; leAudioDevice; leAudioDevice = group->GetNextActiveDevice(leAudioDevice)) {
1944       PrepareAndSendConfigQos(group, leAudioDevice);
1945     }
1946   }
1947 
PrepareAndSendCodecConfigToTheGroup(LeAudioDeviceGroup * group)1948   bool PrepareAndSendCodecConfigToTheGroup(LeAudioDeviceGroup* group) {
1949     log::info("group_id: {}", group->group_id_);
1950     auto leAudioDevice = group->GetFirstActiveDevice();
1951     if (!leAudioDevice) {
1952       log::error("No active device for the group");
1953       return false;
1954     }
1955 
1956     for (; leAudioDevice; leAudioDevice = group->GetNextActiveDevice(leAudioDevice)) {
1957       PrepareAndSendCodecConfigure(group, leAudioDevice);
1958     }
1959     return true;
1960   }
1961 
PrepareAndSendCodecConfigure(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)1962   void PrepareAndSendCodecConfigure(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
1963     struct bluetooth::le_audio::client_parser::ascs::ctp_codec_conf conf;
1964     std::vector<struct bluetooth::le_audio::client_parser::ascs::ctp_codec_conf> confs;
1965     struct ase* ase;
1966     std::stringstream msg_stream;
1967     std::stringstream extra_stream;
1968 
1969     if (!group->cig.AssignCisIds(leAudioDevice)) {
1970       log::error("unable to assign CIS IDs");
1971       StopStream(group);
1972       return;
1973     }
1974 
1975     if (group->cig.GetState() == CigState::CREATED) {
1976       group->AssignCisConnHandlesToAses(leAudioDevice);
1977     }
1978 
1979     msg_stream << kLogAseConfigOp;
1980 
1981     ase = leAudioDevice->GetFirstActiveAse();
1982     log::assert_that(ase, "shouldn't be called without an active ASE");
1983     for (; ase != nullptr; ase = leAudioDevice->GetNextActiveAse(ase)) {
1984       log::debug("device: {}, ase_id: {}, cis_id: {}, ase state: {}", leAudioDevice->address_,
1985                  ase->id, ase->cis_id, ToString(ase->state));
1986       conf.ase_id = ase->id;
1987       conf.target_latency = ase->target_latency;
1988       conf.target_phy = group->GetTargetPhy(ase->direction);
1989       conf.codec_id = ase->codec_config.id;
1990 
1991       if (!ase->codec_config.vendor_params.empty()) {
1992         log::debug("Using vendor codec configuration.");
1993         conf.codec_config = ase->codec_config.vendor_params;
1994       } else {
1995         conf.codec_config = ase->codec_config.params.RawPacket();
1996       }
1997       confs.push_back(conf);
1998 
1999       msg_stream << "ASE_ID " << +conf.ase_id << ",";
2000       if (ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSink) {
2001         extra_stream << "snk,";
2002       } else {
2003         extra_stream << "src,";
2004       }
2005       extra_stream << +conf.codec_id.coding_format << "," << +conf.target_latency << ";;";
2006     }
2007 
2008     leAudioDevice->last_ase_ctp_command_sent =
2009             bluetooth::le_audio::client_parser::ascs::kCtpOpcodeCodecConfiguration;
2010 
2011     std::vector<uint8_t> value;
2012     log::info("{} -> ", leAudioDevice->address_);
2013     bluetooth::le_audio::client_parser::ascs::PrepareAseCtpCodecConfig(confs, value);
2014     WriteToControlPoint(leAudioDevice, value);
2015 
2016     log_history_->AddLogHistory(kLogControlPointCmd, group->group_id_, leAudioDevice->address_,
2017                                 msg_stream.str(), extra_stream.str());
2018   }
2019 
AseStateMachineProcessCodecConfigured(struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr &,struct ase * ase,uint8_t * data,uint16_t len,LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)2020   void AseStateMachineProcessCodecConfigured(
2021           struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr& /*arh*/, struct ase* ase,
2022           uint8_t* data, uint16_t len, LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
2023     if (!group) {
2024       log::error("leAudioDevice doesn't belong to any group");
2025 
2026       return;
2027     }
2028 
2029     /* Internal helper for filling in the QoS parameters for an ASE, based
2030      * on the codec configure state and the prefferend ASE QoS parameters.
2031      * Note: The whole group state dependent parameters (out_cfg.framing, and
2032      *       out.cfg.presentation_delay) are calculated later, in the
2033      *       PrepareAndSendConfigQos(), once the whole group transitions to a
2034      *       proper state.
2035      */
2036     auto qos_config_update = [leAudioDevice](
2037                                      const struct bluetooth::le_audio::client_parser::ascs::
2038                                              ase_codec_configured_state_params& rsp,
2039                                      bluetooth::le_audio::types::AseQosPreferences& out_qos,
2040                                      bluetooth::le_audio::types::AseQosConfiguration& out_cfg) {
2041       out_qos.supported_framing = rsp.framing;
2042       out_qos.preferred_phy = rsp.preferred_phy;
2043       out_qos.preferred_retrans_nb = rsp.preferred_retrans_nb;
2044       out_qos.pres_delay_min = rsp.pres_delay_min;
2045       out_qos.pres_delay_max = rsp.pres_delay_max;
2046       out_qos.preferred_pres_delay_min = rsp.preferred_pres_delay_min;
2047       out_qos.preferred_pres_delay_max = rsp.preferred_pres_delay_max;
2048 
2049       /* Validate and update QoS to be consistent */
2050       if ((!out_cfg.max_transport_latency ||
2051            out_cfg.max_transport_latency > rsp.max_transport_latency) ||
2052           !out_cfg.retrans_nb || !out_cfg.phy) {
2053         out_cfg.max_transport_latency = rsp.max_transport_latency;
2054         out_cfg.retrans_nb = rsp.preferred_retrans_nb;
2055         out_cfg.phy = leAudioDevice->GetPreferredPhyBitmask(rsp.preferred_phy);
2056         log::info(
2057                 "Using server preferred QoS settings. Max Transport Latency: {}, "
2058                 "Retransmission Number: {}, Phy: {}",
2059                 out_cfg.max_transport_latency, out_cfg.retrans_nb, out_cfg.phy);
2060       }
2061     };
2062 
2063     /* ase contain current ASE state. New state is in "arh" */
2064     switch (ase->state) {
2065       case AseState::BTA_LE_AUDIO_ASE_STATE_IDLE: {
2066         struct bluetooth::le_audio::client_parser::ascs::ase_codec_configured_state_params rsp;
2067 
2068         /* Cache codec configured status values for further
2069          * configuration/reconfiguration
2070          */
2071         if (!ParseAseStatusCodecConfiguredStateParams(rsp, len, data)) {
2072           StopStream(group);
2073           return;
2074         }
2075 
2076         uint16_t cig_curr_max_trans_lat_mtos = group->GetMaxTransportLatencyMtos();
2077         uint16_t cig_curr_max_trans_lat_stom = group->GetMaxTransportLatencyStom();
2078 
2079         if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
2080           /* We are here because of the reconnection of the single device.
2081            * Reconfigure CIG if current CIG supported Max Transport Latency for
2082            * a direction, cannot be supported by the newly connected member
2083            * device's ASE for the direction.
2084            */
2085           if ((ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSink &&
2086                cig_curr_max_trans_lat_mtos > rsp.max_transport_latency) ||
2087               (ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSource &&
2088                cig_curr_max_trans_lat_stom > rsp.max_transport_latency)) {
2089             group->SetPendingConfiguration();
2090             StopStream(group);
2091             return;
2092           }
2093         }
2094 
2095         qos_config_update(rsp, ase->qos_preferences, ase->qos_config);
2096         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
2097 
2098         if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {
2099           /* This is autonomus change of the remote device */
2100           log::debug("Autonomus change for device {}, ase id {}. Just store it.",
2101                      leAudioDevice->address_, ase->id);
2102           if (group->HaveAllActiveDevicesAsesTheSameState(
2103                       AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED)) {
2104             group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
2105           }
2106           return;
2107         }
2108 
2109         if (leAudioDevice->HaveAnyUnconfiguredAses()) {
2110           /* More ASEs notification from this device has to come for this group
2111            */
2112           log::debug("More Ases to be configured for the device {}", leAudioDevice->address_);
2113           return;
2114         }
2115 
2116         if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
2117           /* We are here because of the reconnection of the single device. */
2118           /* Make sure that device is ready to be configured as we could also
2119            * get here triggered by the remote device. If device is not connected
2120            * yet, we should wait for the stack to trigger adding device to the
2121            * stream */
2122           if (leAudioDevice->GetConnectionState() ==
2123               bluetooth::le_audio::DeviceConnectState::CONNECTED) {
2124             PrepareAndSendConfigQos(group, leAudioDevice);
2125           } else {
2126             log::debug(
2127                     "Device {} initiated configured state but it is not yet ready to be configured",
2128                     leAudioDevice->address_);
2129           }
2130           return;
2131         }
2132 
2133         /* Configure ASEs for next device in group */
2134         if (group->HaveAnyActiveDeviceInUnconfiguredState()) {
2135           log::debug("Waiting for all the ASES in the Configured state");
2136           return;
2137         }
2138 
2139         /* Last node configured, process group to codec configured state */
2140         group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
2141 
2142         if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING ||
2143             group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
2144           if (group->cig.GetState() == CigState::CREATED) {
2145             /* It can happen on the earbuds switch scenario. When one device
2146              * is getting remove while other is adding to the stream and CIG is
2147              * already created.
2148              * Also if one of the set members got reconnected while the other was in QoSConfigured
2149              * state. In this case, state machine will keep CIG but will send Codec Config to all
2150              * the set members and when ASEs will move to Codec Configured State, we would like a
2151              * whole group to move to QoS Configure.*/
2152             PrepareAndSendQoSToTheGroup(group);
2153           } else if (!CigCreate(group)) {
2154             log::error("Could not create CIG. Stop the stream for group {}", group->group_id_);
2155             StopStream(group);
2156           }
2157           return;
2158         }
2159 
2160         if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED &&
2161             group->IsPendingConfiguration()) {
2162           log::info("Configured state completed");
2163 
2164           /* If all CISes are disconnected, notify upper layer about IDLE
2165            * state, otherwise wait for */
2166           if (!group->HaveAllCisesDisconnected()) {
2167             log::warn("Not all CISes removed before going to CONFIGURED for group {}, waiting...",
2168                       group->group_id_);
2169             group->PrintDebugState();
2170             return;
2171           }
2172 
2173           group->ClearPendingConfiguration();
2174           state_machine_callbacks_->StatusReportCb(group->group_id_,
2175                                                    GroupStreamStatus::CONFIGURED_BY_USER);
2176 
2177           /* No more transition for group */
2178           cancel_watchdog_if_needed(group->group_id_);
2179           return;
2180         }
2181 
2182         log::error(", invalid state transition, from: {} to {}", ToString(group->GetState()),
2183                    ToString(group->GetTargetState()));
2184         StopStream(group);
2185 
2186         break;
2187       }
2188       case AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED: {
2189         /* Received Configured in Configured state. This could be done
2190          * autonomously because of the reconfiguration done by us
2191          */
2192 
2193         struct bluetooth::le_audio::client_parser::ascs::ase_codec_configured_state_params rsp;
2194 
2195         /* Cache codec configured status values for further
2196          * configuration/reconfiguration
2197          */
2198         if (!ParseAseStatusCodecConfiguredStateParams(rsp, len, data)) {
2199           StopStream(group);
2200           return;
2201         }
2202 
2203         /* This may be a notification from a re-configured ASE */
2204         ase->reconfigure = false;
2205         qos_config_update(rsp, ase->qos_preferences, ase->qos_config);
2206 
2207         if (leAudioDevice->HaveAnyUnconfiguredAses()) {
2208           /* Waiting for others to be reconfigured */
2209           return;
2210         }
2211 
2212         if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING &&
2213             group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
2214           /* We are here because of the reconnection of the single device. */
2215           /* Make sure that device is ready to be configured as we could also
2216            * get here triggered by the remote device. If device is not connected
2217            * yet, we should wait for the stack to trigger adding device to the
2218            * stream */
2219           if (leAudioDevice->GetConnectionState() ==
2220               bluetooth::le_audio::DeviceConnectState::CONNECTED) {
2221             PrepareAndSendConfigQos(group, leAudioDevice);
2222           } else {
2223             log::debug(
2224                     "Device {} initiated configured state but it is not yet ready to be configured",
2225                     leAudioDevice->address_);
2226           }
2227           return;
2228         }
2229 
2230         if (group->HaveAnyActiveDeviceInUnconfiguredState()) {
2231           log::debug("Waiting for all the devices to be configured for group id {}",
2232                      group->group_id_);
2233           return;
2234         }
2235 
2236         /* Last node configured, process group to codec configured state */
2237         group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
2238 
2239         if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING ||
2240             group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
2241           if (group->cig.GetState() == CigState::CREATED) {
2242             /* It can happen on the earbuds switch scenario. When one device
2243              * is getting remove while other is adding to the stream and CIG is
2244              * already created */
2245             PrepareAndSendConfigQos(group, leAudioDevice);
2246           } else if (!CigCreate(group)) {
2247             log::error("Could not create CIG. Stop the stream for group {}", group->group_id_);
2248             StopStream(group);
2249           }
2250           return;
2251         }
2252 
2253         if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED &&
2254             group->IsPendingConfiguration()) {
2255           log::info("Configured state completed");
2256           group->ClearPendingConfiguration();
2257           state_machine_callbacks_->StatusReportCb(group->group_id_,
2258                                                    GroupStreamStatus::CONFIGURED_BY_USER);
2259 
2260           /* No more transition for group */
2261           cancel_watchdog_if_needed(group->group_id_);
2262           return;
2263         }
2264 
2265         log::info("Autonomous change, from: {} to {}", ToString(group->GetState()),
2266                   ToString(group->GetTargetState()));
2267 
2268         break;
2269       }
2270       case AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED:
2271         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
2272         group->PrintDebugState();
2273         break;
2274       case AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING:
2275         log::error("Ignore invalid attempt of state transition from {} to {}, {}, ase_id: {}",
2276                    ToString(ase->state),
2277                    ToString(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED),
2278                    leAudioDevice->address_, ase->id);
2279         group->PrintDebugState();
2280         break;
2281       case AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING:
2282         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
2283         ase->active = false;
2284 
2285         if (!leAudioDevice->HaveAllActiveAsesSameState(
2286                     AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED)) {
2287           /* More ASEs notification from this device has to come for this group
2288            */
2289           log::debug("Wait for more ASE to configure for device {}", leAudioDevice->address_);
2290           return;
2291         }
2292 
2293         {
2294           auto activeDevice = group->GetFirstActiveDevice();
2295           if (activeDevice) {
2296             log::debug("There is at least one active device {}, wait to become inactive",
2297                        activeDevice->address_);
2298             return;
2299           }
2300         }
2301 
2302         /* Last node is in releasing state*/
2303         group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED);
2304         /* Remote device has cache and keep staying in configured state after
2305          * release. Therefore, we assume this is a target state requested by
2306          * remote device.
2307          */
2308         group->SetTargetState(group->GetState());
2309 
2310         if (!group->HaveAllCisesDisconnected()) {
2311           log::warn("Not all CISes removed before going to IDLE for group {}, waiting...",
2312                     group->group_id_);
2313           group->PrintDebugState();
2314           return;
2315         }
2316 
2317         cancel_watchdog_if_needed(group->group_id_);
2318 
2319         state_machine_callbacks_->StatusReportCb(group->group_id_,
2320                                                  GroupStreamStatus::CONFIGURED_AUTONOMOUS);
2321         break;
2322       case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING:
2323       case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING:
2324         log::error("Invalid state transition from {} to {}, {}, ase_id: {}. Stopping the stream",
2325                    ToString(ase->state),
2326                    ToString(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED),
2327                    leAudioDevice->address_, ase->id);
2328         group->PrintDebugState();
2329         StopStream(group);
2330         break;
2331     }
2332   }
2333 
AseStateMachineProcessQosConfigured(struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr &,struct ase * ase,LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)2334   void AseStateMachineProcessQosConfigured(
2335           struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr& /*arh*/, struct ase* ase,
2336           LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
2337     if (!group) {
2338       log::error("leAudioDevice doesn't belong to any group");
2339 
2340       return;
2341     }
2342 
2343     switch (ase->state) {
2344       case AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED:
2345         log::info(
2346                 "Unexpected state transition from {} to {}, {}, ase_id: {}, "
2347                 "fallback to transition from {} to {}",
2348                 ToString(ase->state), ToString(AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED),
2349                 leAudioDevice->address_, ase->id,
2350                 ToString(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED),
2351                 ToString(AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED));
2352         group->PrintDebugState();
2353         [[fallthrough]];
2354 
2355       case AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED: {
2356         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
2357 
2358         if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING &&
2359             group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
2360           log::warn("{}, ase_id: {}, target state: {}", leAudioDevice->address_, ase->id,
2361                     ToString(group->GetTargetState()));
2362           group->PrintDebugState();
2363           return;
2364         }
2365 
2366         if (!leAudioDevice->HaveAllActiveAsesSameState(
2367                     AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED)) {
2368           /* More ASEs notification from this device has to come for this group
2369            */
2370           return;
2371         }
2372 
2373         if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
2374           /* We are here because of the reconnection of the single device. */
2375           PrepareAndSendEnable(leAudioDevice);
2376           return;
2377         }
2378 
2379         if (!group->HaveAllActiveDevicesAsesTheSameState(
2380                     AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED)) {
2381           log::debug("Waiting for all the devices to be in QoS state");
2382           return;
2383         }
2384 
2385         group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
2386 
2387         if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
2388           cancel_watchdog_if_needed(group->group_id_);
2389           group->ClearPendingConfiguration();
2390           state_machine_callbacks_->StatusReportCb(group->group_id_,
2391                                                    GroupStreamStatus::CONFIGURED_BY_USER);
2392           return;
2393         }
2394         PrepareAndSendEnableToTheGroup(group);
2395 
2396         break;
2397       }
2398       case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING:
2399         if (ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSource) {
2400           /* Source ASE cannot go from Streaming to QoS Configured state */
2401           log::error("invalid state transition, from: {}, to: {}", static_cast<int>(ase->state),
2402                      static_cast<int>(AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED));
2403           StopStream(group);
2404           return;
2405         }
2406 
2407         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
2408 
2409         if (group->HaveAllActiveDevicesAsesTheSameState(
2410                     AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED)) {
2411           group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
2412         }
2413 
2414         if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
2415           /* Process the Disable Transition of the rest of group members if no
2416            * more ASE notifications has to come from this device. */
2417           ProcessGroupDisable(group);
2418         } else {
2419           /* Remote may autonomously bring ASEs to QoS configured state */
2420           ProcessAutonomousDisable(group, leAudioDevice, ase);
2421         }
2422 
2423         break;
2424 
2425       case AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING: {
2426         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
2427 
2428         /* More ASEs notification from this device has to come for this group */
2429         if (!group->HaveAllActiveDevicesAsesTheSameState(
2430                     AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED)) {
2431           return;
2432         }
2433 
2434         group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
2435 
2436         if (!group->HaveAllCisesDisconnected()) {
2437           return;
2438         }
2439 
2440         if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
2441           /* No more transition for group */
2442           cancel_watchdog_if_needed(group->group_id_);
2443 
2444           state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::SUSPENDED);
2445         } else {
2446           log::error(", invalid state transition, from: {}, to: {}", ToString(group->GetState()),
2447                      ToString(group->GetTargetState()));
2448           StopStream(group);
2449           return;
2450         }
2451         break;
2452       }
2453       case AseState::BTA_LE_AUDIO_ASE_STATE_IDLE:
2454       case AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING:
2455         // Do nothing here, just print an error message
2456         log::error("Ignore invalid attempt of state transition from {} to {}, {}, ase_id: {}",
2457                    ToString(ase->state), ToString(AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED),
2458                    leAudioDevice->address_, ase->id);
2459         group->PrintDebugState();
2460         break;
2461       case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING:
2462         log::error("Invalid state transition from {} to {}, {}, ase_id: {}. Stopping the stream.",
2463                    ToString(ase->state), ToString(AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED),
2464                    leAudioDevice->address_, ase->id);
2465         StopStream(group);
2466         break;
2467     }
2468   }
2469 
ClearGroup(LeAudioDeviceGroup * group,bool report_idle_state)2470   void ClearGroup(LeAudioDeviceGroup* group, bool report_idle_state) {
2471     log::debug("group_id: {}", group->group_id_);
2472     group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2473     group->SetTargetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
2474 
2475     /* Clear group pending status */
2476     group->ClearStreamingMetadataContexts();
2477     group->ClearPendingConfiguration();
2478 
2479     cancel_watchdog_if_needed(group->group_id_);
2480     ReleaseCisIds(group);
2481     RemoveCigForGroup(group);
2482 
2483     if (report_idle_state) {
2484       state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::IDLE);
2485     }
2486   }
2487 
PrepareAndSendEnableToTheGroup(LeAudioDeviceGroup * group)2488   void PrepareAndSendEnableToTheGroup(LeAudioDeviceGroup* group) {
2489     log::info("group_id: {}", group->group_id_);
2490 
2491     auto leAudioDevice = group->GetFirstActiveDevice();
2492     if (!leAudioDevice) {
2493       log::error("No active device for the group");
2494       group->PrintDebugState();
2495       ClearGroup(group, true);
2496       return;
2497     }
2498 
2499     for (; leAudioDevice; leAudioDevice = group->GetNextActiveDevice(leAudioDevice)) {
2500       PrepareAndSendEnable(leAudioDevice);
2501     }
2502   }
2503 
PrepareAndSendEnable(LeAudioDevice * leAudioDevice)2504   void PrepareAndSendEnable(LeAudioDevice* leAudioDevice) {
2505     struct bluetooth::le_audio::client_parser::ascs::ctp_enable conf;
2506     std::vector<struct bluetooth::le_audio::client_parser::ascs::ctp_enable> confs;
2507     std::vector<uint8_t> value;
2508     struct ase* ase;
2509     std::stringstream msg_stream;
2510     std::stringstream extra_stream;
2511 
2512     msg_stream << kLogAseEnableOp;
2513 
2514     ase = leAudioDevice->GetFirstActiveAse();
2515     log::assert_that(ase, "shouldn't be called without an active ASE");
2516     do {
2517       log::debug("device: {}, ase_id: {}, cis_id: {}, ase state: {}", leAudioDevice->address_,
2518                  ase->id, ase->cis_id, ToString(ase->state));
2519       conf.ase_id = ase->id;
2520       conf.metadata = ase->metadata.RawPacket();
2521       confs.push_back(conf);
2522 
2523       /* Below is just for log history */
2524       msg_stream << "ASE_ID " << +ase->id << ",";
2525       extra_stream << "meta: " << base::HexEncode(conf.metadata.data(), conf.metadata.size())
2526                    << ";;";
2527     } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
2528 
2529     leAudioDevice->last_ase_ctp_command_sent =
2530             bluetooth::le_audio::client_parser::ascs::kCtpOpcodeEnable;
2531 
2532     bluetooth::le_audio::client_parser::ascs::PrepareAseCtpEnable(confs, value);
2533     WriteToControlPoint(leAudioDevice, value);
2534 
2535     log::info("group_id: {}, {}", leAudioDevice->group_id_, leAudioDevice->address_);
2536     log_history_->AddLogHistory(kLogControlPointCmd, leAudioDevice->group_id_,
2537                                 leAudioDevice->address_, msg_stream.str(), extra_stream.str());
2538   }
2539 
PrepareAndSendDisableToTheGroup(LeAudioDeviceGroup * group)2540   GroupStreamStatus PrepareAndSendDisableToTheGroup(LeAudioDeviceGroup* group) {
2541     log::info("grop_id: {}", group->group_id_);
2542 
2543     auto leAudioDevice = group->GetFirstActiveDevice();
2544     if (!leAudioDevice) {
2545       log::error("No active device for the group");
2546       group->PrintDebugState();
2547       ClearGroup(group, false);
2548       return GroupStreamStatus::IDLE;
2549     }
2550 
2551     for (; leAudioDevice; leAudioDevice = group->GetNextActiveDevice(leAudioDevice)) {
2552       PrepareAndSendDisable(leAudioDevice);
2553     }
2554     return GroupStreamStatus::SUSPENDING;
2555   }
2556 
PrepareAndSendDisable(LeAudioDevice * leAudioDevice)2557   void PrepareAndSendDisable(LeAudioDevice* leAudioDevice) {
2558     ase* ase = leAudioDevice->GetFirstActiveAse();
2559     log::assert_that(ase, "shouldn't be called without an active ASE");
2560 
2561     std::stringstream msg_stream;
2562     msg_stream << kLogAseDisableOp;
2563 
2564     std::vector<uint8_t> ids;
2565     do {
2566       log::debug("device: {}, ase_id: {}, cis_id: {}, ase state: {}", leAudioDevice->address_,
2567                  ase->id, ase->cis_id, ToString(ase->state));
2568       ids.push_back(ase->id);
2569 
2570       msg_stream << "ASE_ID " << +ase->id << ", ";
2571     } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
2572 
2573     leAudioDevice->last_ase_ctp_command_sent =
2574             bluetooth::le_audio::client_parser::ascs::kCtpOpcodeDisable;
2575 
2576     log::info("group_id: {}, {}", leAudioDevice->group_id_, leAudioDevice->address_);
2577     std::vector<uint8_t> value;
2578     bluetooth::le_audio::client_parser::ascs::PrepareAseCtpDisable(ids, value);
2579     WriteToControlPoint(leAudioDevice, value);
2580 
2581     log_history_->AddLogHistory(kLogControlPointCmd, leAudioDevice->group_id_,
2582                                 leAudioDevice->address_, msg_stream.str());
2583   }
2584 
PrepareAndSendReleaseToTheGroup(LeAudioDeviceGroup * group)2585   GroupStreamStatus PrepareAndSendReleaseToTheGroup(LeAudioDeviceGroup* group) {
2586     log::info("group_id: {}", group->group_id_);
2587     LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice();
2588     if (!leAudioDevice) {
2589       log::error("No active device for the group");
2590       group->PrintDebugState();
2591       ClearGroup(group, false);
2592       return GroupStreamStatus::IDLE;
2593     }
2594 
2595     bool releasing = false;
2596     for (; leAudioDevice; leAudioDevice = group->GetNextActiveDevice(leAudioDevice)) {
2597       releasing |= PrepareAndSendRelease(leAudioDevice);
2598     }
2599 
2600     if (releasing) {
2601       return GroupStreamStatus::RELEASING;
2602     }
2603 
2604     return GroupStreamStatus::IDLE;
2605   }
2606 
PrepareAndSendRelease(LeAudioDevice * leAudioDevice)2607   bool PrepareAndSendRelease(LeAudioDevice* leAudioDevice) {
2608     ase* ase = leAudioDevice->GetFirstActiveAse();
2609     log::assert_that(ase, "shouldn't be called without an active ASE");
2610 
2611     std::vector<uint8_t> ids;
2612     std::stringstream stream;
2613     stream << kLogAseReleaseOp;
2614 
2615     do {
2616       log::debug("device: {}, ase_id: {}, cis_id: {}, ase state: {}", leAudioDevice->address_,
2617                  ase->id, ase->cis_id, ToString(ase->state));
2618       if (ase->state != AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) {
2619         ids.push_back(ase->id);
2620         stream << "ASE_ID " << +ase->id << ",";
2621       } else {
2622         log::info("{}, ase: {} already in idle. Deactivate it", leAudioDevice->address_, ase->id);
2623         ase->active = false;
2624       }
2625     } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
2626 
2627     if (ids.empty()) {
2628       log::info("Nothing to send to {}", leAudioDevice->address_);
2629       return false;
2630     }
2631 
2632     leAudioDevice->last_ase_ctp_command_sent =
2633             bluetooth::le_audio::client_parser::ascs::kCtpOpcodeRelease;
2634 
2635     std::vector<uint8_t> value;
2636     bluetooth::le_audio::client_parser::ascs::PrepareAseCtpRelease(ids, value);
2637     WriteToControlPoint(leAudioDevice, value);
2638 
2639     log::info("group_id: {}, {}", leAudioDevice->group_id_, leAudioDevice->address_);
2640     log_history_->AddLogHistory(kLogControlPointCmd, leAudioDevice->group_id_,
2641                                 leAudioDevice->address_, stream.str());
2642     return true;
2643   }
2644 
PrepareAndSendConfigQos(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)2645   void PrepareAndSendConfigQos(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
2646     std::vector<struct bluetooth::le_audio::client_parser::ascs::ctp_qos_conf> confs;
2647 
2648     bool validate_transport_latency = false;
2649     bool validate_max_sdu_size = false;
2650 
2651     std::stringstream msg_stream;
2652     msg_stream << kLogAseQoSConfigOp;
2653 
2654     std::stringstream extra_stream;
2655     int number_of_active_ases = 0;
2656     int number_of_streaming_ases = 0;
2657 
2658     for (struct ase* ase = leAudioDevice->GetFirstActiveAse(); ase != nullptr;
2659          ase = leAudioDevice->GetNextActiveAse(ase)) {
2660       log::debug("device: {}, ase_id: {}, cis_id: {}, ase state: {}", leAudioDevice->address_,
2661                  ase->id, ase->cis_id, ToString(ase->state));
2662 
2663       /* QoS Config can be done on ASEs which are in Codec Configured and QoS Configured state.
2664        * If ASE is streaming, it can be skipped.
2665        */
2666       number_of_active_ases++;
2667       if (ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
2668         number_of_streaming_ases++;
2669         continue;
2670       }
2671 
2672       /* Fill in the whole group dependent ASE parameters */
2673       if (!group->GetPresentationDelay(&ase->qos_config.presentation_delay, ase->direction)) {
2674         log::error("inconsistent presentation delay for group");
2675         group->PrintDebugState();
2676         StopStream(group);
2677         return;
2678       }
2679       ase->qos_config.framing = group->GetFraming();
2680 
2681       struct bluetooth::le_audio::client_parser::ascs::ctp_qos_conf conf;
2682       conf.ase_id = ase->id;
2683       conf.cig = group->group_id_;
2684       conf.cis = ase->cis_id;
2685       conf.framing = ase->qos_config.framing;
2686       conf.phy = ase->qos_config.phy;
2687       conf.max_sdu = ase->qos_config.max_sdu_size;
2688       conf.retrans_nb = ase->qos_config.retrans_nb;
2689       conf.pres_delay = ase->qos_config.presentation_delay;
2690       conf.sdu_interval = ase->qos_config.sdu_interval;
2691 
2692       if (!conf.sdu_interval) {
2693         log::error("unsupported SDU interval for group");
2694         group->PrintDebugState();
2695         StopStream(group);
2696         return;
2697       }
2698 
2699       msg_stream << "ASE " << +conf.ase_id << ",";
2700       if (ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSink) {
2701         conf.max_transport_latency = group->GetMaxTransportLatencyMtos();
2702         extra_stream << "snk,";
2703       } else {
2704         conf.max_transport_latency = group->GetMaxTransportLatencyStom();
2705         extra_stream << "src,";
2706       }
2707 
2708       if (conf.max_transport_latency > bluetooth::le_audio::types::kMaxTransportLatencyMin) {
2709         validate_transport_latency = true;
2710       }
2711 
2712       if (conf.max_sdu > 0) {
2713         validate_max_sdu_size = true;
2714       }
2715       confs.push_back(conf);
2716 
2717       // dir...cis_id,sdu,lat,rtn,phy,frm;;
2718       extra_stream << +conf.cis << "," << +conf.max_sdu << "," << +conf.max_transport_latency << ","
2719                    << +conf.retrans_nb << "," << +conf.phy << "," << +conf.framing << ";;";
2720     }
2721 
2722     if (number_of_streaming_ases > 0 && number_of_streaming_ases == number_of_active_ases) {
2723       log::debug("Device {} is already streaming", leAudioDevice->address_);
2724       return;
2725     }
2726 
2727     if (confs.size() == 0 || !validate_transport_latency || !validate_max_sdu_size) {
2728       log::error("Invalid configuration or latency or sdu size");
2729       group->PrintDebugState();
2730       StopStream(group);
2731       return;
2732     }
2733 
2734     leAudioDevice->last_ase_ctp_command_sent =
2735             bluetooth::le_audio::client_parser::ascs::kCtpOpcodeQosConfiguration;
2736 
2737     std::vector<uint8_t> value;
2738     bluetooth::le_audio::client_parser::ascs::PrepareAseCtpConfigQos(confs, value);
2739     WriteToControlPoint(leAudioDevice, value);
2740 
2741     log::info("group_id: {}, {}", leAudioDevice->group_id_, leAudioDevice->address_);
2742     log_history_->AddLogHistory(kLogControlPointCmd, group->group_id_, leAudioDevice->address_,
2743                                 msg_stream.str(), extra_stream.str());
2744   }
2745 
PrepareAndSendUpdateMetadata(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,const BidirectionalPair<AudioContexts> & context_types,const BidirectionalPair<std::vector<uint8_t>> & ccid_lists)2746   void PrepareAndSendUpdateMetadata(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
2747                                     const BidirectionalPair<AudioContexts>& context_types,
2748                                     const BidirectionalPair<std::vector<uint8_t>>& ccid_lists) {
2749     std::vector<struct bluetooth::le_audio::client_parser::ascs::ctp_update_metadata> confs;
2750 
2751     std::stringstream msg_stream;
2752     msg_stream << kLogAseUpdateMetadataOp;
2753 
2754     std::stringstream extra_stream;
2755 
2756     if (!leAudioDevice->IsMetadataChanged(context_types, ccid_lists)) {
2757       return;
2758     }
2759 
2760     /* Request server to update ASEs with new metadata */
2761     for (struct ase* ase = leAudioDevice->GetFirstActiveAse(); ase != nullptr;
2762          ase = leAudioDevice->GetNextActiveAse(ase)) {
2763       log::debug("device: {}, ase_id: {}, cis_id: {}, ase state: {}", leAudioDevice->address_,
2764                  ase->id, ase->cis_id, ToString(ase->state));
2765 
2766       if (ase->state != AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING &&
2767           ase->state != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
2768         /* This might happen when update metadata happens on late connect */
2769         log::debug(
2770                 "Metadata for ase_id {} cannot be updated due to invalid ase state - see log above",
2771                 ase->id);
2772         continue;
2773       }
2774 
2775       msg_stream << "ASE_ID " << +ase->id << ",";
2776       if (ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSink) {
2777         extra_stream << "snk,";
2778       } else {
2779         extra_stream << "src,";
2780       }
2781 
2782       /* Filter multidirectional audio context for each ase direction */
2783       auto directional_audio_context =
2784               context_types.get(ase->direction) & group->GetAvailableContexts(ase->direction);
2785 
2786       LeAudioLtvMap new_metadata;
2787       if (directional_audio_context.any()) {
2788         new_metadata = leAudioDevice->GetMetadata(directional_audio_context,
2789                                                   ccid_lists.get(ase->direction));
2790       } else {
2791         new_metadata = leAudioDevice->GetMetadata(AudioContexts(LeAudioContextType::UNSPECIFIED),
2792                                                   std::vector<uint8_t>());
2793       }
2794 
2795       /* Do not update if metadata did not changed. */
2796       if (ase->metadata == new_metadata) {
2797         continue;
2798       }
2799 
2800       ase->metadata = new_metadata;
2801 
2802       struct bluetooth::le_audio::client_parser::ascs::ctp_update_metadata conf;
2803 
2804       conf.ase_id = ase->id;
2805       conf.metadata = ase->metadata.RawPacket();
2806       confs.push_back(conf);
2807 
2808       extra_stream << "meta: " << base::HexEncode(conf.metadata.data(), conf.metadata.size())
2809                    << ";;";
2810     }
2811 
2812     if (confs.size() != 0) {
2813       leAudioDevice->last_ase_ctp_command_sent =
2814               bluetooth::le_audio::client_parser::ascs::kCtpOpcodeUpdateMetadata;
2815 
2816       std::vector<uint8_t> value;
2817       bluetooth::le_audio::client_parser::ascs::PrepareAseCtpUpdateMetadata(confs, value);
2818       WriteToControlPoint(leAudioDevice, value);
2819 
2820       log::info("group_id: {}, {}", leAudioDevice->group_id_, leAudioDevice->address_);
2821 
2822       log_history_->AddLogHistory(kLogControlPointCmd, leAudioDevice->group_id_,
2823                                   leAudioDevice->address_, msg_stream.str(), extra_stream.str());
2824     }
2825   }
2826 
PrepareAndSendReceiverStartReady(LeAudioDevice * leAudioDevice,struct ase * ase)2827   void PrepareAndSendReceiverStartReady(LeAudioDevice* leAudioDevice, struct ase* ase) {
2828     std::vector<uint8_t> ids;
2829     std::vector<uint8_t> value;
2830     std::stringstream stream;
2831 
2832     stream << kLogAseStartReadyOp;
2833 
2834     do {
2835       if (ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSource) {
2836         stream << "ASE_ID " << +ase->id << ",";
2837         ids.push_back(ase->id);
2838       }
2839     } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
2840 
2841     if (ids.size() > 0) {
2842       leAudioDevice->last_ase_ctp_command_sent =
2843               bluetooth::le_audio::client_parser::ascs::kCtpOpcodeReceiverStartReady;
2844 
2845       bluetooth::le_audio::client_parser::ascs::PrepareAseCtpAudioReceiverStartReady(ids, value);
2846       WriteToControlPoint(leAudioDevice, value);
2847 
2848       log::info("group_id: {}, {}", leAudioDevice->group_id_, leAudioDevice->address_);
2849       log_history_->AddLogHistory(kLogControlPointCmd, leAudioDevice->group_id_,
2850                                   leAudioDevice->address_, stream.str());
2851     }
2852   }
2853 
AseStateMachineProcessEnabling(struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr &,struct ase * ase,LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)2854   void AseStateMachineProcessEnabling(
2855           struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr& /*arh*/, struct ase* ase,
2856           LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
2857     if (!group) {
2858       log::error("leAudioDevice doesn't belong to any group");
2859       return;
2860     }
2861 
2862     switch (ase->state) {
2863       case AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED:
2864         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING);
2865 
2866         if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
2867           log::warn("{}, ase_id: {}, target state: {}", leAudioDevice->address_, ase->id,
2868                     ToString(group->GetTargetState()));
2869           group->PrintDebugState();
2870           return;
2871         }
2872 
2873         if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
2874           if (ase->cis_state < CisState::CONNECTING) {
2875             /* We are here because of the reconnection of the single device. */
2876             if (!CisCreateForDevice(group, leAudioDevice)) {
2877               StopStream(group);
2878               return;
2879             }
2880           }
2881 
2882           if (!leAudioDevice->HaveAllActiveAsesCisEst()) {
2883             /* More cis established events has to come */
2884             return;
2885           }
2886 
2887           if (!leAudioDevice->IsReadyToCreateStream()) {
2888             /* Device still remains in ready to create stream state. It means
2889              * that more enabling status notifications has to come.
2890              */
2891             return;
2892           }
2893 
2894           /* All CISes created. Send start ready for source ASE before we can go
2895            * to streaming state.
2896            */
2897           struct ase* ase = leAudioDevice->GetFirstActiveAse();
2898           log::assert_that(ase != nullptr, "shouldn't be called without an active ASE, device {}",
2899                            leAudioDevice->address_.ToString());
2900           PrepareAndSendReceiverStartReady(leAudioDevice, ase);
2901 
2902           return;
2903         }
2904 
2905         if (leAudioDevice->IsReadyToCreateStream()) {
2906           ProcessGroupEnable(group);
2907         }
2908 
2909         break;
2910 
2911       case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING:
2912         /* Enable/Switch Content */
2913         break;
2914       default:
2915         log::error("invalid state transition, from: {}, to: {}", static_cast<int>(ase->state),
2916                    static_cast<int>(AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING));
2917         StopStream(group);
2918         break;
2919     }
2920   }
2921 
AseStateMachineProcessStreaming(struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr &,struct ase * ase,uint8_t * data,uint16_t len,LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)2922   void AseStateMachineProcessStreaming(
2923           struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr& /*arh*/, struct ase* ase,
2924           uint8_t* data, uint16_t len, LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
2925     if (!group) {
2926       log::error("leAudioDevice doesn't belong to any group");
2927 
2928       return;
2929     }
2930 
2931     struct bluetooth::le_audio::client_parser::ascs::ase_transient_state_params rsp;
2932 
2933     bool valid_response = ParseAseStatusTransientStateParams(rsp, len, data);
2934 
2935     std::optional<AudioContexts> streaming_audio_context;
2936     LeAudioLtvMap meta;
2937     if (valid_response && !rsp.metadata.empty() &&
2938         meta.Parse(rsp.metadata.data(), rsp.metadata.size())) {
2939       streaming_audio_context = meta.GetAsLeAudioMetadata().streaming_audio_context;
2940       if (!streaming_audio_context) {
2941         log::error("{}, ase_id: {}, Did not found streaming metadata while parsing metadata: {}",
2942                    leAudioDevice->address_, ase->id, bluetooth::common::ToHexString(rsp.metadata));
2943       }
2944     }
2945 
2946     switch (ase->state) {
2947       case AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED:
2948         log::error("{}, ase_id: {}, moving from QoS Configured to Streaming is impossible.",
2949                    leAudioDevice->address_, ase->id);
2950         group->PrintDebugState();
2951         StopStream(group);
2952         break;
2953 
2954       case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING: {
2955         std::vector<uint8_t> value;
2956 
2957         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2958         if (streaming_audio_context) {
2959           group->SetStreamingMetadataContexts(streaming_audio_context.value(), ase->direction);
2960         }
2961 
2962         if (!group->HaveAllActiveDevicesAsesTheSameState(
2963                     AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)) {
2964           /* More ASEs notification form this device has to come for this group
2965            */
2966           return;
2967         }
2968 
2969         /* The group is not ready to stream yet as there is still pending CIS Establish event and/or
2970          * Data Path setup complete event */
2971         if (!group->IsGroupStreamReady()) {
2972           log::info("CISes are not yet ready, wait for it.");
2973           group->SetNotifyStreamingWhenCisesAreReadyFlag(true);
2974           return;
2975         }
2976 
2977         if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
2978           /* We are here because of the reconnection of the single device */
2979           log::info("{}, Ase id: {}, ase state: {}", leAudioDevice->address_, ase->id,
2980                     bluetooth::common::ToString(ase->state));
2981           cancel_watchdog_if_needed(group->group_id_);
2982           state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::STREAMING);
2983           return;
2984         }
2985 
2986         if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
2987           /* No more transition for group */
2988           cancel_watchdog_if_needed(group->group_id_);
2989 
2990           /* Last node is in streaming state */
2991           group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
2992 
2993           state_machine_callbacks_->StatusReportCb(group->group_id_, GroupStreamStatus::STREAMING);
2994           return;
2995         }
2996 
2997         log::error(", invalid state transition, from: {}, to: {}", ToString(group->GetState()),
2998                    ToString(group->GetTargetState()));
2999         StopStream(group);
3000 
3001         break;
3002       }
3003       case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING: {
3004         if (!valid_response) {
3005           StopStream(group);
3006           return;
3007         }
3008 
3009         /* Cache current as streaming metadata */
3010         if (streaming_audio_context) {
3011           group->SetStreamingMetadataContexts(streaming_audio_context.value(), ase->direction);
3012         }
3013 
3014         break;
3015       }
3016       default:
3017         log::error("invalid state transition, from: {}, to: {}", static_cast<int>(ase->state),
3018                    static_cast<int>(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING));
3019         StopStream(group);
3020         break;
3021     }
3022   }
3023 
AseStateMachineProcessDisabling(struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr &,struct ase * ase,LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)3024   void AseStateMachineProcessDisabling(
3025           struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr& /*arh*/, struct ase* ase,
3026           LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
3027     if (!group) {
3028       log::error("leAudioDevice doesn't belong to any group");
3029 
3030       return;
3031     }
3032 
3033     if (ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSink) {
3034       /* Sink ASE state machine does not have Disabling state */
3035       log::error(", invalid state transition, from: {} , to: {}", ToString(group->GetState()),
3036                  ToString(group->GetTargetState()));
3037       StopStream(group);
3038       return;
3039     }
3040 
3041     switch (ase->state) {
3042       case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING:
3043         /* TODO: Disable */
3044         break;
3045       case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING:
3046         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING);
3047 
3048         /* Remote may autonomously bring ASEs to QoS configured state */
3049         if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
3050           ProcessAutonomousDisable(group, leAudioDevice, ase);
3051           return;
3052         }
3053 
3054         /* Process the Disable Transition of the rest of group members if no
3055          * more ASE notifications has to come from this device. */
3056         if (leAudioDevice->IsReadyToSuspendStream()) {
3057           ProcessGroupDisable(group);
3058         }
3059 
3060         break;
3061 
3062       default:
3063         log::error("invalid state transition, from: {}, to: {}", static_cast<int>(ase->state),
3064                    static_cast<int>(AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING));
3065         StopStream(group);
3066         break;
3067     }
3068   }
3069 
3070   typedef enum {
3071     CIS_DISCONNECTED,
3072     CIS_DISCONNECTING,
3073     CIS_STILL_NEEDED,
3074   } LocalCisDisconnectResult_t;
3075 
DisconnectCisIfNeeded(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,struct ase * ase)3076   LocalCisDisconnectResult_t DisconnectCisIfNeeded(LeAudioDeviceGroup* group,
3077                                                    LeAudioDevice* leAudioDevice, struct ase* ase) {
3078     log::debug(
3079             "Group id: {}, {}, ase id: {}, cis_handle: 0x{:04x}, direction: {}, "
3080             "data_path_state: {}, cis_state: {}",
3081             group->group_id_, leAudioDevice->address_, ase->id, ase->cis_conn_hdl,
3082             ase->direction == bluetooth::le_audio::types::kLeAudioDirectionSink ? "sink" : "source",
3083             bluetooth::common::ToString(ase->data_path_state),
3084             bluetooth::common::ToString(ase->cis_state));
3085 
3086     if (ase->cis_state == CisState::IDLE || ase->cis_state == CisState::ASSIGNED) {
3087       return CIS_DISCONNECTED;
3088     }
3089 
3090     if (ase->cis_state == CisState::DISCONNECTING) {
3091       log::debug(" CIS is already disconnecting, nothing to do here.");
3092       return CIS_DISCONNECTING;
3093     }
3094 
3095     auto bidirection_ase = leAudioDevice->GetAseToMatchBidirectionCis(ase);
3096     if (bidirection_ase != nullptr && bidirection_ase->cis_state == CisState::CONNECTED &&
3097         (bidirection_ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING ||
3098          bidirection_ase->state == AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING)) {
3099       log::info("Still waiting for the bidirectional ase {} to be released ({})",
3100                 bidirection_ase->id, bluetooth::common::ToString(bidirection_ase->state));
3101       return CIS_STILL_NEEDED;
3102     }
3103 
3104     ase->cis_state = CisState::DISCONNECTING;
3105     if (bidirection_ase) {
3106       bidirection_ase->cis_state = CisState::DISCONNECTING;
3107     }
3108 
3109     group->RemoveCisFromStreamIfNeeded(leAudioDevice, ase->cis_conn_hdl);
3110     IsoManager::GetInstance()->DisconnectCis(ase->cis_conn_hdl, HCI_ERR_PEER_USER);
3111     log_history_->AddLogHistory(kLogStateMachineTag, group->group_id_, leAudioDevice->address_,
3112                                 kLogCisDisconnectOp + "cis_h:" + loghex(ase->cis_conn_hdl));
3113     return CIS_DISCONNECTING;
3114   }
3115 
AseStateMachineProcessReleasing(struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr &,struct ase * ase,LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice)3116   void AseStateMachineProcessReleasing(
3117           struct bluetooth::le_audio::client_parser::ascs::ase_rsp_hdr& /*arh*/, struct ase* ase,
3118           LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
3119     if (!group) {
3120       log::error("leAudioDevice doesn't belong to any group");
3121 
3122       return;
3123     }
3124 
3125     switch (ase->state) {
3126       case AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING:
3127       case AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED:
3128       case AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED: {
3129         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING);
3130 
3131         if (group->HaveAllActiveDevicesAsesTheSameState(
3132                     AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING)) {
3133           group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING);
3134         }
3135 
3136         bool remove_cig = (DisconnectCisIfNeeded(group, leAudioDevice, ase) == CIS_DISCONNECTED);
3137 
3138         if (remove_cig && group->cig.GetState() == CigState::CREATED &&
3139             group->HaveAllCisesDisconnected() &&
3140             getDeviceTryingToAttachTheStream(group) == nullptr) {
3141           RemoveCigForGroup(group);
3142         }
3143 
3144         break;
3145       }
3146       case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING: {
3147         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING);
3148 
3149         bool remove_cig = (DisconnectCisIfNeeded(group, leAudioDevice, ase) == CIS_DISCONNECTED);
3150 
3151         if (!group->HaveAllActiveDevicesAsesTheSameState(
3152                     AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING)) {
3153           return;
3154         }
3155         group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING);
3156 
3157         if (remove_cig) {
3158           /* In the ENABLING state most probably there was no CISes created.
3159            * Make sure group is destroyed here */
3160           RemoveCigForGroup(group);
3161         }
3162         break;
3163       }
3164       case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING: {
3165         SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING);
3166 
3167         /* Happens when bi-directional completive ASE releasing state came */
3168         if (ase->cis_state == CisState::DISCONNECTING) {
3169           break;
3170         }
3171 
3172         if (ase->data_path_state == DataPathState::CONFIGURED) {
3173           RemoveDataPathByCisHandle(leAudioDevice, ase->cis_conn_hdl);
3174         } else if ((ase->cis_state == CisState::CONNECTED ||
3175                     ase->cis_state == CisState::CONNECTING) &&
3176                    ase->data_path_state == DataPathState::IDLE) {
3177           DisconnectCisIfNeeded(group, leAudioDevice, ase);
3178         } else {
3179           log::debug("Nothing to do ase data path state: {}",
3180                      static_cast<int>(ase->data_path_state));
3181         }
3182 
3183         if (group->HaveAllActiveDevicesAsesTheSameState(
3184                     AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING)) {
3185           group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING);
3186           group->ClearStreamingMetadataContexts();
3187           if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
3188             log::info("Group {} is doing autonomous release", group->group_id_);
3189             SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
3190             state_machine_callbacks_->StatusReportCb(group->group_id_,
3191                                                      GroupStreamStatus::RELEASING_AUTONOMOUS);
3192           }
3193         }
3194 
3195         break;
3196       }
3197       default:
3198         log::error("invalid state transition, from: {}, to: {}", static_cast<int>(ase->state),
3199                    static_cast<int>(AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING));
3200         break;
3201     }
3202   }
3203 
ProcessGroupEnable(LeAudioDeviceGroup * group)3204   void ProcessGroupEnable(LeAudioDeviceGroup* group) {
3205     if (group->GetState() != AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING) {
3206       /* Check if the group is ready to create stream. If not, keep waiting. */
3207       if (!group->IsGroupReadyToCreateStream()) {
3208         log::debug("Waiting for more ASEs to be in enabling or directly in streaming state");
3209         return;
3210       }
3211 
3212       /* Group can move to Enabling state now. */
3213       group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING);
3214     }
3215 
3216     /* If Target State is not streaming, then something is wrong. */
3217     if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
3218       log::error(", invalid state transition, from: {} , to: {}", ToString(group->GetState()),
3219                  ToString(group->GetTargetState()));
3220       StopStream(group);
3221       return;
3222     }
3223 
3224     /* Try to create CISes for the group */
3225     if (!CisCreate(group)) {
3226       StopStream(group);
3227     }
3228   }
3229 
ProcessGroupDisable(LeAudioDeviceGroup * group)3230   void ProcessGroupDisable(LeAudioDeviceGroup* group) {
3231     /* Disable ASEs for next device in group. */
3232     if (group->GetState() != AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING) {
3233       if (!group->IsGroupReadyToSuspendStream()) {
3234         log::info("Waiting for all devices to be in disable state");
3235         return;
3236       }
3237       group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_DISABLING);
3238     }
3239 
3240     /* At this point all of the active ASEs within group are disabled. As there
3241      * is no Disabling state for Sink ASE, it might happen that all of the
3242      * active ASEs are Sink ASE and will transit to QoS state. So check
3243      * the group state, because we might be ready to release data path. */
3244     if (group->HaveAllActiveDevicesAsesTheSameState(
3245                 AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED)) {
3246       group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED);
3247     }
3248 
3249     /* Transition to QoS configured is done by CIS disconnection */
3250     if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
3251       ReleaseDataPath(group);
3252     } else {
3253       log::error(", invalid state transition, from: {} , to: {}", ToString(group->GetState()),
3254                  ToString(group->GetTargetState()));
3255       StopStream(group);
3256     }
3257   }
3258 
ProcessAutonomousDisable(LeAudioDeviceGroup * group,LeAudioDevice * leAudioDevice,struct ase * ase)3259   void ProcessAutonomousDisable(LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
3260                                 struct ase* ase) {
3261     /* If there is any streaming ASE and connected CIS, there is nothing to do.
3262      * Otherwise, Release all the ASEs.
3263      */
3264     log::info("{}, ase {}", leAudioDevice->address_, ase->id);
3265 
3266     if (group->HaveAnyActiveDeviceInStreamingState() && !group->HaveAllCisesDisconnected()) {
3267       log::info("There is still some ASE streaming, do nothing");
3268       return;
3269     }
3270 
3271     /* If there is no more ASEs streaming, just stop the stream */
3272     StopStream(group);
3273   }
3274 };
3275 }  // namespace
3276 
3277 namespace bluetooth::le_audio {
Initialize(Callbacks * state_machine_callbacks_)3278 void LeAudioGroupStateMachine::Initialize(Callbacks* state_machine_callbacks_) {
3279   if (instance) {
3280     log::error("Already initialized");
3281     return;
3282   }
3283 
3284   instance = new LeAudioGroupStateMachineImpl(state_machine_callbacks_);
3285 }
3286 
Cleanup()3287 void LeAudioGroupStateMachine::Cleanup() {
3288   if (!instance) {
3289     return;
3290   }
3291 
3292   LeAudioGroupStateMachineImpl* ptr = instance;
3293   instance = nullptr;
3294 
3295   delete ptr;
3296 }
3297 
Get()3298 LeAudioGroupStateMachine* LeAudioGroupStateMachine::Get() {
3299   log::assert_that(instance != nullptr, "assert failed: instance != nullptr");
3300   return instance;
3301 }
3302 }  // namespace bluetooth::le_audio
3303