// Unit tests for shared audio transport metadata. // // Scope: exercise `common/src/audio_transport.rs` without GStreamer or network // dependencies. // Targets: `common/src/audio_transport.rs`. // Why: Opus should be evaluated as a transport codec without weakening the // known-good raw PCM microphone path. use lesavka_common::audio_transport::{ AudioTransportProfile, UpstreamAudioCodec, bundle_audio_profile, mark_bundle_audio_profile, mark_packet_opus, mark_packet_pcm_s16le, normalize_audio_encoding, packet_audio_profile, packet_is_raw_pcm_s16le, parse_upstream_audio_codec, }; use lesavka_common::lesavka::{AudioEncoding, AudioPacket, UpstreamMediaBundle}; #[test] fn opus_profile_is_low_bandwidth_without_changing_capture_clock() { let pcm = AudioTransportProfile::pcm_s16le(); let opus = AudioTransportProfile::opus_voice(); assert_eq!(pcm.sample_rate, 48_000); assert_eq!(opus.sample_rate, 48_000); assert_eq!(pcm.channels, 2); assert_eq!(opus.channels, 2); assert_eq!(pcm.frame_duration_us, 20_000); assert_eq!(opus.frame_duration_us, 20_000); assert_eq!(pcm.expected_payload_bytes(), 3_840); assert_eq!(opus.expected_payload_bytes(), 240); } #[test] fn unstamped_legacy_audio_remains_pcm_for_backward_compatibility() { let packet = AudioPacket::default(); assert_eq!( normalize_audio_encoding(packet.encoding), AudioEncoding::PcmS16le ); assert_eq!( packet_audio_profile(&packet), AudioTransportProfile::pcm_s16le() ); assert!(packet_is_raw_pcm_s16le(&packet)); } #[test] fn packet_and_bundle_metadata_can_select_opus_without_payload_guessing() { let packet = AudioPacket { encoding: AudioEncoding::Opus as i32, sample_rate: 48_000, channels: 2, frame_duration_us: 20_000, data: vec![0xaa; 240], ..AudioPacket::default() }; let bundle = UpstreamMediaBundle { audio_encoding: AudioEncoding::Opus as i32, audio_sample_rate: 48_000, audio_channels: 2, audio: vec![packet.clone()], ..UpstreamMediaBundle::default() }; assert_eq!( packet_audio_profile(&packet), AudioTransportProfile::opus_voice() ); assert_eq!( bundle_audio_profile(&bundle), AudioTransportProfile::opus_voice() ); assert!(!packet_is_raw_pcm_s16le(&packet)); } #[test] fn marking_helpers_keep_current_pcm_path_explicit() { let mut packet = AudioPacket { frame_duration_us: 10_000, ..AudioPacket::default() }; mark_packet_pcm_s16le(&mut packet); assert_eq!(packet.encoding, AudioEncoding::PcmS16le as i32); assert_eq!(packet.sample_rate, 48_000); assert_eq!(packet.channels, 2); assert_eq!( packet.frame_duration_us, 10_000, "caller-supplied packet duration should be preserved" ); let mut bundle = UpstreamMediaBundle::default(); mark_bundle_audio_profile(&mut bundle, AudioTransportProfile::pcm_s16le()); assert_eq!(bundle.audio_encoding, AudioEncoding::PcmS16le as i32); assert_eq!(bundle.audio_sample_rate, 48_000); assert_eq!(bundle.audio_channels, 2); } #[test] fn upstream_audio_codec_parser_keeps_opus_and_pcm_names_stable() { assert_eq!(UpstreamAudioCodec::PcmS16le.as_id(), "pcm"); assert_eq!(UpstreamAudioCodec::PcmS16le.label(), "PCM"); assert_eq!( UpstreamAudioCodec::PcmS16le.profile(), AudioTransportProfile::pcm_s16le() ); assert_eq!(UpstreamAudioCodec::Opus.as_id(), "opus"); assert_eq!(UpstreamAudioCodec::Opus.label(), "Opus"); assert_eq!( UpstreamAudioCodec::Opus.profile(), AudioTransportProfile::opus_voice() ); assert_eq!( parse_upstream_audio_codec("opus"), Some(UpstreamAudioCodec::Opus) ); assert_eq!( parse_upstream_audio_codec(" compressed "), Some(UpstreamAudioCodec::Opus) ); assert_eq!( parse_upstream_audio_codec("voice"), Some(UpstreamAudioCodec::Opus) ); assert_eq!( parse_upstream_audio_codec("raw"), Some(UpstreamAudioCodec::PcmS16le) ); assert_eq!( parse_upstream_audio_codec("PCM_S16LE"), Some(UpstreamAudioCodec::PcmS16le) ); assert_eq!( parse_upstream_audio_codec("uncompressed"), Some(UpstreamAudioCodec::PcmS16le) ); assert_eq!(parse_upstream_audio_codec("aac"), None); let mut packet = AudioPacket { data: vec![0xaa; 240], ..AudioPacket::default() }; mark_packet_opus(&mut packet); assert_eq!(packet.encoding, AudioEncoding::Opus as i32); assert_eq!( packet_audio_profile(&packet), AudioTransportProfile::opus_voice() ); } #[test] fn packet_profiles_preserve_explicit_nonzero_pcm_metadata() { let packet = AudioPacket { encoding: AudioEncoding::PcmS16le as i32, sample_rate: 44_100, channels: 1, frame_duration_us: 10_000, ..AudioPacket::default() }; assert_eq!( packet_audio_profile(&packet), AudioTransportProfile { encoding: AudioEncoding::PcmS16le, sample_rate: 44_100, channels: 1, frame_duration_us: 10_000, target_bitrate_bps: None, } ); } #[test] fn bundle_profiles_fallback_from_envelope_to_first_packet() { let packet = AudioPacket { encoding: AudioEncoding::Opus as i32, frame_duration_us: 40_000, ..AudioPacket::default() }; let bundle = UpstreamMediaBundle { audio: vec![packet], ..UpstreamMediaBundle::default() }; assert_eq!( bundle_audio_profile(&bundle), AudioTransportProfile { encoding: AudioEncoding::Opus, sample_rate: 48_000, channels: 2, frame_duration_us: 40_000, target_bitrate_bps: Some(96_000), } ); assert_eq!( bundle_audio_profile(&UpstreamMediaBundle::default()), AudioTransportProfile::pcm_s16le() ); } #[test] fn marking_helpers_fill_default_frame_duration_when_absent() { let mut pcm_packet = AudioPacket::default(); mark_packet_pcm_s16le(&mut pcm_packet); assert_eq!(pcm_packet.frame_duration_us, 20_000); let mut opus_packet = AudioPacket::default(); mark_packet_opus(&mut opus_packet); assert_eq!(opus_packet.frame_duration_us, 20_000); }