diff --git a/cubeb-core/Cargo.toml b/cubeb-core/Cargo.toml index dc1ea7e..6a45293 100644 --- a/cubeb-core/Cargo.toml +++ b/cubeb-core/Cargo.toml @@ -20,3 +20,6 @@ gecko-in-tree = ["cubeb-sys/gecko-in-tree"] [dependencies] bitflags = "1.2.0" cubeb-sys = { path = "../cubeb-sys", version = "0.14" } + +[build-dependencies] +cc = "1.1.30" diff --git a/cubeb-core/build.rs b/cubeb-core/build.rs new file mode 100644 index 0000000..1e6a633 --- /dev/null +++ b/cubeb-core/build.rs @@ -0,0 +1,3 @@ +fn main() { + cc::Build::new().file("src/log.c").compile("cubeb_log_wrap"); +} diff --git a/cubeb-core/src/log.c b/cubeb-core/src/log.c new file mode 100644 index 0000000..df6de37 --- /dev/null +++ b/cubeb-core/src/log.c @@ -0,0 +1,17 @@ +#include +#include + +/** The maximum size of a log message, after having been formatted. */ +#define CUBEB_LOG_MESSAGE_MAX_SIZE 256 + +void rust_write_formatted_msg(char* msg); + +void cubeb_write_log(char const * fmt, ...) { + va_list args; + va_start(args, fmt); + char msg[CUBEB_LOG_MESSAGE_MAX_SIZE]; + vsnprintf(msg, CUBEB_LOG_MESSAGE_MAX_SIZE, fmt, args); + va_end(args); + rust_write_formatted_msg(msg); +} + diff --git a/cubeb-core/src/log.rs b/cubeb-core/src/log.rs index 6bf6ba9..b1c87b4 100644 --- a/cubeb-core/src/log.rs +++ b/cubeb-core/src/log.rs @@ -3,7 +3,9 @@ // This program is made available under an ISC-style license. See the // accompanying file LICENSE for details. -use ffi; +use std::ffi::{c_char, CStr}; +use std::sync::Mutex; +use {ffi, Error, Result}; /// Level (verbosity) of logging for a particular cubeb context. #[derive(PartialEq, Eq, Clone, Debug, Copy, PartialOrd, Ord)] @@ -27,10 +29,60 @@ impl From for LogLevel { } } +impl From for ffi::cubeb_log_level { + fn from(x: LogLevel) -> Self { + use LogLevel::*; + match x { + Normal => ffi::CUBEB_LOG_NORMAL, + Verbose => ffi::CUBEB_LOG_VERBOSE, + Disabled => ffi::CUBEB_LOG_DISABLED, + } + } +} + pub fn log_enabled() -> bool { unsafe { ffi::cubeb_log_get_level() != LogLevel::Disabled as _ } } +static LOG_CALLBACK: Mutex> = Mutex::new(None); + +extern "C" { + fn cubeb_write_log(fmt: *const c_char, ...); +} + +/// # Safety +/// +/// |s| must be null, or a pointer to a valid, nul-terminated, array of chars. +#[no_mangle] +pub unsafe extern "C" fn rust_write_formatted_msg(s: *const c_char) { + if s.is_null() { + // Do nothing if the pointer is null. + return; + } + if let Ok(guard) = LOG_CALLBACK.lock() { + if let Some(f) = *guard { + f(CStr::from_ptr(s)); + } + // Do nothing if there is no callback. + } + // Silently fail if lock cannot be acquired. +} + +pub fn set_logging(level: LogLevel, f: Option) -> Result<()> { + match LOG_CALLBACK.lock() { + Ok(mut guard) => { + *guard = f; + } + Err(_) => return Err(Error::error()), + } + unsafe { + call!(ffi::cubeb_set_log_callback( + level.into(), + Some(cubeb_write_log) + )) + } +} + #[cfg(test)] mod tests { use super::*;