use crate::{get_string, sys::*, AllenResult, Buffer, Listener, Source};
use lazy_static::lazy_static;
use std::{
ffi::{c_char, CString},
ptr,
sync::{Arc, Mutex, MutexGuard},
};
lazy_static! {
static ref SINGLE_CONTEXT_LOCK: Mutex<()> = Mutex::new(());
}
pub(crate) struct ContextInner {
handle: *mut ALCcontext,
}
impl Drop for ContextInner {
fn drop(&mut self) {
unsafe { alcDestroyContext(self.handle) };
}
}
#[derive(Clone)]
pub struct Context {
inner: Arc<ContextInner>,
}
impl Context {
pub(crate) fn from_handle(handle: *mut ALCcontext) -> Context {
Self {
inner: Arc::new(ContextInner { handle }),
}
}
pub fn make_current(&self) -> Option<MutexGuard<()>> {
let function: PFNALCSETTHREADCONTEXTPROC = unsafe {
let name = CString::new("alcSetThreadContext").unwrap();
std::mem::transmute(alcGetProcAddress(
ptr::null_mut(),
name.as_ptr() as *const ALCchar,
))
};
if let Some(function) = function {
unsafe {
function(self.inner.handle);
}
None
} else {
assert_eq!(true as i8, unsafe {
alcMakeContextCurrent(self.inner.handle)
});
Some(SINGLE_CONTEXT_LOCK.lock().unwrap())
}
}
pub fn is_current(&self) -> bool {
let current_context = {
let function: PFNALCGETTHREADCONTEXTPROC = unsafe {
let name = CString::new("alcGetThreadContext").unwrap();
std::mem::transmute(alcGetProcAddress(
ptr::null_mut(),
name.as_ptr() as *const ALCchar,
))
};
if let Some(function) = function {
unsafe { function() }
} else {
unsafe { alcGetCurrentContext() }
}
};
current_context == self.inner.handle
}
pub fn vendor(&self) -> &'static str {
let _lock = self.make_current();
get_string(AL_VENDOR)
}
pub fn version(&self) -> &'static str {
let _lock = self.make_current();
get_string(AL_VERSION)
}
pub fn renderer(&self) -> &'static str {
let _lock = self.make_current();
get_string(AL_RENDERER)
}
pub fn extensions(&self) -> &'static str {
let _lock = self.make_current();
get_string(AL_EXTENSIONS)
}
pub fn listener(&self) -> Listener {
Listener::new(self.clone())
}
pub fn new_buffer(&self) -> AllenResult<Buffer> {
Buffer::new(self.clone())
}
pub fn new_source(&self) -> AllenResult<Source> {
Source::new(self.clone())
}
}