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