rust/bt-{gatt, broadcast-assistant}: Add broadcast name and PA interval

Support LE Audio broadcast metadata in central scanning and assistant
event records to enable broadcast source discovery.

Bug: b/366310724
Test: cargo test
Change-Id: I3c3c06b2df776464c37927816091d325cceaa326
Reviewed-on: https://bluetooth-review.googlesource.com/c/bluetooth/+/2920
diff --git a/rust/README.md b/rust/README.md
index dcd3d7e..4130001 100644
--- a/rust/README.md
+++ b/rust/README.md
@@ -10,6 +10,13 @@
 async features of rust are executor-agnostic - using any async executor
 should be possible.
 
+Additionally, any changes to the repository should also be formatted and
+checked for style, using the commands:
+```
+$ cargo fmt
+$ cargo check
+```
+
 ## Services
 
 Crates that implement services as defined by the published specifications.
@@ -76,9 +83,9 @@
 
 # Important Note about User Data and Privacy
 
-As Bluetooth is often used for data sharing and can send sensitive information,
-care should be taken by integrators of this library to ensure that user data and
-privacy is maintained.
+As Bluetooth is often used for data sharing and can send sensitive
+information, care should be taken by integrators of this library to ensure
+that user data and privacy is maintained.
 
 The crates here do not store any data persistently, and identifiers are stable
 only as long as the connection is maintained.
diff --git a/rust/bt-bass/src/client.rs b/rust/bt-bass/src/client.rs
index 7519501..8ad2ef6 100644
--- a/rust/bt-bass/src/client.rs
+++ b/rust/bt-bass/src/client.rs
@@ -14,7 +14,7 @@
 use parking_lot::Mutex;
 
 use bt_bap::types::BroadcastId;
-use bt_common::core::{AddressType, AdvertisingSetId, PaInterval};
+use bt_common::core::{AddressType, AdvertisingSetId, PeriodicAdvertisingInterval};
 use bt_common::generic_audio::metadata_ltv::Metadata;
 use bt_common::packet_encoding::Decodable;
 use bt_gatt::client::{CharacteristicNotification, PeerService, ServiceCharacteristic};
@@ -270,7 +270,7 @@
         advertiser_address: [u8; ADDRESS_BYTE_SIZE],
         sid: AdvertisingSetId,
         pa_sync: PaSync,
-        pa_interval: PaInterval,
+        pa_interval: PeriodicAdvertisingInterval,
         subgroups: Vec<BigSubgroup>,
     ) -> Result<(), Error> {
         let op = AddSourceOperation::new(
@@ -304,7 +304,7 @@
         &self,
         broadcast_id: BroadcastId,
         pa_sync: PaSync,
-        pa_interval: Option<PaInterval>,
+        pa_interval: Option<PeriodicAdvertisingInterval>,
         bis_sync: Option<HashMap<SubgroupIndex, BisSync>>,
         metadata_map: Option<HashMap<SubgroupIndex, Vec<Metadata>>>,
     ) -> Result<(), Error> {
@@ -347,7 +347,7 @@
             ModifySourceOperation::new(
                 state.source_id,
                 pa_sync,
-                pa_interval.unwrap_or(PaInterval::unknown()),
+                pa_interval.unwrap_or(PeriodicAdvertisingInterval::unknown()),
                 state.subgroups,
             )
         };
@@ -737,7 +737,7 @@
             [0x04, 0x10, 0x00, 0x00, 0x00, 0x00],
             AdvertisingSetId(1),
             PaSync::DoNotSync,
-            PaInterval::unknown(),
+            PeriodicAdvertisingInterval::unknown(),
             vec![],
         );
         pin_mut!(op_fut);
@@ -778,7 +778,7 @@
         let op_fut = client.modify_broadcast_source(
             BroadcastId::try_from(0x11).unwrap(),
             PaSync::DoNotSync,
-            Some(PaInterval(0xAAAA)),
+            Some(PeriodicAdvertisingInterval(0xAAAA)),
             None,
             None,
         );
diff --git a/rust/bt-bass/src/types.rs b/rust/bt-bass/src/types.rs
index 70c97ad..e8db40e 100644
--- a/rust/bt-bass/src/types.rs
+++ b/rust/bt-bass/src/types.rs
@@ -4,7 +4,7 @@
 
 use bt_bap::types::BroadcastId;
 use bt_common::core::ltv::LtValue;
