bt_bap/
types.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// Broadcast_ID is a 3-byte data on the wire.
12/// Defined in BAP spec v1.0.1 section 3.7.2.1.
13#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
14pub struct BroadcastId(u32);
15
16impl BroadcastId {
17    // On the wire, Broadcast_ID is transported in 3 bytes.
18    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        // Since 3-byte value is being fit into u32, we ignore the most significant
72        // byte.
73        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/// To associate a PA, used to expose broadcast Audio Stream parameters, with a
83/// broadcast Audio Stream, the Broadcast Source shall transmit EA PDUs that
84/// include the following data. This struct represents the AD data value
85/// excluding the 2-octet Service UUID. See BAP v1.0.1 Section 3.7.2.1 for more
86/// details.
87#[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                // According to the spec, broadcast audio announcement service data inlcudes
107                // broadcast id and any additional service data. We don't store any
108                // additional parameters, so for now we just "consume" all of data buffer
109                // without doing anything.
110                (Ok(Self { broadcast_id }), buf.len())
111            }
112            (Err(e), _) => (Err(e), buf.len()),
113        }
114    }
115}
116
117/// Parameters exposed as part of Basic Audio Announcement from Broadcast
118/// Sources. See BAP v1.0.1 Section 3.7.2.2 for more details.
119// TODO(b/308481381): Fill out the struct.
120#[derive(Clone, Debug, PartialEq)]
121pub struct BroadcastAudioSourceEndpoint {
122    // Actual value is 3 bytes long.
123    pub presentation_delay_ms: u32,
124    pub big: Vec<BroadcastIsochronousGroup>,
125}
126
127impl BroadcastAudioSourceEndpoint {
128    // Should contain presentation delay, num BIG, and at least one BIG praram.
129    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/// A single subgroup in a Basic Audio Announcement as outlined in
172/// BAP spec v1.0.1 Section 3.7.2.2. Each subgroup is used to
173/// group BISes present in the broadcast isochronous group.
174#[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    // Should contain num BIS, codec id, codec specific config len, metadata len,
184    // and at least one BIS praram.
185    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            // Ignore any undecodable metadata types
247            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        // Value bigger than 3 bytes is not a valid broadcast ID.
327        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, /* some other additional data */
357        ];
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,                          // bis index and codec specific config len
368            0x02, 0x01, 0x06,                    // sampling frequency LTV
369            0x05, 0x03, 0x03, 0x00, 0x00, 0x0C,  // audio location LTV
370        ];
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,  // num of bis, codec id
395            0x04, 0x03, 0x04, 0x04, 0x10,         // codec specific config len, octets per codec frame LTV
396            0x03, 0x02, 0x08, 0x01,               // metadata len, audio active state LTV
397            0x01, 0x00,                           // bis index, codec specific config len (bis #1)
398            0x02, 0x03, 0x02, 0x02, 0x01,         // bis index, codec specific config len, frame duration LTV (bis #2)
399        ];
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,               // presentation delay, num of subgroups
426            0x01, 0x03, 0x00, 0x00, 0x00, 0x00,   // num of bis, codec id (big #1)
427            0x00,                                 // codec specific config len
428            0x00,                                 // metadata len,
429            0x01, 0x00,                           // bis index, codec specific config len (big #1 / bis #1)
430            0x01, 0x02, 0x00, 0x00, 0x00, 0x00,   // num of bis, codec id (big #2)
431            0x00,                                 // codec specific config len
432            0x00,                                 // metadata len,
433            0x01, 0x03, 0x02, 0x05, 0x08,         // bis index, codec specific config len, codec frame blocks LTV (big #2 / bis #2)
434        ];
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,  // presentation_delay_ms: 20000 (little-endian)
470            0x01,  // # of subgroups
471            0x02,  // # of BIS in group 1
472            0x06, 0x00, 0x00, 0x00, 0x00,  // Codec ID (Lc3)
473            0x10,  // codec_specific_configuration_length of group 1
474            0x02, 0x01, 0x05,  // sampling frequency 24 kHz
475            0x02, 0x02, 0x01,  // 10 ms frame duration
476            0x05, 0x03, 0x03, 0x00, 0x00, 0x00,  // front left audio channel
477            0x03, 0x04, 0x3c, 0x00,  // 60 octets per codec frame
478            0x04,  // metadata_length of group 1
479            0x03, 0x02, 0x04, 0x00,  // media streaming audio context
480            0x01,  // BIS index of the 1st BIS in group 1
481            0x06,  // codec_specific_configuration_length of the 1st BIS
482            0x05, 0x03, 0x01, 0x00, 0x00, 0x00,  // front left audio channel
483            0x02,  // BIS index of the 2nd BIS in group 1
484            0x06,  // codec_specific_configuration_length of the 2nd BIS
485            0x05, 0x03, 0x02, 0x00, 0x00, 0x00,  // front right audio channel
486        ];
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,  // presentation_delay_ms: 20000 (little-endian)
497            0x01,  // # of subgroups
498            0x01,  // # of BIS in group 1
499            0x06, 0x00, 0x00, 0x00, 0x00,  // Codec ID (Lc3)
500            0x10,  // codec_specific_configuration_length of group 1
501            0x02, 0x01, 0x05,  // sampling frequency 24 kHz
502            0x02, 0x02, 0x01,  // 10 ms frame duration
503            0x05, 0x03, 0x01, 0x00, 0x00, 0x00,  // front left audio channel
504            0x03, 0x04, 0x3c, 0x00,  // 60 octets per codec frame
505            0x02,  // metadata_length of group 1
506            0x01, 0x09,  // broadcast audio immediate rendering flag
507            0x01,  // BIS index of the 1st BIS in group 1
508            0x03,  // codec_specific_configuration_length of the 1st BIS
509            0x02, 0x01, 0x05,  // sampling frequency 24 kHz
510        ];
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}