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<<(std::ostream& os,
118                                 const bluetooth::le_audio::LeAudioHealthGroupStatType& stat) {
119   switch (stat) {
120     case bluetooth::le_audio::LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS:
121       os << "STREAM_CREATE_SUCCESS";
122       break;
123     case bluetooth::le_audio::LeAudioHealthGroupStatType::STREAM_CREATE_CIS_FAILED:
124       os << "STREAM_CREATE_CIS_FAILED";
125       break;
126     case bluetooth::le_audio::LeAudioHealthGroupStatType::STREAM_CREATE_SIGNALING_FAILED:
127       os << "STREAM_CREATE_SIGNALING_FAILED";
128       break;
129     case bluetooth::le_audio::LeAudioHealthGroupStatType::STREAM_CONTEXT_NOT_AVAILABLE:
130       os << "STREAM_CONTEXT_NOT_AVAILABLE";
131       break;
132     default:
133       os << "UNKNOWN";
134       break;
135   }
136   return os;
137 }
138 
139 inline std::ostream& operator<<(std::ostream& os,
140                                 const bluetooth::le_audio::LeAudioHealthDeviceStatType& stat) {
141   switch (stat) {
142     case bluetooth::le_audio::LeAudioHealthDeviceStatType::INVALID_DB:
143       os << "INVALID_DB";
144       break;
145     case bluetooth::le_audio::LeAudioHealthDeviceStatType::VALID_DB:
146       os << "VALID_DB";
147       break;
148     case bluetooth::le_audio::LeAudioHealthDeviceStatType::INVALID_CSIS:
149       os << "INVALID_CSIS";
150       break;
151     case bluetooth::le_audio::LeAudioHealthDeviceStatType::VALID_CSIS:
152       os << "VALID_CSIS";
153       break;
154     default:
155       os << "UNKNOWN";
156       break;
157   }
158   return os;
159 }
160 }  // namespace bluetooth::le_audio
161 
162 namespace std {
163 template <>
164 struct formatter<bluetooth::le_audio::LeAudioHealthDeviceStatType>
165     : enum_formatter<bluetooth::le_audio::LeAudioHealthDeviceStatType> {};
166 template <>
167 struct formatter<bluetooth::le_audio::LeAudioHealthGroupStatType>
168     : enum_formatter<bluetooth::le_audio::LeAudioHealthGroupStatType> {};
169 }  // namespace std
170