From 8e40611a8a444bb284ff354366b6dee4c00c83ea Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 29 Dec 2018 15:10:39 -0700 Subject: [PATCH] Implement most functions --- Cargo.toml | 2 + src/main.rs | 122 +++++++++++++++++++++++++++++++++++++++++++++++++- src/scheme.rs | 80 +++++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 src/scheme.rs diff --git a/Cargo.toml b/Cargo.toml index b372edf52c..08c44e7403 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,7 @@ name = "audiod" version = "0.1.0" authors = ["Jeremy Soller "] +edition = "2018" [dependencies] +redox_syscall = "0.1" diff --git a/src/main.rs b/src/main.rs index f328e4d9d0..456b0d9b89 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1 +1,121 @@ -fn main() {} +extern crate syscall; + +use std::{fs, io, mem, process, slice, thread}; +use std::io::{Read, Write}; +use std::sync::{Arc, Mutex}; +use syscall::data::{Packet, SigAction}; +use syscall::flag::{O_CLOEXEC, SIGUSR1}; +use syscall::scheme::SchemeBlockMut; + +use self::scheme::AudioScheme; + +mod scheme; + +fn from_syscall_error(error: syscall::Error) -> io::Error { + io::Error::from_raw_os_error(error.errno as i32) +} + +extern "C" fn sigusr_handler(_sig: usize) {} + +fn thread(scheme: Arc>, pid: usize, mut hda_file: fs::File) -> io::Result<()> { + loop { + let buffer = scheme.lock().unwrap().buffer(); + let buffer_u8 = unsafe { + slice::from_raw_parts( + buffer.as_ptr() as *const u8, + mem::size_of_val(&buffer) + ) + }; + + // Wake up the scheme thread + syscall::kill(pid, SIGUSR1).map_err(from_syscall_error)?; + + hda_file.write(&buffer_u8)?; + } +} + +fn daemon(pipe_fd: usize) -> io::Result<()> { + // Handle signals from the hda thread + syscall::sigaction(SIGUSR1, Some(&SigAction { + sa_handler: sigusr_handler, + sa_mask: [0; 2], + sa_flags: 0, + }), None).map_err(from_syscall_error)?; + + let pid = syscall::getpid().map_err(from_syscall_error)?; + + let hda_file = fs::OpenOptions::new().write(true).open("hda:")?; + + let mut scheme_file = fs::OpenOptions::new().create(true).read(true).write(true).open(":audio")?; + + // The scheme is now ready to accept requests, notify the original process + syscall::write(pipe_fd, &[1]).map_err(from_syscall_error)?; + let _ = syscall::close(pipe_fd); + + // Enter the null namespace + syscall::setrens(0, 0).map_err(from_syscall_error)?; + + let scheme = Arc::new(Mutex::new(AudioScheme::new())); + + // Spawn a thread to mix and send audio data + let scheme_thread = scheme.clone(); + let _thread = thread::spawn(move || thread(scheme_thread, pid, hda_file)); + + let mut todo = Vec::new(); + loop { + let mut packet = Packet::default(); + let count = match scheme_file.read(&mut packet) { + Ok(ok) => ok, + Err(err) => if err.kind() == io::ErrorKind::Interrupted { + 0 + } else { + return Err(err); + } + }; + + if count > 0 { + if let Some(a) = scheme.lock().unwrap().handle(&mut packet) { + packet.a = a; + scheme_file.write(&packet)?; + } else { + todo.push(packet); + } + } + + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.lock().unwrap().handle(&mut todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + scheme_file.write(&packet)?; + } else { + i += 1; + } + } + } +} + +fn audiod() -> io::Result<()> { + let mut pipe = [0; 2]; + syscall::pipe2(&mut pipe, O_CLOEXEC).map_err(from_syscall_error)?; + + // Daemonize + if unsafe { syscall::clone(0) }.map_err(from_syscall_error)? == 0 { + let _ = syscall::close(pipe[0]); + return daemon(pipe[1]); + } else { + let _ = syscall::close(pipe[1]); + + syscall::read(pipe[0], &mut [0]).map_err(from_syscall_error)?; + let _ = syscall::close(pipe[0]); + + Ok(()) + } +} + +fn main() { + if let Err(err) = audiod() { + eprintln!("audiod: {}", err); + process::exit(1); + } +} diff --git a/src/scheme.rs b/src/scheme.rs new file mode 100644 index 0000000000..9422c8e423 --- /dev/null +++ b/src/scheme.rs @@ -0,0 +1,80 @@ +use std::collections::{BTreeMap, VecDeque}; +use syscall::error::{EBADF, Error, Result}; +use syscall::scheme::SchemeBlockMut; + +// The strict buffer size of the hda: driver +const HDA_BUFFER_SIZE: usize = 512; +// The desired buffer size of each handle +const HANDLE_BUFFER_SIZE: usize = 4096; + +struct Handle { + flags: usize, + buffer: VecDeque<(u16, u16)>, +} + +pub struct AudioScheme { + next_id: usize, + handles: BTreeMap +} + +impl AudioScheme { + pub fn new() -> Self { + AudioScheme { + next_id: 0, + handles: BTreeMap::new() + } + } + + pub fn buffer(&mut self) -> [(u16, u16); HDA_BUFFER_SIZE] { + let mut buffer = [(0, 0); HDA_BUFFER_SIZE]; + + for (_id, handle) in self.handles.iter_mut() { + let mut i = 0; + while i < buffer.len() { + if let Some(sample) = handle.buffer.pop_front() { + buffer[i].0 += sample.0; + buffer[i].1 += sample.1; + } else { + break; + } + i += 1; + } + } + + buffer + } +} + +impl SchemeBlockMut for AudioScheme { + fn open(&mut self, _path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result> { + self.next_id += 1; + let id = self.next_id; + + self.handles.insert(id, Handle { + flags, + buffer: VecDeque::new() + }); + + Ok(Some(id)) + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + let mut handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + if handle.buffer.len() >= HANDLE_BUFFER_SIZE { + Ok(None) + } else { + let mut i = 0; + while i + 4 <= buf.len() { + handle.buffer.push_back(( + (buf[i] as u16) | ((buf[i + 1] as u16) << 8), + (buf[i + 2] as u16) | ((buf[i + 3] as u16) << 8) + )); + + i += 4; + } + + Ok(Some(i)) + } + } +}