1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <base/functional/callback.h>
20 
21 #include <ostream>
22 
23 #include "device_groups.h"
24 #include "devices.h"
25 #include "hardware/bt_le_audio.h"
26 #include "types/raw_address.h"
27 
28 using bluetooth::le_audio::LeAudioHealthBasedAction;
29 
30 namespace bluetooth::le_audio {
31 using LeAudioRecommendationActionCb = base::RepeatingCallback<void(
32     const RawAddress& address, int group_id, LeAudioHealthBasedAction action)>;
33 
34 /* This should be set by the client of this module to provide information about
35  * basic LeAudio support of the device which is exposing ASCS UUIDs. Should be
36  * used with AddStatisticForDevice API
37  */
38 enum class LeAudioHealthDeviceStatType {
39   /* Should be used whenever LeAudio device has invalid GATT Database structure.
40    * e.g. missing mandatory services or characteristics. */
41   INVALID_DB = 0,
42   /* Should be used when LeAudio devie GATT DB contains at least mandatory
43    * services and characteristics. */
44   VALID_DB,
45   /* Should be used when device expose CSIS support but service is not valid. */
46   INVALID_CSIS,
47   /* Should be used when device expose CSIS and Group ID has been
48    * successfully assigned to device. */
49   VALID_CSIS,
50 };
51 
52 /* When LeAudio device (s) are ready to use, we look at those as a group.
53  * Using Group stats we measure how good we are in creating streams.
54  * Should be used with AddStatisticForGroup API
55  */
56 enum class LeAudioHealthGroupStatType {
57   /* Whenever stream is successfully established. */
58   STREAM_CREATE_SUCCESS,
59   /* Whenever stream creation failes due to CIS failures */
60   STREAM_CREATE_CIS_FAILED,
61   /* Whenever stream creation failes due to ASCS signaling failures
62    * e.g. ASE does not go to the proper State on time
63    */
64   STREAM_CREATE_SIGNALING_FAILED,
65   /* Context stream not available */
66   STREAM_CONTEXT_NOT_AVAILABLE,
67 };
68 
69 class LeAudioHealthStatus {
70  public:
71   virtual ~LeAudioHealthStatus(void) = default;
72   static LeAudioHealthStatus* Get(void);
73   static void Cleanup(void);
74   static void DebugDump(int fd);
75 
76   virtual void RegisterCallback(LeAudioRecommendationActionCb cb) = 0;
77   virtual void AddStatisticForDevice(const LeAudioDevice* device,
78                                      LeAudioHealthDeviceStatType type) = 0;
79   virtual void AddStatisticForGroup(const LeAudioDeviceGroup* group,
80                                     LeAudioHealthGroupStatType type) = 0;
81   virtual void RemoveStatistics(const RawAddress& address, int group) = 0;
82 
83   struct group_stats {
group_statsgroup_stats84     group_stats(int group_id)
85         : group_id_(group_id),
86           latest_recommendation_(LeAudioHealthBasedAction::NONE),
87           stream_success_cnt_(0),
88           stream_failures_cnt_(0),
89           stream_cis_failures_cnt_(0),
90           stream_signaling_failures_cnt_(0),
91           stream_context_not_avail_cnt_(0){};
92 
93     int group_id_;
94     LeAudioHealthBasedAction latest_recommendation_;
95 
96     int stream_success_cnt_;
97     int stream_failures_cnt_;
98     int stream_cis_failures_cnt_;
99     int stream_signaling_failures_cnt_;
100     int stream_context_not_avail_cnt_;
101   };
102 
103   struct device_stats {
device_statsdevice_stats104     device_stats(RawAddress address)
105         : address_(address),
106           latest_recommendation_(LeAudioHealthBasedAction::NONE),
107           is_valid_service_(true),
108           is_valid_group_member_(true){};
109     RawAddress address_;
110     LeAudioHealthBasedAction latest_recommendation_;
111 
112     bool is_valid_service_;
113     bool is_valid_group_member_;
114   };
115 };
116 
117 inline std::ostream& operator<<(
118     std::ostream& os,
119     const bluetooth::le_audio::LeAudioHealthGroupStatType& stat) {
120   switch (stat) {
121     case bluetooth::le_audio::LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS:
122       os << "STREAM_CREATE_SUCCESS";
123       break;
124     case bluetooth::le_audio::LeAudioHealthGroupStatType::
125         STREAM_CREATE_CIS_FAILED:
126       os << "STREAM_CREATE_CIS_FAILED";
127       break;
128     case bluetooth::le_audio::LeAudioHealthGroupStatType::
129         STREAM_CREATE_SIGNALING_FAILED:
130       os << "STREAM_CREATE_SIGNALING_FAILED";
131       break;
132     case bluetooth::le_audio::LeAudioHealthGroupStatType::
133         STREAM_CONTEXT_NOT_AVAILABLE:
134       os << "STREAM_CONTEXT_NOT_AVAILABLE";
135       break;
136     default:
137       os << "UNKNOWN";
138       break;
139   }
140   return os;
141 }
142 
143 inline std::ostream& operator<<(
144     std::ostream& os,
145     const bluetooth::le_audio::LeAudioHealthDeviceStatType& stat) {
146   switch (stat) {
147     case bluetooth::le_audio::LeAudioHealthDeviceStatType::INVALID_DB:
148       os << "INVALID_DB";
149       break;
150     case bluetooth::le_audio::LeAudioHealthDeviceStatType::VALID_DB:
151       os << "VALID_DB";
152       break;
153     case bluetooth::le_audio::LeAudioHealthDeviceStatType::INVALID_CSIS:
154       os << "INVALID_CSIS";
155       break;
156     case bluetooth::le_audio::LeAudioHealthDeviceStatType::VALID_CSIS:
157       os << "VALID_CSIS";
158       break;
159     default:
160       os << "UNKNOWN";
161       break;
162   }
163   return os;
164 }
165 }  // namespace bluetooth::le_audio
166 
167 namespace fmt {
168 template <>
169 struct formatter<bluetooth::le_audio::LeAudioHealthDeviceStatType>
170     : enum_formatter<bluetooth::le_audio::LeAudioHealthDeviceStatType> {};
171 template <>
172 struct formatter<bluetooth::le_audio::LeAudioHealthGroupStatType>
173     : enum_formatter<bluetooth::le_audio::LeAudioHealthGroupStatType> {};
174 }  // namespace fmt
175