-use bt_common::core::{AddressType, AdvertisingSetId, PaInterval};
+use bt_common::core::{AddressType, AdvertisingSetId, PeriodicAdvertisingInterval};
 use bt_common::generic_audio::metadata_ltv::*;
 use bt_common::packet_encoding::{Decodable, Encodable, Error as PacketError};
 use bt_common::{decodable_enum, Uuid};
@@ -155,7 +155,7 @@
     pub(crate) advertising_sid: AdvertisingSetId,
     pub(crate) broadcast_id: BroadcastId,
     pub(crate) pa_sync: PaSync,
-    pub(crate) pa_interval: PaInterval,
+    pub(crate) pa_interval: PeriodicAdvertisingInterval,
     pub(crate) subgroups: Vec<BigSubgroup>,
 }
 
@@ -166,7 +166,7 @@
         + AdvertisingSetId::BYTE_SIZE
         + BroadcastId::BYTE_SIZE
         + PA_SYNC_BYTE_SIZE
-        + PaInterval::BYTE_SIZE
+        + PeriodicAdvertisingInterval::BYTE_SIZE
         + NUM_SUBGROUPS_BYTE_SIZE;
 
     pub fn new(
@@ -175,7 +175,7 @@
         advertising_sid: AdvertisingSetId,
         broadcast_id: BroadcastId,
         pa_sync: PaSync,
-        pa_interval: PaInterval,
+        pa_interval: PeriodicAdvertisingInterval,
         subgroups: Vec<BigSubgroup>,
     ) -> Self {
         AddSourceOperation {
@@ -212,7 +212,8 @@
             let advertising_sid = AdvertisingSetId(buf[8]);
             let broadcast_id = BroadcastId::decode(&buf[9..12]).0?;
             let pa_sync = PaSync::try_from(buf[12])?;
-            let pa_interval = PaInterval(u16::from_le_bytes(buf[13..15].try_into().unwrap()));
+            let pa_interval =
+                PeriodicAdvertisingInterval(u16::from_le_bytes(buf[13..15].try_into().unwrap()));
             let num_subgroups = buf[15] as usize;
             let mut subgroups = Vec::new();
 
@@ -284,7 +285,7 @@
 pub struct ModifySourceOperation {
     source_id: SourceId,
     pa_sync: PaSync,
-    pa_interval: PaInterval,
+    pa_interval: PeriodicAdvertisingInterval,
     subgroups: Vec<BigSubgroup>,
 }
 
@@ -292,13 +293,13 @@
     const MIN_PACKET_SIZE: usize = ControlPointOpcode::BYTE_SIZE
         + SOURCE_ID_BYTE_SIZE
         + PA_SYNC_BYTE_SIZE
-        + PaInterval::BYTE_SIZE
+        + PeriodicAdvertisingInterval::BYTE_SIZE
         + NUM_SUBGROUPS_BYTE_SIZE;
 
     pub fn new(
         source_id: SourceId,
         pa_sync: PaSync,
-        pa_interval: PaInterval,
+        pa_interval: PeriodicAdvertisingInterval,
         subgroups: Vec<BigSubgroup>,
     ) -> Self {
         ModifySourceOperation { source_id, pa_sync, pa_interval, subgroups }
@@ -323,7 +324,8 @@
             let _ = Self::check_opcode(buf[0])?;
             let source_id = buf[1];
             let pa_sync = PaSync::try_from(buf[2])?;
-            let pa_interval = PaInterval(u16::from_le_bytes(buf[3..5].try_into().unwrap()));
+            let pa_interval =
+                PeriodicAdvertisingInterval(u16::from_le_bytes(buf[3..5].try_into().unwrap()));
             let num_subgroups = buf[5] as usize;
             let mut subgroups = Vec::new();
 
@@ -1154,7 +1156,7 @@
             AdvertisingSetId(1),
             BroadcastId::try_from(0x11).unwrap(),
             PaSync::DoNotSync,
-            PaInterval::unknown(),
+            PeriodicAdvertisingInterval::unknown(),
             vec![],
         );
         assert_eq!(op.encoded_len(), 16);
@@ -1186,7 +1188,7 @@
             AdvertisingSetId(1),
             BroadcastId::try_from(0x11).unwrap(),
             PaSync::SyncPastAvailable,
-            PaInterval::unknown(),
+            PeriodicAdvertisingInterval::unknown(),
             subgroups,
         );
         assert_eq!(op.encoded_len(), 31); // 16 for minimum params and params 15 for the subgroup.
@@ -1210,8 +1212,12 @@
     #[test]
     fn modify_source_without_subgroups() {
         // Encoding operation with no subgroups.
-        let op =
-            ModifySourceOperation::new(0x0A, PaSync::SyncPastAvailable, PaInterval(0x1004), vec![]);
+        let op = ModifySourceOperation::new(
+            0x0A,
+            PaSync::SyncPastAvailable,
+            PeriodicAdvertisingInterval(0x1004),
+            vec![],
+        );
         assert_eq!(op.encoded_len(), 6);
         let mut buf = vec![0u8; op.encoded_len()];
         op.encode(&mut buf[..]).expect("shoud succeed");
@@ -1233,8 +1239,12 @@
             BigSubgroup::new(Some(BisSync(0x000000FE)))
                 .with_metadata(vec![Metadata::BroadcastAudioImmediateRenderingFlag]), /* encoded_len = 7 */
         ];
-        let op =
-            ModifySourceOperation::new(0x0B, PaSync::DoNotSync, PaInterval::unknown(), subgroups);
+        let op = ModifySourceOperation::new(
+            0x0B,
+            PaSync::DoNotSync,
+            PeriodicAdvertisingInterval::unknown(),
+            subgroups,
+        );
         assert_eq!(op.encoded_len(), 21); // 6 for minimum params and params 15 for two subgroups.
         let mut buf = vec![0u8; op.encoded_len()];
         op.encode(&mut buf[..]).expect("shoud succeed");
diff --git a/rust/bt-broadcast-assistant/src/assistant.rs b/rust/bt-broadcast-assistant/src/assistant.rs
index b8b50af..495ed85 100644
--- a/rust/bt-broadcast-assistant/src/assistant.rs
+++ b/rust/bt-broadcast-assistant/src/assistant.rs
@@ -196,7 +196,7 @@
             address_type: Some(address_type),
             advertising_sid: Some(advertising_sid),
             broadcast_id: None,
-            pa_interval: None,
+            periodic_advertising_interval: None,
             endpoint: None,
         };
 
