From e8c134664ba4063db5a5f06d5417182d2c7514f6 Mon Sep 17 00:00:00 2001 From: Gnome! Date: Sun, 23 Feb 2025 13:02:29 +0000 Subject: [PATCH] Move decode config into DecodeMode::Decode (#272) --- examples/serenity/voice_receive/src/main.rs | 5 +-- src/config.rs | 34 +-------------------- src/driver/decode_mode.rs | 34 ++++++++++++++++++++- src/driver/tasks/message/udp_rx.rs | 4 +-- src/driver/tasks/mixer/mod.rs | 9 +++--- src/driver/tasks/udp_rx/mod.rs | 15 +++++---- src/driver/tasks/udp_rx/ssrc_state.rs | 29 +++++++++--------- src/events/context/data/voice.rs | 6 ++-- 8 files changed, 68 insertions(+), 68 deletions(-) diff --git a/examples/serenity/voice_receive/src/main.rs b/examples/serenity/voice_receive/src/main.rs index 4d20d4f..3554c9a 100644 --- a/examples/serenity/voice_receive/src/main.rs +++ b/examples/serenity/voice_receive/src/main.rs @@ -34,7 +34,7 @@ use serenity::{ }; use songbird::{ - driver::DecodeMode, + driver::{DecodeConfig, DecodeMode}, model::{ id::UserId, payload::{ClientDisconnect, Speaking}, @@ -217,7 +217,8 @@ async fn main() { // Here, we need to configure Songbird to decode all incoming voice packets. // If you want, you can do this on a per-call basis---here, we need it to // read the audio data that other people are sending us! - let songbird_config = Config::default().decode_mode(DecodeMode::Decode); + let songbird_config = + Config::default().decode_mode(DecodeMode::Decode(DecodeConfig::default())); let mut client = Client::builder(&token, intents) .event_handler(Handler) diff --git a/src/config.rs b/src/config.rs index 4717792..49b7fe3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,5 @@ #[cfg(all(feature = "driver", feature = "receive"))] -use crate::driver::{Channels, DecodeMode, SampleRate}; +use crate::driver::DecodeMode; #[cfg(feature = "driver")] use crate::{ driver::{ @@ -61,18 +61,6 @@ pub struct Config { /// [User speaking state]: crate::events::CoreEvent::VoiceTick pub decode_mode: DecodeMode, - #[cfg(all(feature = "driver", feature = "receive"))] - /// Configures the channel layout for output audio when using [`DecodeMode::Decode`]. - /// - /// Defaults to [`Channels::Stereo`]. - pub decode_channels: Channels, - - #[cfg(all(feature = "driver", feature = "receive"))] - /// Configures the sample rate for output audio when using [`DecodeMode::Decode`]. - /// - /// Defaults to [`SampleRate::Hz48000`]. - pub decode_sample_rate: SampleRate, - #[cfg(all(feature = "driver", feature = "receive"))] /// Configures the amount of time after a user/SSRC is inactive before their decoder state /// should be removed. @@ -223,10 +211,6 @@ impl Default for Config { #[cfg(all(feature = "driver", feature = "receive"))] decode_mode: DecodeMode::Decrypt, #[cfg(all(feature = "driver", feature = "receive"))] - decode_channels: Channels::Stereo, - #[cfg(all(feature = "driver", feature = "receive"))] - decode_sample_rate: SampleRate::Hz48000, - #[cfg(all(feature = "driver", feature = "receive"))] decode_state_timeout: Duration::from_secs(60), #[cfg(all(feature = "driver", feature = "receive"))] playout_buffer_length: NonZeroUsize::new(5).unwrap(), @@ -279,22 +263,6 @@ impl Config { self } - #[cfg(feature = "receive")] - /// Sets this `Config`'s channel layout for output audio when using [`DecodeMode::Decode`] - #[must_use] - pub fn decode_channels(mut self, decode_channels: Channels) -> Self { - self.decode_channels = decode_channels; - self - } - - #[cfg(feature = "receive")] - /// Sets this `Config`'s sample rate for output audio when using [`DecodeMode::Decode`] - #[must_use] - pub fn decode_sample_rate(mut self, decode_sample_rate: SampleRate) -> Self { - self.decode_sample_rate = decode_sample_rate; - self - } - #[cfg(feature = "receive")] /// Sets this `Config`'s received packet decoder cleanup timer. #[must_use] diff --git a/src/driver/decode_mode.rs b/src/driver/decode_mode.rs index 8b8976e..269c8c2 100644 --- a/src/driver/decode_mode.rs +++ b/src/driver/decode_mode.rs @@ -16,10 +16,16 @@ pub enum DecodeMode { /// Decrypts and decodes each received packet, correctly accounting for losses. /// /// Larger per-packet CPU use. - Decode, + Decode(DecodeConfig), } impl DecodeMode { + /// Returns whether this mode will decrypt and decode received packets. + #[must_use] + pub fn should_decode(self) -> bool { + matches!(self, DecodeMode::Decode(..)) + } + /// Returns whether this mode will decrypt received packets. #[must_use] pub fn should_decrypt(self) -> bool { @@ -27,6 +33,32 @@ impl DecodeMode { } } +/// Configuration for [`DecodeMode::Decode`] +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)] +pub struct DecodeConfig { + /// Configures the channel layout for output audio. + /// + /// Defaults to [`Channels::Stereo`]. + pub channels: Channels, + + /// Configures the sample rate for output audio. + /// + /// Defaults to [`SampleRate::Hz48000`]. + pub sample_rate: SampleRate, +} + +impl DecodeConfig { + /// Creates a new [`DecodeConfig`] with the specified channels and sample rate. + #[must_use] + pub fn new(channels: Channels, sample_rate: SampleRate) -> Self { + Self { + channels, + sample_rate, + } + } +} + /// The channel layout of output audio when using [`DecodeMode::Decode`]. #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)] #[non_exhaustive] diff --git a/src/driver/tasks/message/udp_rx.rs b/src/driver/tasks/message/udp_rx.rs index 202dd54..5795fa1 100644 --- a/src/driver/tasks/message/udp_rx.rs +++ b/src/driver/tasks/message/udp_rx.rs @@ -1,12 +1,12 @@ #![allow(missing_docs)] use super::Interconnect; -use crate::driver::Config; +use crate::driver::DecodeConfig; use dashmap::{DashMap, DashSet}; use serenity_voice_model::id::UserId; pub enum UdpRxMessage { - SetConfig(Config), + SetConfig(DecodeConfig), ReplaceInterconnect(Interconnect), } diff --git a/src/driver/tasks/mixer/mod.rs b/src/driver/tasks/mixer/mod.rs index 39eea78..66e5fc7 100644 --- a/src/driver/tasks/mixer/mod.rs +++ b/src/driver/tasks/mixer/mod.rs @@ -329,10 +329,11 @@ impl Mixer { #[cfg(feature = "receive")] if let Some(conn) = &self.conn_active { - conn_failure |= conn - .udp_rx - .send(UdpRxMessage::SetConfig(new_config)) - .is_err(); + if let crate::driver::DecodeMode::Decode(decode_config) = new_config.decode_mode + { + let msg = UdpRxMessage::SetConfig(decode_config); + conn_failure |= conn.udp_rx.send(msg).is_err(); + } } Ok(()) diff --git a/src/driver/tasks/udp_rx/mod.rs b/src/driver/tasks/udp_rx/mod.rs index 4ee7b1e..74c9af1 100644 --- a/src/driver/tasks/udp_rx/mod.rs +++ b/src/driver/tasks/udp_rx/mod.rs @@ -5,7 +5,7 @@ mod ssrc_state; use self::{decode_sizes::*, playout_buffer::*, ssrc_state::*}; use super::message::*; -use crate::driver::CryptoMode; +use crate::driver::{CryptoMode, DecodeMode}; use crate::{ constants::*, driver::crypto::Cipher, @@ -65,13 +65,12 @@ impl UdpRx { Ok(UdpRxMessage::ReplaceInterconnect(i)) => { *interconnect = i; }, - Ok(UdpRxMessage::SetConfig(c)) => { - let old_coder = (self.config.decode_channels, self.config.decode_sample_rate); - let new_coder = (c.decode_channels, c.decode_sample_rate); - self.config = c; - - if old_coder != new_coder { - self.decoder_map.values_mut().for_each(|v| v.reconfigure_decoder(&self.config)); + Ok(UdpRxMessage::SetConfig(new_config)) => { + if let DecodeMode::Decode(old_config) = &mut self.config.decode_mode { + if *old_config != new_config { + *old_config = new_config; + self.decoder_map.values_mut().for_each(|v| v.reconfigure_decoder(new_config)); + } } }, Err(flume::RecvError::Disconnected) => break, diff --git a/src/driver/tasks/udp_rx/ssrc_state.rs b/src/driver/tasks/udp_rx/ssrc_state.rs index 7149964..952c8b7 100644 --- a/src/driver/tasks/udp_rx/ssrc_state.rs +++ b/src/driver/tasks/udp_rx/ssrc_state.rs @@ -3,6 +3,7 @@ use crate::{ driver::{ tasks::error::{Error, Result}, Channels, + DecodeConfig, DecodeMode, }, events::context_data::{RtpData, VoiceData}, @@ -29,29 +30,28 @@ pub struct SsrcState { impl SsrcState { pub fn new(pkt: &RtpPacket<'_>, crypto_mode: CryptoMode, config: &Config) -> Self { let playout_capacity = config.playout_buffer_length.get() + config.playout_spike_length; + let (sample_rate, channels) = match config.decode_mode { + DecodeMode::Decode(config) => (config.sample_rate, config.channels), + DecodeMode::Decrypt | DecodeMode::Pass => Default::default(), + }; Self { playout_buffer: PlayoutBuffer::new(playout_capacity, pkt.get_sequence().0), crypto_mode, - decoder: OpusDecoder::new( - config.decode_sample_rate.into(), - config.decode_channels.into(), - ) - .expect("Failed to create new Opus decoder for source."), + decoder: OpusDecoder::new(sample_rate.into(), channels.into()) + .expect("Failed to create new Opus decoder for source."), decode_size: PacketDecodeSize::TwentyMillis, prune_time: Instant::now() + config.decode_state_timeout, disconnected: false, - channels: config.decode_channels, + channels, } } - pub fn reconfigure_decoder(&mut self, config: &Config) { - self.decoder = OpusDecoder::new( - config.decode_sample_rate.into(), - config.decode_channels.into(), - ) - .expect("Failed to create new Opus decoder for source."); - self.channels = config.decode_channels; + pub fn reconfigure_decoder(&mut self, config: DecodeConfig) { + self.decoder = OpusDecoder::new(config.sample_rate.into(), config.channels.into()) + .expect("Failed to create new Opus decoder for source."); + + self.channels = config.channels; } pub fn store_packet(&mut self, packet: StoredPacket, config: &Config) { @@ -80,8 +80,7 @@ impl SsrcState { decoded_voice: None, }; - let should_decode = config.decode_mode == DecodeMode::Decode; - + let should_decode = config.decode_mode.should_decode(); if let Some((packet, decrypted)) = pkt { let rtp = RtpPacket::new(&packet).unwrap(); let extensions = rtp.get_extension() != 0; diff --git a/src/events/context/data/voice.rs b/src/events/context/data/voice.rs index b953b51..5c164f2 100644 --- a/src/events/context/data/voice.rs +++ b/src/events/context/data/voice.rs @@ -32,12 +32,12 @@ pub struct VoiceData { /// /// Valid audio data (`Some(audio)` where `audio.len >= 0`) typically contains 20ms of 16-bit PCM audio /// using native endianness. This defaults to stereo audio at 48kHz, and can be configured via - /// [`Config::decode_channels`] and [`Config::decode_sample_rate`] -- channels are interleaved + /// [`DecodeConfig::sample_rate`] and [`DecodeConfig::sample_rate`] -- channels are interleaved /// (i.e., `L, R, L, R, ...`) if stereo. /// /// This value will be `None` if Songbird is not configured to decode audio. /// - /// [`Config::decode_channels`]: crate::Config::decode_channels - /// [`Config::decode_sample_rate`]: crate::Config::decode_sample_rate + /// [`DecodeConfig::decode_channels`]: crate::driver::DecodeConfig::channels + /// [`DecodeConfig::sample_rate`]: crate::driver::DecodeConfig::sample_rate pub decoded_voice: Option>, }