Implement most functions

This commit is contained in:
Jeremy Soller
2018-12-29 15:10:39 -07:00
parent c02d06c5da
commit 8e40611a8a
3 changed files with 203 additions and 1 deletions
+2
View File
@@ -2,5 +2,7 @@
name = "audiod"
version = "0.1.0"
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
edition = "2018"
[dependencies]
redox_syscall = "0.1"
+121 -1
View File
@@ -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<Mutex<AudioScheme>>, 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);
}
}
+80
View File
@@ -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<usize, Handle>
}
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<Option<usize>> {
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<Option<usize>> {
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))
}
}
}