1use bt_gatt::Characteristic;
8use bt_gatt::client::FromCharacteristic;
9use bt_gatt::types::{
10 AttributePermissions, CharacteristicProperties, CharacteristicProperty, Handle, SecurityLevels,
11};
12
13use std::collections::HashSet;
14
15use crate::*;
16
17pub(crate) const SUPPORTED_AUDIO_CONTEXTS_HANDLE: Handle = Handle(1);
18pub(crate) const AVAILABLE_AUDIO_CONTEXTS_HANDLE: Handle = Handle(2);
19pub(crate) const HANDLE_OFFSET: u64 = 3;
20
21impl From<&SupportedAudioContexts> for Characteristic {
22 fn from(_value: &SupportedAudioContexts) -> Self {
23 let properties: CharacteristicProperties = CharacteristicProperty::Read.into();
25
26 Characteristic {
27 handle: SUPPORTED_AUDIO_CONTEXTS_HANDLE,
28 uuid: <SupportedAudioContexts as FromCharacteristic>::UUID,
29 properties: properties.clone(),
30 permissions: AttributePermissions::with_levels(
31 &properties,
32 &SecurityLevels::encryption_required(),
33 ),
34 descriptors: Vec::new(),
35 }
36 }
37}
38
39impl From<&AvailableAudioContexts> for Characteristic {
40 fn from(_value: &AvailableAudioContexts) -> Self {
41 let properties = CharacteristicProperty::Read | CharacteristicProperty::Notify;
42
43 Characteristic {
44 handle: AVAILABLE_AUDIO_CONTEXTS_HANDLE,
45 uuid: <AvailableAudioContexts as FromCharacteristic>::UUID,
46 properties: properties.clone(),
47 permissions: AttributePermissions::with_levels(
48 &properties,
49 &SecurityLevels::encryption_required(),
50 ),
51 descriptors: Vec::new(),
52 }
53 }
54}
55
56impl From<&SourcePac> for Characteristic {
57 fn from(value: &SourcePac) -> Self {
58 let properties: CharacteristicProperties = CharacteristicProperty::Read.into();
60
61 Characteristic {
62 handle: value.handle,
63 uuid: <SourcePac as FromCharacteristic>::UUID,
64 properties: properties.clone(),
65 permissions: AttributePermissions::with_levels(
66 &properties,
67 &SecurityLevels::encryption_required(),
68 ),
69 descriptors: Vec::new(),
70 }
71 }
72}
73
74impl From<&SinkPac> for Characteristic {
75 fn from(value: &SinkPac) -> Self {
76 let properties: CharacteristicProperties = CharacteristicProperty::Read.into();
78
79 Characteristic {
80 handle: value.handle,
81 uuid: <SinkPac as FromCharacteristic>::UUID,
82 properties: properties.clone(),
83 permissions: AttributePermissions::with_levels(
84 &properties,
85 &SecurityLevels::encryption_required(),
86 ),
87 descriptors: Vec::new(),
88 }
89 }
90}
91
92impl From<&SourceAudioLocations> for Characteristic {
93 fn from(value: &SourceAudioLocations) -> Self {
94 let properties: CharacteristicProperties = CharacteristicProperty::Read.into();
96
97 Characteristic {
98 handle: value.handle,
99 uuid: <SourceAudioLocations as FromCharacteristic>::UUID,
100 properties: properties.clone(),
101 permissions: AttributePermissions::with_levels(
102 &properties,
103 &SecurityLevels::encryption_required(),
104 ),
105 descriptors: Vec::new(),
106 }
107 }
108}
109
110impl From<&SinkAudioLocations> for Characteristic {
111 fn from(value: &SinkAudioLocations) -> Self {
112 let properties: CharacteristicProperties = CharacteristicProperty::Read.into();
114
115 Characteristic {
116 handle: value.handle,
117 uuid: <SinkAudioLocations as FromCharacteristic>::UUID,
118 properties: properties.clone(),
119 permissions: AttributePermissions::with_levels(
120 &properties,
121 &SecurityLevels::encryption_required(),
122 ),
123 descriptors: Vec::new(),
124 }
125 }
126}
127
128#[derive(Default)]
129pub struct AudioContexts {
130 pub(crate) sink: HashSet<ContextType>,
131 pub(crate) source: HashSet<ContextType>,
132}
133
134impl AudioContexts {
135 pub fn new(sink: HashSet<ContextType>, source: HashSet<ContextType>) -> Self {
136 AudioContexts { sink, source }
137 }
138}
139
140pub type PacRecords = Vec<PacRecord>;
142
143#[derive(Debug, PartialEq)]
144pub(crate) enum PublishedAudioCapability {
145 Sink(SinkPac),
146 Source(SourcePac),
147}
148
149impl PublishedAudioCapability {
150 pub fn new_sink(handle: Handle, records: PacRecords) -> Self {
151 Self::Sink(SinkPac { handle: handle, capabilities: records })
152 }
153
154 pub fn new_source(handle: Handle, records: PacRecords) -> Self {
155 Self::Source(SourcePac { handle: handle, capabilities: records })
156 }
157
158 #[cfg(test)]
159 pub fn is_sink(&self) -> bool {
160 match self {
161 PublishedAudioCapability::Sink(_) => true,
162 PublishedAudioCapability::Source(_) => false,
163 }
164 }
165
166 #[cfg(test)]
167 pub fn is_source(&self) -> bool {
168 match self {
169 PublishedAudioCapability::Sink(_) => false,
170 PublishedAudioCapability::Source(_) => true,
171 }
172 }
173
174 #[cfg(test)]
175 pub fn pac_records(&self) -> &Vec<PacRecord> {
176 match self {
177 PublishedAudioCapability::Sink(pac) => &pac.capabilities,
178 PublishedAudioCapability::Source(pac) => &pac.capabilities,
179 }
180 }
181
182 pub(crate) fn encode(&self) -> Vec<u8> {
185 match self {
186 PublishedAudioCapability::Sink(pac) => pac_records_into_char_value(&pac.capabilities),
187 PublishedAudioCapability::Source(pac) => pac_records_into_char_value(&pac.capabilities),
188 }
189 }
190}
191
192impl From<&PublishedAudioCapability> for Characteristic {
193 fn from(value: &PublishedAudioCapability) -> Self {
194 match value {
195 PublishedAudioCapability::Sink(pac) => pac.into(),
196 PublishedAudioCapability::Source(pac) => pac.into(),
197 }
198 }
199}