From 8ff9a0bed61c678d53c73224865f8bea5eab17d3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Nov 2022 09:53:47 -0700 Subject: [PATCH] Add volume control --- src/scheme.rs | 156 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 114 insertions(+), 42 deletions(-) diff --git a/src/scheme.rs b/src/scheme.rs index 260324379f..0dd1c63209 100644 --- a/src/scheme.rs +++ b/src/scheme.rs @@ -1,5 +1,6 @@ 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; @@ -8,78 +9,149 @@ 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 + handles: BTreeMap, + 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); HW_BUFFER_SIZE] { - let mut buffer = [(0i16, 0i16); HW_BUFFER_SIZE]; + let mut mix_buffer = [(0i16, 0i16); HW_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 = 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 i32 * self.volume) / 100) as i16; + let right = ((sample.1 as i32 * self.volume) / 100) 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> { - self.next_id += 1; - let id = self.next_id; + fn open(&mut self, path: &str, flags: usize, _uid: u32, _gid: u32) -> Result> { + 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 read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + //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(); + + 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> { - let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + //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) + )); - if handle.buffer.len() >= HANDLE_BUFFER_SIZE { - if handle.flags & O_NONBLOCK > 0 { - Err(Error::new(EWOULDBLOCK)) - } else { - Ok(None) + 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::() + .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)) + } } - } 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; - } - - Ok(Some(i)) } } }