• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Collection of Profile UUIDs and helpers to use them.
2 
3 use num_derive::{FromPrimitive, ToPrimitive};
4 use std::collections::{HashMap, HashSet};
5 use std::fmt::{Debug, Display, Formatter};
6 use std::sync::LazyLock;
7 
8 use bt_topshim::btif::Uuid;
9 
10 // List of profile uuids
11 pub const A2DP_SINK: &str = "0000110B-0000-1000-8000-00805F9B34FB";
12 pub const A2DP_SOURCE: &str = "0000110A-0000-1000-8000-00805F9B34FB";
13 pub const ADV_AUDIO_DIST: &str = "0000110D-0000-1000-8000-00805F9B34FB";
14 pub const BAS: &str = "0000180F-0000-1000-8000-00805F9B34FB";
15 pub const DIS: &str = "0000180A-0000-1000-8000-00805F9B34FB";
16 pub const HSP: &str = "00001108-0000-1000-8000-00805F9B34FB";
17 pub const HSP_AG: &str = "00001112-0000-1000-8000-00805F9B34FB";
18 pub const HFP: &str = "0000111E-0000-1000-8000-00805F9B34FB";
19 pub const HFP_AG: &str = "0000111F-0000-1000-8000-00805F9B34FB";
20 pub const AVRCP_CONTROLLER: &str = "0000110E-0000-1000-8000-00805F9B34FB";
21 pub const AVRCP_TARGET: &str = "0000110C-0000-1000-8000-00805F9B34FB";
22 pub const OBEX_OBJECT_PUSH: &str = "00001105-0000-1000-8000-00805f9b34fb";
23 pub const HID: &str = "00001124-0000-1000-8000-00805f9b34fb";
24 pub const HOGP: &str = "00001812-0000-1000-8000-00805f9b34fb";
25 pub const PANU: &str = "00001115-0000-1000-8000-00805F9B34FB";
26 pub const NAP: &str = "00001116-0000-1000-8000-00805F9B34FB";
27 pub const BNEP: &str = "0000000f-0000-1000-8000-00805F9B34FB";
28 pub const PBAP_PCE: &str = "0000112e-0000-1000-8000-00805F9B34FB";
29 pub const PBAP_PSE: &str = "0000112f-0000-1000-8000-00805F9B34FB";
30 pub const MAP: &str = "00001134-0000-1000-8000-00805F9B34FB";
31 pub const MNS: &str = "00001133-0000-1000-8000-00805F9B34FB";
32 pub const MAS: &str = "00001132-0000-1000-8000-00805F9B34FB";
33 pub const SAP: &str = "0000112D-0000-1000-8000-00805F9B34FB";
34 pub const HEARING_AID: &str = "0000FDF0-0000-1000-8000-00805f9b34fb";
35 pub const LE_AUDIO: &str = "0000184E-0000-1000-8000-00805F9B34FB";
36 pub const DIP: &str = "00001200-0000-1000-8000-00805F9B34FB";
37 pub const VOLUME_CONTROL: &str = "00001844-0000-1000-8000-00805F9B34FB";
38 pub const GENERIC_MEDIA_CONTROL: &str = "00001849-0000-1000-8000-00805F9B34FB";
39 pub const MEDIA_CONTROL: &str = "00001848-0000-1000-8000-00805F9B34FB";
40 pub const COORDINATED_SET: &str = "00001846-0000-1000-8000-00805F9B34FB";
41 pub const BASE_UUID: &str = "00000000-0000-1000-8000-00805F9B34FB";
42 
43 // List of descriptor uuids
44 pub const CCCD_UUID: &str = "00002902-0000-1000-8000-00805f9b34fb";
45 
46 /// List of profiles that with known uuids.
47 /// Append new profiles to the end of the enum. Do not insert it in the middle.
48 #[derive(Clone, Debug, Hash, PartialEq, PartialOrd, Eq, Ord, FromPrimitive, ToPrimitive, Copy)]
49 #[repr(u32)]
50 pub enum Profile {
51     A2dpSink,
52     A2dpSource,
53     AdvAudioDist,
54     Bas,
55     Dis,
56     Hsp,
57     HspAg,
58     Hfp,
59     HfpAg,
60     AvrcpController,
61     AvrcpTarget,
62     ObexObjectPush,
63     Hid,
64     Hogp,
65     Panu,
66     Nap,
67     Bnep,
68     PbapPce,
69     PbapPse,
70     Map,
71     Mns,
72     Mas,
73     Sap,
74     HearingAid,
75     LeAudio,
76     Dip,
77     VolumeControl,
78     GenericMediaControl,
79     MediaControl,
80     CoordinatedSet,
81 }
82 
83 impl Display for Profile {
fmt(&self, f: &mut Formatter) -> std::fmt::Result84     fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
85         Debug::fmt(self, f)
86     }
87 }
88 
89 pub struct UuidHelper {}
90 
91 // AVRCP fights with A2DP when initializing, so let's initiate profiles in a known good order.
92 // Specifically, A2DP must be initialized before AVRCP.
93 // TODO (b/286991526): remove after issue is resolved
94 static ORDERED_SUPPORTED_PROFILES: LazyLock<Vec<Profile>> = LazyLock::new(|| {
95     vec![
96         Profile::A2dpSink,
97         Profile::A2dpSource,
98         Profile::AvrcpController,
99         Profile::AvrcpTarget,
100         Profile::Bas,
101         Profile::Hsp,
102         Profile::Hfp,
103         Profile::Hid,
104         Profile::Hogp,
105         Profile::LeAudio,
106         Profile::Panu,
107         Profile::PbapPce,
108         Profile::Map,
109         Profile::HearingAid,
110         Profile::VolumeControl,
111         Profile::CoordinatedSet,
112     ]
113 });
114 
115 static SUPPORTED_PROFILES: LazyLock<HashSet<Profile>> =
116     LazyLock::new(|| ORDERED_SUPPORTED_PROFILES.iter().cloned().collect());
117 
118 static PROFILES: LazyLock<HashMap<Uuid, Profile>> = LazyLock::new(|| {
119     [
120         (Uuid::from_string(A2DP_SINK).unwrap(), Profile::A2dpSink),
121         (Uuid::from_string(A2DP_SOURCE).unwrap(), Profile::A2dpSource),
122         (Uuid::from_string(ADV_AUDIO_DIST).unwrap(), Profile::AdvAudioDist),
123         (Uuid::from_string(BAS).unwrap(), Profile::Bas),
124         (Uuid::from_string(DIS).unwrap(), Profile::Dis),
125         (Uuid::from_string(HSP).unwrap(), Profile::Hsp),
126         (Uuid::from_string(HSP_AG).unwrap(), Profile::HspAg),
127         (Uuid::from_string(HFP).unwrap(), Profile::Hfp),
128         (Uuid::from_string(HFP_AG).unwrap(), Profile::HfpAg),
129         (Uuid::from_string(AVRCP_CONTROLLER).unwrap(), Profile::AvrcpController),
130         (Uuid::from_string(AVRCP_TARGET).unwrap(), Profile::AvrcpTarget),
131         (Uuid::from_string(OBEX_OBJECT_PUSH).unwrap(), Profile::ObexObjectPush),
132         (Uuid::from_string(HID).unwrap(), Profile::Hid),
133         (Uuid::from_string(HOGP).unwrap(), Profile::Hogp),
134         (Uuid::from_string(PANU).unwrap(), Profile::Panu),
135         (Uuid::from_string(NAP).unwrap(), Profile::Nap),
136         (Uuid::from_string(BNEP).unwrap(), Profile::Bnep),
137         (Uuid::from_string(PBAP_PCE).unwrap(), Profile::PbapPce),
138         (Uuid::from_string(PBAP_PSE).unwrap(), Profile::PbapPse),
139         (Uuid::from_string(MAP).unwrap(), Profile::Map),
140         (Uuid::from_string(MNS).unwrap(), Profile::Mns),
141         (Uuid::from_string(MAS).unwrap(), Profile::Mas),
142         (Uuid::from_string(SAP).unwrap(), Profile::Sap),
143         (Uuid::from_string(HEARING_AID).unwrap(), Profile::HearingAid),
144         (Uuid::from_string(LE_AUDIO).unwrap(), Profile::LeAudio),
145         (Uuid::from_string(DIP).unwrap(), Profile::Dip),
146         (Uuid::from_string(VOLUME_CONTROL).unwrap(), Profile::VolumeControl),
147         (Uuid::from_string(GENERIC_MEDIA_CONTROL).unwrap(), Profile::GenericMediaControl),
148         (Uuid::from_string(MEDIA_CONTROL).unwrap(), Profile::MediaControl),
149         (Uuid::from_string(COORDINATED_SET).unwrap(), Profile::CoordinatedSet),
150     ]
151     .iter()
152     .cloned()
153     .collect()
154 });
155 
156 static PROFILES_UUIDS: LazyLock<HashMap<Profile, Uuid>> =
157     LazyLock::new(|| PROFILES.iter().map(|(k, v)| (*v, *k)).collect());
158 
159 impl UuidHelper {
160     /// Checks whether a UUID corresponds to a currently enabled profile.
is_profile_supported(profile: &Profile) -> bool161     pub fn is_profile_supported(profile: &Profile) -> bool {
162         SUPPORTED_PROFILES.contains(profile)
163     }
164 
165     /// Converts a UUID to a known profile enum.
is_known_profile(uuid: &Uuid) -> Option<Profile>166     pub fn is_known_profile(uuid: &Uuid) -> Option<Profile> {
167         PROFILES.get(uuid).cloned()
168     }
169 
170     // AVRCP fights with A2DP when initializing, so let's initiate profiles in a known good order.
171     // TODO (b/286991526): remove after issue is resolved
get_ordered_supported_profiles() -> Vec<Profile>172     pub fn get_ordered_supported_profiles() -> Vec<Profile> {
173         ORDERED_SUPPORTED_PROFILES.clone()
174     }
175 
get_supported_profiles() -> HashSet<Profile>176     pub fn get_supported_profiles() -> HashSet<Profile> {
177         SUPPORTED_PROFILES.clone()
178     }
179 
180     /// Converts a profile enum to its UUID if known.
get_profile_uuid(profile: &Profile) -> Option<&Uuid>181     pub fn get_profile_uuid(profile: &Profile) -> Option<&Uuid> {
182         PROFILES_UUIDS.get(profile)
183     }
184 
185     /// If a uuid is known to be a certain service, convert it into a formatted
186     /// string that shows the service name. Else just format the uuid.
known_uuid_to_string(uuid: &Uuid) -> String187     pub fn known_uuid_to_string(uuid: &Uuid) -> String {
188         if let Some(p) = Self::is_known_profile(uuid) {
189             format!("{}: {:?}", uuid, p)
190         } else {
191             uuid.to_string()
192         }
193     }
194 }
195 
196 #[cfg(test)]
197 mod tests {
198     use bt_topshim::btif::Uuid;
199 
200     #[test]
test_uuidhelper()201     fn test_uuidhelper() {
202         for (uuid, _) in super::PROFILES.iter() {
203             let converted = Uuid::from_string(uuid.to_string()).unwrap();
204             assert_eq!(*uuid, converted);
205         }
206     }
207 }
208