Skip to content

Commit

Permalink
Send audio as f32 and set bitrate to 512000.
Browse files Browse the repository at this point in the history
  • Loading branch information
hgaiser committed Dec 9, 2024
1 parent 7ceefaf commit 83ab9c2
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 19 deletions.
37 changes: 23 additions & 14 deletions src/session/stream/audio/capture/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,11 @@ pub struct AudioCapture {
}

impl AudioCapture {
pub async fn new(audio_tx: Sender<Vec<i16>>) -> Result<Self, ()> {
pub async fn new(audio_tx: Sender<Vec<f32>>) -> Result<Self, ()> {
// TODO: Make configurable.
let channels = 2u8;
let sample_rate = 48000u32;
let sample_time_ms = 5;

let default_sink_name = match get_default_sink_name() {
Ok(name) => name,
Expand All @@ -107,7 +109,7 @@ impl AudioCapture {
let monitor_name = format!("{default_sink_name}.monitor");

let sample_spec = Spec {
format: pulse::sample::Format::S16le,
format: pulse::sample::Format::F32le,
channels,
rate: sample_rate,
};
Expand All @@ -122,11 +124,11 @@ impl AudioCapture {
&sample_spec, // Sample specification.
None, // Use default channel map.
Some(&BufferAttr {
maxlength: std::mem::size_of::<i16>() as u32 * sample_rate * channels as u32 * 5 / 1000,
tlength: std::u32::MAX,
prebuf: std::u32::MAX,
minreq: std::u32::MAX,
fragsize: std::u32::MAX,
maxlength: u32::MAX,
tlength: u32::MAX,
prebuf: u32::MAX,
minreq: u32::MAX,
fragsize: std::mem::size_of::<f32>() as u32 * sample_rate * channels as u32 * sample_time_ms / 1000,
}),
).map_err(|e| tracing::error!("Failed to create audio capture device: {e}"));

Expand Down Expand Up @@ -159,25 +161,32 @@ impl AudioCapture {

struct AudioCaptureInner {
/// Channel to communicate audio fragments over.
audio_tx: Sender<Vec<i16>>,
audio_tx: Sender<Vec<f32>>,
}

impl AudioCaptureInner {
fn run(self, stream: pulse_simple::Simple) -> Result<(), ()> {
// TODO: Make configurable.
const SAMPLE_RATE: usize = 48000;
const SAMPLE_TIME_MS: usize = 5;
const FRAME_SIZE: usize = std::mem::size_of::<f32>() * SAMPLE_RATE * SAMPLE_TIME_MS / 1000;

// Start recording.
loop {
// Allocate uninitialized buffer for recording.
let buffer: Vec<MaybeUninit<u8>> = vec![MaybeUninit::uninit(); 480];
let mut buffer = unsafe { std::mem::transmute::<_, Vec<u8>>(buffer) };
let buffer: Vec<MaybeUninit<u8>> = vec![MaybeUninit::uninit(); FRAME_SIZE];
let mut buffer = unsafe {
std::mem::transmute::<std::vec::Vec<std::mem::MaybeUninit<u8>>, std::vec::Vec<u8>>(buffer)
};

match stream.read(&mut buffer) {
Ok(()) => {
// Convert Vec<u8> to Vec<i16>.
// Convert Vec<u8> to Vec<f32>.
let samples = unsafe {
Vec::from_raw_parts(
buffer.as_ptr() as *mut i16,
buffer.len() / std::mem::size_of::<i16>(),
buffer.len() / std::mem::size_of::<i16>(),
buffer.as_ptr() as *mut f32,
buffer.len() / std::mem::size_of::<f32>(),
buffer.len() / std::mem::size_of::<f32>(),
)
};

Expand Down
15 changes: 11 additions & 4 deletions src/session/stream/audio/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ impl AudioEncoder {
pub fn new(
sample_rate: u32,
channels: u8,
audio_rx: mpsc::Receiver<Vec<i16>>,
audio_rx: mpsc::Receiver<Vec<f32>>,
keys: SessionKeys,
packet_tx: mpsc::Sender<Vec<u8>>
) -> Result<Self, ()> {
// TODO: Make this configurable.
let audio_bitrate = 512000;

tracing::debug!("Creating audio encoder with sample rate {} and {} channels.", sample_rate, channels);
let mut encoder = opus::Encoder::new(
sample_rate,
Expand All @@ -41,6 +44,8 @@ impl AudioEncoder {
// Moonlight expects a constant bitrate.
encoder.set_vbr(false)
.map_err(|e| tracing::error!("Failed to disable variable bitrate: {e}"))?;
encoder.set_bitrate(opus::Bitrate::Bits(audio_bitrate))
.map_err(|e| tracing::error!("Failed to set audio bitrate: {e}"))?;

let (command_tx, command_rx) = mpsc::channel(10);
let inner = AudioEncoderInner { };
Expand All @@ -65,7 +70,7 @@ impl AudioEncoderInner {
fn run(
self,
mut command_rx: mpsc::Receiver<AudioEncoderCommand>,
mut audio_rx: mpsc::Receiver<Vec<i16>>,
mut audio_rx: mpsc::Receiver<Vec<f32>>,
mut encoder: opus::Encoder,
mut keys: SessionKeys,
packet_tx: mpsc::Sender<Vec<u8>>,
Expand Down Expand Up @@ -98,7 +103,7 @@ impl AudioEncoderInner {

// A buffer for an audio sample after it has been encoded.
// TODO: Decide the correct size for this buffer.
let mut encoded_audio = vec![0u8; 1024];
let mut encoded_audio = vec![0u8; 1400];

loop {
// Check if there's a command.
Expand All @@ -124,8 +129,9 @@ impl AudioEncoderInner {
break;
};

// TODO: Figure out the 1000 / 90 value.
let timestamp = ((std::time::Instant::now() - stream_start_time).as_micros() / (1000 / 90)) as u32;
let encoded_size = match encoder.encode(&audio_fragment, &mut encoded_audio) {
let encoded_size = match encoder.encode_float(&audio_fragment, &mut encoded_audio) {
Ok(encoded_size) => encoded_size,
Err(e) => {
tracing::warn!("Failed to encode audio: {e}");
Expand All @@ -134,6 +140,7 @@ impl AudioEncoderInner {
}
};


// Encrypt the audio data.
// TODO: Check if we should, some clients (ie. Steam Link) don't support this.
let iv = keys.remote_input_key_id as u32 + sequence_number as u32;
Expand Down
2 changes: 1 addition & 1 deletion src/session/stream/video/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ impl Encoder {
encoder.set_time_base((framerate as i32, 1));
encoder.set_max_b_frames(0);
encoder.set_bit_rate(bitrate);
encoder.set_gop(i32::max_value() as u32);
encoder.set_gop(i32::MAX as u32);
unsafe {
(*encoder.as_mut_ptr()).pix_fmt = Pixel::CUDA.into();
(*encoder.as_mut_ptr()).hw_frames_ctx = hw_frame_context.as_raw_mut();
Expand Down

0 comments on commit 83ab9c2

Please sign in to comment.