1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use std::ffi::{CStr, c_void};

use steam_audio_sys::ffi::{self, iplContextRetain};

use crate::prelude::*;

#[derive(Debug, Default)]
pub struct ContextSettings {
    version: Option<u32>,
    simd_level: Option<ffi::IPLSIMDLevel>,
}

unsafe extern "C" fn log_callback(level: ffi::IPLLogLevel, message: *const ::std::os::raw::c_char) {
    dbg!();
    let c_str: &CStr = CStr::from_ptr(message);
    let str = c_str.to_str().unwrap();
    eprintln!("{:?}: {}", level, str);
}

unsafe extern "C" fn alloc_callback(size: ffi::IPLsize, alignment: ffi::IPLsize) -> *mut c_void {
    let layout = match std::alloc::Layout::from_size_align(size as usize, alignment as usize) {
        Ok(layout) => layout,
        _ => return std::ptr::null_mut(),
    };

    std::alloc::alloc(layout) as *mut c_void
}

unsafe extern "C" fn free_callback(size: ffi::IPLsize, alignment: ffi::IPLsize) -> *mut c_void {
    let layout = match std::alloc::Layout::from_size_align(size as usize, alignment as usize) {
        Ok(layout) => layout,
        _ => return std::ptr::null_mut(),
    };

    std::alloc::alloc(layout) as *mut c_void
}

impl Into<ffi::IPLContextSettings> for ContextSettings {
    fn into(self) -> ffi::IPLContextSettings {
        ffi::IPLContextSettings {
            version: self.version.unwrap_or(ffi::STEAMAUDIO_VERSION),
            logCallback: Some(log_callback),
            //logCallback: None,
            allocateCallback: Some(alloc_callback),
            simdLevel: self
                .simd_level
                .unwrap_or(ffi::IPLSIMDLevel::IPL_SIMDLEVEL_SSE2),
            freeCallback: None,
        }
    }
}
pub struct Context {
    pub(crate) inner: ffi::IPLContext,
    settings: ffi::IPLContextSettings,
}

impl Context {
    pub fn new(settings: ContextSettings) -> Result<Self, SteamAudioError> {
        let mut ipl_settings: ffi::IPLContextSettings = settings.into();
        let mut context = Self {
            inner: unsafe { std::mem::zeroed() },
            settings: ipl_settings,
        };

        unsafe {
            match ffi::iplContextCreate(&mut context.settings, &mut context.inner) {
                ffi::IPLerror::IPL_STATUS_SUCCESS => Ok(context),
                err => Err(SteamAudioError::IPLError(err)),
            }
        }
    }

    pub unsafe fn inner(&self) -> ffi::IPLContext {
        self.inner
    }

    pub fn retain(&self) -> Context {
        unsafe {
            let new_context = iplContextRetain(self.inner);
            Context {
                inner: new_context,
                settings: self.settings,
            }
        }
    }

    pub fn debug(&mut self) {
        dbg!(self.inner);
        dbg!(self.settings);
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            ffi::iplContextRelease(&mut self.inner);
        }
    }
}