usecrate::ClientContext; usecrate::{assert_not_in_callback, run_in_callback}; use audioipc::messages::{self, CallbackReq, CallbackResp, ClientMessage, ServerMessage}; use audioipc::shm::SharedMem; use audioipc::{rpccore, sys}; use cubeb_backend::{ffi, DeviceRef, Error, InputProcessingParams, Result, Stream, StreamOps}; use std::convert::TryFrom; use std::ffi::{CStr, CString}; use std::os::raw::c_void; use std::ptr; use std::sync::mpsc; use std::sync::{Arc, Mutex};
pubstruct Device(ffi::cubeb_device);
impl Drop for Device { fn drop(&mutself) { unsafe { if !self.0.input_name.is_null() { let _ = CString::from_raw(self.0.input_name as *mut _);
} if !self.0.output_name.is_null() { let _ = CString::from_raw(self.0.output_name as *mut _);
}
}
}
}
// ClientStream's layout *must* match cubeb.c's `struct cubeb_stream` for the // common fields. #[repr(C)] #[derive(Debug)] pubstruct ClientStream<'ctx> { // This must be a reference to Context for cubeb, cubeb accesses // stream methods via stream->context->ops
context: &'ctx ClientContext,
user_ptr: *mut c_void,
token: usize,
device_change_cb: Arc<Mutex<ffi::cubeb_device_changed_callback>>, // Signals ClientStream that CallbackServer has dropped.
shutdown_rx: mpsc::Receiver<()>,
}
impl rpccore::Server for CallbackServer { type ServerMessage = CallbackReq; type ClientMessage = CallbackResp;
fn process(&mutself, req: Self::ServerMessage) -> Self::ClientMessage { match req {
CallbackReq::Data { nframes } => { let Ok(nframes) = usize::try_from(nframes) else {
warn!("stream_thread: Data Callback: invalid nframes={nframes}"); return CallbackResp::Error(ffi::CUBEB_ERROR);
};
let input_frame_size = self.input_frame_size.unwrap_or(0); let output_frame_size = self.output_frame_size.unwrap_or(0); let shm_size = self.shm.get_size();
trace!( "stream_thread: Data Callback: nframes={nframes} input_fs={input_frame_size} output_fs={output_frame_size}",
);
let Some(input_nbytes) = nframes
.checked_mul(input_frame_size)
.filter(|&n| n <= shm_size) else {
warn!("stream_thread: Data Callback: invalid nframes={nframes} input_fs={input_frame_size} shm={}", shm_size); return CallbackResp::Error(ffi::CUBEB_ERROR);
};
let Some(output_nbytes) = nframes
.checked_mul(output_frame_size)
.filter(|&n| n <= shm_size) else {
warn!("stream_thread: Data Callback: invalid nframes={nframes} output_fs={output_frame_size} shm={}", shm_size); return CallbackResp::Error(ffi::CUBEB_ERROR);
};
// Input and output reuse the same shmem backing. Unfortunately, cubeb's data_callback isn't // specified in such a way that would require the callee to consume all of the input before // writing to the output (i.e., it is passed as two pointers that aren't expected to alias). // That means we need to copy the input here. iflet Some(buf) = &mutself.duplex_input {
assert!(input_nbytes > 0);
assert!(buf.capacity() >= input_nbytes); unsafe { let input = self.shm.get_slice(input_nbytes).unwrap();
ptr::copy_nonoverlapping(input.as_ptr(), buf.as_mut_ptr(), input.len());
}
}
impl Drop for ClientStream<'_> { fn drop(&mutself) {
debug!("ClientStream drop"); let _ = send_recv!(self.context.rpc(), StreamDestroy(self.token) => StreamDestroyed);
debug!("ClientStream drop - stream destroyed"); // Wait for CallbackServer to shutdown. The remote server drops the RPC // connection during StreamDestroy, which will cause CallbackServer to drop // once the connection close is detected. Dropping CallbackServer will // cause the shutdown channel to error on recv, which we rely on to // synchronize with CallbackServer dropping. let _ = self.shutdown_rx.recv();
debug!("ClientStream dropped");
}
}
impl StreamOps for ClientStream<'_> { fn start(&mutself) -> Result<()> {
assert_not_in_callback(); let rpc = self.context.rpc();
send_recv!(rpc, StreamStart(self.token) => StreamStarted)
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.