@@ -231,7 +231,7 @@
             address_type: None,
             advertising_sid: None,
             broadcast_id: None,
-            pa_interval: None,
+            periodic_advertising_interval: None,
             endpoint: Some(endpoint),
         };
 
@@ -284,7 +284,7 @@
                 address_type: Some(AddressType::Public),
                 advertising_sid: Some(AdvertisingSetId(1)),
                 broadcast_id: Some(bid),
-                pa_interval: None,
+                periodic_advertising_interval: None,
                 endpoint: None,
             }
         );
@@ -303,7 +303,7 @@
                 address_type: Some(AddressType::Random),
                 advertising_sid: Some(AdvertisingSetId(1)),
                 broadcast_id: Some(bid),
-                pa_interval: None,
+                periodic_advertising_interval: None,
                 endpoint: Some(BroadcastAudioSourceEndpoint {
                     presentation_delay_ms: 32,
                     big: vec![]
diff --git a/rust/bt-broadcast-assistant/src/assistant/event.rs b/rust/bt-broadcast-assistant/src/assistant/event.rs
index 741c04c..d9a535a 100644
--- a/rust/bt-broadcast-assistant/src/assistant/event.rs
+++ b/rust/bt-broadcast-assistant/src/assistant/event.rs
@@ -9,7 +9,7 @@
 use std::task::Poll;
 
 use bt_bap::types::{BroadcastAudioSourceEndpoint, BroadcastId};
-use bt_common::core::AdvertisingSetId;
+use bt_common::core::{AdvertisingSetId, PeriodicAdvertisingInterval};
 use bt_common::packet_encoding::Decodable;
 use bt_common::packet_encoding::Error as PacketError;
 use bt_common::PeerId;
@@ -73,7 +73,9 @@
             }
         }
         if let Some(src) = &mut source {
-            src.advertising_sid = Some(AdvertisingSetId(scan_result.advertising_sid));
+            src.advertising_sid = scan_result.advertising_sid.map(AdvertisingSetId);
+            src.periodic_advertising_interval =
+                scan_result.periodic_advertising_interval.map(PeriodicAdvertisingInterval);
         }
         Ok(source)
     }
