From 54153914d22180777b25a1d4f5089ed2ae2839df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Wed, 13 Jan 2021 23:19:05 +0100 Subject: de-pub links on mumlib channels --- mumd/src/state/channel.rs | 13 +++++-------- mumlib/src/state.rs | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/mumd/src/state/channel.rs b/mumd/src/state/channel.rs index 6995e1e..2ed05c5 100644 --- a/mumd/src/state/channel.rs +++ b/mumd/src/state/channel.rs @@ -169,13 +169,10 @@ pub fn into_channel( impl From<&Channel> for mumlib::state::Channel { fn from(channel: &Channel) -> Self { - mumlib::state::Channel { - description: channel.description.clone(), - links: Vec::new(), - max_users: channel.max_users, - name: channel.name.clone(), - children: Vec::new(), - users: Vec::new(), - } + mumlib::state::Channel::new( + channel.name.clone(), + channel.description.clone(), + channel.max_users, + ) } } diff --git a/mumlib/src/state.rs b/mumlib/src/state.rs index 6fad332..772e822 100644 --- a/mumlib/src/state.rs +++ b/mumlib/src/state.rs @@ -12,14 +12,30 @@ pub struct Server { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Channel { pub description: Option, - pub links: Vec>, //to represent several walks through the tree to find channels its linked to pub max_users: u32, pub name: String, pub children: Vec, pub users: Vec, + + links: Vec>, //to represent several walks through the tree to find channels its linked to } impl Channel { + pub fn new( + name: String, + description: Option, + max_users: u32, + ) -> Self { + Self { + description, + max_users, + name, + children: Vec::new(), + users: Vec::new(), + + links: Vec::new(), + } + } pub fn iter(&self) -> Iter<'_> { Iter { me: Some(&self), -- cgit v1.2.1 From eee62e0892b1247ce321cd30747ab90d58f49732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Wed, 13 Jan 2021 23:19:22 +0100 Subject: document mumlib --- mumlib/src/command.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ mumlib/src/config.rs | 23 +++++++++++++++++++++++ mumlib/src/lib.rs | 2 ++ mumlib/src/state.rs | 7 +++++++ 4 files changed, 76 insertions(+) diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs index 8cb7cb9..642c8b9 100644 --- a/mumlib/src/command.rs +++ b/mumlib/src/command.rs @@ -1,3 +1,7 @@ +//! [Command]s can be sent from a controller to mumd who might respond with a +//! [CommandResponse]. The commands and their responses are serializable and +//! can be sent in any way you want. + use crate::state::{Channel, Server}; use chrono::NaiveDateTime; @@ -56,29 +60,51 @@ impl fmt::Display for MumbleEventKind { } } +/// Sent by a controller to mumd who might respond with a [CommandResponse]. Not +/// all commands receive a response. #[derive(Clone, Debug, Deserialize, Serialize)] pub enum Command { + /// No response. ChannelJoin { channel_identifier: String, }, + + /// Response: [CommandResponse::ChannelList]. ChannelList, + + /// Force reloading of config file from disk. No response. ConfigReload, + /// Response: [CommandResponse::DeafenStatus]. Toggles if None. DeafenSelf(Option), Events { block: bool }, + /// Set the outgoing audio volume (i.e. from you to the server). No response. InputVolumeSet(f32), + + /// Response: [CommandResponse::MuteStatus]. Toggles if None. MuteOther(String, Option), + + /// Response: [CommandResponse::MuteStatus]. Toggles if None. MuteSelf(Option), + + /// Set the master incoming audio volume (i.e. from the server to you). + /// No response. OutputVolumeSet(f32), + PastMessages { block: bool, }, + + /// Response: [CommandResponse::Pong]. Used to test existance of a + /// mumd-instance. Ping, + SendMessage { message: String, targets: MessageTarget, }, + /// Connect to the specified server. Response: [CommandResponse::ServerConnect]. ServerConnect { host: String, port: u16, @@ -86,43 +112,61 @@ pub enum Command { password: Option, accept_invalid_cert: bool, }, + + /// No response. ServerDisconnect, + + /// Send a server status request via UDP (e.g. not requiring a TCP connection). + /// Response: [CommandResponse::ServerStatus]. ServerStatus { host: String, port: u16, }, + + /// Response: [CommandResponse::Status]. Status, + + /// No response. UserVolumeSet(String, f32), } +/// A response to a sent [Command]. #[derive(Debug, Deserialize, Serialize)] pub enum CommandResponse { ChannelList { channels: Channel, }, + DeafenStatus { is_deafened: bool, }, + Event { event: MumbleEvent, }, + MuteStatus { is_muted: bool, }, + PastMessage { message: (NaiveDateTime, String, String), }, + Pong, + ServerConnect { welcome_message: Option, server_state: Server, }, + ServerStatus { version: u32, users: u32, max_users: u32, bandwidth: u32, }, + Status { server_state: Server, }, diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index 3edef37..b5bcdb1 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -23,6 +23,8 @@ struct TOMLConfig { servers: Option, } +/// Our representation of the mumdrc config file. +// Deserialized via [TOMLConfig]. #[derive(Clone, Debug, Default)] pub struct Config { pub audio: AudioConfig, @@ -34,6 +36,15 @@ pub struct Config { } impl Config { + /// Writes this config to the specified path. + /// + /// Pass create = true if you want the file to be created if it doesn't already exist. + /// + /// # Errors + /// + /// - [ConfigError::WontCreateFile] if the file doesn't exist and create = false was passed. + /// - Any [ConfigError::TOMLErrorSer] encountered when serializing the config. + /// - Any [ConfigError::IOError] encountered when writing the file. pub fn write(&self, path: &Path, create: bool) -> Result<(), ConfigError> { // Possible race here. It's fine since it shows when: // 1) the file doesn't exist when checked and is then created @@ -90,6 +101,10 @@ impl ServerConfig { } } +/// Finds the default path of the configuration file. +/// +/// The user config dir is looked for first (cross-platform friendly) and +/// `/etc/mumdrc` is used as a fallback. pub fn default_cfg_path() -> PathBuf { match dirs::config_dir() { Some(mut p) => { @@ -143,6 +158,14 @@ impl From for TOMLConfig { } } +/// Reads the config at the specified path. +/// +/// If the file isn't found, returns a default config. +/// +/// # Errors +/// +/// - Any [ConfigError::TOMLErrorDe] encountered when deserializing the config. +/// - Any [ConfigError::IOError] encountered when reading the file. pub fn read_cfg(path: &Path) -> Result { match fs::read_to_string(path) { Ok(s) => { diff --git a/mumlib/src/lib.rs b/mumlib/src/lib.rs index 9b7d686..4b302e3 100644 --- a/mumlib/src/lib.rs +++ b/mumlib/src/lib.rs @@ -9,6 +9,8 @@ use colored::*; use log::*; pub const SOCKET_PATH: &str = "/tmp/mumd"; + +/// The default mumble port. pub const DEFAULT_PORT: u16 = 64738; pub fn setup_logger>(target: T, color: bool) { diff --git a/mumlib/src/state.rs b/mumlib/src/state.rs index 772e822..182a8fc 100644 --- a/mumlib/src/state.rs +++ b/mumlib/src/state.rs @@ -36,6 +36,9 @@ impl Channel { links: Vec::new(), } } + + /// Create an iterator over this channel and its children in a pre-order + /// traversal. pub fn iter(&self) -> Iter<'_> { Iter { me: Some(&self), @@ -48,6 +51,8 @@ impl Channel { } } + /// Create an iterator over this channel and its childrens connected users + /// in a pre-order traversal. pub fn users_iter(&self) -> UsersIter<'_> { UsersIter { channels: self.children.iter().map(|e| e.users_iter()).collect(), @@ -62,6 +67,7 @@ impl Channel { } } +/// An iterator over channels. Created by [Channel::iter]. pub struct Iter<'a> { me: Option<&'a Channel>, channel: Option, @@ -92,6 +98,7 @@ impl<'a> Iterator for Iter<'a> { } } +/// An iterator over users. Created by [Channel::users_iter]. pub struct UsersIter<'a> { channel: Option, channels: Vec>, -- cgit v1.2.1 From 64978fa17b6e0882d6bacb6e626b0bc9ead2c81d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Thu, 8 Apr 2021 14:42:18 +0200 Subject: document mumd::audio --- mumd/src/audio.rs | 25 ++++++++++++++++++++++++- mumd/src/audio/input.rs | 12 ++++++++++++ mumd/src/audio/output.rs | 16 ++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs index 2e20583..46f7050 100644 --- a/mumd/src/audio.rs +++ b/mumd/src/audio.rs @@ -1,3 +1,7 @@ +//! All things audio. +//! +//! Audio is handled mostly as signals from [dasp_signal]. Input/output is handled by [cpal]. + pub mod input; pub mod output; pub mod transformers; @@ -27,8 +31,11 @@ use strum::IntoEnumIterator; use strum_macros::EnumIter; use tokio::sync::watch; +/// The sample rate used internally. const SAMPLE_RATE: u32 = 48000; +/// All types of notifications that can be shown. Each notification can be bound to its own audio +/// file. #[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, EnumIter)] pub enum NotificationEvents { ServerConnect, @@ -65,9 +72,11 @@ impl TryFrom<&str> for NotificationEvents { } } +/// Input audio state. pub struct AudioInput { device: DefaultAudioInputDevice, + /// Voice packets received from the network. channel_receiver: Arc> + Unpin>>>, } @@ -114,10 +123,15 @@ impl AudioInput { pub struct AudioOutput { device: DefaultAudioOutputDevice, + /// The volume and mute-status of a user ID. user_volumes: Arc>>, + /// The client stream per user ID. A separate stream is kept for UDP and TCP. + /// + /// Shared with [DefaultAudioOutputDevice]. client_streams: Arc>, + /// Which sound effect should be played on an event. sounds: HashMap>, } @@ -140,6 +154,7 @@ impl AudioOutput { Ok(res) } + /// Loads sound effects, getting unspecified effects from [get_default_sfx]. pub fn load_sound_effects(&mut self, sound_effects: &[SoundEffect]) { let overrides: HashMap<_, _> = sound_effects .iter() @@ -153,6 +168,7 @@ impl AudioOutput { }) .collect(); + // This makes sure that every [NotificationEvent] is present in [self.sounds]. self.sounds = NotificationEvents::iter() .map(|event| { let bytes = overrides @@ -195,6 +211,7 @@ impl AudioOutput { .collect(); } + /// Decodes a voice packet. pub fn decode_packet_payload( &self, stream_type: VoiceStreamType, @@ -207,11 +224,13 @@ impl AudioOutput { .decode_packet((stream_type, session_id), payload); } + /// Sets the volume of the output device. pub fn set_volume(&self, output_volume: f32) { self.device.set_volume(output_volume); } - pub fn set_user_volume(&self, id: u32, volume: f32) { + /// Sets the incoming volume of a user. + pub(crate) fn set_user_volume(&self, id: u32, volume: f32) { match self.user_volumes.lock().unwrap().entry(id) { Entry::Occupied(mut entry) => { entry.get_mut().0 = volume; @@ -222,6 +241,7 @@ impl AudioOutput { } } + /// Mutes another user. pub fn set_mute(&self, id: u32, mute: bool) { match self.user_volumes.lock().unwrap().entry(id) { Entry::Occupied(mut entry) => { @@ -233,12 +253,14 @@ impl AudioOutput { } } + /// Queues a sound effect. pub fn play_effect(&self, effect: NotificationEvents) { let samples = self.sounds.get(&effect).unwrap(); self.client_streams.lock().unwrap().extend(None, samples); } } +/// Reads a sound effect from disk. // moo fn get_sfx(file: &str) -> Cow<'static, [u8]> { let mut buf: Vec = Vec::new(); @@ -251,6 +273,7 @@ fn get_sfx(file: &str) -> Cow<'static, [u8]> { } } +/// Gets the default sound effect. fn get_default_sfx() -> Cow<'static, [u8]> { Cow::from(include_bytes!("fallback_sfx.wav").as_ref()) } diff --git a/mumd/src/audio/input.rs b/mumd/src/audio/input.rs index a1227e3..10aea91 100644 --- a/mumd/src/audio/input.rs +++ b/mumd/src/audio/input.rs @@ -1,3 +1,4 @@ +//! Listens to the microphone and sends it to the networking. use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use cpal::{InputCallbackInfo, Sample, SampleFormat, SampleRate, StreamConfig}; use log::*; @@ -8,6 +9,7 @@ use crate::audio::transformers::{NoiseGate, Transformer}; use crate::error::{AudioError, AudioStream}; use crate::state::StatePhase; +/// Generates a callback that receives [Sample]s and sends them as floats to a [futures_channel::mpsc::Sender]. pub fn callback( mut input_sender: futures_channel::mpsc::Sender>, mut transformers: Vec>, @@ -44,10 +46,15 @@ pub fn callback( } pub trait AudioInputDevice { + /// Starts the device. fn play(&self) -> Result<(), AudioError>; + /// Stops the device. fn pause(&self) -> Result<(), AudioError>; + /// Sets the input volume of the device. fn set_volume(&self, volume: f32); + /// Returns a receiver to this device's values. fn sample_receiver(&mut self) -> Option>>; + /// The amount of channels this device has. fn num_channels(&self) -> usize; } @@ -59,6 +66,7 @@ pub struct DefaultAudioInputDevice { } impl DefaultAudioInputDevice { + /// Initializes the default audio input. pub fn new( input_volume: f32, phase_watcher: watch::Receiver, @@ -162,17 +170,21 @@ impl AudioInputDevice for DefaultAudioInputDevice { .play() .map_err(|e| AudioError::InputPlayError(e)) } + fn pause(&self) -> Result<(), AudioError> { self.stream .pause() .map_err(|e| AudioError::InputPauseError(e)) } + fn set_volume(&self, volume: f32) { self.volume_sender.send(volume).unwrap(); } + fn sample_receiver(&mut self) -> Option>> { self.sample_receiver.take() } + fn num_channels(&self) -> usize { self.channels as usize } diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs index a2f6bcc..3d886d6 100644 --- a/mumd/src/audio/output.rs +++ b/mumd/src/audio/output.rs @@ -1,3 +1,4 @@ +//! Receives audio packets from the networking and plays them. use crate::audio::SAMPLE_RATE; use crate::error::{AudioError, AudioStream}; use crate::network::VoiceStreamType; @@ -13,6 +14,7 @@ use tokio::sync::watch; type ClientStreamKey = (VoiceStreamType, u32); +/// Collected state for client opus decoders and sound effects. pub struct ClientStream { buffer_clients: HashMap, opus::Decoder)>, //TODO ring buffer? buffer_effects: VecDeque, @@ -44,6 +46,7 @@ impl ClientStream { }) } + /// Decodes a voice packet. pub fn decode_packet(&mut self, client: ClientStreamKey, payload: VoicePacketPayload) { match payload { VoicePacketPayload::Opus(bytes, _eot) => { @@ -61,6 +64,7 @@ impl ClientStream { } } + /// Extends either a decoder queue or the buffer effect queue with some received values. pub fn extend(&mut self, client: Option, values: &[f32]) { let buffer = match client { Some(x) => &mut self.get_client(x).0, @@ -70,6 +74,12 @@ impl ClientStream { } } +/// Adds two values in some saturating way. +/// +/// Since we support [f32], [i16] and [u16] we need some way of adding two values +/// without peaking above/below the edge values. This trait ensures that we can +/// use all three primitive types as a generic parameter. + pub trait SaturatingAdd { fn saturating_add(self, rhs: Self) -> Self; } @@ -107,11 +117,16 @@ pub trait AudioOutputDevice { pub struct DefaultAudioOutputDevice { config: StreamConfig, stream: cpal::Stream, + /// The client stream per user ID. A separate stream is kept for UDP and TCP. + /// + /// Shared with [super::AudioOutput]. client_streams: Arc>, + /// Output volume configuration. volume_sender: watch::Sender, } impl DefaultAudioOutputDevice { + /// Initializes the default audio output. pub fn new( output_volume: f32, user_volumes: Arc>>, @@ -211,6 +226,7 @@ impl AudioOutputDevice for DefaultAudioOutputDevice { } } +/// Over-engineered way of handling multiple types of samples. pub fn curry_callback( user_bufs: Arc>, output_volume_receiver: watch::Receiver, -- cgit v1.2.1 From ed4b641f6d4816325aa07e0f13b6132c1c4dafa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 12:50:01 +0200 Subject: more mumlib doc just because --- mumlib/src/command.rs | 8 ++++++++ mumlib/src/config.rs | 33 ++++++++++++++++++++++++++------- mumlib/src/lib.rs | 8 ++++++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs index 642c8b9..3c56130 100644 --- a/mumlib/src/command.rs +++ b/mumlib/src/command.rs @@ -11,7 +11,9 @@ use std::fmt; /// Something that happened in our channel at a point in time. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MumbleEvent { + /// When the event occured. pub timestamp: NaiveDateTime, + /// What occured. pub kind: MumbleEventKind } @@ -24,11 +26,17 @@ impl fmt::Display for MumbleEvent { /// The different kinds of events that can happen. #[derive(Debug, Clone, Serialize, Deserialize)] pub enum MumbleEventKind { + /// A user connected to the server and joined our channel. Contains `(user, channel)`. UserConnected(String, String), + /// A user disconnected from the server while in our channel. Contains `(user, channel)`. UserDisconnected(String, String), + /// A user {un,}{muted,deafened}. Contains a rendered message with what changed and the user. UserMuteStateChanged(String), // This logic is kinda weird so we only store the rendered message. + /// A text message was received. Contains who sent the message. TextMessageReceived(String), + /// A user switched to our channel from some other channel. Contains `(user, previous-channel)`. UserJoinedChannel(String, String), + /// A user switched from our channel to some other channel. Contains `(user, new-channel)`. UserLeftChannel(String, String), } diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index b5bcdb1..932e013 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -1,3 +1,5 @@ +//! Representations of the mumdrc configuration file. + use crate::error::ConfigError; use crate::DEFAULT_PORT; @@ -27,7 +29,9 @@ struct TOMLConfig { // Deserialized via [TOMLConfig]. #[derive(Clone, Debug, Default)] pub struct Config { + /// General audio configuration. pub audio: AudioConfig, + /// Saved servers. pub servers: Vec, /// Whether we allow connecting to servers with invalid server certificates. /// @@ -66,38 +70,53 @@ impl Config { } } +/// Overwrite a specific sound effect with a file that should be played instead. #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct SoundEffect { + /// During which event the effect should be played. pub event: String, + /// The file that should be played. pub file: String, } +/// General audio configuration. #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct AudioConfig { + /// The microphone input sensitivity. pub input_volume: Option, + /// The output main gain. pub output_volume: Option, + /// Overriden sound effects. pub sound_effects: Option>, } +/// A saved server. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ServerConfig { + /// The alias of the server. pub name: String, + /// The host (URL or IP-adress) of the server. pub host: String, + /// The port, if non-default. pub port: Option, + /// The username to connect with. Prompted on connection if omitted. pub username: Option, + /// The password to connect with. Nothing is sent to the server if omitted. pub password: Option, + /// Whether to accept invalid server certifications for this server. pub accept_invalid_cert: Option, } impl ServerConfig { + /// Creates a [SocketAddr] for this server. + /// + /// Returns `None` if no resolution could be made. See + /// [std::net::ToSocketAddrs] for more information. pub fn to_socket_addr(&self) -> Option { - match (self.host.as_str(), self.port.unwrap_or(DEFAULT_PORT)) - .to_socket_addrs() - .map(|mut e| e.next()) - { - Ok(Some(addr)) => Some(addr), - _ => None, - } + Some((self.host.as_str(), self.port.unwrap_or(DEFAULT_PORT)) + .to_socket_addrs() + .ok()? + .next()?) } } diff --git a/mumlib/src/lib.rs b/mumlib/src/lib.rs index 4b302e3..679db8d 100644 --- a/mumlib/src/lib.rs +++ b/mumlib/src/lib.rs @@ -1,3 +1,7 @@ +//! Shared items for crates that want to communicate with mumd and/or mumctl. + +// #![warn(missing_docs)] + pub mod command; pub mod config; pub mod error; @@ -8,11 +12,15 @@ pub use error::Error; use colored::*; use log::*; +/// The default file path to use for the socket. pub const SOCKET_PATH: &str = "/tmp/mumd"; /// The default mumble port. pub const DEFAULT_PORT: u16 = 64738; +/// Setup a minimal fern logger. +/// +/// Format: `LEVEL [yyyy-mm-dd][HH:MM:SS] FILE:LINE MESSAGE` pub fn setup_logger>(target: T, color: bool) { fern::Dispatch::new() .format(move |out, message, record| { -- cgit v1.2.1 From 0f94d30e5ab7945582e1fc7124bbe50c42f37a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 12:51:46 +0200 Subject: incoming -> outgoing packets --- mumd/src/audio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs index 46f7050..b3c809d 100644 --- a/mumd/src/audio.rs +++ b/mumd/src/audio.rs @@ -76,7 +76,7 @@ impl TryFrom<&str> for NotificationEvents { pub struct AudioInput { device: DefaultAudioInputDevice, - /// Voice packets received from the network. + /// Outgoing voice packets that should be sent over the network. channel_receiver: Arc> + Unpin>>>, } -- cgit v1.2.1 From 9350dd303bbfc1534f61f996bd4206b1e10e5f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 12:52:48 +0200 Subject: more audioinput --- mumd/src/audio.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs index b3c809d..f52389a 100644 --- a/mumd/src/audio.rs +++ b/mumd/src/audio.rs @@ -72,7 +72,8 @@ impl TryFrom<&str> for NotificationEvents { } } -/// Input audio state. +/// Input audio state. Input audio is picket up from an [AudioInputDevice] (e.g. +/// a microphone) and sent over the network. pub struct AudioInput { device: DefaultAudioInputDevice, -- cgit v1.2.1 From bbaf2c576b324cf2f519220930d5c99b0496023e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 12:54:19 +0200 Subject: audioouput doc --- mumd/src/audio.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs index f52389a..6c20d08 100644 --- a/mumd/src/audio.rs +++ b/mumd/src/audio.rs @@ -122,6 +122,9 @@ impl AudioInput { } } +/// Audio output state. The audio is received from each client over the network, +/// decoded, merged and finally played to an [AudioOutputDevice] (e.g. speaker, +/// headphones, ...). pub struct AudioOutput { device: DefaultAudioOutputDevice, /// The volume and mute-status of a user ID. -- cgit v1.2.1 From 988ac16195e24c71ba17c4103448addb299c58bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 12:54:52 +0200 Subject: ~~pub(crate)~~ --- mumd/src/audio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs index 6c20d08..78e10b9 100644 --- a/mumd/src/audio.rs +++ b/mumd/src/audio.rs @@ -234,7 +234,7 @@ impl AudioOutput { } /// Sets the incoming volume of a user. - pub(crate) fn set_user_volume(&self, id: u32, volume: f32) { + pub fn set_user_volume(&self, id: u32, volume: f32) { match self.user_volumes.lock().unwrap().entry(id) { Entry::Occupied(mut entry) => { entry.get_mut().0 = volume; -- cgit v1.2.1 From bc270b506270a17fe830cc1a41426708fedcbdb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 13:21:37 +0200 Subject: doc trait audioinputdevice --- mumd/src/audio/input.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mumd/src/audio/input.rs b/mumd/src/audio/input.rs index 10aea91..5721996 100644 --- a/mumd/src/audio/input.rs +++ b/mumd/src/audio/input.rs @@ -45,6 +45,9 @@ pub fn callback( } } +/// Something that can listen to audio and send it somewhere. +/// +/// One sample is assumed to be an encoded opus frame. See [opus::Encoder]. pub trait AudioInputDevice { /// Starts the device. fn play(&self) -> Result<(), AudioError>; -- cgit v1.2.1 From b97645143c70b8c69d659e46e5d0cfce97220b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 13:25:16 +0200 Subject: saturating add method doc --- mumd/src/audio/output.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs index 3d886d6..3c00116 100644 --- a/mumd/src/audio/output.rs +++ b/mumd/src/audio/output.rs @@ -1,4 +1,5 @@ //! Receives audio packets from the networking and plays them. + use crate::audio::SAMPLE_RATE; use crate::error::{AudioError, AudioStream}; use crate::network::VoiceStreamType; @@ -79,8 +80,8 @@ impl ClientStream { /// Since we support [f32], [i16] and [u16] we need some way of adding two values /// without peaking above/below the edge values. This trait ensures that we can /// use all three primitive types as a generic parameter. - pub trait SaturatingAdd { + /// Adds two values in some saturating way. See trait documentation. fn saturating_add(self, rhs: Self) -> Self; } -- cgit v1.2.1 From 17feef9da27aa7740c1b553a8ac331d10a1a391c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 13:26:08 +0200 Subject: default audio ouput device --- mumd/src/audio/output.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs index 3c00116..597dcf0 100644 --- a/mumd/src/audio/output.rs +++ b/mumd/src/audio/output.rs @@ -115,6 +115,7 @@ pub trait AudioOutputDevice { fn client_streams(&self) -> Arc>; } +/// The default audio output device, as determined by [cpal]. pub struct DefaultAudioOutputDevice { config: StreamConfig, stream: cpal::Stream, -- cgit v1.2.1 From 1aec4a2385cc134ffd189e122f8b77c975e3dcb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 13:29:58 +0200 Subject: better curry callback --- mumd/src/audio/output.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs index 597dcf0..a3ce064 100644 --- a/mumd/src/audio/output.rs +++ b/mumd/src/audio/output.rs @@ -228,7 +228,8 @@ impl AudioOutputDevice for DefaultAudioOutputDevice { } } -/// Over-engineered way of handling multiple types of samples. +/// Returns a function that fills a buffer with audio from client streams +/// modified according to some audio configuration. pub fn curry_callback( user_bufs: Arc>, output_volume_receiver: watch::Receiver, -- cgit v1.2.1 From f03d0d1d8def80c905a59c2bba9722d21a95ffae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 13:30:45 +0200 Subject: remove cruft --- mumlib/src/command.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs index 3c56130..79343cf 100644 --- a/mumlib/src/command.rs +++ b/mumlib/src/command.rs @@ -1,6 +1,5 @@ -//! [Command]s can be sent from a controller to mumd who might respond with a -//! [CommandResponse]. The commands and their responses are serializable and -//! can be sent in any way you want. +//! [Command]s can be sent from a controller to mumd which might respond with a +//! [CommandResponse]. use crate::state::{Channel, Server}; -- cgit v1.2.1 From 14ecdfe2365682e37df99569747b96943ec55426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 13:41:45 +0200 Subject: doc mumlib state --- mumlib/src/command.rs | 21 ++++++++++++++++----- mumlib/src/state.rs | 12 ++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs index 79343cf..9d98a38 100644 --- a/mumlib/src/command.rs +++ b/mumlib/src/command.rs @@ -89,16 +89,18 @@ pub enum Command { /// Set the outgoing audio volume (i.e. from you to the server). No response. InputVolumeSet(f32), - /// Response: [CommandResponse::MuteStatus]. Toggles if None. + /// Response: [CommandResponse::MuteStatus]. Toggles mute state if None. MuteOther(String, Option), - /// Response: [CommandResponse::MuteStatus]. Toggles if None. + /// Response: [CommandResponse::MuteStatus]. Toggles mute state if None. MuteSelf(Option), /// Set the master incoming audio volume (i.e. from the server to you). /// No response. OutputVolumeSet(f32), + /// Request a list of past messages. Blocks while waiting for more messages + /// if block is true. Response: multiple [CommandResponse::PastMessage]. PastMessages { block: bool, }, @@ -107,20 +109,29 @@ pub enum Command { /// mumd-instance. Ping, + /// Send a message to some [MessageTarget]. SendMessage { + /// The message to send. message: String, + /// The target(s) to send the message to. targets: MessageTarget, }, + /// Connect to the specified server. Response: [CommandResponse::ServerConnect]. ServerConnect { + /// The URL or IP-adress to connect to. host: String, + /// The port to connect to. port: u16, + /// The username to connect with. username: String, + /// The server password, if applicable. Not sent if None. password: Option, + /// Whether to accept an invalid server certificate or not. accept_invalid_cert: bool, }, - /// No response. + /// Disconnect from the currently connected server. No response. ServerDisconnect, /// Send a server status request via UDP (e.g. not requiring a TCP connection). @@ -130,10 +141,10 @@ pub enum Command { port: u16, }, - /// Response: [CommandResponse::Status]. + /// Request the status of the current server. Response: [CommandResponse::Status]. Status, - /// No response. + /// The the volume of the specified user. No response. UserVolumeSet(String, f32), } diff --git a/mumlib/src/state.rs b/mumlib/src/state.rs index 182a8fc..a5262e0 100644 --- a/mumlib/src/state.rs +++ b/mumlib/src/state.rs @@ -1,26 +1,38 @@ use serde::{Deserialize, Serialize}; use std::fmt; +/// The state of the currently connected Mumble server. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Server { + /// State of the currently connected channel. pub channels: Channel, + /// The welcome text we received when we connected. pub welcome_text: Option, + /// Our username. pub username: String, + /// The host (ip:port) of the server. pub host: String, } +/// A representation of a channel in a Mumble server. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Channel { + /// The description of the channel, if set. pub description: Option, + /// The maximum number of allowed users in this channel. pub max_users: u32, + /// The name of this channel. pub name: String, + /// Any children this channel has. pub children: Vec, + /// This channel's connected users. pub users: Vec, links: Vec>, //to represent several walks through the tree to find channels its linked to } impl Channel { + /// Create a new Channel representation. pub fn new( name: String, description: Option, -- cgit v1.2.1 From c774aadf26b7ecc08a548ed5d781ea3fc5eac1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Tue, 15 Jun 2021 13:48:24 +0200 Subject: expand on pre order traversal --- mumlib/src/state.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mumlib/src/state.rs b/mumlib/src/state.rs index a5262e0..72c01a6 100644 --- a/mumlib/src/state.rs +++ b/mumlib/src/state.rs @@ -49,8 +49,10 @@ impl Channel { } } - /// Create an iterator over this channel and its children in a pre-order - /// traversal. + /// Create an iterator over this channel and its children in a [pre-order + /// traversal](https://en.wikipedia.org/wiki/Tree_traversal#Pre-order,_NLR) + /// which ensures that parent channels are returned before any of its + /// children. pub fn iter(&self) -> Iter<'_> { Iter { me: Some(&self), -- cgit v1.2.1 From 5e8a2bca472612526b0b340ab294d2a4a78f698a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sat, 19 Jun 2021 17:23:47 +0200 Subject: add known issues --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 93ae6f2..73750bc 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,12 @@ ServerRoot $ mumctl channel connect Channel2 ``` +## Known issues + +- Administration tools are not present. +- Surround output. If this is something you want, open an issue so we can take a + look at implementing it. + ## Why? Mostly because it's a fun way of learning a new language. Also: -- cgit v1.2.1 From fce1283edf5751481984f51a2abc66da0cf287fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sat, 19 Jun 2021 17:38:31 +0200 Subject: update known issues with links --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 73750bc..ea71b0e 100644 --- a/README.md +++ b/README.md @@ -118,9 +118,15 @@ $ mumctl channel connect Channel2 ## Known issues -- Administration tools are not present. -- Surround output. If this is something you want, open an issue so we can take a - look at implementing it. +The main hub for issues is [our issue +tracker](https://github.com/mum-rs/mum/issues). Additionally, there are some +things that aren't present on the issue tracker: + +- Administration tools are not present. See [the admin tools + project](https://github.com/mum-rs/mum/projects/1). +- Surround output. If this is something you want, [open an + issue](https://github.com/mum-rs/mum/issues/new) so we can take a look at + implementing it. ## Why? -- cgit v1.2.1 From d7a1738dc2c9f71788540baed6fb86276b44e840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sat, 19 Jun 2021 17:40:15 +0200 Subject: remove double "present" --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ea71b0e..e8a4946 100644 --- a/README.md +++ b/README.md @@ -120,9 +120,9 @@ $ mumctl channel connect Channel2 The main hub for issues is [our issue tracker](https://github.com/mum-rs/mum/issues). Additionally, there are some -things that aren't present on the issue tracker: +features that aren't present on the issue tracker: -- Administration tools are not present. See [the admin tools +- Administration tools. See [the admin tools project](https://github.com/mum-rs/mum/projects/1). - Surround output. If this is something you want, [open an issue](https://github.com/mum-rs/mum/issues/new) so we can take a look at -- cgit v1.2.1 From 37f1089cb5f2468c0659f7d83c7530b35eedeaec Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Sat, 19 Jun 2021 17:48:21 +0200 Subject: fix compiler warning --- mumd/src/audio/output.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs index 2015435..cdb7b8e 100644 --- a/mumd/src/audio/output.rs +++ b/mumd/src/audio/output.rs @@ -180,14 +180,6 @@ impl DefaultAudioOutputDevice { let err_fn = |err| error!("An error occurred on the output audio stream: {}", err); let (output_volume_sender, output_volume_receiver) = watch::channel::(output_volume); - let output_channels = match output_config.channels { - 1 => opus::Channels::Mono, - 2 => opus::Channels::Stereo, - _ => { - warn!("Trying to output to an unsupported number of channels ({}), defaulting to mono", output_config.channels); - opus::Channels::Mono - } - }; let output_stream = match output_supported_sample_format { SampleFormat::F32 => output_device.build_output_stream( @@ -196,7 +188,6 @@ impl DefaultAudioOutputDevice { Arc::clone(&client_streams), output_volume_receiver, user_volumes, - output_channels, ), err_fn, ), @@ -206,7 +197,6 @@ impl DefaultAudioOutputDevice { Arc::clone(&client_streams), output_volume_receiver, user_volumes, - output_channels, ), err_fn, ), @@ -216,7 +206,6 @@ impl DefaultAudioOutputDevice { Arc::clone(&client_streams), output_volume_receiver, user_volumes, - output_channels, ), err_fn, ), @@ -262,7 +251,6 @@ pub fn callback( user_bufs: Arc>, output_volume_receiver: watch::Receiver, user_volumes: Arc>>, - output_channels: opus::Channels, ) -> impl FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static { move |data: &mut [T], _info: &OutputCallbackInfo| { for sample in data.iter_mut() { -- cgit v1.2.1