| // 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); | |
| } | |
| } |