@@ -185,7 +187,8 @@
                 BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE,
                 vec![0x01, 0x02, 0x03],
             )],
-            advertising_sid: 0,
+            advertising_sid: Some(0),
+            periodic_advertising_interval: None,
         }));
 
         // Found broadcast source event shouldn't have been sent since braodcast source
@@ -230,7 +233,8 @@
                 BASIC_AUDIO_ANNOUNCEMENT_SERVICE,
                 base_data.clone(),
             )],
-            advertising_sid: 1,
+            advertising_sid: Some(1),
+            periodic_advertising_interval: Some(0x0100),
         }));
 
         // Expect the stream to send out broadcast source found event since information
@@ -241,6 +245,7 @@
         assert_matches!(event, Event::FoundBroadcastSource{peer, source} => {
             assert_eq!(peer, broadcast_source_pid);
             assert_eq!(source.advertising_sid, Some(AdvertisingSetId(1)));
+            assert_eq!(source.periodic_advertising_interval, Some(PeriodicAdvertisingInterval(0x0100)));
         });
 
         assert!(stream.poll_next_unpin(&mut noop_cx).is_pending());
@@ -254,7 +259,8 @@
                 BASIC_AUDIO_ANNOUNCEMENT_SERVICE,
                 base_data.clone(),
             )],
-            advertising_sid: 1,
+            advertising_sid: Some(1),
+            periodic_advertising_interval: Some(0x0100),
         }));
 
         // Shouldn't have gotten the event again since the information remained the
diff --git a/rust/bt-broadcast-assistant/src/assistant/peer.rs b/rust/bt-broadcast-assistant/src/assistant/peer.rs
index 73029d8..30be3f1 100644
--- a/rust/bt-broadcast-assistant/src/assistant/peer.rs
+++ b/rust/bt-broadcast-assistant/src/assistant/peer.rs
@@ -15,7 +15,7 @@
 #[cfg(any(test, feature = "debug"))]
 use bt_bass::types::BroadcastReceiveState;
 use bt_bass::types::{BisSync, PaSync};
-use bt_common::core::PaInterval;
+use bt_common::core::PeriodicAdvertisingInterval;
 use bt_common::packet_encoding::Error as PacketError;
 use bt_common::PeerId;
 #[cfg(any(test, feature = "debug"))]
@@ -129,7 +129,9 @@
                 broadcast_source.address.unwrap(),
                 broadcast_source.advertising_sid.unwrap(),
                 pa_sync,
-                broadcast_source.pa_interval.unwrap_or(PaInterval::unknown()),
+                broadcast_source
+                    .periodic_advertising_interval
+                    .unwrap_or(PeriodicAdvertisingInterval::unknown()),
                 broadcast_source.endpoint_to_big_subgroups(bis_sync).map_err(Error::PacketError)?,
             )
             .await
@@ -154,7 +156,7 @@
         let pa_interval = self
             .broadcast_sources
             .get_by_broadcast_id(&broadcast_id)
-            .map(|bs| bs.pa_interval)
+            .map(|bs| bs.periodic_advertising_interval)
             .unwrap_or(None);
 
         self.bass
diff --git a/rust/bt-broadcast-assistant/src/types.rs b/rust/bt-broadcast-assistant/src/types.rs
index 2cd8d96..e1b6312 100644
--- a/rust/bt-broadcast-assistant/src/types.rs
+++ b/rust/bt-broadcast-assistant/src/types.rs
@@ -5,7 +5,7 @@
 use bt_bap::types::*;
 use bt_bass::types::{BigSubgroup, BisSync};
 use bt_common::core::{Address, AddressType};
-use bt_common::core::{AdvertisingSetId, PaInterval};
+use bt_common::core::{AdvertisingSetId, PeriodicAdvertisingInterval};
 use bt_common::packet_encoding::Error as PacketError;
 use std::collections::HashMap;
 
@@ -19,7 +19,7 @@
     pub(crate) address_type: Option<AddressType>,
     pub(crate) advertising_sid: Option<AdvertisingSetId>,
     pub(crate) broadcast_id: Option<BroadcastId>,
-    pub(crate) pa_interval: Option<PaInterval>,
+    pub(crate) periodic_advertising_interval: Option<PeriodicAdvertisingInterval>,
     pub(crate) endpoint: Option<BroadcastAudioSourceEndpoint>,
 }
 
