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