Skip to main content

xaac_rs/
decoder.rs

1use std::ffi::c_void;
2use std::ptr;
3
4use crate::error::{Error, Result};
5use crate::ffi::{check_decoder, decoder_version};
6use crate::util::{AlignedBuffer, VersionInfo};
7
8const IA_DRC_DEC_CONFIG_PARAM_PCM_WDSZ: i32 = 0x0000;
9const IA_DRC_DEC_CONFIG_PARAM_SAMP_FREQ: i32 = 0x0001;
10const IA_DRC_DEC_CONFIG_PARAM_NUM_CHANNELS: i32 = 0x0002;
11const IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT: i32 = 0x0007;
12const IA_DRC_DEC_CONFIG_PARAM_INT_PRESENT: i32 = 0x0008;
13const IA_DRC_DEC_CONFIG_PARAM_FRAME_SIZE: i32 = 0x000E;
14const IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG: i32 = 0x0010;
15const IA_DRC_DEC_CONFIG_DRC_EFFECT_TYPE: i32 = 0x0011;
16const IA_DRC_DEC_CONFIG_DRC_TARGET_LOUDNESS: i32 = 0x0012;
17const IA_DRC_DEC_CONFIG_DRC_LOUD_NORM: i32 = 0x0013;
18const IA_DRC_DEC_CONFIG_PARAM_APPLY_CROSSFADE: i32 = 0x0017;
19const IA_DRC_DEC_CONFIG_PARAM_CONFIG_CHANGED: i32 = 0x0018;
20const IA_DRC_DEC_CONFIG_DRC_LOUDNESS_LEVELING: i32 = 0x0019;
21const IA_CMD_TYPE_INIT_CPY_BSF_BUFF: i32 = 0x0201;
22const IA_CMD_TYPE_INIT_CPY_IC_BSF_BUFF: i32 = 0x0202;
23const IA_CMD_TYPE_INIT_CPY_IL_BSF_BUFF: i32 = 0x0203;
24const IA_CMD_TYPE_INIT_CPY_IN_BSF_BUFF: i32 = 0x0205;
25const IA_XHEAAC_DEC_CONFIG_PARAM_DRC_LOUDNESS_LEVELING: i32 = 0x0029;
26const DECODER_MIN_INIT_BYTES: usize = 256;
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum DecoderTransport {
30    Auto,
31    Raw,
32    Mp4Raw,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum DrcEffectType {
37    None,
38    Night,
39    Noisy,
40    Limited,
41    LowLevel,
42    Dialog,
43    GeneralCompression,
44    Expanded,
45    Articulated,
46    Headphone,
47    PortableSpeaker,
48    StereoDownmix,
49}
50
51impl DrcEffectType {
52    fn raw(self) -> i32 {
53        match self {
54            Self::None => 0,
55            Self::Night => 1,
56            Self::Noisy => 2,
57            Self::Limited => 3,
58            Self::LowLevel => 4,
59            Self::Dialog => 5,
60            Self::GeneralCompression => 6,
61            Self::Expanded => 7,
62            Self::Articulated => 8,
63            Self::Headphone => 9,
64            Self::PortableSpeaker => 10,
65            Self::StereoDownmix => 11,
66        }
67    }
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub enum SbrMode {
72    Unknown,
73    Disabled,
74    Enabled,
75    Downsampled,
76    Esbr,
77}
78
79impl SbrMode {
80    fn frame_samples(self) -> u32 {
81        match self {
82            Self::Enabled => 2048,
83            Self::Esbr => 4096,
84            _ => 1024,
85        }
86    }
87}
88
89impl From<i32> for SbrMode {
90    fn from(value: i32) -> Self {
91        match value {
92            0 => Self::Disabled,
93            1 => Self::Enabled,
94            2 => Self::Downsampled,
95            3 => Self::Esbr,
96            _ => Self::Unknown,
97        }
98    }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102pub enum ChannelMode {
103    Mono,
104    Stereo,
105    DualMono,
106    ParametricStereo,
107    Unknown(i32),
108}
109
110impl From<i32> for ChannelMode {
111    fn from(value: i32) -> Self {
112        match value {
113            0 => Self::Mono,
114            1 => Self::Stereo,
115            2 => Self::DualMono,
116            3 => Self::ParametricStereo,
117            other => Self::Unknown(other),
118        }
119    }
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub struct RawStreamConfig {
124    pub sample_rate: u32,
125    pub audio_object_type: ProfileHint,
126}
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub enum ProfileHint {
130    AacLc,
131    HeAacV1,
132    AacLd,
133    HeAacV2,
134    AacEld,
135    Usac,
136}
137
138impl ProfileHint {
139    fn aot(self) -> i32 {
140        match self {
141            Self::AacLc => libxaac_sys::AOT_AAC_LC as i32,
142            Self::HeAacV1 => libxaac_sys::AOT_SBR as i32,
143            Self::AacLd => libxaac_sys::AOT_AAC_LD as i32,
144            Self::HeAacV2 => libxaac_sys::AOT_PS as i32,
145            Self::AacEld => libxaac_sys::AOT_AAC_ELD as i32,
146            Self::Usac => libxaac_sys::AOT_USAC as i32,
147        }
148    }
149}
150
151#[derive(Debug, Clone, PartialEq)]
152pub struct DecoderDrcConfig {
153    pub enabled: bool,
154    pub cut: f32,
155    pub boost: f32,
156    pub target_level: u8,
157    pub heavy_compression: bool,
158    pub effect_type: DrcEffectType,
159    pub target_loudness: Option<i32>,
160    pub loudness_leveling: Option<bool>,
161}
162
163impl Default for DecoderDrcConfig {
164    fn default() -> Self {
165        Self {
166            enabled: true,
167            cut: 1.0,
168            boost: 1.0,
169            target_level: 108,
170            heavy_compression: false,
171            effect_type: DrcEffectType::None,
172            target_loudness: None,
173            loudness_leveling: None,
174        }
175    }
176}
177
178#[derive(Debug, Clone)]
179pub struct DecoderConfig {
180    pub transport: DecoderTransport,
181    pub pcm_word_size: u16,
182    pub raw: Option<RawStreamConfig>,
183    pub downmix_to_mono: bool,
184    pub to_stereo: bool,
185    pub downsample_sbr: bool,
186    pub max_channels: u8,
187    pub coupling_channels: u8,
188    pub downmix_to_stereo: bool,
189    pub disable_sync: bool,
190    pub auto_sbr_upsample: bool,
191    pub ld_frame_480: bool,
192    pub hq_esbr: bool,
193    pub ps_enable: bool,
194    pub peak_limiter: bool,
195    pub frame_length_960: bool,
196    pub error_concealment: bool,
197    pub enable_esbr: bool,
198    pub drc: DecoderDrcConfig,
199}
200
201impl Default for DecoderConfig {
202    fn default() -> Self {
203        Self {
204            transport: DecoderTransport::Auto,
205            pcm_word_size: 16,
206            raw: None,
207            downmix_to_mono: false,
208            to_stereo: false,
209            downsample_sbr: false,
210            max_channels: 2,
211            coupling_channels: 0,
212            downmix_to_stereo: false,
213            disable_sync: false,
214            auto_sbr_upsample: true,
215            ld_frame_480: false,
216            hq_esbr: false,
217            ps_enable: false,
218            peak_limiter: true,
219            frame_length_960: false,
220            error_concealment: true,
221            enable_esbr: false,
222            drc: DecoderDrcConfig::default(),
223        }
224    }
225}
226
227impl DecoderConfig {
228    fn validate(&self) -> Result<()> {
229        if !matches!(self.pcm_word_size, 16 | 24) {
230            return Err(Error::InvalidConfig("pcm_word_size must be 16 or 24"));
231        }
232        if self.max_channels == 0 {
233            return Err(Error::InvalidConfig(
234                "max_channels must be greater than zero",
235            ));
236        }
237        if matches!(
238            self.transport,
239            DecoderTransport::Raw | DecoderTransport::Mp4Raw
240        ) && self.raw.is_none()
241        {
242            return Err(Error::InvalidConfig(
243                "raw transport requires RawStreamConfig",
244            ));
245        }
246        Ok(())
247    }
248}
249
250#[derive(Debug, Clone, PartialEq, Eq)]
251pub struct StreamInfo {
252    pub sample_rate: u32,
253    pub channels: u16,
254    pub channel_mask: u32,
255    pub channel_mode: Option<ChannelMode>,
256    pub pcm_word_size: u16,
257    pub sbr_mode: SbrMode,
258    pub audio_object_type: i32,
259    pub drc_effect_type: Option<DrcEffectType>,
260    pub drc_target_loudness: Option<i32>,
261    pub drc_loudness_norm: Option<i32>,
262    pub loudness_leveling: Option<bool>,
263    pub preroll_frames: Option<u32>,
264    pub drc_config_changed: Option<bool>,
265    pub drc_apply_crossfade: Option<bool>,
266    pub extension_elements: Option<u32>,
267    pub config_extensions: Option<u32>,
268    pub gain_payload_len: Option<u32>,
269    pub drc_active: bool,
270}
271
272#[derive(Debug, Clone, PartialEq, Eq)]
273pub struct DecodeProgress {
274    pub initialized: bool,
275    pub stream_info: Option<StreamInfo>,
276}
277
278#[derive(Debug, Clone, PartialEq, Eq)]
279pub enum DecodeStatus {
280    Frame(DecodedFrame),
281    NeedMoreInput(DecodeProgress),
282    EndOfStream,
283}
284
285#[derive(Debug, Clone, PartialEq, Eq)]
286pub struct DecodedFrame {
287    pub pcm: Vec<u8>,
288    pub bytes_consumed: usize,
289    pub stream_info: StreamInfo,
290}
291
292impl DecodedFrame {
293    pub fn pcm_i16(&self) -> Option<Vec<i16>> {
294        if self.stream_info.pcm_word_size != 16 || self.pcm.len() % 2 != 0 {
295            return None;
296        }
297
298        Some(
299            self.pcm
300                .chunks_exact(2)
301                .map(|chunk| i16::from_le_bytes([chunk[0], chunk[1]]))
302                .collect(),
303        )
304    }
305
306    pub fn pcm_i24(&self) -> Option<Vec<i32>> {
307        if self.stream_info.pcm_word_size != 24 || self.pcm.len() % 3 != 0 {
308            return None;
309        }
310
311        Some(
312            self.pcm
313                .chunks_exact(3)
314                .map(|chunk| {
315                    let value = i32::from(chunk[0])
316                        | (i32::from(chunk[1]) << 8)
317                        | (i32::from(chunk[2]) << 16);
318                    if (value & 0x0080_0000) != 0 {
319                        value | !0x00ff_ffff
320                    } else {
321                        value
322                    }
323                })
324                .collect(),
325        )
326    }
327}
328
329#[derive(Debug)]
330struct DrcDecoder {
331    api: AlignedBuffer,
332    memtabs: AlignedBuffer,
333    memblocks: Vec<AlignedBuffer>,
334    input_index: usize,
335    output_index: usize,
336}
337
338impl DrcDecoder {
339    fn new(stream_info: &StreamInfo) -> Result<Self> {
340        let mut api_size = 0u32;
341        check_decoder(unsafe {
342            libxaac_sys::ia_drc_dec_api(
343                ptr::null_mut(),
344                libxaac_sys::IA_API_CMD_GET_API_SIZE as i32,
345                0,
346                (&mut api_size as *mut _) as *mut c_void,
347            )
348        })?;
349
350        let api = AlignedBuffer::new(api_size as usize, 8)?;
351        check_decoder(unsafe {
352            libxaac_sys::ia_drc_dec_api(
353                api.as_ptr().cast::<c_void>(),
354                libxaac_sys::IA_API_CMD_INIT as i32,
355                libxaac_sys::IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS as i32,
356                ptr::null_mut(),
357            )
358        })?;
359
360        let mut drc = Self {
361            api,
362            memtabs: AlignedBuffer::new(4, 4)?,
363            memblocks: Vec::new(),
364            input_index: 2,
365            output_index: 3,
366        };
367        drc.set_config(
368            IA_DRC_DEC_CONFIG_PARAM_SAMP_FREQ,
369            stream_info.sample_rate as i32,
370        )?;
371        drc.set_config(
372            IA_DRC_DEC_CONFIG_PARAM_NUM_CHANNELS,
373            i32::from(stream_info.channels),
374        )?;
375        drc.set_config(
376            IA_DRC_DEC_CONFIG_PARAM_PCM_WDSZ,
377            i32::from(stream_info.pcm_word_size),
378        )?;
379        drc.set_config(
380            IA_DRC_DEC_CONFIG_PARAM_FRAME_SIZE,
381            stream_info.sbr_mode.frame_samples() as i32,
382        )?;
383        drc.allocate_memory()?;
384        Ok(drc)
385    }
386
387    fn allocate_memory(&mut self) -> Result<()> {
388        let mut memtabs_size = 0u32;
389        check_decoder(self.call_with_value(
390            libxaac_sys::IA_API_CMD_GET_MEMTABS_SIZE as i32,
391            0,
392            (&mut memtabs_size as *mut _) as *mut c_void,
393        ))?;
394        self.memtabs = AlignedBuffer::new(memtabs_size as usize, 8)?;
395        check_decoder(self.call_with_value(
396            libxaac_sys::IA_API_CMD_SET_MEMTABS_PTR as i32,
397            0,
398            self.memtabs.as_ptr().cast::<c_void>(),
399        ))?;
400        check_decoder(self.call(
401            libxaac_sys::IA_API_CMD_INIT as i32,
402            libxaac_sys::IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS as i32,
403            ptr::null_mut(),
404        ))?;
405
406        let mut mem_count = 0i32;
407        check_decoder(self.call_with_value(
408            libxaac_sys::IA_API_CMD_GET_N_MEMTABS as i32,
409            0,
410            (&mut mem_count as *mut _) as *mut c_void,
411        ))?;
412
413        for index in 0..mem_count {
414            let mut size = 0u32;
415            let mut alignment = 0u32;
416            check_decoder(self.call_with_value(
417                libxaac_sys::IA_API_CMD_GET_MEM_INFO_SIZE as i32,
418                index,
419                (&mut size as *mut _) as *mut c_void,
420            ))?;
421            check_decoder(self.call_with_value(
422                libxaac_sys::IA_API_CMD_GET_MEM_INFO_ALIGNMENT as i32,
423                index,
424                (&mut alignment as *mut _) as *mut c_void,
425            ))?;
426            let block = AlignedBuffer::new(size as usize, alignment.max(1) as usize)?;
427            check_decoder(self.call_with_value(
428                libxaac_sys::IA_API_CMD_SET_MEM_PTR as i32,
429                index,
430                block.as_ptr().cast::<c_void>(),
431            ))?;
432            self.memblocks.push(block);
433        }
434
435        Ok(())
436    }
437
438    fn sync_stream_info(&mut self, info: &StreamInfo) -> Result<()> {
439        self.set_config(
440            IA_DRC_DEC_CONFIG_PARAM_FRAME_SIZE,
441            info.sbr_mode.frame_samples() as i32,
442        )?;
443        self.set_config(IA_DRC_DEC_CONFIG_PARAM_SAMP_FREQ, info.sample_rate as i32)?;
444        self.set_config(
445            IA_DRC_DEC_CONFIG_PARAM_NUM_CHANNELS,
446            i32::from(info.channels),
447        )?;
448        self.set_config(
449            IA_DRC_DEC_CONFIG_PARAM_PCM_WDSZ,
450            i32::from(info.pcm_word_size),
451        )?;
452        if let Some(loudness) = info.drc_target_loudness {
453            self.set_config(IA_DRC_DEC_CONFIG_DRC_TARGET_LOUDNESS, loudness)?;
454        }
455        if let Some(loud_norm) = info.drc_loudness_norm {
456            self.set_config(IA_DRC_DEC_CONFIG_DRC_LOUD_NORM, loud_norm)?;
457        }
458        if let Some(effect) = info.drc_effect_type {
459            self.set_config(IA_DRC_DEC_CONFIG_DRC_EFFECT_TYPE, effect.raw())?;
460        }
461        if let Some(leveling) = info.loudness_leveling {
462            self.set_config(IA_DRC_DEC_CONFIG_DRC_LOUDNESS_LEVELING, i32::from(leveling))?;
463        }
464        if let Some(changed) = info.drc_config_changed {
465            self.set_config(IA_DRC_DEC_CONFIG_PARAM_CONFIG_CHANGED, i32::from(changed))?;
466        }
467        if let Some(crossfade) = info.drc_apply_crossfade {
468            self.set_config(
469                IA_DRC_DEC_CONFIG_PARAM_APPLY_CROSSFADE,
470                i32::from(crossfade),
471            )?;
472        }
473        Ok(())
474    }
475
476    fn copy_split_payload(
477        &mut self,
478        input_len_cmd: i32,
479        init_cmd: i32,
480        payload: &[u8],
481        bits_format: i32,
482    ) -> Result<()> {
483        if payload.is_empty() {
484            return Ok(());
485        }
486        self.set_config(IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, bits_format)?;
487        self.copy_to_input(payload)?;
488        let mut size = payload.len() as i32;
489        check_decoder(self.call_with_value(
490            input_len_cmd,
491            0,
492            (&mut size as *mut _) as *mut c_void,
493        ))?;
494        check_decoder(self.call(
495            libxaac_sys::IA_API_CMD_INIT as i32,
496            init_cmd,
497            ptr::null_mut(),
498        ))
499    }
500
501    fn copy_to_input(&mut self, data: &[u8]) -> Result<()> {
502        let input = self
503            .memblocks
504            .get(self.input_index)
505            .ok_or(Error::InvalidConfig("drc input buffer missing"))?
506            .as_ptr();
507        let capacity = self.input_capacity();
508        if data.len() > capacity {
509            return Err(Error::InputTooLarge {
510                capacity,
511                actual: data.len(),
512            });
513        }
514        unsafe {
515            ptr::copy_nonoverlapping(data.as_ptr(), input, data.len());
516            if data.len() < capacity {
517                ptr::write_bytes(input.add(data.len()), 0, capacity - data.len());
518            }
519        }
520        Ok(())
521    }
522
523    fn input_capacity(&self) -> usize {
524        self.memblocks
525            .get(self.input_index)
526            .map(|_| {
527                self.query_mem_size(self.input_index as i32)
528                    .unwrap_or_default() as usize
529            })
530            .unwrap_or_default()
531    }
532
533    fn output_capacity(&self) -> usize {
534        self.memblocks
535            .get(self.output_index)
536            .map(|_| {
537                self.query_mem_size(self.output_index as i32)
538                    .unwrap_or_default() as usize
539            })
540            .unwrap_or_default()
541    }
542
543    fn process_pcm(
544        &mut self,
545        pcm: &[u8],
546        info: &StreamInfo,
547        gain_payload: Option<&[u8]>,
548    ) -> Result<Vec<u8>> {
549        self.sync_stream_info(info)?;
550        self.copy_to_input(pcm)?;
551        if let Some(gain_payload) = gain_payload.filter(|payload| !payload.is_empty()) {
552            self.set_config(IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, 1)?;
553            let gain_stream_flag = 1i32;
554            self.call_with_value(
555                libxaac_sys::IA_API_CMD_SET_INPUT_BYTES as i32,
556                0,
557                (&mut (pcm.len() as i32) as *mut _) as *mut c_void,
558            );
559            self.copy_to_input(gain_payload)?;
560            let mut gain_len = gain_payload.len() as i32;
561            check_decoder(self.call_with_value(
562                0x000B,
563                0,
564                (&mut gain_len as *mut _) as *mut c_void,
565            ))?;
566            self.set_config(IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG, gain_stream_flag)?;
567            check_decoder(self.call(
568                libxaac_sys::IA_API_CMD_INIT as i32,
569                IA_CMD_TYPE_INIT_CPY_BSF_BUFF,
570                ptr::null_mut(),
571            ))?;
572            self.copy_to_input(pcm)?;
573        }
574
575        let mut pcm_len = pcm.len() as i32;
576        check_decoder(self.call_with_value(
577            libxaac_sys::IA_API_CMD_SET_INPUT_BYTES as i32,
578            0,
579            (&mut pcm_len as *mut _) as *mut c_void,
580        ))?;
581        check_decoder(self.call(
582            libxaac_sys::IA_API_CMD_EXECUTE as i32,
583            libxaac_sys::IA_CMD_TYPE_DO_EXECUTE as i32,
584            ptr::null_mut(),
585        ))?;
586        let out = self
587            .memblocks
588            .get(self.output_index)
589            .ok_or(Error::InvalidConfig("drc output buffer missing"))?
590            .as_ptr();
591        let len = pcm.len().min(self.output_capacity());
592        Ok(unsafe { std::slice::from_raw_parts(out, len) }.to_vec())
593    }
594
595    fn query_mem_size(&self, index: i32) -> Result<u32> {
596        let mut size = 0u32;
597        check_decoder(self.call_with_value(
598            libxaac_sys::IA_API_CMD_GET_MEM_INFO_SIZE as i32,
599            index,
600            (&mut size as *mut _) as *mut c_void,
601        ))?;
602        Ok(size)
603    }
604
605    fn set_config(&mut self, index: i32, value: i32) -> Result<()> {
606        let mut value = value;
607        check_decoder(self.call_with_value(
608            libxaac_sys::IA_API_CMD_SET_CONFIG_PARAM as i32,
609            index,
610            (&mut value as *mut _) as *mut c_void,
611        ))
612    }
613
614    fn call(&self, cmd: i32, idx: i32, value: *mut c_void) -> i32 {
615        unsafe { libxaac_sys::ia_drc_dec_api(self.api.as_ptr().cast::<c_void>(), cmd, idx, value) }
616    }
617
618    fn call_with_value(&self, cmd: i32, idx: i32, value: *mut c_void) -> i32 {
619        self.call(cmd, idx, value)
620    }
621}
622
623#[derive(Debug)]
624pub struct Decoder {
625    config: DecoderConfig,
626    version: VersionInfo,
627    api: AlignedBuffer,
628    memtabs: AlignedBuffer,
629    memblocks: Vec<AlignedBuffer>,
630    input_index: usize,
631    output_index: usize,
632    input_capacity: usize,
633    initialized: bool,
634    input_over_signaled: bool,
635    finished: bool,
636    pending_input: Vec<u8>,
637    cached_info: Option<StreamInfo>,
638    drc_decoder: Option<DrcDecoder>,
639}
640
641impl Decoder {
642    pub fn new(config: DecoderConfig) -> Result<Self> {
643        config.validate()?;
644
645        let version = decoder_version();
646        let mut api_size = 0u32;
647        check_decoder(unsafe {
648            libxaac_sys::ixheaacd_dec_api(
649                ptr::null_mut(),
650                libxaac_sys::IA_API_CMD_GET_API_SIZE as i32,
651                0,
652                (&mut api_size as *mut _) as *mut c_void,
653            )
654        })?;
655
656        let api = AlignedBuffer::new(api_size as usize, 4)?;
657        check_decoder(unsafe {
658            libxaac_sys::ixheaacd_dec_api(
659                api.as_ptr().cast::<c_void>(),
660                libxaac_sys::IA_API_CMD_INIT as i32,
661                libxaac_sys::IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS as i32,
662                ptr::null_mut(),
663            )
664        })?;
665
666        let mut decoder = Self {
667            config,
668            version,
669            api,
670            memtabs: AlignedBuffer::new(4, 4)?,
671            memblocks: Vec::new(),
672            input_index: 0,
673            output_index: 0,
674            input_capacity: 0,
675            initialized: false,
676            input_over_signaled: false,
677            finished: false,
678            pending_input: Vec::new(),
679            cached_info: None,
680            drc_decoder: None,
681        };
682        decoder.apply_config()?;
683        decoder.allocate_memory()?;
684        Ok(decoder)
685    }
686
687    pub fn config(&self) -> &DecoderConfig {
688        &self.config
689    }
690
691    pub fn version(&self) -> &VersionInfo {
692        &self.version
693    }
694
695    pub fn input_capacity(&self) -> usize {
696        self.input_capacity
697    }
698
699    pub fn stream_info(&self) -> Option<&StreamInfo> {
700        self.cached_info.as_ref()
701    }
702
703    pub fn probe_stream_info(&mut self, data: &[u8]) -> Result<StreamInfo> {
704        if self.cached_info.is_some() {
705            return Ok(self.cached_info.clone().expect("cached stream info"));
706        }
707        self.pending_input.extend_from_slice(data);
708        loop {
709            match self.drive_initialization(data.is_empty())? {
710                InitState::Ready => return self.refresh_stream_info(),
711                InitState::NeedMoreInput => {
712                    self.ensure_input_over()?;
713                }
714                InitState::Continue => {}
715                InitState::EndOfStream => {
716                    return Err(Error::DecoderError(libxaac_sys::IA_FATAL_ERROR as i32));
717                }
718            }
719        }
720    }
721
722    pub fn decode(&mut self, input: &[u8]) -> Result<DecodedFrame> {
723        match self.decode_stream_chunk(input)? {
724            DecodeStatus::Frame(frame) => Ok(frame),
725            DecodeStatus::NeedMoreInput(_) => Err(Error::NeedMoreInput),
726            DecodeStatus::EndOfStream => Err(Error::EndOfStream),
727        }
728    }
729
730    pub fn decode_stream_chunk(&mut self, input: &[u8]) -> Result<DecodeStatus> {
731        if self.finished {
732            return Ok(DecodeStatus::EndOfStream);
733        }
734        self.pending_input.extend_from_slice(input);
735        self.drive(false)
736    }
737
738    pub fn finish(&mut self) -> Result<DecodeStatus> {
739        if self.finished {
740            return Ok(DecodeStatus::EndOfStream);
741        }
742        self.drive(true)
743    }
744
745    pub fn signal_end_of_input(&mut self) -> Result<()> {
746        self.ensure_input_over()
747    }
748
749    fn drive(&mut self, finalize: bool) -> Result<DecodeStatus> {
750        loop {
751            if !self.initialized {
752                match self.drive_initialization(finalize)? {
753                    InitState::Ready => {}
754                    InitState::NeedMoreInput => {
755                        return Ok(DecodeStatus::NeedMoreInput(self.progress()));
756                    }
757                    InitState::Continue => continue,
758                    InitState::EndOfStream => {
759                        self.finished = true;
760                        return Ok(DecodeStatus::EndOfStream);
761                    }
762                }
763            }
764
765            match self.execute_once(finalize)? {
766                ExecuteState::Frame(frame) => return Ok(DecodeStatus::Frame(frame)),
767                ExecuteState::NeedMoreInput => {
768                    return Ok(DecodeStatus::NeedMoreInput(self.progress()));
769                }
770                ExecuteState::Continue => continue,
771                ExecuteState::EndOfStream => {
772                    self.finished = true;
773                    return Ok(DecodeStatus::EndOfStream);
774                }
775            }
776        }
777    }
778
779    fn drive_initialization(&mut self, finalize: bool) -> Result<InitState> {
780        if !finalize && self.pending_input.len() < DECODER_MIN_INIT_BYTES {
781            return Ok(InitState::NeedMoreInput);
782        }
783        if self.pending_input.is_empty() && finalize {
784            self.ensure_input_over()?;
785        }
786        if self.pending_input.is_empty() && self.input_over_signaled {
787            return Ok(InitState::EndOfStream);
788        }
789
790        let bytes = self.load_input_window();
791        if bytes == 0 {
792            return Ok(InitState::NeedMoreInput);
793        }
794
795        let mut bytes_i32 = bytes as i32;
796        check_decoder(self.call_with_value(
797            libxaac_sys::IA_API_CMD_SET_INPUT_BYTES as i32,
798            0,
799            (&mut bytes_i32 as *mut _) as *mut c_void,
800        ))?;
801        let status = self.call(
802            libxaac_sys::IA_API_CMD_INIT as i32,
803            libxaac_sys::IA_CMD_TYPE_INIT_PROCESS as i32,
804            ptr::null_mut(),
805        );
806        if is_fatal(status) {
807            return Err(Error::DecoderError(status));
808        }
809
810        let consumed = self.query_consumed()? as usize;
811        self.consume_pending(consumed)?;
812
813        let mut init_done = 0i32;
814        check_decoder(self.call_with_value(
815            libxaac_sys::IA_API_CMD_INIT as i32,
816            libxaac_sys::IA_CMD_TYPE_INIT_DONE_QUERY as i32,
817            (&mut init_done as *mut _) as *mut c_void,
818        ))?;
819
820        if init_done != 0 {
821            self.initialized = true;
822            let info = self.refresh_stream_info()?;
823            self.try_initialize_drc(&info)?;
824            return Ok(InitState::Ready);
825        }
826
827        if !finalize && consumed == 0 && bytes < self.input_capacity {
828            return Ok(InitState::NeedMoreInput);
829        }
830
831        if self.pending_input.is_empty() && finalize {
832            self.ensure_input_over()?;
833            if self.pending_input.is_empty() && self.input_over_signaled {
834                return Ok(InitState::NeedMoreInput);
835            }
836        }
837
838        if self.pending_input.is_empty() {
839            Ok(InitState::NeedMoreInput)
840        } else {
841            Ok(InitState::Continue)
842        }
843    }
844
845    fn execute_once(&mut self, finalize: bool) -> Result<ExecuteState> {
846        if self.pending_input.is_empty() && finalize {
847            self.ensure_input_over()?;
848        }
849        if self.pending_input.is_empty() && self.input_over_signaled {
850            return Ok(ExecuteState::EndOfStream);
851        }
852
853        let bytes = self.load_input_window();
854        let mut bytes_i32 = bytes as i32;
855        check_decoder(self.call_with_value(
856            libxaac_sys::IA_API_CMD_SET_INPUT_BYTES as i32,
857            0,
858            (&mut bytes_i32 as *mut _) as *mut c_void,
859        ))?;
860        let status = self.call(
861            libxaac_sys::IA_API_CMD_EXECUTE as i32,
862            libxaac_sys::IA_CMD_TYPE_DO_EXECUTE as i32,
863            ptr::null_mut(),
864        );
865        if is_fatal(status) {
866            return Err(Error::DecoderError(status));
867        }
868
869        let consumed = self.query_consumed()? as usize;
870        self.consume_pending(consumed)?;
871
872        let mut done = 0i32;
873        check_decoder(self.call_with_value(
874            libxaac_sys::IA_API_CMD_EXECUTE as i32,
875            libxaac_sys::IA_CMD_TYPE_DONE_QUERY as i32,
876            (&mut done as *mut _) as *mut c_void,
877        ))?;
878
879        let mut out_bytes = 0i32;
880        check_decoder(self.call_with_value(
881            libxaac_sys::IA_API_CMD_GET_OUTPUT_BYTES as i32,
882            0,
883            (&mut out_bytes as *mut _) as *mut c_void,
884        ))?;
885
886        let info = self.refresh_stream_info()?;
887        let mut pcm = self.read_output_bytes(out_bytes.max(0) as usize)?;
888        if !pcm.is_empty() {
889            let gain_payload = if info.drc_active {
890                self.read_optional_buffer(
891                    libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF as i32,
892                    libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN as i32,
893                )?
894            } else {
895                None
896            };
897            if let Some(drc) = self.drc_decoder.as_mut().filter(|_| info.drc_active) {
898                pcm = drc.process_pcm(&pcm, &info, gain_payload.as_deref())?;
899            }
900            return Ok(ExecuteState::Frame(DecodedFrame {
901                pcm,
902                bytes_consumed: consumed,
903                stream_info: info,
904            }));
905        }
906
907        if !finalize && consumed == 0 && bytes < self.input_capacity && done == 0 {
908            return Ok(ExecuteState::NeedMoreInput);
909        }
910
911        if done != 0 && self.pending_input.is_empty() && self.input_over_signaled {
912            return Ok(ExecuteState::EndOfStream);
913        }
914        if self.pending_input.is_empty() && !finalize && !self.input_over_signaled {
915            return Ok(ExecuteState::NeedMoreInput);
916        }
917        if self.pending_input.is_empty() && finalize && self.input_over_signaled {
918            return Ok(ExecuteState::EndOfStream);
919        }
920        Ok(ExecuteState::Continue)
921    }
922
923    fn apply_config(&mut self) -> Result<()> {
924        self.set_config(
925            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_PCM_WDSZ as i32,
926            self.config.pcm_word_size as i32,
927        )?;
928        self.set_config(
929            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_DOWNMIX as i32,
930            i32::from(self.config.downmix_to_mono),
931        )?;
932        self.set_config(
933            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_TOSTEREO as i32,
934            i32::from(self.config.to_stereo),
935        )?;
936        self.set_config(
937            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_DSAMPLE as i32,
938            i32::from(self.config.downsample_sbr),
939        )?;
940        self.set_config(
941            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_ISMP4 as i32,
942            i32::from(matches!(self.config.transport, DecoderTransport::Mp4Raw)),
943        )?;
944        self.set_config(
945            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_MAX_CHANNEL as i32,
946            i32::from(self.config.max_channels),
947        )?;
948        self.set_config(
949            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_COUP_CHANNEL as i32,
950            i32::from(self.config.coupling_channels),
951        )?;
952        self.set_config(
953            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_DOWNMIX_STEREO as i32,
954            i32::from(self.config.downmix_to_stereo),
955        )?;
956        self.set_config(
957            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_DISABLE_SYNC as i32,
958            i32::from(
959                self.config.disable_sync
960                    || matches!(
961                        self.config.transport,
962                        DecoderTransport::Raw | DecoderTransport::Mp4Raw
963                    ),
964            ),
965        )?;
966        self.set_config(
967            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_AUTO_SBR_UPSAMPLE as i32,
968            i32::from(self.config.auto_sbr_upsample),
969        )?;
970        self.set_config_f32(
971            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_CUT as i32,
972            self.config.drc.cut,
973        )?;
974        self.set_config_f32(
975            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_BOOST as i32,
976            self.config.drc.boost,
977        )?;
978        self.set_config(
979            libxaac_sys::IA_XHEAAC_DEC_CONFIG_PARAM_DRC_TARGET_LEVEL as i32,
980            i32::from(self.config.drc.target_level),
981        )?;
982        self.set_config(
983            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_HEAVY_COMP as i32,
984            i32::from(self.config.drc.heavy_compression),
985        )?;
986        self.set_config(
987            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_EFFECT_TYPE as i32,
988            self.config.drc.effect_type.raw(),
989        )?;
990        if let Some(target_loudness) = self.config.drc.target_loudness {
991            self.set_config(
992                libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LOUDNESS as i32,
993                target_loudness,
994            )?;
995        }
996        if let Some(leveling) = self.config.drc.loudness_leveling {
997            let _ = self.set_config_optional(
998                IA_XHEAAC_DEC_CONFIG_PARAM_DRC_LOUDNESS_LEVELING,
999                i32::from(leveling),
1000            );
1001        }
1002        self.set_config(
1003            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_FRAMESIZE as i32,
1004            i32::from(self.config.ld_frame_480),
1005        )?;
1006        self.set_config(
1007            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_HQ_ESBR as i32,
1008            i32::from(self.config.hq_esbr),
1009        )?;
1010        self.set_config(
1011            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_PS_ENABLE as i32,
1012            i32::from(self.config.ps_enable),
1013        )?;
1014        self.set_config(
1015            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_PEAK_LIMITER as i32,
1016            i32::from(!self.config.peak_limiter),
1017        )?;
1018        self.set_config(
1019            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_FRAMELENGTH_FLAG as i32,
1020            i32::from(self.config.frame_length_960),
1021        )?;
1022        self.set_config(
1023            libxaac_sys::IA_XHEAAC_DEC_CONFIG_ERROR_CONCEALMENT as i32,
1024            i32::from(self.config.error_concealment),
1025        )?;
1026        self.set_config(
1027            libxaac_sys::IA_XHEAAC_DEC_CONFIG_PARAM_ESBR as i32,
1028            i32::from(self.config.enable_esbr),
1029        )?;
1030
1031        if let Some(raw) = self.config.raw {
1032            self.set_config(
1033                libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_SAMP_FREQ as i32,
1034                raw.sample_rate as i32,
1035            )?;
1036            self.set_config(
1037                libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_AOT as i32,
1038                raw.audio_object_type.aot(),
1039            )?;
1040        }
1041        Ok(())
1042    }
1043
1044    fn allocate_memory(&mut self) -> Result<()> {
1045        let mut memtabs_size = 0u32;
1046        check_decoder(self.call_with_value(
1047            libxaac_sys::IA_API_CMD_GET_MEMTABS_SIZE as i32,
1048            0,
1049            (&mut memtabs_size as *mut _) as *mut c_void,
1050        ))?;
1051        self.memtabs = AlignedBuffer::new(memtabs_size as usize, 4)?;
1052        check_decoder(self.call_with_value(
1053            libxaac_sys::IA_API_CMD_SET_MEMTABS_PTR as i32,
1054            0,
1055            self.memtabs.as_ptr().cast::<c_void>(),
1056        ))?;
1057
1058        check_decoder(self.call(
1059            libxaac_sys::IA_API_CMD_INIT as i32,
1060            libxaac_sys::IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS as i32,
1061            ptr::null_mut(),
1062        ))?;
1063
1064        let mut mem_count = 0i32;
1065        check_decoder(self.call_with_value(
1066            libxaac_sys::IA_API_CMD_GET_N_MEMTABS as i32,
1067            0,
1068            (&mut mem_count as *mut _) as *mut c_void,
1069        ))?;
1070
1071        for index in 0..mem_count {
1072            let mut size = 0u32;
1073            let mut alignment = 0u32;
1074            let mut mem_type = 0u32;
1075
1076            check_decoder(self.call_with_value(
1077                libxaac_sys::IA_API_CMD_GET_MEM_INFO_SIZE as i32,
1078                index,
1079                (&mut size as *mut _) as *mut c_void,
1080            ))?;
1081            check_decoder(self.call_with_value(
1082                libxaac_sys::IA_API_CMD_GET_MEM_INFO_ALIGNMENT as i32,
1083                index,
1084                (&mut alignment as *mut _) as *mut c_void,
1085            ))?;
1086            check_decoder(self.call_with_value(
1087                libxaac_sys::IA_API_CMD_GET_MEM_INFO_TYPE as i32,
1088                index,
1089                (&mut mem_type as *mut _) as *mut c_void,
1090            ))?;
1091
1092            let block = AlignedBuffer::new(size as usize, alignment.max(1) as usize)?;
1093            let ptr = block.as_ptr().cast::<c_void>();
1094            check_decoder(self.call_with_value(
1095                libxaac_sys::IA_API_CMD_SET_MEM_PTR as i32,
1096                index,
1097                ptr,
1098            ))?;
1099
1100            if mem_type == libxaac_sys::IA_MEMTYPE_INPUT {
1101                self.input_index = self.memblocks.len();
1102                self.input_capacity = size as usize;
1103            } else if mem_type == libxaac_sys::IA_MEMTYPE_OUTPUT {
1104                self.output_index = self.memblocks.len();
1105            }
1106
1107            self.memblocks.push(block);
1108        }
1109
1110        Ok(())
1111    }
1112
1113    fn try_initialize_drc(&mut self, info: &StreamInfo) -> Result<()> {
1114        if !self.config.drc.enabled || self.drc_decoder.is_some() {
1115            return Ok(());
1116        }
1117        if info.extension_elements.unwrap_or(0) == 0
1118            && info.config_extensions.unwrap_or(0) == 0
1119            && info.gain_payload_len.unwrap_or(0) == 0
1120        {
1121            return Ok(());
1122        }
1123
1124        let mut drc = DrcDecoder::new(info)?;
1125        if let Some(payloads) = self.read_extension_payloads()? {
1126            for payload in &payloads.loudness_payloads {
1127                drc.copy_split_payload(0x000D, IA_CMD_TYPE_INIT_CPY_IL_BSF_BUFF, payload, 1)?;
1128            }
1129            for payload in &payloads.config_payloads {
1130                drc.copy_split_payload(0x000C, IA_CMD_TYPE_INIT_CPY_IC_BSF_BUFF, payload, 1)?;
1131            }
1132            if !payloads.has_any() {
1133                self.drc_decoder = Some(drc);
1134                return Ok(());
1135            }
1136            let interface_present = 1i32;
1137            drc.set_config(IA_DRC_DEC_CONFIG_PARAM_INT_PRESENT, interface_present)?;
1138            check_decoder(drc.call(
1139                libxaac_sys::IA_API_CMD_INIT as i32,
1140                IA_CMD_TYPE_INIT_CPY_IN_BSF_BUFF,
1141                ptr::null_mut(),
1142            ))?;
1143            check_decoder(drc.call(
1144                libxaac_sys::IA_API_CMD_INIT as i32,
1145                libxaac_sys::IA_CMD_TYPE_INIT_PROCESS as i32,
1146                ptr::null_mut(),
1147            ))?;
1148        }
1149        self.drc_decoder = Some(drc);
1150        if let Some(cached) = self.cached_info.as_mut() {
1151            cached.drc_active = true;
1152        }
1153        Ok(())
1154    }
1155
1156    fn refresh_stream_info(&mut self) -> Result<StreamInfo> {
1157        let sample_rate =
1158            self.get_config_required(libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_SAMP_FREQ as i32)?;
1159        let channels = self
1160            .get_config_required(libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_NUM_CHANNELS as i32)?;
1161        let channel_mask = self
1162            .get_config_required(libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_CHANNEL_MASK as i32)?;
1163        let sbr_mode =
1164            self.get_config_required(libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE as i32)?;
1165        let aot =
1166            self.get_config_required(libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_AOT as i32)?;
1167
1168        let info = StreamInfo {
1169            sample_rate: sample_rate.max(0) as u32,
1170            channels: channels.max(0) as u16,
1171            channel_mask: channel_mask.max(0) as u32,
1172            channel_mode: self
1173                .get_config_optional(
1174                    libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_CHANNEL_MODE as i32,
1175                )?
1176                .map(ChannelMode::from),
1177            pcm_word_size: self.config.pcm_word_size,
1178            sbr_mode: SbrMode::from(sbr_mode),
1179            audio_object_type: aot,
1180            drc_effect_type: self
1181                .get_config_optional(
1182                    libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_EFFECT_TYPE as i32,
1183                )?
1184                .map(DrcEffectType::from_raw),
1185            drc_target_loudness: self.get_config_optional(
1186                libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LOUDNESS as i32,
1187            )?,
1188            drc_loudness_norm: self.get_config_optional(
1189                libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_LOUD_NORM as i32,
1190            )?,
1191            loudness_leveling: self
1192                .get_config_optional(IA_XHEAAC_DEC_CONFIG_PARAM_DRC_LOUDNESS_LEVELING)?
1193                .map(|value| value != 0),
1194            preroll_frames: self
1195                .get_config_optional(
1196                    libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES as i32,
1197                )?
1198                .map(|value| value.max(0) as u32),
1199            drc_config_changed: self
1200                .get_config_optional(libxaac_sys::IA_ENHAACPLUS_DEC_DRC_IS_CONFIG_CHANGED as i32)?
1201                .map(|value| value != 0),
1202            drc_apply_crossfade: self
1203                .get_config_optional(libxaac_sys::IA_ENHAACPLUS_DEC_DRC_APPLY_CROSSFADE as i32)?
1204                .map(|value| value != 0),
1205            extension_elements: self
1206                .get_config_optional(libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_NUM_ELE as i32)?
1207                .map(|value| value.max(0) as u32),
1208            config_extensions: self
1209                .get_config_optional(libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_NUM_CONFIG_EXT as i32)?
1210                .map(|value| value.max(0) as u32),
1211            gain_payload_len: self
1212                .get_config_optional(libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN as i32)?
1213                .map(|value| value.max(0) as u32),
1214            drc_active: self.drc_decoder.is_some(),
1215        };
1216        self.cached_info = Some(info.clone());
1217        Ok(info)
1218    }
1219
1220    fn read_extension_payloads(&self) -> Result<Option<ExtensionPayloads>> {
1221        let num_elements = self
1222            .get_config_optional(libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_NUM_ELE as i32)?
1223            .unwrap_or_default()
1224            .max(0) as usize;
1225        let num_config_ext = self
1226            .get_config_optional(libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_NUM_CONFIG_EXT as i32)?
1227            .unwrap_or_default()
1228            .max(0) as usize;
1229        if num_elements == 0 && num_config_ext == 0 {
1230            return Ok(None);
1231        }
1232
1233        let mut sizes = [[0i32; 16]; 2];
1234        check_decoder(self.get_config_raw(
1235            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_EXT_ELE_BUF_SIZES as i32,
1236            sizes.as_mut_ptr().cast::<c_void>(),
1237        ))?;
1238        let mut ptrs = [[ptr::null_mut::<u8>(); 16]; 2];
1239        check_decoder(self.get_config_raw(
1240            libxaac_sys::IA_ENHAACPLUS_DEC_CONFIG_EXT_ELE_PTR as i32,
1241            ptrs.as_mut_ptr().cast::<c_void>(),
1242        ))?;
1243
1244        let mut payloads = ExtensionPayloads::default();
1245        for index in 0..num_config_ext.min(16) {
1246            let size = sizes[0][index].max(0) as usize;
1247            if size == 0 || ptrs[0][index].is_null() {
1248                continue;
1249            }
1250            payloads.loudness_payloads.push(unsafe {
1251                std::slice::from_raw_parts(ptrs[0][index].cast::<u8>(), size).to_vec()
1252            });
1253        }
1254        for index in 0..num_elements.min(16) {
1255            let size = sizes[1][index].max(0) as usize;
1256            if size == 0 || ptrs[1][index].is_null() {
1257                continue;
1258            }
1259            payloads.config_payloads.push(unsafe {
1260                std::slice::from_raw_parts(ptrs[1][index].cast::<u8>(), size).to_vec()
1261            });
1262        }
1263        Ok(Some(payloads))
1264    }
1265
1266    fn read_optional_buffer(&self, ptr_index: i32, len_index: i32) -> Result<Option<Vec<u8>>> {
1267        let len = match self.get_config_optional(len_index)? {
1268            Some(len) if len > 0 => len as usize,
1269            _ => return Ok(None),
1270        };
1271        let mut ptr_value: *mut u8 = ptr::null_mut();
1272        check_decoder(self.get_config_raw(ptr_index, (&mut ptr_value as *mut _) as *mut c_void))?;
1273        if ptr_value.is_null() {
1274            return Ok(None);
1275        }
1276        Ok(Some(unsafe {
1277            std::slice::from_raw_parts(ptr_value.cast::<u8>(), len).to_vec()
1278        }))
1279    }
1280
1281    fn progress(&self) -> DecodeProgress {
1282        DecodeProgress {
1283            initialized: self.initialized,
1284            stream_info: self.cached_info.clone(),
1285        }
1286    }
1287
1288    fn load_input_window(&mut self) -> usize {
1289        let len = self.pending_input.len().min(self.input_capacity);
1290        let input_ptr = self.memblocks[self.input_index].as_ptr();
1291        unsafe {
1292            if len != 0 {
1293                ptr::copy_nonoverlapping(self.pending_input.as_ptr(), input_ptr, len);
1294            }
1295            if len < self.input_capacity {
1296                ptr::write_bytes(input_ptr.add(len), 0, self.input_capacity - len);
1297            }
1298        }
1299        len
1300    }
1301
1302    fn read_output_bytes(&self, len: usize) -> Result<Vec<u8>> {
1303        let out_ptr = self.memblocks[self.output_index].as_ptr();
1304        if out_ptr.is_null() {
1305            return Err(Error::InvalidConfig("decoder output buffer missing"));
1306        }
1307        Ok(unsafe { std::slice::from_raw_parts(out_ptr, len) }.to_vec())
1308    }
1309
1310    fn consume_pending(&mut self, consumed: usize) -> Result<()> {
1311        if consumed > self.pending_input.len() {
1312            return Err(Error::DecoderError(libxaac_sys::IA_FATAL_ERROR as i32));
1313        }
1314        self.pending_input.drain(..consumed);
1315        Ok(())
1316    }
1317
1318    fn ensure_input_over(&mut self) -> Result<()> {
1319        if self.input_over_signaled {
1320            return Ok(());
1321        }
1322        check_decoder(self.call(
1323            libxaac_sys::IA_API_CMD_INPUT_OVER as i32,
1324            0,
1325            ptr::null_mut(),
1326        ))?;
1327        self.input_over_signaled = true;
1328        Ok(())
1329    }
1330
1331    fn query_consumed(&self) -> Result<i32> {
1332        let mut consumed = 0i32;
1333        check_decoder(self.call_with_value(
1334            libxaac_sys::IA_API_CMD_GET_CURIDX_INPUT_BUF as i32,
1335            0,
1336            (&mut consumed as *mut _) as *mut c_void,
1337        ))?;
1338        Ok(consumed.max(0))
1339    }
1340
1341    fn set_config(&mut self, index: i32, value: i32) -> Result<()> {
1342        let mut value = value;
1343        check_decoder(self.call_with_value(
1344            libxaac_sys::IA_API_CMD_SET_CONFIG_PARAM as i32,
1345            index,
1346            (&mut value as *mut _) as *mut c_void,
1347        ))
1348    }
1349
1350    fn set_config_optional(&mut self, index: i32, value: i32) -> Result<()> {
1351        let mut value = value;
1352        let status = self.call_with_value(
1353            libxaac_sys::IA_API_CMD_SET_CONFIG_PARAM as i32,
1354            index,
1355            (&mut value as *mut _) as *mut c_void,
1356        );
1357        if status == libxaac_sys::IA_NO_ERROR as i32 || !is_fatal(status) {
1358            Ok(())
1359        } else {
1360            Err(Error::DecoderError(status))
1361        }
1362    }
1363
1364    fn set_config_f32(&mut self, index: i32, value: f32) -> Result<()> {
1365        let mut value = value;
1366        check_decoder(self.call_with_value(
1367            libxaac_sys::IA_API_CMD_SET_CONFIG_PARAM as i32,
1368            index,
1369            (&mut value as *mut _) as *mut c_void,
1370        ))
1371    }
1372
1373    fn get_config_required(&self, index: i32) -> Result<i32> {
1374        self.get_config_optional(index)?
1375            .ok_or(Error::DecoderError(libxaac_sys::IA_FATAL_ERROR as i32))
1376    }
1377
1378    fn get_config_optional(&self, index: i32) -> Result<Option<i32>> {
1379        let mut value = 0i32;
1380        let status = self.get_config(index, &mut value);
1381        if status == libxaac_sys::IA_NO_ERROR as i32 {
1382            Ok(Some(value))
1383        } else if is_fatal(status) {
1384            Err(Error::DecoderError(status))
1385        } else {
1386            Ok(None)
1387        }
1388    }
1389
1390    fn get_config_raw(&self, index: i32, value: *mut c_void) -> i32 {
1391        unsafe {
1392            libxaac_sys::ixheaacd_dec_api(
1393                self.api.as_ptr().cast::<c_void>(),
1394                libxaac_sys::IA_API_CMD_GET_CONFIG_PARAM as i32,
1395                index,
1396                value,
1397            )
1398        }
1399    }
1400
1401    fn get_config(&self, index: i32, value: &mut i32) -> i32 {
1402        self.get_config_raw(index, (value as *mut _) as *mut c_void)
1403    }
1404
1405    fn call(&self, cmd: i32, idx: i32, value: *mut c_void) -> i32 {
1406        unsafe {
1407            libxaac_sys::ixheaacd_dec_api(self.api.as_ptr().cast::<c_void>(), cmd, idx, value)
1408        }
1409    }
1410
1411    fn call_with_value(&self, cmd: i32, idx: i32, value: *mut c_void) -> i32 {
1412        self.call(cmd, idx, value)
1413    }
1414}
1415
1416#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1417enum InitState {
1418    Ready,
1419    NeedMoreInput,
1420    Continue,
1421    EndOfStream,
1422}
1423
1424#[derive(Debug, Clone, PartialEq, Eq)]
1425enum ExecuteState {
1426    Frame(DecodedFrame),
1427    NeedMoreInput,
1428    Continue,
1429    EndOfStream,
1430}
1431
1432#[derive(Debug, Default)]
1433struct ExtensionPayloads {
1434    loudness_payloads: Vec<Vec<u8>>,
1435    config_payloads: Vec<Vec<u8>>,
1436}
1437
1438impl ExtensionPayloads {
1439    fn has_any(&self) -> bool {
1440        !self.loudness_payloads.is_empty() || !self.config_payloads.is_empty()
1441    }
1442}
1443
1444impl DrcEffectType {
1445    fn from_raw(value: i32) -> Self {
1446        match value {
1447            1 => Self::Night,
1448            2 => Self::Noisy,
1449            3 => Self::Limited,
1450            4 => Self::LowLevel,
1451            5 => Self::Dialog,
1452            6 => Self::GeneralCompression,
1453            7 => Self::Expanded,
1454            8 => Self::Articulated,
1455            9 => Self::Headphone,
1456            10 => Self::PortableSpeaker,
1457            11 => Self::StereoDownmix,
1458            _ => Self::None,
1459        }
1460    }
1461}
1462
1463fn is_fatal(status: i32) -> bool {
1464    (status as u32 & libxaac_sys::IA_FATAL_ERROR) != 0
1465}