diff --git a/src/main.rs b/src/main.rs index c8ac3ec..17c0f9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,13 @@ -use std::{collections::HashMap, env, sync::Arc, time::Duration}; +use std::{collections::HashMap, sync::Arc, time::Duration}; use serde::Deserialize; use tsclientlib::{ClientId, Connection, DisconnectOptions, Identity, StreamItem}; use tsproto_packets::packets::{AudioData, CodecType, OutAudio, OutPacket}; use audiopus::coder::Encoder; use futures::{lock::Mutex, prelude::*}; -use sdl2::audio::{AudioCallback, AudioDevice, AudioSpec, AudioSpecDesired, AudioStatus}; -use sdl2::AudioSubsystem; -use slog::{debug, info, o, Drain, Logger}; -use tokio::{sync::mpsc, task}; +use slog::{debug, o, Drain, Logger}; +use tokio::{task}; use tokio::task::LocalSet; use anyhow::*; -use tsproto_packets::packets::{Direction, InAudioBuf}; -use songbird::opus; - mod ts_voice; mod discord; @@ -68,7 +63,8 @@ impl TypeMapKey for ListenerHolder { const TICK_TIME: u64 = 15; const FRAME_SIZE_MS: usize = 20; const STEREO_20MS: usize = 48000 * 2 * FRAME_SIZE_MS / 1000; - +/// The maximum size of an opus frame is 1275 as from RFC6716. +const MAX_OPUS_FRAME_SIZE: usize = 1275; #[tokio::main] async fn main() -> Result<()> { tracing_subscriber::fmt::init(); diff --git a/src/ts_voice/audio_to_ts.rs b/src/ts_voice/audio_to_ts.rs deleted file mode 100644 index 66fe42d..0000000 --- a/src/ts_voice/audio_to_ts.rs +++ /dev/null @@ -1,181 +0,0 @@ -use std::sync::{Arc, Mutex}; - -use anyhow::{format_err, Result}; -use audiopus::coder::Encoder; -use futures::prelude::*; -use sdl2::audio::{AudioCallback, AudioDevice, AudioSpec, AudioSpecDesired, AudioStatus}; -use sdl2::AudioSubsystem; -use slog::{debug, error, o, Logger}; -use tokio::sync::mpsc; -use tokio::task::LocalSet; -use tokio::time::{self, Duration}; -use tokio_stream::wrappers::IntervalStream; -use tsproto_packets::packets::{AudioData, CodecType, OutAudio, OutPacket}; - -use super::*; - -pub struct AudioToTs { - logger: Logger, - audio_subsystem: AudioSubsystem, - listener: Arc>>>, - device: AudioDevice, - - is_playing: bool, - volume: Arc>, -} - -struct SdlCallback { - logger: Logger, - spec: AudioSpec, - encoder: Encoder, - listener: Arc>>>, - volume: Arc>, - - opus_output: [u8; MAX_OPUS_FRAME_SIZE], -} - -impl AudioToTs { - pub fn new( - logger: Logger, audio_subsystem: AudioSubsystem, local_set: &LocalSet, - ) -> Result>> { - let logger = logger.new(o!("pipeline" => "audio-to-ts")); - let listener = Arc::new(Mutex::new(Default::default())); - let volume = Arc::new(Mutex::new(1.0)); - - let device = - Self::open_capture(logger.clone(), &audio_subsystem, listener.clone(), volume.clone())?; - - let res = Arc::new(Mutex::new(Self { - logger, - audio_subsystem, - listener, - device, - - is_playing: false, - volume, - })); - - Self::start(res.clone(), local_set); - - Ok(res) - } - - fn open_capture( - logger: Logger, audio_subsystem: &AudioSubsystem, - listener: Arc>>>, volume: Arc>, - ) -> Result> { - let desired_spec = AudioSpecDesired { - freq: Some(48000), - channels: Some(1), - // Default sample size, 20 ms per packet - samples: Some(48000 / 50), - }; - - audio_subsystem.open_capture(None, &desired_spec, |spec| { - // This spec will always be the desired spec, the sdl wrapper passes - // zero as `allowed_changes`. - debug!(logger, "Got capture spec"; "spec" => ?spec, "driver" => audio_subsystem.current_audio_driver()); - let opus_channels = if spec.channels == 1 { - audiopus::Channels::Mono - } else { - audiopus::Channels::Stereo - }; - - let encoder = Encoder::new(audiopus::SampleRate::Hz48000, - opus_channels, audiopus::Application::Voip) - .expect("Could not create encoder"); - - SdlCallback { - logger, - spec, - encoder, - listener, - volume, - opus_output: [0; MAX_OPUS_FRAME_SIZE], - } - }).map_err(|e| format_err!("SDL error: {}", e)) - } - - pub fn set_listener(&self, sender: mpsc::Sender) { - let mut listener = self.listener.lock().unwrap(); - *listener = Some(sender); - } - - pub fn set_volume(&mut self, volume: f32) { *self.volume.lock().unwrap() = volume; } - - pub fn set_playing(&mut self, playing: bool) { - if playing { - self.device.resume(); - } else { - self.device.pause(); - } - self.is_playing = playing; - } - - fn start(a2t: Arc>, local_set: &LocalSet) { - local_set.spawn_local( - IntervalStream::new(time::interval(Duration::from_secs(1))).for_each(move |_| { - let mut a2t = a2t.lock().unwrap(); - if a2t.device.status() == AudioStatus::Stopped { - // Try to reconnect to audio - match Self::open_capture( - a2t.logger.clone(), - &a2t.audio_subsystem, - a2t.listener.clone(), - a2t.volume.clone(), - ) { - Ok(d) => { - a2t.device = d; - debug!(a2t.logger, "Reconnected to capture device"); - if a2t.is_playing { - a2t.device.resume(); - } - } - Err(e) => { - error!(a2t.logger, "Failed to open capture device"; "error" => %e); - } - }; - } - future::ready(()) - }), - ); - } -} - -impl AudioCallback for SdlCallback { - type Channel = f32; - fn callback(&mut self, buffer: &mut [Self::Channel]) { - // Handle volume - let volume = *self.volume.lock().unwrap(); - if volume != 1.0 { - for d in &mut *buffer { - *d *= volume; - } - } - - match self.encoder.encode_float(buffer, &mut self.opus_output[..]) { - Err(e) => { - error!(self.logger, "Failed to encode opus"; "error" => %e); - } - Ok(len) => { - // Create packet - let codec = if self.spec.channels == 1 { - CodecType::OpusVoice - } else { - CodecType::OpusMusic - }; - let packet = - OutAudio::new(&AudioData::C2S { id: 0, codec, data: &self.opus_output[..len] }); - - // Write into packet sink - let mut listener = self.listener.lock().unwrap(); - if let Some(lis) = &mut *listener { - match lis.try_send(packet) { - Err(mpsc::error::TrySendError::Closed(_)) => *listener = None, - _ => {} - } - } - } - } - } -} diff --git a/src/ts_voice/mod.rs b/src/ts_voice/mod.rs index 1885774..df28ae2 100644 --- a/src/ts_voice/mod.rs +++ b/src/ts_voice/mod.rs @@ -4,10 +4,10 @@ use anyhow::Result; use slog::Logger; use tokio::task::LocalSet; -use audio_to_ts::AudioToTs; + use ts_to_audio::TsToAudio; -pub mod audio_to_ts; + pub mod ts_to_audio; /// The usual frame size. @@ -16,12 +16,10 @@ pub mod ts_to_audio; /// This means 1920 samples and 7.5 kiB. const USUAL_FRAME_SIZE: usize = 48000 / 50; -/// The maximum size of an opus frame is 1275 as from RFC6716. -const MAX_OPUS_FRAME_SIZE: usize = 1275; + #[derive(Clone)] pub struct AudioData { - pub a2ts: Arc>, pub ts2a: Arc>, } @@ -35,7 +33,7 @@ pub fn start(logger: Logger, local_set: &LocalSet) -> Result { } let ts2a = TsToAudio::new(logger.clone(), audio_subsystem.clone(), local_set)?; - let a2ts = AudioToTs::new(logger.clone(), audio_subsystem, local_set)?; + - Ok(AudioData { a2ts, ts2a }) + Ok(AudioData { ts2a }) } \ No newline at end of file