1use bt_common::core::CodecId;
6use bt_common::core::ltv::LtValue;
7use bt_common::generic_audio::codec_configuration::CodecConfiguration;
8use bt_common::generic_audio::metadata_ltv::Metadata;
9use bt_common::packet_encoding::{Decodable, Encodable, Error as PacketError};
10
11#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
14pub struct BroadcastId(u32);
15
16impl BroadcastId {
17 pub const BYTE_SIZE: usize = 3;
19
20 pub fn new(raw_value: u32) -> Self {
21 Self(raw_value)
22 }
23}
24
25impl std::fmt::Display for BroadcastId {
26 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
27 write!(f, "{:#08x}", self.0)
28 }
29}
30
31impl From<BroadcastId> for u32 {
32 fn from(value: BroadcastId) -> u32 {
33 value.0
34 }
35}
36
37impl TryFrom<u32> for BroadcastId {
38 type Error = PacketError;
39
40 fn try_from(value: u32) -> Result<Self, Self::Error> {
41 const MAX_VALUE: u32 = 0xFFFFFF;
42 if value > MAX_VALUE {
43 return Err(PacketError::InvalidParameter(format!(
44 "Broadcast ID cannot exceed 3 bytes"
45 )));
46 }
47 Ok(BroadcastId(value))
48 }
49}
50
51impl Decodable for BroadcastId {
52 type Error = PacketError;
53
54 fn decode(buf: &[u8]) -> (core::result::Result<Self, Self::Error>, usize) {
55 if buf.len() != Self::BYTE_SIZE {
56 return (Err(PacketError::UnexpectedDataLength), buf.len());
57 }
58
59 let padded_bytes = [buf[0], buf[1], buf[2], 0x00];
60 (Ok(BroadcastId(u32::from_le_bytes(padded_bytes))), Self::BYTE_SIZE)
61 }
62}
63
64impl Encodable for BroadcastId {
65 type Error = PacketError;
66
67 fn encode(&self, buf: &mut [u8]) -> core::result::Result<(), Self::Error> {
68 if buf.len() < self.encoded_len() {
69 return Err(PacketError::BufferTooSmall);
70 }
71 buf[0..3].copy_from_slice(&self.0.to_le_bytes()[0..3]);
74 Ok(())
75 }
76
77 fn encoded_len(&self) -> core::primitive::usize {
78 Self::BYTE_SIZE
79 }
80}
81
82#[derive(Clone, Copy, Debug, PartialEq)]
88pub struct BroadcastAudioAnnouncement {
89 pub broadcast_id: BroadcastId,
90}
91
92impl BroadcastAudioAnnouncement {
93 const PACKET_SIZE: usize = BroadcastId::BYTE_SIZE;
94}
95
96impl Decodable for BroadcastAudioAnnouncement {
97 type Error = PacketError;
98
99 fn decode(buf: &[u8]) -> (core::result::Result<Self, Self::Error>, usize) {
100 if buf.len() < Self::PACKET_SIZE {
101 return (Err(PacketError::UnexpectedDataLength), buf.len());
102 }
103
104 match BroadcastId::decode(&buf[0..3]) {
105 (Ok(broadcast_id), _) => {
106 (Ok(Self { broadcast_id }), buf.len())
111 }
112 (Err(e), _) => (Err(e), buf.len()),
113 }
114 }
115}
116
117#[derive(Clone, Debug, PartialEq)]
121pub struct BroadcastAudioSourceEndpoint {
122 pub presentation_delay_ms: u32,
124 pub big: Vec<BroadcastIsochronousGroup>,
125}
126
127impl BroadcastAudioSourceEndpoint {
128 const MIN_PACKET_SIZE: usize = 3 + 1 + BroadcastIsochronousGroup::MIN_PACKET_SIZE;
130}
131
132impl Decodable for BroadcastAudioSourceEndpoint {
133 type Error = PacketError;
134
135 fn decode(buf: &[u8]) -> (core::result::Result<Self, Self::Error>, usize) {
136 if buf.len() < Self::MIN_PACKET_SIZE {
137 return (Err(PacketError::UnexpectedDataLength), buf.len());
138 }
139
140 let mut idx = 0 as usize;
141 let presentation_delay = u32::from_le_bytes([buf[idx], buf[idx + 1], buf[idx + 2], 0x00]);
142 idx += 3;
143
144 let num_big: usize = buf[idx] as usize;
145 idx += 1;
146 if num_big < 1 {
147 return (
148 Err(PacketError::InvalidParameter(format!(
149 "num of subgroups shall be at least 1 got {num_big}"
150 ))),
151 buf.len(),
152 );
153 }
154 let mut big = Vec::new();
155 while big.len() < num_big {
156 match BroadcastIsochronousGroup::decode(&buf[idx..]) {
157 (Ok(group), consumed) => {
158 big.push(group);
159 idx += consumed;
160 }
161 (Err(e), _) => {
162 return (Err(PacketError::InvalidParameter(e.to_string())), buf.len());
163 }
164 };
165 }
166
167 (Ok(Self { presentation_delay_ms: presentation_delay, big }), idx)
168 }
169}
170
171#[derive(Clone, Debug, PartialEq)]
175pub struct BroadcastIsochronousGroup {
176 pub codec_id: CodecId,
177 pub codec_specific_configs: Vec<CodecConfiguration>,
178 pub metadata: Vec<Metadata>,
179 pub bis: Vec<BroadcastIsochronousStream>,
180}
181
182impl BroadcastIsochronousGroup {
183 const MIN_PACKET_SIZE: usize =
186 1 + CodecId::BYTE_SIZE + 1 + 1 + BroadcastIsochronousStream::MIN_PACKET_SIZE;
187}
188
189impl Decodable for BroadcastIsochronousGroup {
190 type Error = PacketError;
191
192 fn decode(buf: &[u8]) -> (core::result::Result<Self, Self::Error>, usize) {
193 if buf.len() < BroadcastIsochronousGroup::MIN_PACKET_SIZE {
194 return (Err(PacketError::UnexpectedDataLength), buf.len());
195 }
196
197 let mut idx = 0;
198 let num_bis = buf[idx] as usize;
199 idx += 1;
200 if num_bis < 1 {
201 return (
202 Err(PacketError::InvalidParameter(format!(
203 "num of BIS shall be at least 1 got {num_bis}"
204 ))),
205 buf.len(),
206 );
207 }
208
209 let mut decode_fn = || {
210 let codec_id;
211 match CodecId::decode(&buf[idx..]) {
212 (Ok(id), consumed) => {
213 codec_id = id;
214 idx += consumed;
215 }
216 (Err(e), _) => {
217 return Err(e);
218 }
219 };
220
221 let codec_config_len = buf[idx] as usize;
222 idx += 1;
223 if idx + codec_config_len > buf.len() {
224 return Err(bt_common::packet_encoding::Error::UnexpectedDataLength);
225 }
226 let (results, consumed) =
227 CodecConfiguration::decode_all(&buf[idx..idx + codec_config_len]);
228 if consumed != codec_config_len {
229 return Err(bt_common::packet_encoding::Error::UnexpectedDataLength);
230 }
231
232 let codec_specific_configs = results.into_iter().filter_map(Result::ok).collect();
233 idx += codec_config_len;
234
235 let metadata_len = buf[idx] as usize;
236 idx += 1;
237 if idx + metadata_len > buf.len() {
238 return Err(bt_common::packet_encoding::Error::UnexpectedDataLength);
239 }
240
241 let (results_metadata, consumed_len) =
242 Metadata::decode_all(&buf[idx..idx + metadata_len]);
243 if consumed_len != metadata_len {
244 return Err(PacketError::UnexpectedDataLength);
245 }
246 let metadata = results_metadata.into_iter().filter_map(Result::ok).collect();
248 idx += consumed_len;
249
250 let mut bis = Vec::new();
251 while bis.len() < num_bis {
252 match BroadcastIsochronousStream::decode(&buf[idx..]) {
253 (Ok(stream), consumed) => {
254 bis.push(stream);
255 idx += consumed;
256 }
257 (Err(e), _consumed) => {
258 return Err(PacketError::InvalidParameter(e.to_string()));
259 }
260 }
261 }
262
263 Ok((BroadcastIsochronousGroup { codec_id, codec_specific_configs, metadata, bis }, idx))
264 };
265 match decode_fn() {
266 Ok((obj, consumed)) => (Ok(obj), consumed),
267 Err(e) => (Err(e), buf.len()),
268 }
269 }
270}
271
272#[derive(Clone, Debug, PartialEq)]
273pub struct BroadcastIsochronousStream {
274 pub bis_index: u8,
275 pub codec_specific_config: Vec<CodecConfiguration>,
276}
277
278impl BroadcastIsochronousStream {
279 const MIN_PACKET_SIZE: usize = 1 + 1;
280}
281
282impl Decodable for BroadcastIsochronousStream {
283 type Error = PacketError;
284
285 fn decode(buf: &[u8]) -> (core::result::Result<Self, Self::Error>, usize) {
286 if buf.len() < BroadcastIsochronousStream::MIN_PACKET_SIZE {
287 return (Err(PacketError::UnexpectedDataLength), buf.len());
288 }
289
290 let mut idx = 0;
291
292 let bis_index = buf[idx];
293 idx += 1;
294
295 let codec_config_len = buf[idx] as usize;
296 idx += 1;
297
298 let (results, consumed) = CodecConfiguration::decode_all(&buf[idx..idx + codec_config_len]);
299 if consumed != codec_config_len {
300 return (Err(bt_common::packet_encoding::Error::UnexpectedDataLength), buf.len());
301 }
302 let codec_specific_configs = results.into_iter().filter_map(Result::ok).collect();
303 idx += codec_config_len;
304
305 (
306 Ok(BroadcastIsochronousStream {
307 bis_index,
308 codec_specific_config: codec_specific_configs,
309 }),
310 idx,
311 )
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318
319 use std::collections::HashSet;
320
321 use bt_common::generic_audio::AudioLocation;
322 use bt_common::generic_audio::codec_configuration::{FrameDuration, SamplingFrequency};
323
324 #[test]
325 fn broadcast_id() {
326 let _ = BroadcastId::try_from(0x010A0B0C).expect_err("should fail");
328
329 let id = BroadcastId::try_from(0x000A0B0C).expect("should succeed");
330
331 assert_eq!(id.encoded_len(), 3);
332 let mut buf = vec![0; id.encoded_len()];
333 let _ = id.encode(&mut buf[..]).expect("should have succeeded");
334
335 let bytes = vec![0x0C, 0x0B, 0x0A];
336 assert_eq!(buf, bytes);
337
338 let (got, bytes) = BroadcastId::decode(&bytes);
339 assert_eq!(got, Ok(id));
340 assert_eq!(bytes, BroadcastId::BYTE_SIZE);
341 let got = BroadcastId::try_from(u32::from_le_bytes([0x0C, 0x0B, 0x0A, 0x00]))
342 .expect("should succeed");
343 assert_eq!(got, id);
344 }
345
346 #[test]
347 fn broadcast_audio_announcement() {
348 let bytes = vec![0x0C, 0x0B, 0x0A];
349 let broadcast_id = BroadcastId::try_from(0x000A0B0C).unwrap();
350
351 let (got, consumed) = BroadcastAudioAnnouncement::decode(&bytes);
352 assert_eq!(got, Ok(BroadcastAudioAnnouncement { broadcast_id }));
353 assert_eq!(consumed, 3);
354
355 let bytes = vec![
356 0x0C, 0x0B, 0x0A, 0x01, 0x02, 0x03, 0x04, 0x05, ];
358 let (got, consumed) = BroadcastAudioAnnouncement::decode(&bytes);
359 assert_eq!(got, Ok(BroadcastAudioAnnouncement { broadcast_id }));
360 assert_eq!(consumed, 8);
361 }
362
363 #[test]
364 fn decode_bis() {
365 #[rustfmt::skip]
366 let buf = [
367 0x01, 0x09, 0x02, 0x01, 0x06, 0x05, 0x03, 0x03, 0x00, 0x00, 0x0C, ];
371
372 let (bis, _read_bytes) = BroadcastIsochronousStream::decode(&buf[..]);
373 assert_eq!(
374 bis,
375 Ok(BroadcastIsochronousStream {
376 bis_index: 0x01,
377 codec_specific_config: vec![
378 CodecConfiguration::SamplingFrequency(SamplingFrequency::F32000Hz),
379 CodecConfiguration::AudioChannelAllocation(HashSet::from([
380 AudioLocation::FrontLeft,
381 AudioLocation::FrontRight,
382 AudioLocation::LeftSurround,
383 AudioLocation::RightSurround
384 ])),
385 ],
386 })
387 );
388 }
389
390 #[test]
391 fn decode_big() {
392 #[rustfmt::skip]
393 let buf = [
394 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x04, 0x04, 0x10, 0x03, 0x02, 0x08, 0x01, 0x01, 0x00, 0x02, 0x03, 0x02, 0x02, 0x01, ];
400
401 let big = BroadcastIsochronousGroup::decode(&buf[..]).0.expect("should not fail");
402 assert_eq!(
403 big,
404 BroadcastIsochronousGroup {
405 codec_id: CodecId::Assigned(bt_common::core::CodingFormat::Transparent),
406 codec_specific_configs: vec![CodecConfiguration::OctetsPerCodecFrame(0x1004),],
407 metadata: vec![Metadata::AudioActiveState(true)],
408 bis: vec![
409 BroadcastIsochronousStream { bis_index: 0x01, codec_specific_config: vec![] },
410 BroadcastIsochronousStream {
411 bis_index: 0x02,
412 codec_specific_config: vec![CodecConfiguration::FrameDuration(
413 FrameDuration::TenMs
414 )],
415 },
416 ],
417 }
418 );
419 }
420
421 #[test]
422 fn decode_base() {
423 #[rustfmt::skip]
424 let buf = [
425 0x10, 0x20, 0x30, 0x02, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x02, 0x05, 0x08, ];
435
436 let base = BroadcastAudioSourceEndpoint::decode(&buf[..]).0.expect("should not fail");
437 assert_eq!(base.presentation_delay_ms, 0x00302010);
438 assert_eq!(base.big.len(), 2);
439 assert_eq!(
440 base.big[0],
441 BroadcastIsochronousGroup {
442 codec_id: CodecId::Assigned(bt_common::core::CodingFormat::Transparent),
443 codec_specific_configs: vec![],
444 metadata: vec![],
445 bis: vec![BroadcastIsochronousStream {
446 bis_index: 0x01,
447 codec_specific_config: vec![],
448 },],
449 }
450 );
451 assert_eq!(
452 base.big[1],
453 BroadcastIsochronousGroup {
454 codec_id: CodecId::Assigned(bt_common::core::CodingFormat::Cvsd),
455 codec_specific_configs: vec![],
456 metadata: vec![],
457 bis: vec![BroadcastIsochronousStream {
458 bis_index: 0x01,
459 codec_specific_config: vec![CodecConfiguration::CodecFramesPerSdu(0x08)],
460 },],
461 }
462 );
463 }
464
465 #[test]
466 fn decode_base_complex() {
467 #[rustfmt::skip]
468 let buf = [
469 0x20, 0x4e, 0x00, 0x01, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x04, 0x3c, 0x00, 0x04, 0x03, 0x02, 0x04, 0x00, 0x01, 0x06, 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, 0x02, 0x06, 0x05, 0x03, 0x02, 0x00, 0x00, 0x00, ];
487 let (base, read_bytes) = BroadcastAudioSourceEndpoint::decode(&buf[..]);
488 let base = base.expect("should not fail");
489 assert_eq!(read_bytes, buf.len());
490 assert_eq!(base.presentation_delay_ms, 20000);
491 assert_eq!(base.big.len(), 1);
492 assert_eq!(base.big[0].bis.len(), 2);
493
494 #[rustfmt::skip]
495 let buf = [
496 0x20, 0x4e, 0x00, 0x01, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03, 0x04, 0x3c, 0x00, 0x02, 0x01, 0x09, 0x01, 0x03, 0x02, 0x01, 0x05, ];
511 let (base, read_bytes) = BroadcastAudioSourceEndpoint::decode(&buf[..]);
512 let base = base.expect("should not fail");
513 assert_eq!(read_bytes, buf.len());
514 assert_eq!(base.presentation_delay_ms, 20000);
515 assert_eq!(base.big.len(), 1);
516 assert_eq!(base.big[0].bis.len(), 1);
517 }
518}