use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Mutex, PoisonError};
use rusty_esp_core::pcm::{PcmFormat, SampleFormat};
use crate::board::{self, Pcm};
use crate::error;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Config {
pub format: PcmFormat,
pub frame_ms: u32,
}
const fn format(rate: u32, channels: u8, sample: SampleFormat) -> PcmFormat {
match PcmFormat::new(rate, channels, sample) {
Ok(f) => f,
Err(_) => panic!("a non-zero rate and channel count"),
}
}
impl Config {
#[must_use]
pub const fn pcm16_16k() -> Self {
Config {
format: format(16_000, 1, SampleFormat::I16),
frame_ms: 20,
}
}
#[must_use]
pub const fn pcm16_48k() -> Self {
Config {
format: format(48_000, 1, SampleFormat::I16),
frame_ms: 20,
}
}
#[must_use]
pub const fn blocks_of_ms(mut self, frame_ms: u32) -> Self {
self.frame_ms = frame_ms;
self
}
#[must_use]
pub const fn block_bytes(&self) -> usize {
self.format.bytes_for_micros(self.frame_ms as u64 * 1000)
}
}
static CONFIG: Mutex<Option<Config>> = Mutex::new(None);
static BLOCKS: AtomicU32 = AtomicU32::new(0);
pub fn begin(config: Config) -> bool {
let r = board::with(|b| b.mic_begin(&config));
if r.is_ok() {
*CONFIG.lock().unwrap_or_else(PoisonError::into_inner) = Some(config);
}
error::ok(r)
}
pub fn read() -> Option<Pcm> {
let pcm = error::some(board::with(|b| b.mic_read()));
if pcm.is_some() {
BLOCKS.fetch_add(1, Ordering::Relaxed);
}
pcm
}
#[must_use]
pub fn blocks() -> u32 {
BLOCKS.load(Ordering::Relaxed)
}
#[must_use]
pub fn config() -> Option<Config> {
*CONFIG.lock().unwrap_or_else(PoisonError::into_inner)
}