@@ -53,6 +53,14 @@
         self
     }
 
+    pub fn with_periodic_advertising_interval(
+        &mut self,
+        interval: PeriodicAdvertisingInterval,
+    ) -> &mut Self {
+        self.periodic_advertising_interval = Some(interval);
+        self
+    }
+
     pub fn with_endpoint(&mut self, endpoint: BroadcastAudioSourceEndpoint) -> &mut Self {
         self.endpoint = Some(endpoint);
         self
@@ -75,8 +83,8 @@
         if let Some(broadcast_id) = other.broadcast_id {
             self.broadcast_id = Some(broadcast_id);
         }
-        if let Some(pa_interval) = other.pa_interval {
-            self.pa_interval = Some(pa_interval);
+        if let Some(pa_interval) = other.periodic_advertising_interval {
+            self.periodic_advertising_interval = Some(pa_interval);
         }
         if let Some(endpoint) = &other.endpoint {
             self.endpoint = Some(endpoint.clone());
diff --git a/rust/bt-common/src/core.rs b/rust/bt-common/src/core.rs
index fee3dc7..9fab7e3 100644
--- a/rust/bt-common/src/core.rs
+++ b/rust/bt-common/src/core.rs
@@ -60,9 +60,9 @@
 
 /// SyncInfo Interval value which is 2 bytes long.
 #[derive(Debug, Clone, Copy, PartialEq)]
-pub struct PaInterval(pub u16);
+pub struct PeriodicAdvertisingInterval(pub u16);
 
-impl PaInterval {
+impl PeriodicAdvertisingInterval {
     pub const BYTE_SIZE: usize = 2;
     pub const UNKNOWN_VALUE: u16 = 0xFFFF;
 
@@ -71,7 +71,7 @@
     }
 }
 
-impl Encodable for PaInterval {
+impl Encodable for PeriodicAdvertisingInterval {
     type Error = PacketError;
 
     /// Encodees the PaInterval to 2 byte value using little endian encoding.
@@ -244,8 +244,8 @@
 
     #[test]
     fn encode_pa_interval() {
-        let mut buf = [0; PaInterval::BYTE_SIZE];
-        let interval = PaInterval(0x1004);
+        let mut buf = [0; PeriodicAdvertisingInterval::BYTE_SIZE];
+        let interval = PeriodicAdvertisingInterval(0x1004);
 
         interval.encode(&mut buf[..]).expect("should succeed");
         assert_eq!(buf, [0x04, 0x10]);
@@ -254,7 +254,7 @@
     #[test]
     fn encode_pa_interval_fails() {
         let mut buf = [0; 1]; // Not enough buffer space.
-        let interval = PaInterval(0x1004);
+        let interval = PeriodicAdvertisingInterval(0x1004);
 
         interval.encode(&mut buf[..]).expect_err("should fail");
     }
diff --git a/rust/bt-gatt/src/central.rs b/rust/bt-gatt/src/central.rs
index c896717..af55cd0 100644
--- a/rust/bt-gatt/src/central.rs
+++ b/rust/bt-gatt/src/central.rs
@@ -20,6 +20,7 @@
     Appearance(u16),
     TxPowerLevel(i8),
     Uri(String),
+    BroadcastName(String),
 }
 
 /// Matches a single advertised attribute or condition from a Bluetooth Low
@@ -75,7 +76,8 @@
     pub connectable: bool,
     pub name: PeerName,
     pub advertised: Vec<AdvertisingDatum>,
-    pub advertising_sid: u8,
+    pub advertising_sid: Option<u8>,
+    pub periodic_advertising_interval: Option<u16>,
 }
 
 pub trait Central<T: crate::GattTypes> {
diff --git a/rust/bt-gatt/src/tests.rs b/rust/bt-gatt/src/tests.rs
index cc51dd5..6cab78b 100644
--- a/rust/bt-gatt/src/tests.rs
+++ b/rust/bt-gatt/src/tests.rs
@@ -243,7 +243,8 @@
         connectable: true,
         name: PeerName::CompleteName("Marie's Pixel 7 Pro".to_owned()),
         advertised: vec![AdvertisingDatum::Services(vec![Uuid::from_u16(0x1844)])],
-        advertising_sid: 0,
+        advertising_sid: Some(0),
+        periodic_advertising_interval: None,
     };
     let _ = scan_results.set_scanned_result(Ok(scanned_result));