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