bt_broadcast_assistant/
types.rs1use bt_bap::types::*;
6use bt_bass::types::{BigSubgroup, BisSync};
7use bt_common::core::{Address, AddressType};
8use bt_common::core::{AdvertisingSetId, PaInterval};
9use bt_common::packet_encoding::Error as PacketError;
10use std::collections::HashMap;
11
12#[derive(Clone, Default, Debug, PartialEq)]
17pub struct BroadcastSource {
18 pub(crate) address: Option<Address>,
19 pub(crate) address_type: Option<AddressType>,
20 pub(crate) advertising_sid: Option<AdvertisingSetId>,
21 pub(crate) broadcast_id: Option<BroadcastId>,
22 pub(crate) pa_interval: Option<PaInterval>,
23 pub(crate) endpoint: Option<BroadcastAudioSourceEndpoint>,
24}
25
26impl BroadcastSource {
27 pub(crate) fn into_add_source(&self) -> bool {
30 self.advertising_sid.is_some() && self.broadcast_id.is_some() && self.endpoint.is_some()
34 }
35
36 pub fn with_address(&mut self, address: [u8; 6]) -> &mut Self {
37 self.address = Some(address);
38 self
39 }
40
41 pub fn with_address_type(&mut self, type_: AddressType) -> &mut Self {
42 self.address_type = Some(type_);
43 self
44 }
45
46 pub fn with_broadcast_id(&mut self, bid: BroadcastId) -> &mut Self {
47 self.broadcast_id = Some(bid);
48 self
49 }
50
51 pub fn with_advertising_sid(&mut self, sid: AdvertisingSetId) -> &mut Self {
52 self.advertising_sid = Some(sid);
53 self
54 }
55
56 pub fn with_endpoint(&mut self, endpoint: BroadcastAudioSourceEndpoint) -> &mut Self {
57 self.endpoint = Some(endpoint);
58 self
59 }
60
61 pub(crate) fn merge(&mut self, other: &BroadcastSource) {
66 if let Some(address) = other.address {
67 self.address = Some(address);
68 }
69 if let Some(address_type) = other.address_type {
70 self.address_type = Some(address_type);
71 }
72 if let Some(advertising_sid) = other.advertising_sid {
73 self.advertising_sid = Some(advertising_sid);
74 }
75 if let Some(broadcast_id) = other.broadcast_id {
76 self.broadcast_id = Some(broadcast_id);
77 }
78 if let Some(pa_interval) = other.pa_interval {
79 self.pa_interval = Some(pa_interval);
80 }
81 if let Some(endpoint) = &other.endpoint {
82 self.endpoint = Some(endpoint.clone());
83 }
84 }
85
86 pub(crate) fn endpoint_to_big_subgroups(
95 &self,
96 bis_sync: HashMap<u8, BisSync>,
97 ) -> Result<Vec<BigSubgroup>, PacketError> {
98 if self.endpoint.is_none() {
99 return Err(PacketError::InvalidParameter(
100 "cannot convert empty Broadcast Audio Source Endpoint data to BIG subgroups data"
101 .to_string(),
102 ));
103 }
104 let mut subgroups = Vec::new();
105
106 for (big_index, group) in self.endpoint.as_ref().unwrap().big.iter().enumerate() {
107 let bis_sync = bis_sync.get(&(big_index as u8)).cloned().unwrap_or_default();
108 subgroups.push(BigSubgroup::new(Some(bis_sync)).with_metadata(group.metadata.clone()));
109 }
110 Ok(subgroups)
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 use std::collections::HashMap;
119
120 use bt_common::core::CodecId;
121 use bt_common::generic_audio::metadata_ltv::Metadata;
122
123 #[test]
124 fn broadcast_source() {
125 let mut b = BroadcastSource::default();
126 assert!(!b.into_add_source());
127
128 b.with_advertising_sid(AdvertisingSetId(0x1));
129 assert!(!b.into_add_source());
130
131 b.with_broadcast_id(BroadcastId::try_from(0x010203).unwrap());
132 assert!(!b.into_add_source());
133
134 b.endpoint_to_big_subgroups(HashMap::from([(0, BisSync::sync(vec![1]).unwrap())]))
135 .expect_err("should fail no endpoint data");
136
137 b.with_endpoint(BroadcastAudioSourceEndpoint {
138 presentation_delay_ms: 0x010203,
139 big: vec![BroadcastIsochronousGroup {
140 codec_id: CodecId::Assigned(bt_common::core::CodingFormat::Cvsd),
141 codec_specific_configs: vec![],
142 metadata: vec![Metadata::BroadcastAudioImmediateRenderingFlag],
143 bis: vec![BroadcastIsochronousStream {
144 bis_index: 1,
145 codec_specific_config: vec![],
146 }],
147 }],
148 });
149
150 assert!(b.into_add_source());
151 let subgroups = b
152 .endpoint_to_big_subgroups(HashMap::from([
153 (0, BisSync::sync(vec![1]).unwrap()),
154 (1, BisSync::sync(vec![1]).unwrap()),
155 ]))
156 .expect("should succeed");
157 assert_eq!(subgroups.len(), 1);
158 assert_eq!(
159 subgroups[0],
160 BigSubgroup::new(Some(BisSync::sync(vec![1]).unwrap()))
161 .with_metadata(vec![Metadata::BroadcastAudioImmediateRenderingFlag])
162 );
163 }
164}