usecrate::ClientContext; usecrate::{assert_not_in_callback, run_in_callback}; use audioipc::messages::StreamCreateParams; 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::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<()>,
}
let input_nbytes = nframes as usize * input_frame_size; let output_nbytes = nframes as usize * output_frame_size;
// 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());
}
}
run_in_callback(|| { let nframes = unsafe { let input_ptr = if input_frame_size > 0 { iflet Some(buf) = &mutself.duplex_input {
buf.as_ptr()
} else { self.shm.get_slice(input_nbytes).unwrap().as_ptr()
}
} else {
ptr::null()
}; let output_ptr = if output_frame_size > 0 { self.shm.get_mut_slice(output_nbytes).unwrap().as_mut_ptr()
} else {
ptr::null_mut()
};
self.data_cb.unwrap()(
ptr::null_mut(), // https://github.com/kinetiknz/cubeb/issues/518 self.user_ptr as *mut c_void,
input_ptr as *const _,
output_ptr as *mut _,
nframes as _,
)
};
CallbackResp::Data(nframes as isize)
})
}
CallbackReq::State(state) => {
trace!("stream_thread: State Callback: {:?}", state);
run_in_callback(|| unsafe { self.state_cb.unwrap()(ptr::null_mut(), self.user_ptr as *mut _, state);
});
CallbackResp::State
}
CallbackReq::DeviceChange => {
run_in_callback(|| { let cb = *self.device_change_cb.lock().unwrap(); iflet Some(cb) = cb { unsafe {
cb(self.user_ptr as *mut _);
}
} else {
warn!("DeviceChange received with null callback");
}
});
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.