Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • redox-os/audiod
  • 4lDO2/audiod
  • bjorn3/audiod
3 results
Show changes
Commits on Source (7)
......@@ -6,6 +6,7 @@ version = 3
name = "audiod"
version = "0.1.0"
dependencies = [
"redox-daemon",
"redox_syscall",
]
......@@ -15,11 +16,27 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "libc"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "redox-daemon"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e31c834277709c7ff3eb74959fe62be4b45b1189ba9d41fd3744cd3a9c554f"
dependencies = [
"libc",
"redox_syscall",
]
[[package]]
name = "redox_syscall"
version = "0.2.12"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
......@@ -5,4 +5,5 @@ authors = ["Jeremy Soller <jackpot51@gmail.com>"]
edition = "2018"
[dependencies]
redox-daemon = "0.1"
redox_syscall = "0.2.12"
......@@ -3,10 +3,13 @@ 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::{CloneFlags, SigActionFlags, O_CLOEXEC, SIGUSR1};
use syscall::flag::{SigActionFlags, SIGUSR1};
use syscall::scheme::SchemeBlockMut;
use redox_daemon::Daemon;
use self::scheme::AudioScheme;
mod scheme;
......@@ -17,7 +20,7 @@ fn from_syscall_error(error: syscall::Error) -> io::Error {
extern "C" fn sigusr_handler(_sig: usize) {}
fn thread(scheme: Arc<Mutex<AudioScheme>>, pid: usize, mut hda_file: fs::File) -> io::Result<()> {
fn thread(scheme: Arc<Mutex<AudioScheme>>, pid: usize, mut hw_file: fs::File) -> io::Result<()> {
// Enter null namespace
syscall::setrens(0, 0).map_err(from_syscall_error)?;
......@@ -33,12 +36,12 @@ fn thread(scheme: Arc<Mutex<AudioScheme>>, pid: usize, mut hda_file: fs::File) -
// Wake up the scheme thread
syscall::kill(pid, SIGUSR1).map_err(from_syscall_error)?;
hda_file.write(&buffer_u8)?;
hw_file.write(&buffer_u8)?;
}
}
fn daemon(pipe_fd: usize) -> io::Result<()> {
// Handle signals from the hda thread
fn daemon(daemon: Daemon) -> io::Result<()> {
// Handle signals from the hw thread
syscall::sigaction(SIGUSR1, Some(&SigAction {
sa_handler: Some(sigusr_handler),
sa_mask: [0; 2],
......@@ -47,24 +50,23 @@ fn daemon(pipe_fd: usize) -> io::Result<()> {
let pid = syscall::getpid().map_err(from_syscall_error)?;
let hda_file = fs::OpenOptions::new().write(true).open("hda:")?;
let hw_file = fs::OpenOptions::new().write(true).open("audiohw:")?;
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);
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 _thread = thread::spawn(move || thread(scheme_thread, pid, hw_file));
// Enter the null namespace - done after thread is created so
// memory: can be accessed for stack allocation
syscall::setrens(0, 0).map_err(from_syscall_error)?;
// The scheme is now ready to accept requests, notify the original process
daemon.ready().map_err(from_syscall_error)?;
let mut todo = Vec::new();
loop {
let mut packet = Packet::default();
......@@ -99,26 +101,18 @@ fn daemon(pipe_fd: usize) -> io::Result<()> {
}
}
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(CloneFlags::empty()) }.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() {
if let Err(err) = Daemon::new(|x| {
match daemon(x) {
Ok(()) => {
process::exit(0);
},
Err(err) => {
eprintln!("audiod: {}", err);
process::exit(1);
}
}
}) {
eprintln!("audiod: {}", err);
process::exit(1);
}
......
use std::collections::{BTreeMap, VecDeque};
use syscall::error::{EBADF, EWOULDBLOCK, Error, Result};
use std::str;
use syscall::error::{EBADF, EINVAL, ENOENT, EWOULDBLOCK, Error, Result};
use syscall::flag::O_NONBLOCK;
use syscall::scheme::SchemeBlockMut;
// The strict buffer size of the hda: driver
const HDA_BUFFER_SIZE: usize = 512;
// The strict buffer size of the audiohw: driver
const HW_BUFFER_SIZE: usize = 512;
// The desired buffer size of each handle
const HANDLE_BUFFER_SIZE: usize = 4096;
struct Handle {
flags: usize,
buffer: VecDeque<(i16, i16)>,
enum Handle {
Audio {
flags: usize,
buffer: VecDeque<(i16, i16)>,
},
//TODO: move volume to audiohw:?
Volume {
flags: usize,
offset: usize,
}
}
pub struct AudioScheme {
next_id: usize,
handles: BTreeMap<usize, Handle>
handles: BTreeMap<usize, Handle>,
volume: i32,
}
impl AudioScheme {
pub fn new() -> Self {
AudioScheme {
next_id: 0,
handles: BTreeMap::new()
handles: BTreeMap::new(),
volume: 50,
}
}
pub fn buffer(&mut self) -> [(i16, i16); HDA_BUFFER_SIZE] {
let mut buffer = [(0i16, 0i16); HDA_BUFFER_SIZE];
pub fn buffer(&mut self) -> [(i16, i16); HW_BUFFER_SIZE] {
let mut mix_buffer = [(0i16, 0i16); HW_BUFFER_SIZE];
// Multiply each sample by the cube of volume divided by 100
// This mimics natural perception of loudness
let volume_factor = ((self.volume as f32) / 100.0).powi(3);
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 = buffer[i].0.saturating_add(sample.0);
buffer[i].1 = buffer[i].1.saturating_add(sample.1);
} else {
break;
}
i += 1;
match handle {
Handle::Audio { flags: _, ref mut buffer } => {
let mut i = 0;
while i < mix_buffer.len() {
if let Some(sample) = buffer.pop_front() {
let left = (sample.0 as f32 * volume_factor) as i16;
let right = (sample.1 as f32 * volume_factor) as i16;
mix_buffer[i].0 = mix_buffer[i].0.saturating_add(left);
mix_buffer[i].1 = mix_buffer[i].1.saturating_add(right);
} else {
break;
}
i += 1;
}
},
_ => (),
}
}
buffer
mix_buffer
}
}
impl SchemeBlockMut for AudioScheme {
fn open(&mut self, _path: &str, flags: usize, _uid: u32, _gid: u32) -> Result<Option<usize>> {
self.next_id += 1;
let id = self.next_id;
fn open(&mut self, path: &str, flags: usize, _uid: u32, _gid: u32) -> Result<Option<usize>> {
let handle = match path.trim_matches('/') {
"" => Handle::Audio {
flags,
buffer: VecDeque::new()
},
"volume" => Handle::Volume {
flags,
offset: 0,
},
_ => return Err(Error::new(ENOENT)),
};
self.handles.insert(id, Handle {
flags,
buffer: VecDeque::new()
});
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, handle);
Ok(Some(id))
}
fn write(&mut self, id: usize, buf: &[u8]) -> Result<Option<usize>> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
//TODO: check flags for readable
match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
Handle::Audio { flags: _, buffer: _ } => {
//TODO: audio input?
Err(Error::new(EBADF))
},
Handle::Volume { flags: _, ref mut offset } => {
//TODO: should we allocate every time?
let string = format!("{}", self.volume);
let bytes = string.as_bytes();
if handle.buffer.len() >= HANDLE_BUFFER_SIZE {
if handle.flags & O_NONBLOCK > 0 {
Err(Error::new(EWOULDBLOCK))
} else {
Ok(None)
}
} else {
let mut i = 0;
while i + 4 <= buf.len() {
handle.buffer.push_back((
(buf[i] as i16) | ((buf[i + 1] as i16) << 8),
(buf[i + 2] as i16) | ((buf[i + 3] as i16) << 8)
));
i += 4;
let mut i = 0;
while i < buf.len() && *offset + i < bytes.len() {
buf[i] = bytes[*offset + i];
i += 1;
}
*offset += i;
Ok(Some(i))
}
}
}
fn write(&mut self, id: usize, buf: &[u8]) -> Result<Option<usize>> {
//TODO: check flags for writable
match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
Handle::Audio { ref flags, ref mut buffer } => {
if buffer.len() >= HANDLE_BUFFER_SIZE {
if flags & O_NONBLOCK > 0 {
Err(Error::new(EWOULDBLOCK))
} else {
Ok(None)
}
} else {
let mut i = 0;
while i + 4 <= buf.len() {
buffer.push_back((
(buf[i] as i16) | ((buf[i + 1] as i16) << 8),
(buf[i + 2] as i16) | ((buf[i + 3] as i16) << 8)
));
Ok(Some(i))
i += 4;
}
Ok(Some(i))
}
},
Handle::Volume { flags: _, ref mut offset } => {
//TODO: support other offsets?
if *offset == 0 {
let value = str::from_utf8(buf)
.map_err(|_| Error::new(EINVAL))?
.trim()
.parse::<i32>()
.map_err(|_| Error::new(EINVAL))?;
if value >= 0 && value <= 100 {
self.volume = value;
*offset += buf.len();
Ok(Some(buf.len()))
} else {
Err(Error::new(EINVAL))
}
} else {
// EOF
Ok(Some(0))
}
}
}
}
}