| // Copyright 2023 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| pub mod codec_capabilities; |
| pub mod codec_configuration; |
| pub mod metadata_ltv; |
| |
| use crate::{codable_as_bitmask, decodable_enum}; |
| |
| // Source: |
| // https://bitbucket.org/bluetooth-SIG/public/src/main/assigned_numbers/profiles_and_services/generic_audio/context_type.yaml |
| decodable_enum! { |
| pub enum ContextType<u16, crate::packet_encoding::Error, OutOfRange> { |
| Unspecified = 0x0001, |
| Conversational = 0x0002, |
| Media = 0x0004, |
| Game = 0x0008, |
| Instructional = 0x0010, |
| VoiceAssistants = 0x0020, |
| Live = 0x0040, |
| SoundEffects = 0x0080, |
| Notifications = 0x0100, |
| Ringtone = 0x0200, |
| Alerts = 0x0400, |
| EmergencyAlarm = 0x0800, |
| } |
| } |
| |
| codable_as_bitmask!(ContextType, u16); |
| |
| // Source: |
| // https://bitbucket.org/bluetooth-SIG/public/src/main/assigned_numbers/profiles_and_services/generic_audio/audio_location_definitions.yaml |
| // Regexp magic for quick variants: |
| // %s/ - value: \(\S\+\)\n audio_location: \(.*\)\n/\2 = \1\r,/g |
| // with subsequent removal of Spaces |
| decodable_enum! { |
| pub enum AudioLocation<u32, crate::packet_encoding::Error, OutOfRange> { |
| FrontLeft = 0x00000001, |
| FrontRight = 0x00000002, |
| FrontCenter = 0x00000004, |
| LowFrequencyEffects1 = 0x00000008, |
| BackLeft = 0x00000010, |
| BackRight = 0x00000020, |
| FrontLeftOfCenter = 0x00000040, |
| FrontRightOfCenter = 0x00000080, |
| BackCenter = 0x00000100, |
| LowFrequencyEffects2 = 0x00000200, |
| SideLeft = 0x00000400, |
| SideRight = 0x00000800, |
| TopFrontLeft = 0x00001000, |
| TopFrontRight = 0x00002000, |
| TopFrontCenter = 0x00004000, |
| TopCenter = 0x00008000, |
| TopBackLeft = 0x00010000, |
| TopBackRight = 0x00020000, |
| TopSideLeft = 0x00040000, |
| TopSideRight = 0x00080000, |
| TopBackCenter = 0x00100000, |
| BottomFrontCenter = 0x00200000, |
| BottomFrontLeft = 0x00400000, |
| BottomFrontRight = 0x00800000, |
| FrontLeftWide = 0x01000000, |
| FrontRightWide = 0x02000000, |
| LeftSurround = 0x04000000, |
| RightSurround = 0x08000000, |
| } |
| } |
| |
| codable_as_bitmask!(AudioLocation, u32); |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| #[test] |
| fn locations_decodable() { |
| let five_point_one = 0b111111; |
| |
| let locations: std::collections::HashSet<AudioLocation> = |
| AudioLocation::from_bits(five_point_one).collect(); |
| |
| assert_eq!(6, locations.len()); |
| |
| let expected_locations = [ |
| AudioLocation::FrontLeft, |
| AudioLocation::FrontRight, |
| AudioLocation::FrontCenter, |
| AudioLocation::LowFrequencyEffects1, |
| AudioLocation::BackLeft, |
| AudioLocation::BackRight, |
| ] |
| .into_iter() |
| .collect(); |
| |
| assert_eq!(locations, expected_locations); |
| |
| assert_eq!(AudioLocation::try_from(0x4), Ok(AudioLocation::FrontCenter)); |
| |
| // Directly decoding a location that is not a single bit is an error. |
| assert!(AudioLocation::try_from(0b1010101).is_err()); |
| } |
| |
| #[test] |
| fn locations_encodable() { |
| let locations_missing_sub = [ |
| AudioLocation::FrontLeft, |
| AudioLocation::FrontRight, |
| AudioLocation::FrontCenter, |
| AudioLocation::BackLeft, |
| AudioLocation::BackRight, |
| ]; |
| |
| let value = AudioLocation::to_bits(locations_missing_sub.iter()); |
| |
| assert_eq!(0b110111, value); |
| } |
| |
| #[test] |
| fn context_type_decodable() { |
| let contexts: Vec<ContextType> = ContextType::from_bits(0b10).collect(); |
| assert_eq!(contexts.len(), 1); |
| assert_eq!(contexts[0], ContextType::Conversational); |
| |
| let live_and_instructional = 0b1010000; |
| let contexts: std::collections::HashSet<ContextType> = |
| ContextType::from_bits(live_and_instructional).collect(); |
| |
| assert_eq!(contexts.len(), 2); |
| assert_eq!(contexts, [ContextType::Live, ContextType::Instructional].into_iter().collect()); |
| |
| let alerts_and_conversational = 0x0402; |
| |
| let contexts: std::collections::HashSet<ContextType> = |
| ContextType::from_bits(alerts_and_conversational).collect(); |
| |
| assert_eq!(contexts.len(), 2); |
| assert_eq!( |
| contexts, |
| [ContextType::Alerts, ContextType::Conversational].into_iter().collect() |
| ); |
| } |
| |
| #[test] |
| fn context_type_encodable() { |
| let contexts = [ContextType::Notifications, ContextType::SoundEffects, ContextType::Game]; |
| |
| let value = ContextType::to_bits(contexts.iter()); |
| |
| assert_eq!(0x188, value); |
| } |
| } |