use std::{borrow::Borrow, ffi::CString, os::unix::prelude::OsStrExt, path::Path};
use crate::{error::CheckResult, Comments, Result};
#[derive(Debug)]
pub struct Encoder {
ptr: *mut crate::ffi::OggOpusEnc,
channels: usize,
}
impl Drop for Encoder {
fn drop(&mut self) {
unsafe { crate::ffi::ope_encoder_destroy(self.ptr) }
}
}
impl Encoder {
pub fn create_file(
path: impl AsRef<Path>,
comments: impl Borrow<Comments>,
rate: i32,
channels: usize,
family: MappingFamily,
) -> Result<Self> {
let path = CString::new(path.as_ref().as_os_str().as_bytes())?;
let mut error = 0;
let ptr = unsafe {
crate::ffi::ope_encoder_create_file(
path.as_ptr(),
comments.borrow().ptr(),
rate,
channels.try_into().unwrap(),
family as i32,
&mut error,
)
};
error.check_result()?;
assert!(!ptr.is_null());
Ok(Self { ptr, channels })
}
pub fn create_pull(
comments: impl Borrow<Comments>,
rate: i32,
channels: usize,
family: MappingFamily,
) -> Result<Self> {
let mut error = 0;
let ptr = unsafe {
crate::ffi::ope_encoder_create_pull(
comments.borrow().ptr(),
rate,
channels.try_into().unwrap(),
family as i32,
&mut error,
)
};
error.check_result()?;
assert!(!ptr.is_null());
Ok(Self { ptr, channels })
}
}
impl Encoder {
pub fn write_float(&mut self, pcm: &[f32]) -> Result<()> {
if pcm.len() % self.channels != 0 {
panic!("sample count must be a multiple of channel count")
}
unsafe {
crate::ffi::ope_encoder_write_float(
self.ptr,
pcm.as_ptr(),
(pcm.len() / self.channels).try_into().unwrap(),
)
}
.check_result()
}
pub fn write(&mut self, pcm: &[i16]) -> Result<()> {
if pcm.len() % self.channels != 0 {
panic!("sample count must be a multiple of channel count")
}
unsafe {
crate::ffi::ope_encoder_write(
self.ptr,
pcm.as_ptr(),
(pcm.len() / self.channels).try_into().unwrap(),
)
}
.check_result()
}
pub fn get_page(&mut self, flush: bool) -> Option<&[u8]> {
let mut page_ptr: *mut std::ffi::c_uchar = std::ptr::null_mut();
let mut page_size = 0;
unsafe {
let available = crate::ffi::ope_encoder_get_page(
self.ptr,
&mut page_ptr,
&mut page_size,
flush as i32,
);
if available == 1 {
Some(std::slice::from_raw_parts(page_ptr, page_size as usize))
} else {
None
}
}
}
pub fn drain(&mut self) -> Result<()> {
unsafe { crate::ffi::ope_encoder_drain(self.ptr) }.check_result()
}
pub fn chain_current(&mut self, comments: impl Borrow<Comments>) -> Result<()> {
unsafe { crate::ffi::ope_encoder_chain_current(self.ptr, comments.borrow().ptr()) }
.check_result()
}
pub fn continue_new_file(
&mut self,
path: impl AsRef<Path>,
comments: impl Borrow<Comments>,
) -> Result<()> {
let path = CString::new(path.as_ref().as_os_str().as_bytes())?;
unsafe {
crate::ffi::ope_encoder_continue_new_file(
self.ptr,
path.as_ptr(),
comments.borrow().ptr(),
)
}
.check_result()
}
pub fn flush_header(&mut self) -> Result<()> {
unsafe { crate::ffi::ope_encoder_flush_header(self.ptr) }.check_result()
}
#[inline]
#[cfg(feature = "encoder-options")]
pub fn get_option(&self, request: u32) -> Result<i32> {
let mut x = 0;
unsafe { crate::ffi::ope_encoder_get_option(self.ptr, request, &mut x) }.check_result()?;
Ok(x)
}
#[inline]
#[cfg(feature = "encoder-options")]
pub fn set_option(&mut self, request: u32, value: i32) -> Result<()> {
unsafe { crate::ffi::ope_encoder_set_option(self.ptr, request, value) }.check_result()
}
}
impl Encoder {
pub fn ptr(&self) -> *mut crate::ffi::OggOpusEnc {
self.ptr
}
}
#[derive(Copy, Clone, Debug)]
#[repr(i32)]
pub enum MappingFamily {
MonoStereo,
Surround,
}