// Copyright © 2017 Mozilla Foundation // // This program is made available under an ISC-style license. See the // accompanying file LICENSE for details. use context; use ffi; use operation; use std::ffi::CStr; use std::mem::{self, forget, MaybeUninit}; use std::os::raw::{c_int, c_void}; use std::ptr; use util::*; use *; #[derive(Debug)] pub struct Stream(*mut ffi::pa_stream); impl Stream { pub fn new<'a, CM>( c: &Context, name: &::std::ffi::CStr, ss: &SampleSpec, map: CM, ) -> Option where CM: Into>, { let ptr = unsafe { ffi::pa_stream_new( c.raw_mut(), name.as_ptr(), ss as *const _, to_ptr(map.into()), ) }; if ptr.is_null() { None } else { Some(Stream(ptr)) } } #[doc(hidden)] pub fn raw_mut(&self) -> &mut ffi::pa_stream { unsafe { &mut *self.0 } } pub fn unref(self) { unsafe { ffi::pa_stream_unref(self.raw_mut()); } } pub fn get_state(&self) -> StreamState { StreamState::try_from(unsafe { ffi::pa_stream_get_state(self.raw_mut()) }) .expect("pa_stream_get_state returned invalid StreamState") } pub fn get_context(&self) -> Option { let ptr = unsafe { ffi::pa_stream_get_context(self.raw_mut()) }; if ptr.is_null() { return None; } let ctx = unsafe { context::from_raw_ptr(ptr) }; Some(ctx) } pub fn get_index(&self) -> u32 { unsafe { ffi::pa_stream_get_index(self.raw_mut()) } } pub fn get_device_name<'a>(&'a self) -> Result<&'a CStr> { let r = unsafe { ffi::pa_stream_get_device_name(self.raw_mut()) }; if r.is_null() { let err = if let Some(c) = self.get_context() { c.errno() } else { ffi::PA_ERR_UNKNOWN }; return Err(ErrorCode::from_error_code(err)); } Ok(unsafe { CStr::from_ptr(r) }) } pub fn is_suspended(&self) -> Result { let r = unsafe { ffi::pa_stream_is_suspended(self.raw_mut()) }; error_result!(r != 0, r) } pub fn is_corked(&self) -> Result { let r = unsafe { ffi::pa_stream_is_corked(self.raw_mut()) }; error_result!(r != 0, r) } pub fn connect_playback<'a, D, A, V, S>( &self, dev: D, attr: A, flags: StreamFlags, volume: V, sync_stream: S, ) -> Result<()> where D: Into>, A: Into>, V: Into>, S: Into>, { let r = unsafe { ffi::pa_stream_connect_playback( self.raw_mut(), str_to_ptr(dev.into()), to_ptr(attr.into()), flags.into(), to_ptr(volume.into()), map_to_mut_ptr(sync_stream.into(), |p| p.0), ) }; error_result!((), r) } pub fn connect_record<'a, D, A>(&self, dev: D, attr: A, flags: StreamFlags) -> Result<()> where D: Into>, A: Into>, { let r = unsafe { ffi::pa_stream_connect_record( self.raw_mut(), str_to_ptr(dev.into()), to_ptr(attr.into()), flags.into(), ) }; error_result!((), r) } pub fn disconnect(&self) -> Result<()> { let r = unsafe { ffi::pa_stream_disconnect(self.raw_mut()) }; error_result!((), r) } pub fn begin_write(&self, req_bytes: usize) -> Result<(*mut c_void, usize)> { let mut data: *mut c_void = ptr::null_mut(); let mut nbytes = req_bytes; let r = unsafe { ffi::pa_stream_begin_write(self.raw_mut(), &mut data, &mut nbytes) }; error_result!((data, nbytes), r) } pub fn cancel_write(&self) -> Result<()> { let r = unsafe { ffi::pa_stream_cancel_write(self.raw_mut()) }; error_result!((), r) } pub fn write( &self, data: *const c_void, nbytes: usize, offset: i64, seek: SeekMode, ) -> Result<()> { let r = unsafe { ffi::pa_stream_write(self.raw_mut(), data, nbytes, None, offset, seek.into()) }; error_result!((), r) } pub unsafe fn peek(&self, data: *mut *const c_void, length: *mut usize) -> Result<()> { let r = ffi::pa_stream_peek(self.raw_mut(), data, length); error_result!((), r) } pub fn drop(&self) -> Result<()> { let r = unsafe { ffi::pa_stream_drop(self.raw_mut()) }; error_result!((), r) } pub fn writable_size(&self) -> Result { let r = unsafe { ffi::pa_stream_writable_size(self.raw_mut()) }; if r == ::std::usize::MAX { let err = if let Some(c) = self.get_context() { c.errno() } else { ffi::PA_ERR_UNKNOWN }; return Err(ErrorCode::from_error_code(err)); } Ok(r) } pub fn readable_size(&self) -> Result { let r = unsafe { ffi::pa_stream_readable_size(self.raw_mut()) }; if r == ::std::usize::MAX { let err = if let Some(c) = self.get_context() { c.errno() } else { ffi::PA_ERR_UNKNOWN }; return Err(ErrorCode::from_error_code(err)); } Ok(r) } pub fn update_timing_info(&self, _: CB, userdata: *mut c_void) -> Result where CB: Fn(&Stream, i32, *mut c_void), { assert_eq!(mem::size_of::(), 0); // See: A note about `wrapped` functions unsafe extern "C" fn wrapped( s: *mut ffi::pa_stream, success: c_int, userdata: *mut c_void, ) where F: Fn(&Stream, i32, *mut c_void), { let mut stm = stream::from_raw_ptr(s); let cb = MaybeUninit::::uninit(); let result = (*cb.as_ptr())(&mut stm, success, userdata); forget(stm); result } let r = unsafe { ffi::pa_stream_update_timing_info(self.raw_mut(), Some(wrapped::), userdata) }; if r.is_null() { let err = if let Some(c) = self.get_context() { c.errno() } else { ffi::PA_ERR_UNKNOWN }; return Err(ErrorCode::from_error_code(err)); } Ok(unsafe { operation::from_raw_ptr(r) }) } pub fn clear_state_callback(&self) { unsafe { ffi::pa_stream_set_state_callback(self.raw_mut(), None, ptr::null_mut()); } } pub fn set_state_callback(&self, _: CB, userdata: *mut c_void) where CB: Fn(&Stream, *mut c_void), { assert_eq!(mem::size_of::(), 0); // See: A note about `wrapped` functions unsafe extern "C" fn wrapped(s: *mut ffi::pa_stream, userdata: *mut c_void) where F: Fn(&Stream, *mut c_void), { let mut stm = stream::from_raw_ptr(s); let cb = MaybeUninit::::uninit(); let result = (*cb.as_ptr())(&mut stm, userdata); forget(stm); result } unsafe { ffi::pa_stream_set_state_callback(self.raw_mut(), Some(wrapped::), userdata); } } pub fn clear_write_callback(&self) { unsafe { ffi::pa_stream_set_write_callback(self.raw_mut(), None, ptr::null_mut()); } } pub fn set_write_callback(&self, _: CB, userdata: *mut c_void) where CB: Fn(&Stream, usize, *mut c_void), { assert_eq!(mem::size_of::(), 0); // See: A note about `wrapped` functions unsafe extern "C" fn wrapped( s: *mut ffi::pa_stream, nbytes: usize, userdata: *mut c_void, ) where F: Fn(&Stream, usize, *mut c_void), { let mut stm = stream::from_raw_ptr(s); let cb = MaybeUninit::::uninit(); let result = (*cb.as_ptr())(&mut stm, nbytes, userdata); forget(stm); result } unsafe { ffi::pa_stream_set_write_callback(self.raw_mut(), Some(wrapped::), userdata); } } pub fn clear_read_callback(&self) { unsafe { ffi::pa_stream_set_read_callback(self.raw_mut(), None, ptr::null_mut()); } } pub fn set_read_callback(&self, _: CB, userdata: *mut c_void) where CB: Fn(&Stream, usize, *mut c_void), { assert_eq!(mem::size_of::(), 0); // See: A note about `wrapped` functions unsafe extern "C" fn wrapped( s: *mut ffi::pa_stream, nbytes: usize, userdata: *mut c_void, ) where F: Fn(&Stream, usize, *mut c_void), { let mut stm = stream::from_raw_ptr(s); let cb = MaybeUninit::::uninit(); let result = (*cb.as_ptr())(&mut stm, nbytes, userdata); forget(stm); result } unsafe { ffi::pa_stream_set_read_callback(self.raw_mut(), Some(wrapped::), userdata); } } pub fn cork(&self, b: i32, _: CB, userdata: *mut c_void) -> Result where CB: Fn(&Stream, i32, *mut c_void), { assert_eq!(mem::size_of::(), 0); // See: A note about `wrapped` functions unsafe extern "C" fn wrapped( s: *mut ffi::pa_stream, success: c_int, userdata: *mut c_void, ) where F: Fn(&Stream, i32, *mut c_void), { let mut stm = stream::from_raw_ptr(s); let cb = MaybeUninit::::uninit(); let result = (*cb.as_ptr())(&mut stm, success, userdata); forget(stm); result } let r = unsafe { ffi::pa_stream_cork(self.raw_mut(), b, Some(wrapped::), userdata) }; if r.is_null() { let err = if let Some(c) = self.get_context() { c.errno() } else { ffi::PA_ERR_UNKNOWN }; return Err(ErrorCode::from_error_code(err)); } Ok(unsafe { operation::from_raw_ptr(r) }) } pub fn get_time(&self) -> Result { let mut usec: USec = 0; let r = unsafe { ffi::pa_stream_get_time(self.raw_mut(), &mut usec) }; error_result!(usec, r) } pub fn get_latency(&self) -> Result { let mut usec: u64 = 0; let mut negative: i32 = 0; let r = unsafe { ffi::pa_stream_get_latency(self.raw_mut(), &mut usec, &mut negative) }; error_result!( if negative == 0 { StreamLatency::Positive(usec) } else { StreamLatency::Negative(usec) }, r ) } pub fn get_sample_spec(&self) -> &SampleSpec { unsafe { let ptr = ffi::pa_stream_get_sample_spec(self.raw_mut()); debug_assert!(!ptr.is_null()); &*ptr } } pub fn get_channel_map(&self) -> &ChannelMap { unsafe { let ptr = ffi::pa_stream_get_channel_map(self.raw_mut()); debug_assert!(!ptr.is_null()); &*ptr } } pub fn get_buffer_attr(&self) -> &BufferAttr { unsafe { let ptr = ffi::pa_stream_get_buffer_attr(self.raw_mut()); debug_assert!(!ptr.is_null()); &*ptr } } pub fn set_name(&self, name: &CStr, _: CB, userdata: *mut c_void) -> Result where CB: Fn(&Stream, i32, *mut c_void), { assert_eq!(mem::size_of::(), 0); // See: A note about `wrapped` functions unsafe extern "C" fn wrapped( s: *mut ffi::pa_stream, success: c_int, userdata: *mut c_void, ) where F: Fn(&Stream, i32, *mut c_void), { let mut stm = stream::from_raw_ptr(s); let cb = MaybeUninit::::uninit(); let result = (*cb.as_ptr())(&mut stm, success, userdata); forget(stm); result } let r = unsafe { ffi::pa_stream_set_name(self.raw_mut(), name.as_ptr(), Some(wrapped::), userdata) }; if r.is_null() { let err = if let Some(c) = self.get_context() { c.errno() } else { ffi::PA_ERR_UNKNOWN }; return Err(ErrorCode::from_error_code(err)); } Ok(unsafe { operation::from_raw_ptr(r) }) } } #[doc(hidden)] pub unsafe fn from_raw_ptr(ptr: *mut ffi::pa_stream) -> Stream { Stream(ptr) }