bt_broadcast_assistant/
types.rs1use bt_bap::types::*;
6use bt_bass::types::{BigSubgroup, BisSync};
7use bt_common::core::PeriodicAdvertisingInterval;
8use bt_common::core::{Address, AddressType};
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) broadcast_id: Option<BroadcastId>,
21 pub(crate) periodic_advertising_interval: Option<PeriodicAdvertisingInterval>,
22 pub(crate) endpoint: Option<BroadcastAudioSourceEndpoint>,
23 pub(crate) broadcast_name: Option<String>,
24}
25
26impl BroadcastSource {
27 pub(crate) fn is_ready_to_add(&self) -> bool {
30 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_periodic_advertising_interval(
52 &mut self,
53 interval: PeriodicAdvertisingInterval,
54 ) -> &mut Self {
55 self.periodic_advertising_interval = Some(interval);
56 self
57 }
58
59 pub fn with_endpoint(&mut self, endpoint: BroadcastAudioSourceEndpoint) -> &mut Self {
60 self.endpoint = Some(endpoint);
61 self
62 }
63
64 pub fn with_broadcast_name(&mut self, name: String) -> &mut Self {
65 self.broadcast_name = Some(name);
66 self
67 }
68
69 pub(crate) fn merge(&mut self, other: &BroadcastSource) {
74 if let Some(address) = other.address {
75 self.address = Some(address);
76 }
77 if let Some(address_type) = other.address_type {
78 self.address_type = Some(address_type);
79 }
80 if let Some(broadcast_id) = other.broadcast_id {
81 self.broadcast_id = Some(broadcast_id);
82 }
83 if let Some(pa_interval) = other.periodic_advertising_interval {
84 self.periodic_advertising_interval = Some(pa_interval);
85 }
86 if let Some(endpoint) = &other.endpoint {
87 self.endpoint = Some(endpoint.clone());
88 }
89 if let Some(broadcast_name) = &other.broadcast_name {
90 self.broadcast_name = Some(broadcast_name.clone());
91 }
92 }
93
94 pub(crate) fn endpoint_to_big_subgroups(
103 &self,
104 bis_sync: HashMap<u8, BisSync>,
105 ) -> Result<Vec<BigSubgroup>, PacketError> {
106 if self.endpoint.is_none() {
107 return Err(PacketError::InvalidParameter(
108 "cannot convert empty Broadcast Audio Source Endpoint data to BIG subgroups data"
109 .to_string(),
110 ));
111 }
112 let mut subgroups = Vec::new();
113
114 for (big_index, group) in self.endpoint.as_ref().unwrap().big.iter().enumerate() {
115 let bis_sync = bis_sync.get(&(big_index as u8)).cloned().unwrap_or_default();
116 subgroups.push(BigSubgroup::new(Some(bis_sync)).with_metadata(group.metadata.clone()));
117 }
118 Ok(subgroups)
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 use std::collections::HashMap;
127
128 use bt_common::core::CodecId;
129 use bt_common::generic_audio::metadata_ltv::Metadata;
130
131 #[test]
132 fn broadcast_source() {
133 let mut b = BroadcastSource::default();
134 assert!(!b.is_ready_to_add());
135
136 b.with_broadcast_id(BroadcastId::try_from(0x010203).unwrap());
137 assert!(!b.is_ready_to_add());
138
139 b.endpoint_to_big_subgroups(HashMap::from([(0, BisSync::sync(vec![1]).unwrap())]))
140 .expect_err("should fail no endpoint data");
141
142 b.with_endpoint(BroadcastAudioSourceEndpoint {
143 presentation_delay_ms: 0x010203,
144 big: vec![BroadcastIsochronousGroup {
145 codec_id: CodecId::Assigned(bt_common::core::CodingFormat::Cvsd),
146 codec_specific_configs: vec![],
147 metadata: vec![Metadata::BroadcastAudioImmediateRenderingFlag],
148 bis: vec![BroadcastIsochronousStream {
149 bis_index: 1,
150 codec_specific_config: vec![],
151 }],
152 }],
153 });
154
155 assert!(b.is_ready_to_add());
156 let subgroups = b
157 .endpoint_to_big_subgroups(HashMap::from([
158 (0, BisSync::sync(vec![1]).unwrap()),
159 (1, BisSync::sync(vec![1]).unwrap()),
160 ]))
161 .expect("should succeed");
162 assert_eq!(subgroups.len(), 1);
163 assert_eq!(
164 subgroups[0],
165 BigSubgroup::new(Some(BisSync::sync(vec![1]).unwrap()))
166 .with_metadata(vec![Metadata::BroadcastAudioImmediateRenderingFlag])
167 );
168 }
169}