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