use std::{marker::PhantomData, mem::MaybeUninit};
use crate::{
at::audio,
at::audio::component::{InitializedState, State, UninitializedState},
os,
};
#[derive(Debug)]
#[repr(transparent)]
pub struct Codec(audio::component::Instance);
#[derive(Debug)]
pub struct CodecRef<S>(&'static mut Codec, PhantomData<S>)
where
S: State<Codec>;
impl State<Codec> for InitializedState {
fn release_resources(instance: &mut Codec) -> os::Result {
unsafe { AudioCodecUninitialize(instance).result() }
}
}
impl State<Codec> for UninitializedState {}
#[repr(transparent)]
pub struct GlobalPropId(pub u32);
#[repr(transparent)]
pub struct InstancePropId(pub u32);
impl GlobalPropId {
#[doc(alias = "kAudioCodecPropertySupportedInputFormats")]
pub const SUPPORTED_INPUT_FORMATS: Self = Self(u32::from_be_bytes(*b"ifm#"));
#[doc(alias = "kAudioCodecPropertySupportedOutputFormats")]
pub const SUPPORTED_OUTPUT_FORMATS: Self = Self(u32::from_be_bytes(*b"ofm#"));
#[doc(alias = "kAudioCodecPropertyAvailableInputSampleRates")]
pub const AVAILABLE_INPUT_SAMPLE_RATES: Self = Self(u32::from_be_bytes(*b"aisr"));
#[doc(alias = "kAudioCodecPropertyAvailableOutputSampleRates")]
pub const AVAILABLE_OUTPUT_SAMPLE_RATES: Self = Self(u32::from_be_bytes(*b"aosr"));
#[doc(alias = "kAudioCodecPropertyAvailableBitRateRange")]
pub const AVAILABLE_BIT_RATE_RANGE: Self = Self(u32::from_be_bytes(*b"abrt"));
#[doc(alias = "kAudioCodecPropertyMinimumNumberInputPackets")]
pub const MINIMUM_NUMBER_INPUT_PACKETS: Self = Self(u32::from_be_bytes(*b"mnip"));
#[doc(alias = "kAudioCodecPropertyMinimumNumberOutputPackets")]
pub const MINIMUM_NUMBER_OUTPUT_PACKETS: Self = Self(u32::from_be_bytes(*b"mnop"));
#[doc(alias = "kAudioCodecPropertyAvailableNumberChannels")]
pub const AVAILABLE_NUMBER_CHANNELS: Self = Self(u32::from_be_bytes(*b"cmnc"));
#[doc(alias = "kAudioCodecPropertyDoesSampleRateConversion")]
pub const DOES_SAMPLE_RATE_CONVERSION: Self = Self(u32::from_be_bytes(*b"lmrc"));
#[doc(alias = "kAudioCodecPropertyAvailableInputChannelLayoutTags")]
pub const AVAILABLE_INPUT_CHANNEL_LAYOUT_TAGS: Self = Self(u32::from_be_bytes(*b"aicl"));
#[doc(alias = "kAudioCodecPropertyAvailableOutputChannelLayoutTags")]
pub const AVAILABLE_OUTPUT_CHANNEL_LAYOUT_TAGS: Self = Self(u32::from_be_bytes(*b"aocl"));
#[doc(alias = "kAudioCodecPropertyInputFormatsForOutputFormat")]
pub const INPUT_FORMATS_FOR_OUTPUT_FORMAT: Self = Self(u32::from_be_bytes(*b"if4o"));
#[doc(alias = "kAudioCodecPropertyOutputFormatsForInputFormat")]
pub const OUTPUT_FORMATS_FOR_INPUT_FORMAT: Self = Self(u32::from_be_bytes(*b"of4i"));
#[doc(alias = "kAudioCodecPropertyFormatInfo")]
pub const FORMAT_INFO: Self = Self(u32::from_be_bytes(*b"acfi"));
}
impl InstancePropId {
#[doc(alias = "kAudioCodecPropertyInputBufferSize")]
pub const INPUT_BUF_SIZE: Self = Self(u32::from_be_bytes(*b"tbuf"));
#[doc(alias = "kAudioCodecPropertyPacketFrameSize")]
pub const PACKET_FRAME_SIZE: Self = Self(u32::from_be_bytes(*b"pakf"));
#[doc(alias = "kAudioCodecPropertyHasVariablePacketByteSizes")]
pub const HAS_VARIABLE_PACKET_BYTE_SIZES: Self = Self(u32::from_be_bytes(*b"vpk?"));
#[doc(alias = "kAudioCodecPropertyEmploysDependentPackets")]
pub const EMPLOYS_DEPENDENT_PACKETS: Self = Self(u32::from_be_bytes(*b"dpk?"));
#[doc(alias = "kAudioCodecPropertyMaximumPacketByteSize")]
pub const MAXIMUM_PACKET_BYTE_SIZE: Self = Self(u32::from_be_bytes(*b"pakb"));
#[doc(alias = "kAudioCodecPropertyPacketSizeLimitForVBR")]
pub const PACKET_SIZE_LIMIT_FOR_VBR: Self = Self(u32::from_be_bytes(*b"pakl"));
#[doc(alias = "kAudioCodecPropertyCurrentInputFormat")]
pub const CURRENT_INPUT_FORMAT: Self = Self(u32::from_be_bytes(*b"ifmt"));
#[doc(alias = "kAudioCodecPropertyCurrentOutputFormat")]
pub const CURRENT_OUTPUT_FORMAT: Self = Self(u32::from_be_bytes(*b"ofmt"));
#[doc(alias = "kAudioCodecPropertyMagicCookie")]
pub const MAGIC_COOKIE: Self = Self(u32::from_be_bytes(*b"kuki"));
#[doc(alias = "kAudioCodecPropertyUsedInputBufferSize")]
pub const USED_INPUT_BUF_SIZE: Self = Self(u32::from_be_bytes(*b"ubuf"));
#[doc(alias = "kAudioCodecPropertyIsInitialized")]
pub const IS_INITIALIZED: Self = Self(u32::from_be_bytes(*b"init"));
#[doc(alias = "kAudioCodecPropertyCurrentTargetBitRate")]
pub const CURRENT_TARGET_BIT_RATE: Self = Self(u32::from_be_bytes(*b"brat"));
#[doc(alias = "kAudioCodecPropertyCurrentInputSampleRate")]
pub const CURRENT_INPUT_SAMPLE_RATE: Self = Self(u32::from_be_bytes(*b"cisr"));
#[doc(alias = "kAudioCodecPropertyCurrentOutputSampleRate")]
pub const CURRENT_OUTPUT_SAMPLE_RATE: Self = Self(u32::from_be_bytes(*b"cosr"));
#[doc(alias = "kAudioCodecPropertyQualitySetting")]
pub const QUALITY_SETTING: Self = Self(u32::from_be_bytes(*b"srcq"));
#[doc(alias = "kAudioCodecPropertyApplicableBitRateRange")]
pub const APPLICABLE_BIT_RATE_RANGE: Self = Self(u32::from_be_bytes(*b"brta"));
#[doc(alias = "kAudioCodecPropertyRecommendedBitRateRange")]
pub const RECOMMENDED_BIT_RATE_RANGE: Self = Self(u32::from_be_bytes(*b"brtr"));
#[doc(alias = "kAudioCodecPropertyApplicableInputSampleRates")]
pub const APPLICABLE_INPUT_SAMPLE_RATES: Self = Self(u32::from_be_bytes(*b"isra"));
#[doc(alias = "kAudioCodecPropertyApplicableOutputSampleRates")]
pub const APPLICABLE_OUTPUT_SAMPLE_RATES: Self = Self(u32::from_be_bytes(*b"osra"));
#[doc(alias = "kAudioCodecPropertyPaddedZeros")]
pub const PADDED_ZEROS: Self = Self(u32::from_be_bytes(*b"pad0"));
#[doc(alias = "kAudioCodecPropertyPrimeMethod")]
pub const PRIME_METHOD: Self = Self(u32::from_be_bytes(*b"prmm"));
#[doc(alias = "kAudioCodecPropertyPrimeInfo")]
pub const PRIME_INFO: Self = Self(u32::from_be_bytes(*b"prim"));
#[doc(alias = "kAudioCodecPropertyCurrentInputChannelLayout")]
pub const CURRENT_INPUT_CHANNEL_LAYOUT: Self = Self(u32::from_be_bytes(*b"icl "));
#[doc(alias = "kAudioCodecPropertyCurrentOutputChannelLayout")]
pub const CURRENT_OUTPUT_CHANNEL_LAYOUT: Self = Self(u32::from_be_bytes(*b"ocl "));
#[doc(alias = "kAudioCodecPropertySettings")]
pub const SETTINGS: Self = Self(u32::from_be_bytes(*b"acs "));
#[doc(alias = "kAudioCodecPropertyFormatList")]
pub const FORMAT_LIST: Self = Self(u32::from_be_bytes(*b"acfl"));
#[doc(alias = "kAudioCodecPropertyBitRateControlMode")]
pub const BIT_RATE_CONTROL_MODE: Self = Self(u32::from_be_bytes(*b"acbf"));
#[doc(alias = "kAudioCodecPropertySoundQualityForVBR")]
pub const SOUND_QUALITY_FOR_VBR: Self = Self(u32::from_be_bytes(*b"vbrq"));
#[doc(alias = "kAudioCodecPropertyBitRateForVBR")]
pub const BIT_RATE_FOR_VBR: Self = Self(u32::from_be_bytes(*b"vbrb"));
#[doc(alias = "kAudioCodecPropertyDelayMode")]
pub const DELAY_MODE: Self = Self(u32::from_be_bytes(*b"dmod"));
#[doc(alias = "kAudioCodecPropertyAdjustLocalQuality")]
pub const ADJUST_LOCAL_QUALITY: Self = Self(u32::from_be_bytes(*b"^qal"));
#[doc(alias = "kAudioCodecPropertyProgramTargetLevel")]
pub const PROGRAM_TARGET_LEVEL: Self = Self(u32::from_be_bytes(*b"pptl"));
#[doc(alias = "kAudioCodecPropertyDynamicRangeControlMode")]
pub const DYNAMIC_RANGE_CONTROL_MODE: Self = Self(u32::from_be_bytes(*b"mdrc"));
#[doc(alias = "kAudioCodecPropertyProgramTargetLevelConstant")]
pub const PROGRAM_TARGET_LEVEL_CONSTANT: Self = Self(u32::from_be_bytes(*b"ptlc"));
#[doc(alias = "kAudioCodecPropertyAdjustCompressionProfile")]
pub const ADJUST_COMPRESSION_PROFILE: Self = Self(u32::from_be_bytes(*b"^pro"));
#[doc(alias = "kAudioCodecPropertyAdjustTargetLevel")]
pub const ADJUST_TARGET_LEVEL: Self = Self(u32::from_be_bytes(*b"^ptl"));
#[doc(alias = "kAudioCodecPropertyAdjustTargetLevelConstant")]
pub const ADJUST_TARGET_LEVEL_CONSTANT: Self = Self(u32::from_be_bytes(*b"^tlc"));
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u32)]
pub enum ProgramTargetLevel {
#[doc(alias = "kProgramTargetLevel_None")]
None = 0,
#[doc(alias = "kProgramTargetLevel_Minus31dB")]
Minus31dB = 1,
#[doc(alias = "kProgramTargetLevel_Minus23dB")]
Minus23dB = 2,
#[doc(alias = "kProgramTargetLevel_Minus20dB")]
Minus20dB = 3,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u32)]
pub enum DynamicRangeCompressionProfile {
#[doc(alias = "kDynamicRangeCompressionProfile_None")]
None = 0,
#[doc(alias = "kDynamicRangeCompressionProfile_LateNight")]
LateNight = 1,
#[doc(alias = "kDynamicRangeCompressionProfile_NoisyEnvironment")]
NoisyEnvironment = 2,
#[doc(alias = "kDynamicRangeCompressionProfile_LimitedPlaybackRange")]
LimitedPlaybackRange = 3,
#[doc(alias = "kDynamicRangeCompressionProfile_GeneralCompression")]
GeneralCompression = 6,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u32)]
pub enum BitRateControlMode {
Constant = 0,
LongTermAverage = 1,
VariableConstrained = 2,
Variable = 3,
}
#[doc(alias = "kAudioDecoderComponentType")]
pub const DECODER_COMPONENT_TYPE: os::Type = u32::from_be_bytes(*b"adec");
#[doc(alias = "kAudioEncoderComponentType")]
pub const ENCODER_COMPONENT_TYPE: os::Type = u32::from_be_bytes(*b"aenc");
#[doc(alias = "kAudioUnityCodecComponentType")]
pub const UNITY_CODEC_COMPONENT_TYPE: os::Type = u32::from_be_bytes(*b"acdc");
#[repr(C)]
pub struct MagicCookieInfo {
pub size: u32,
pub value: *const u8,
}
#[derive(Debug)]
pub struct Consumed {
pub bytes: u32,
pub packets: u32,
}
#[derive(Debug)]
pub struct Produced {
pub bytes: u32,
pub packets: u32,
pub status: ProduceOutputPacketStatus,
}
impl CodecRef<UninitializedState> {
pub fn new_apple_aac_encoder() -> os::Result<Self> {
let desc = audio::ComponentDesc {
type_: audio::ENCODER_COMPONENT_TYPE,
sub_type: audio::Format::MPEG4_AAC.0,
manufacturer: audio::unit::Manufacturer::APPLE.0,
..Default::default()
};
let comp = desc
.into_iter()
.next()
.ok_or(audio::unit::component_err::UNSUPPORTED_TYPE)?;
comp.open_codec()
}
pub fn new_apple_opus_encoder() -> os::Result<Self> {
let desc = audio::ComponentDesc {
type_: audio::ENCODER_COMPONENT_TYPE,
sub_type: audio::Format::OPUS.0,
manufacturer: audio::unit::Manufacturer::APPLE.0,
..Default::default()
};
let comp = desc
.into_iter()
.next()
.ok_or(audio::unit::component_err::UNSUPPORTED_TYPE)?;
comp.open_codec()
}
pub fn initialize(
self,
input_format: *const audio::StreamBasicDesc,
output_format: *const audio::StreamBasicDesc,
magic_cookie: Option<&[u8]>,
) -> os::Result<CodecRef<InitializedState>> {
unsafe {
self.0
.init_codec(input_format, output_format, magic_cookie)?;
Ok(CodecRef(std::mem::transmute(self), PhantomData))
}
}
#[inline]
pub fn set_quality(&mut self, val: u32) -> os::Result {
self.0.set_quality(val)
}
#[inline]
pub fn set_bit_rate_control_mode(&mut self, val: BitRateControlMode) -> os::Result {
self.0.set_bit_rate_control_mode(val)
}
#[inline]
pub fn set_current_target_bit_rate(&mut self, val: u32) -> os::Result {
self.0.set_current_target_bit_rate(val)
}
}
impl<S: State<Codec>> Drop for CodecRef<S> {
#[inline]
fn drop(&mut self) {
let res = S::release_resources(self.0);
debug_assert!(res.is_ok());
let res = unsafe { self.0.0.dispose() };
debug_assert!(res.is_ok());
}
}
impl CodecRef<InitializedState> {
pub fn uninitialize(mut self) -> os::Result<CodecRef<UninitializedState>> {
Ok(unsafe {
AudioCodecUninitialize(&mut self.0).result()?;
std::mem::transmute(self)
})
}
#[doc(alias = "AudioCodecAppendInputData")]
#[inline]
pub fn append(&mut self, data: &[u8]) -> os::Result<u32> {
let mut data_len: u32 = data.len() as _;
unsafe {
AudioCodecAppendInputData(
&mut self.0,
data.as_ptr(),
&mut data_len,
std::ptr::null_mut(),
std::ptr::null(),
)
.result()?;
}
Ok(data_len)
}
#[doc(alias = "AudioCodecAppendInputData")]
#[inline]
pub fn append_data(
&mut self,
data: &[u8],
packets: &[audio::StreamPacketDesc],
) -> os::Result<Consumed> {
let mut data_len: u32 = data.len() as _;
let mut packets_len: u32 = packets.len() as _;
unsafe {
AudioCodecAppendInputData(
&mut self.0,
data.as_ptr(),
&mut data_len,
&mut packets_len,
packets.as_ptr(),
)
.result()?;
}
Ok(Consumed {
bytes: data_len,
packets: packets_len,
})
}
#[doc(alias = "AudioCodecProduceOutputPackets")]
#[inline]
pub fn produce_packet(
&mut self,
data: &mut [u8],
) -> os::Result<(u32, ProduceOutputPacketStatus)> {
let mut data_len: u32 = data.len() as _;
let mut packets_len: u32 = 1;
let mut status = ProduceOutputPacketStatus::Failure;
unsafe {
AudioCodecProduceOutputPackets(
&mut self.0,
data.as_mut_ptr(),
&mut data_len,
&mut packets_len,
std::ptr::null_mut(),
&mut status,
)
.result()?;
}
Ok((data_len, status))
}
#[doc(alias = "AudioCodecProduceOutputPackets")]
#[inline]
pub fn produce_packets(
&mut self,
data: &mut [u8],
out_packet_descriptions: &mut [audio::StreamPacketDesc],
) -> os::Result<Produced> {
let mut data_len: u32 = data.len() as _;
let mut packets_len: u32 = out_packet_descriptions.len() as _;
let mut status = ProduceOutputPacketStatus::Failure;
unsafe {
AudioCodecProduceOutputPackets(
&mut self.0,
data.as_mut_ptr(),
&mut data_len,
&mut packets_len,
out_packet_descriptions.as_mut_ptr(),
&mut status,
)
.result()?;
}
Ok(Produced {
bytes: data_len,
packets: packets_len,
status,
})
}
#[doc(alias = "AudioCodecAppendInputBufferList")]
#[inline]
pub fn append_buf_list(
&mut self,
in_buf_list: &audio::BufList,
packet_descriptions: &mut [audio::StreamPacketDesc],
) -> os::Result<Consumed> {
let mut bytes_consumed: u32 = 0;
let mut packets_len: u32 = packet_descriptions.len() as _;
unsafe {
AudioCodecAppendInputBufferList(
&mut self.0,
in_buf_list,
&mut packets_len,
packet_descriptions.as_ptr(),
&mut bytes_consumed,
)
.result()?;
}
Ok(Consumed {
bytes: bytes_consumed,
packets: packets_len,
})
}
#[doc(alias = "AudioCodecProduceOutputBufferList")]
#[inline]
pub fn produce_buf_list(
&mut self,
buf_list: &mut audio::BufList,
number_of_packets: &mut u32,
) -> os::Result<os::Status> {
let mut status = os::Status::NO_ERR;
unsafe {
AudioCodecProduceOutputBufferList(
&mut self.0,
buf_list,
number_of_packets,
std::ptr::null_mut(),
&mut status,
)
.result()?;
}
Ok(status)
}
#[doc(alias = "AudioCodecProduceOutputBufferList")]
#[inline]
pub fn produce_buf_list_with_descs(
&mut self,
buf_list: &mut audio::BufList,
packet_descriptions: &mut [audio::StreamPacketDesc],
) -> os::Result<(u32, os::Status)> {
let mut number_packets: u32 = packet_descriptions.len() as _;
let mut status = os::Status::NO_ERR;
unsafe {
AudioCodecProduceOutputBufferList(
&mut self.0,
buf_list,
&mut number_packets,
packet_descriptions.as_mut_ptr(),
&mut status,
)
.result()?;
}
Ok((number_packets, status))
}
}
impl Codec {
pub unsafe fn init_codec(
&mut self,
input_format: *const audio::StreamBasicDesc,
output_format: *const audio::StreamBasicDesc,
magic_cookie: Option<&[u8]>,
) -> os::Result {
unsafe {
match magic_cookie {
Some(cookie) => AudioCodecInitialize(
self,
input_format,
output_format,
cookie.as_ptr(),
cookie.len() as _,
)
.result(),
None => {
AudioCodecInitialize(self, input_format, output_format, std::ptr::null(), 0)
.result()
}
}
}
}
#[doc(alias = "AudioCodecGetPropertyInfo")]
#[inline]
pub fn prop_info(&self, prop_id: u32) -> os::Result<(u32, bool)> {
let (mut size, mut writable) = (0u32, false);
unsafe { AudioCodecGetPropertyInfo(&self, prop_id, &mut size, &mut writable).result()? };
Ok((size, writable))
}
#[doc(alias = "AudioCodecGetProperty")]
#[inline]
pub unsafe fn prop_vec<T: Sized + Default + Clone>(&self, prop_id: u32) -> os::Result<Vec<T>> {
let (mut size, _) = self.prop_info(prop_id)?;
if size == 0 {
return Ok(vec![]);
}
let mut vec = vec![T::default(); size as usize / std::mem::size_of::<T>()];
unsafe {
AudioCodecGetProperty(self, prop_id, &mut size, vec.as_mut_ptr() as _).result()?;
}
Ok(vec)
}
#[doc(alias = "AudioCodecGetProperty")]
pub fn prop<T: Sized>(&self, prop_id: u32) -> os::Result<T> {
let mut size = std::mem::size_of::<T>() as u32;
unsafe {
let mut value = MaybeUninit::<T>::uninit();
AudioCodecGetProperty(self, prop_id, &mut size, value.as_mut_ptr() as _).result()?;
Ok(value.assume_init())
}
}
pub unsafe fn set_prop<T: Sized>(&mut self, property_id: u32, val: &T) -> os::Result {
let size = std::mem::size_of::<T>() as u32;
unsafe { AudioCodecSetProperty(self, property_id, size, val as *const _ as _).result() }
}
#[inline]
pub fn quality(&self) -> os::Result<u32> {
self.prop(InstancePropId::QUALITY_SETTING.0)
}
#[inline]
pub fn set_quality(&mut self, val: u32) -> os::Result {
unsafe { self.set_prop(InstancePropId::QUALITY_SETTING.0, &val) }
}
#[inline]
pub fn bit_rate_control_mode(&self) -> os::Result<BitRateControlMode> {
self.prop(InstancePropId::BIT_RATE_CONTROL_MODE.0)
}
#[inline]
pub fn set_bit_rate_control_mode(&mut self, val: BitRateControlMode) -> os::Result {
unsafe { self.set_prop(InstancePropId::BIT_RATE_CONTROL_MODE.0, &val) }
}
#[inline]
pub fn current_target_bit_rate(&self) -> os::Result<u32> {
self.prop(InstancePropId::CURRENT_TARGET_BIT_RATE.0)
}
#[inline]
pub fn set_current_target_bit_rate(&mut self, val: u32) -> os::Result {
unsafe { self.set_prop(InstancePropId::CURRENT_TARGET_BIT_RATE.0, &val) }
}
#[inline]
pub fn current_input_sample_rate(&self) -> os::Result<f64> {
self.prop(InstancePropId::CURRENT_INPUT_SAMPLE_RATE.0)
}
#[inline]
pub fn set_current_input_sample_rate(&mut self, val: f64) -> os::Result {
unsafe { self.set_prop(InstancePropId::CURRENT_INPUT_SAMPLE_RATE.0, &val) }
}
#[inline]
pub fn current_output_sample_rate(&self) -> os::Result<f64> {
self.prop(InstancePropId::CURRENT_OUTPUT_SAMPLE_RATE.0)
}
#[inline]
pub fn set_current_output_sample_rate(&mut self, val: f64) -> os::Result {
unsafe { self.set_prop(InstancePropId::CURRENT_OUTPUT_SAMPLE_RATE.0, &val) }
}
#[inline]
pub fn set_current_input_channel_layout<const N: usize>(
&mut self,
val: &audio::ChannelLayout<N>,
) -> os::Result {
unsafe { self.set_prop(InstancePropId::CURRENT_INPUT_CHANNEL_LAYOUT.0, val) }
}
#[inline]
pub fn current_input_channel_layout<const N: usize>(
&self,
) -> os::Result<audio::ChannelLayout<N>> {
self.prop(InstancePropId::CURRENT_INPUT_CHANNEL_LAYOUT.0)
}
#[inline]
pub fn set_current_output_channel_layout<const N: usize>(
&mut self,
val: &audio::ChannelLayout<N>,
) -> os::Result {
unsafe { self.set_prop(InstancePropId::CURRENT_OUTPUT_CHANNEL_LAYOUT.0, val) }
}
#[inline]
pub fn current_output_channel_layout<const N: usize>(
&self,
) -> os::Result<audio::ChannelLayout<N>> {
self.prop(InstancePropId::CURRENT_OUTPUT_CHANNEL_LAYOUT.0)
}
#[inline]
pub fn applicable_input_sample_rates(&self) -> os::Result<Vec<audio::ValueRange>> {
unsafe { self.prop_vec(InstancePropId::APPLICABLE_INPUT_SAMPLE_RATES.0) }
}
#[inline]
pub fn applicable_output_sample_rates(&self) -> os::Result<Vec<audio::ValueRange>> {
unsafe { self.prop_vec(InstancePropId::APPLICABLE_OUTPUT_SAMPLE_RATES.0) }
}
#[inline]
pub fn recommended_bit_rate_range(&self) -> os::Result<Vec<audio::ValueRange>> {
unsafe { self.prop_vec(InstancePropId::RECOMMENDED_BIT_RATE_RANGE.0) }
}
#[inline]
pub fn applicable_bit_rate_range(&self) -> os::Result<Vec<audio::ValueRange>> {
unsafe { self.prop_vec(InstancePropId::APPLICABLE_BIT_RATE_RANGE.0) }
}
#[inline]
pub fn supported_input_formats(&self) -> os::Result<Vec<audio::StreamBasicDesc>> {
unsafe { self.prop_vec(GlobalPropId::SUPPORTED_INPUT_FORMATS.0) }
}
#[inline]
pub fn supported_output_formats(&self) -> os::Result<Vec<audio::StreamBasicDesc>> {
unsafe { self.prop_vec(GlobalPropId::SUPPORTED_OUTPUT_FORMATS.0) }
}
#[doc(alias = "AudioCodecReset")]
pub fn reset(&mut self) -> os::Result {
unsafe { AudioCodecReset(self).result() }
}
}
impl<S> CodecRef<S>
where
S: State<Codec>,
{
#[inline]
pub fn supported_input_formats(&self) -> os::Result<Vec<audio::StreamBasicDesc>> {
self.0.supported_input_formats()
}
#[inline]
pub fn supported_output_formats(&self) -> os::Result<Vec<audio::StreamBasicDesc>> {
self.0.supported_output_formats()
}
#[inline]
pub fn bit_rate_control_mode(&self) -> os::Result<BitRateControlMode> {
self.0.bit_rate_control_mode()
}
#[inline]
pub fn recommended_bit_rate_range(&self) -> os::Result<Vec<audio::ValueRange>> {
self.0.recommended_bit_rate_range()
}
#[inline]
pub fn applicable_output_sample_rates(&self) -> os::Result<Vec<audio::ValueRange>> {
self.0.applicable_output_sample_rates()
}
#[inline]
pub fn applicable_input_sample_rates(&self) -> os::Result<Vec<audio::ValueRange>> {
self.0.applicable_input_sample_rates()
}
#[inline]
pub fn applicable_bit_rate_range(&self) -> os::Result<Vec<audio::ValueRange>> {
self.0.applicable_bit_rate_range()
}
#[inline]
pub fn current_target_bit_rate(&self) -> os::Result<u32> {
self.0.current_target_bit_rate()
}
#[inline]
pub fn magic_cookie(&self) -> os::Result<Vec<u8>> {
unsafe { self.0.prop_vec(InstancePropId::MAGIC_COOKIE.0) }
}
#[inline]
pub fn current_output_format(&self) -> os::Result<audio::StreamBasicDesc> {
let mut value = audio::StreamBasicDesc::default();
let mut size = std::mem::size_of::<audio::StreamBasicDesc>() as u32;
unsafe {
AudioCodecGetProperty(
&self.0,
InstancePropId::CURRENT_OUTPUT_FORMAT.0,
&mut size,
&mut value as *mut _ as _,
)
.result()?;
}
Ok(value)
}
#[inline]
pub fn current_input_format(&self) -> os::Result<audio::StreamBasicDesc> {
let mut value = audio::StreamBasicDesc::default();
let mut size = std::mem::size_of::<audio::StreamBasicDesc>() as u32;
unsafe {
AudioCodecGetProperty(
&self.0,
InstancePropId::CURRENT_INPUT_FORMAT.0,
&mut size,
&mut value as *mut _ as _,
)
.result()?;
}
Ok(value)
}
#[inline]
pub fn max_packet_byte_size(&self) -> os::Result<u32> {
let (mut value, mut size) = (0u32, 4u32);
unsafe {
AudioCodecGetProperty(
&self.0,
InstancePropId::MAXIMUM_PACKET_BYTE_SIZE.0,
&mut size,
&mut value as *mut u32 as *mut u8,
)
.result()?;
}
Ok(value)
}
#[inline]
pub fn input_buf_size(&self) -> os::Result<u32> {
let (mut value, mut size) = (0u32, 4u32);
unsafe {
AudioCodecGetProperty(
&self.0,
InstancePropId::INPUT_BUF_SIZE.0,
&mut size,
&mut value as *mut u32 as *mut u8,
)
.result()?;
}
Ok(value)
}
#[inline]
pub fn quality(&self) -> os::Result<u32> {
self.0.quality()
}
}
impl audio::Component {
pub fn open_codec(&self) -> os::Result<CodecRef<UninitializedState>> {
Ok(unsafe { std::mem::transmute(self.open()?) })
}
}
#[doc(alias = "AudioCodecProduceOutputPacketStatus")]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(u32)]
pub enum ProduceOutputPacketStatus {
#[doc(alias = "kAudioCodecProduceOutputPacketFailure")]
Failure = 1,
#[doc(alias = "kAudioCodecProduceOutputPacketSuccess")]
Success = 2,
#[doc(alias = "kAudioCodecProduceOutputPacketSuccessHasMore")]
SuccessHasMore = 3,
#[doc(alias = "kAudioCodecProduceOutputPacketNeedsMoreInputData")]
NeedsMoreInputData = 4,
#[doc(alias = "kAudioCodecProduceOutputPacketAtEOF")]
AtEof = 5,
#[doc(alias = "kAudioCodecProduceOutputPacketSuccessConcealed")]
SuccessConcealed = 6,
}
pub mod quality {
#[doc(alias = "kAudioCodecQuality_Max")]
pub const MAX: u32 = 0x7F;
#[doc(alias = "kAudioCodecQuality_High")]
pub const HIGH: u32 = 0x60;
#[doc(alias = "kAudioCodecQuality_Medium")]
pub const MEDIUM: u32 = 0x40;
#[doc(alias = "kAudioCodecQuality_Low")]
pub const LOW: u32 = 0x20;
#[doc(alias = "kAudioCodecQuality_Min")]
pub const MIN: u32 = 0x00;
}
unsafe extern "C-unwind" {
fn AudioCodecReset(in_codec: &mut Codec) -> os::Status;
fn AudioCodecInitialize(
in_codec: &mut Codec,
in_input_format: *const audio::StreamBasicDesc,
in_output_format: *const audio::StreamBasicDesc,
in_magic_cookie: *const u8,
in_magic_cookie_size: u32,
) -> os::Status;
fn AudioCodecUninitialize(in_codec: &mut Codec) -> os::Status;
fn AudioCodecAppendInputData(
in_codec: &mut Codec,
in_input_data: *const u8,
io_input_data_byte_size: &mut u32,
io_number_packets: *mut u32,
in_packet_description: *const audio::StreamPacketDesc,
) -> os::Status;
fn AudioCodecProduceOutputPackets(
in_codec: &mut Codec,
out_output_data: *mut u8,
io_output_data_byte_size: &mut u32,
io_number_packets: &mut u32,
out_packet_description: *mut audio::StreamPacketDesc,
out_status: &mut ProduceOutputPacketStatus,
) -> os::Status;
fn AudioCodecAppendInputBufferList(
in_codec: &mut Codec,
in_buffer_list: *const audio::BufList,
io_number_packets: &mut u32,
in_packet_descriptions: *const audio::StreamPacketDesc,
out_bytes_consumed: &mut u32,
) -> os::Status;
fn AudioCodecProduceOutputBufferList(
in_codec: &mut Codec,
io_buffer_list: &mut audio::BufList,
io_number_packets: &mut u32,
out_packet_description: *mut audio::StreamPacketDesc,
out_status: &mut os::Status,
) -> os::Status;
fn AudioCodecSetProperty(
in_codec: &mut Codec,
in_property_id: u32,
in_property_size: u32,
in_property_data: *const u8,
) -> os::Status;
fn AudioCodecGetProperty(
in_codec: &Codec,
in_property_id: u32,
io_property_data_size: &mut u32,
out_property_data: *mut u8,
) -> os::Status;
fn AudioCodecGetPropertyInfo(
in_codec: &Codec,
in_property_id: u32,
out_size: *mut u32,
out_writable: *mut bool,
) -> os::Status;
}
#[cfg(test)]
mod tests {
use audio::CodecRef;
use crate::{at::audio, four_cc_to_str};
#[test]
fn basics() {
let channels_per_frame = 2;
let sample_rate = 44_100.0;
let src_asbd = audio::StreamBasicDesc {
sample_rate,
channels_per_frame,
format: audio::Format::LINEAR_PCM,
format_flags: audio::FormatFlags::IS_FLOAT | audio::FormatFlags::IS_PACKED,
bytes_per_packet: 4 * channels_per_frame,
frames_per_packet: 1,
bytes_per_frame: 4 * channels_per_frame,
bits_per_channel: 32,
..Default::default()
};
let dst_asbd = audio::StreamBasicDesc {
sample_rate,
channels_per_frame,
format: audio::Format::MPEG4_AAC,
format_flags: audio::FormatFlags::ALL_CLEAR,
frames_per_packet: 1024,
..Default::default()
};
let desc = audio::ComponentDesc {
type_: audio::ENCODER_COMPONENT_TYPE,
sub_type: u32::from_be_bytes(*b"aac "),
..Default::default()
};
let inst = desc.into_iter().last().unwrap();
let codec = inst.open_codec().unwrap();
let recommended_bit_rate_range = codec.recommended_bit_rate_range().unwrap();
println!("{recommended_bit_rate_range:?}");
assert!(!recommended_bit_rate_range.is_empty());
let applicable_output_sample_rates = codec.applicable_output_sample_rates().unwrap();
println!("{applicable_output_sample_rates:?}");
assert!(!applicable_output_sample_rates.is_empty());
let supported_input_formats = codec.supported_input_formats().unwrap();
println!("{supported_input_formats:?}");
assert!(!supported_input_formats.is_empty());
let applicable_output_sample_rates = codec.applicable_output_sample_rates().unwrap();
println!("{applicable_output_sample_rates:?}");
assert!(!applicable_output_sample_rates.is_empty());
let mode = codec.bit_rate_control_mode().unwrap();
assert_eq!(audio::CodecBitRateControlMode::LongTermAverage, mode);
let codec = codec.initialize(&src_asbd, &dst_asbd, None).unwrap();
let cookie_info = codec.magic_cookie().unwrap();
assert!(!cookie_info.is_empty());
let max_packet_size = codec.max_packet_byte_size().unwrap();
assert_eq!(max_packet_size, 1536);
let quality = codec.quality().unwrap();
assert_eq!(quality, audio::codec_quality::MEDIUM);
}
#[test]
fn encoder_list() {
let desc = audio::ComponentDesc {
type_: audio::ENCODER_COMPONENT_TYPE,
manufacturer: audio::UnitManufacturer::APPLE.0,
..Default::default()
};
for comp in desc.into_iter() {
println!(
"desc {:?} {:?} {}",
comp.name(),
comp.desc(),
four_cc_to_str(&mut comp.desc().unwrap().sub_type.to_be_bytes())
);
}
}
#[test]
fn codec_init() {
let sample_rate = 48000.0;
let channels_per_frame = 2;
let src_asbd = audio::StreamBasicDesc {
sample_rate,
format: audio::Format(1819304813),
format_flags: audio::FormatFlags(41),
bytes_per_packet: 4,
frames_per_packet: 1,
bytes_per_frame: 4,
channels_per_frame,
bits_per_channel: 32,
reserved: 0,
};
let src_asbd2 = audio::StreamBasicDesc {
sample_rate,
channels_per_frame,
format: audio::Format::LINEAR_PCM,
format_flags: audio::FormatFlags::NATIVE_FLOAT_PACKED, bytes_per_packet: 4 * channels_per_frame,
frames_per_packet: 1,
bytes_per_frame: 4 * channels_per_frame,
bits_per_channel: 32,
..Default::default()
};
println!(
"
{src_asbd:#?}
{src_asbd2:#?}
"
);
let dst_asbd = audio::StreamBasicDesc {
sample_rate,
channels_per_frame,
format: audio::Format::MPEG4_AAC,
format_flags: audio::FormatFlags::ALL_CLEAR,
frames_per_packet: 1024,
..Default::default()
};
let encoder = CodecRef::new_apple_aac_encoder().unwrap();
let _encoder = encoder.initialize(&src_asbd2, &dst_asbd, None).unwrap();
}
}