Remove unused parts of ts example
Signed-off-by: Aron Heinecke <aron.heinecke@t-online.de>
This commit is contained in:
parent
52e4a5306d
commit
3c0acf3ffe
3 changed files with 10 additions and 197 deletions
14
src/main.rs
14
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 serde::Deserialize;
|
||||||
use tsclientlib::{ClientId, Connection, DisconnectOptions, Identity, StreamItem};
|
use tsclientlib::{ClientId, Connection, DisconnectOptions, Identity, StreamItem};
|
||||||
use tsproto_packets::packets::{AudioData, CodecType, OutAudio, OutPacket};
|
use tsproto_packets::packets::{AudioData, CodecType, OutAudio, OutPacket};
|
||||||
use audiopus::coder::Encoder;
|
use audiopus::coder::Encoder;
|
||||||
use futures::{lock::Mutex, prelude::*};
|
use futures::{lock::Mutex, prelude::*};
|
||||||
use sdl2::audio::{AudioCallback, AudioDevice, AudioSpec, AudioSpecDesired, AudioStatus};
|
use slog::{debug, o, Drain, Logger};
|
||||||
use sdl2::AudioSubsystem;
|
use tokio::{task};
|
||||||
use slog::{debug, info, o, Drain, Logger};
|
|
||||||
use tokio::{sync::mpsc, task};
|
|
||||||
use tokio::task::LocalSet;
|
use tokio::task::LocalSet;
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use tsproto_packets::packets::{Direction, InAudioBuf};
|
|
||||||
use songbird::opus;
|
|
||||||
|
|
||||||
mod ts_voice;
|
mod ts_voice;
|
||||||
mod discord;
|
mod discord;
|
||||||
|
|
||||||
|
@ -68,7 +63,8 @@ impl TypeMapKey for ListenerHolder {
|
||||||
const TICK_TIME: u64 = 15;
|
const TICK_TIME: u64 = 15;
|
||||||
const FRAME_SIZE_MS: usize = 20;
|
const FRAME_SIZE_MS: usize = 20;
|
||||||
const STEREO_20MS: usize = 48000 * 2 * FRAME_SIZE_MS / 1000;
|
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]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
|
@ -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<Mutex<Option<mpsc::Sender<OutPacket>>>>,
|
|
||||||
device: AudioDevice<SdlCallback>,
|
|
||||||
|
|
||||||
is_playing: bool,
|
|
||||||
volume: Arc<Mutex<f32>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SdlCallback {
|
|
||||||
logger: Logger,
|
|
||||||
spec: AudioSpec,
|
|
||||||
encoder: Encoder,
|
|
||||||
listener: Arc<Mutex<Option<mpsc::Sender<OutPacket>>>>,
|
|
||||||
volume: Arc<Mutex<f32>>,
|
|
||||||
|
|
||||||
opus_output: [u8; MAX_OPUS_FRAME_SIZE],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AudioToTs {
|
|
||||||
pub fn new(
|
|
||||||
logger: Logger, audio_subsystem: AudioSubsystem, local_set: &LocalSet,
|
|
||||||
) -> Result<Arc<Mutex<Self>>> {
|
|
||||||
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<Mutex<Option<mpsc::Sender<OutPacket>>>>, volume: Arc<Mutex<f32>>,
|
|
||||||
) -> Result<AudioDevice<SdlCallback>> {
|
|
||||||
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<OutPacket>) {
|
|
||||||
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<Mutex<Self>>, 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,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,10 +4,10 @@ use anyhow::Result;
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
use tokio::task::LocalSet;
|
use tokio::task::LocalSet;
|
||||||
|
|
||||||
use audio_to_ts::AudioToTs;
|
|
||||||
use ts_to_audio::TsToAudio;
|
use ts_to_audio::TsToAudio;
|
||||||
|
|
||||||
pub mod audio_to_ts;
|
|
||||||
pub mod ts_to_audio;
|
pub mod ts_to_audio;
|
||||||
|
|
||||||
/// The usual frame size.
|
/// The usual frame size.
|
||||||
|
@ -16,12 +16,10 @@ pub mod ts_to_audio;
|
||||||
/// This means 1920 samples and 7.5 kiB.
|
/// This means 1920 samples and 7.5 kiB.
|
||||||
const USUAL_FRAME_SIZE: usize = 48000 / 50;
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct AudioData {
|
pub struct AudioData {
|
||||||
pub a2ts: Arc<Mutex<AudioToTs>>,
|
|
||||||
pub ts2a: Arc<Mutex<TsToAudio>>,
|
pub ts2a: Arc<Mutex<TsToAudio>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +33,7 @@ pub fn start(logger: Logger, local_set: &LocalSet) -> Result<AudioData> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let ts2a = TsToAudio::new(logger.clone(), audio_subsystem.clone(), local_set)?;
|
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 })
|
||||||
}
|
}
|
Loading…
Reference in a new issue