summaryrefslogtreecommitdiff
path: root/oss.rs
diff options
context:
space:
mode:
Diffstat (limited to 'oss.rs')
-rw-r--r--oss.rs139
1 files changed, 139 insertions, 0 deletions
diff --git a/oss.rs b/oss.rs
new file mode 100644
index 0000000..b870c45
--- /dev/null
+++ b/oss.rs
@@ -0,0 +1,139 @@
+use std::libc::{c_int, c_void, close, O_RDONLY, open, read};
+use std::rt::io::{io_error, IoError, OtherIoError};
+use std::vec;
+
+macro_rules! _SIO(
+ ($x: expr, $y: expr) => (($x << 8) | $y);
+)
+
+/* rust doesn't have a sizeof you can use in constant expressions >.<
+macro_rules! _SIOWR(
+ ($x: expr, $y: expr, $t: ty) => (
+ 0xc0000000 as c_int | (size_of::<$t>() as c_int << 16) | ($x << 8) | $y);
+)
+*/
+
+macro_rules! _SIOWR(
+ ($x: expr, $y: expr, $t: expr) => (
+ 0xc0000000 as c_int | ($t << 16) | ($x << 8) | $y);
+)
+
+static SNDCTL_DSP_RESET: c_int = _SIO!('P' as c_int, 0);
+static SNDCTL_DSP_SYNC: c_int = _SIO!('P' as c_int, 1);
+static SNDCTL_DSP_SPEED: c_int = _SIOWR!('P' as c_int, 2, 4);
+static SNDCTL_DSP_STEREO: c_int = _SIOWR!('P' as c_int, 3, 4);
+static SNDCTL_DSP_GETBLKSIZE: c_int = _SIOWR!('P' as c_int, 4, 4);
+static SNDCTL_DSP_SETFMT: c_int = _SIOWR!('P' as c_int, 5, 4);
+static AFMT_S16_LE: c_int = 0x00000010;
+
+extern {
+ fn ioctl(fd: c_int, ioctl: c_int, arg: *mut c_int) -> c_int;
+}
+
+pub struct OssDevice {
+ fd: c_int,
+}
+
+impl OssDevice {
+ #[fixed_stack_segment]
+ pub fn new(path: &Path) -> Option<OssDevice> {
+ let fd = do path.with_c_str |path| {
+ unsafe { open(path, O_RDONLY, 0777) }
+ };
+ if fd != -1 {
+ Some(OssDevice { fd: fd })
+ } else {
+ None
+ }
+ }
+ #[fixed_stack_segment]
+ pub fn reset(&self) {
+ unsafe {
+ if ioctl(self.fd, SNDCTL_DSP_RESET, 0 as *mut c_int) == -1 {
+ io_error::cond.raise(IoError { kind: OtherIoError,
+ desc: "Unable to reset dsp",
+ detail: None });
+ }
+ };
+ }
+ #[fixed_stack_segment]
+ pub fn set_format(&self) {
+ unsafe {
+ let mut i: c_int = AFMT_S16_LE;
+ if ioctl(self.fd, SNDCTL_DSP_SETFMT, &mut i) == -1 {
+ io_error::cond.raise(IoError { kind: OtherIoError,
+ desc: "Unable to set dsp format",
+ detail: None });
+ }
+ };
+ }
+ #[fixed_stack_segment]
+ pub fn set_stereo(&self) {
+ unsafe {
+ let mut i: c_int = 1;
+ if ioctl(self.fd, SNDCTL_DSP_STEREO, &mut i) == -1 {
+ io_error::cond.raise(IoError { kind: OtherIoError,
+ desc: "Unable to set dsp stereo",
+ detail: None });
+ }
+ };
+ }
+ #[fixed_stack_segment]
+ pub fn set_speed(&self, rate: int) {
+ unsafe {
+ let mut i: c_int = rate as c_int;
+ if ioctl(self.fd, SNDCTL_DSP_SPEED, &mut i) == -1 {
+ io_error::cond.raise(IoError { kind: OtherIoError,
+ desc: "Unable to set dsp speed",
+ detail: None });
+ }
+ };
+ }
+ #[fixed_stack_segment]
+ pub fn get_block_size(&self) -> uint {
+ unsafe {
+ let mut i: c_int = 0;
+ if ioctl(self.fd, SNDCTL_DSP_GETBLKSIZE, &mut i) == -1 {
+ io_error::cond.raise(IoError { kind: OtherIoError,
+ desc: "Unable to get dsp block size",
+ detail: None });
+ };
+ i as uint
+ }
+ }
+ #[fixed_stack_segment]
+ pub fn sync(&self) {
+ unsafe {
+ if ioctl(self.fd, SNDCTL_DSP_SYNC, 0 as *mut c_int) == -1 {
+ io_error::cond.raise(IoError { kind: OtherIoError,
+ desc: "Unable to get sync dsp",
+ detail: None });
+ };
+ }
+ }
+ #[fixed_stack_segment]
+ pub fn read_all(&self, chan: &Chan<~[u8]>) {
+ let block_size = self.get_block_size();
+ self.sync();
+ loop {
+ let mut buffer: ~[u8] = vec::with_capacity(block_size);
+ unsafe {
+ let length = read(self.fd,
+ vec::raw::to_mut_ptr(buffer) as *mut c_void,
+ block_size as u32);
+ if length == -1 {
+ break;
+ }
+ vec::raw::set_len(&mut buffer, length as uint);
+ }
+ chan.send(buffer);
+ }
+ }
+}
+
+impl Drop for OssDevice {
+ #[fixed_stack_segment]
+ fn drop(&mut self) {
+ unsafe { close(self.fd) };
+ }
+}