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