use embassy_time::Delay;
use esp_hal::Async;
use esp_hal::dma::{DmaError, DmaRxStreamBuf, DmaTxStreamBuf};
use esp_hal::i2s::master::{
Channels, DataFormat, I2s, I2sRx, I2sRxDmaTransfer, I2sTx, I2sTxDmaTransfer, TdmConfig,
};
use esp_hal::peripherals::{DMA_CH1, GPIO41, GPIO42, GPIO43, GPIO46, I2S0};
use esp_hal::time::Rate;
use oxstack_drivers::es8311::{ADDRESS_CE_LOW, Es8311, Mode};
pub use oxstack_drivers::es8311::{MicGain, SampleRate, Volume};
use crate::i2c::{SysI2cBus, SysI2cDevice, device};
pub const FRAME_BYTES: usize = 4;
const CHUNK: usize = 2048;
const STREAM_BYTES: usize = 8 * 4092;
pub type Codec = Es8311<SysI2cDevice>;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
I2c(embassy_embedded_hal::shared_bus::I2cDeviceError<esp_hal::i2c::master::Error>),
Config(esp_hal::i2s::master::ConfigError),
I2s(esp_hal::i2s::master::Error),
Dma(DmaError),
Overrun,
Underrun,
}
impl From<embassy_embedded_hal::shared_bus::I2cDeviceError<esp_hal::i2c::master::Error>> for Error {
fn from(
e: embassy_embedded_hal::shared_bus::I2cDeviceError<esp_hal::i2c::master::Error>,
) -> Self {
Error::I2c(e)
}
}
#[allow(missing_docs)]
pub struct AudioResources<'d> {
pub i2s: I2S0<'d>,
pub dma: DMA_CH1<'d>,
pub bclk: GPIO41<'d>,
pub ws: GPIO43<'d>,
pub dout: GPIO42<'d>,
pub din: GPIO46<'d>,
}
reborrow_group!(AudioResources {
i2s,
dma,
bclk,
ws,
dout,
din
});
fn i2s_config(rate: SampleRate) -> TdmConfig {
TdmConfig::new_tdm_philips()
.with_sample_rate(Rate::from_hz(rate.hz()))
.with_data_format(DataFormat::Data16Channel16)
.with_channels(Channels::STEREO)
}
macro_rules! stream_memory {
() => {
static_dma_memory!(STREAM_BYTES, CHUNK)
};
}
impl<'d> AudioResources<'d> {
pub async fn recorder(
&mut self,
bus: &'static SysI2cBus,
rate: SampleRate,
gain: MicGain,
) -> Result<Recorder<'_>, Error> {
let i2s = I2s::new(self.i2s.reborrow(), self.dma.reborrow(), i2s_config(rate))
.map_err(Error::Config)?
.into_async();
let rx = i2s
.i2s_rx
.with_bclk(self.bclk.reborrow())
.with_ws(self.ws.reborrow())
.with_din(self.din.reborrow())
.build();
let (buffer, descriptors) = stream_memory!();
let buf = DmaRxStreamBuf::new(descriptors, buffer).expect("valid DMA stream buffer");
let transfer = rx.read(buf).map_err(|(e, _, _)| Error::I2s(e))?;
let mut codec = Es8311::new(device(bus), ADDRESS_CE_LOW);
codec.init(&mut Delay).await?;
codec.set_mic_gain(gain).await?;
codec.set_mode(Mode::Record).await?;
Ok(Recorder {
codec,
rx: Stream::Running(transfer),
rate,
})
}
pub async fn player(
&mut self,
bus: &'static SysI2cBus,
rate: SampleRate,
volume: Volume,
) -> Result<Player<'_>, Error> {
let i2s = I2s::new(self.i2s.reborrow(), self.dma.reborrow(), i2s_config(rate))
.map_err(Error::Config)?
.into_async();
let tx = i2s
.i2s_tx
.with_bclk(self.bclk.reborrow())
.with_ws(self.ws.reborrow())
.with_dout(self.dout.reborrow())
.build();
let (mut buffer, descriptors) = stream_memory!();
buffer.fill(0);
let buf = DmaTxStreamBuf::new(descriptors, buffer).expect("valid DMA stream buffer");
let transfer = tx.write(buf).map_err(|(e, _, _)| Error::I2s(e))?;
let mut codec = Es8311::new(device(bus), ADDRESS_CE_LOW);
codec.init(&mut Delay).await?;
codec.set_mode(Mode::Playback).await?;
codec.set_dac_volume(volume).await?;
Ok(Player {
codec,
tx: Stream::Running(transfer),
rate,
muted: true,
})
}
}
enum Stream<T, U, B> {
Running(T),
Stopped(U, B),
Poisoned,
}
type RxStream<'d> =
Stream<I2sRxDmaTransfer<'d, Async, DmaRxStreamBuf>, I2sRx<'d, Async>, DmaRxStreamBuf>;
type TxStream<'d> =
Stream<I2sTxDmaTransfer<'d, Async, DmaTxStreamBuf>, I2sTx<'d, Async>, DmaTxStreamBuf>;
pub struct Recorder<'d> {
codec: Codec,
rx: RxStream<'d>,
rate: SampleRate,
}
impl Recorder<'_> {
pub async fn read(&mut self, out: &mut [i16]) -> Result<usize, Error> {
let want = out.len() / 2 * FRAME_BYTES;
if want == 0 {
return Ok(0);
}
loop {
let Stream::Running(t) = &mut self.rx else {
self.restart()?;
continue;
};
let avail = t.available_bytes();
if avail >= FRAME_BYTES {
let n = avail.min(want) / FRAME_BYTES * FRAME_BYTES;
let popped = t.pop(as_bytes_mut(out, n));
return Ok(popped / 2);
}
if t.wait_for_available_async().await.is_err() {
self.restart()?;
return Err(Error::Overrun);
}
}
}
pub fn buffered_bytes(&mut self) -> usize {
match &mut self.rx {
Stream::Running(t) => t.available_bytes(),
_ => 0,
}
}
pub fn is_stopped(&mut self) -> bool {
match &mut self.rx {
Stream::Running(t) => t.is_done(),
_ => true,
}
}
pub async fn set_gain(&mut self, gain: MicGain) -> Result<(), Error> {
Ok(self.codec.set_mic_gain(gain).await?)
}
pub fn rate(&self) -> SampleRate {
self.rate
}
pub fn codec(&mut self) -> &mut Codec {
&mut self.codec
}
pub async fn shutdown(mut self) -> Result<(), Error> {
self.codec.set_mode(Mode::Off).await?;
Ok(()) }
fn restart(&mut self) -> Result<(), Error> {
let (rx, buf) = match core::mem::replace(&mut self.rx, Stream::Poisoned) {
Stream::Running(t) => t.stop(),
Stream::Stopped(rx, buf) => (rx, buf),
Stream::Poisoned => return Err(Error::Dma(DmaError::DescriptorError)),
};
match rx.read(buf) {
Ok(t) => {
self.rx = Stream::Running(t);
Ok(())
}
Err((e, rx, buf)) => {
self.rx = Stream::Stopped(rx, buf);
Err(Error::I2s(e))
}
}
}
}
pub struct Player<'d> {
codec: Codec,
tx: TxStream<'d>,
rate: SampleRate,
muted: bool,
}
impl Player<'_> {
pub async fn write(&mut self, samples: &[i16]) -> Result<(), Error> {
let mut rest = samples;
while !rest.is_empty() {
let n = self.write_some(rest).await?;
rest = &rest[n..];
}
Ok(())
}
pub async fn write_some(&mut self, samples: &[i16]) -> Result<usize, Error> {
let bytes = as_bytes(samples);
let bytes = &bytes[..bytes.len() / FRAME_BYTES * FRAME_BYTES];
if bytes.is_empty() {
return Ok(0);
}
loop {
let Stream::Running(t) = &mut self.tx else {
self.restart()?;
continue;
};
let space = t.available_bytes() / FRAME_BYTES * FRAME_BYTES;
if space > 0 {
let n = t.push(&bytes[..space.min(bytes.len())]);
if self.muted {
self.codec.set_dac_mute(false).await?;
self.muted = false;
}
return Ok(n / 2);
}
if t.wait_for_available_async().await.is_err() {
self.restart()?;
return Err(Error::Underrun);
}
}
}
pub async fn set_volume(&mut self, volume: Volume) -> Result<(), Error> {
Ok(self.codec.set_dac_volume(volume).await?)
}
pub async fn set_mute(&mut self, mute: bool) -> Result<(), Error> {
self.codec.set_dac_mute(mute).await?;
self.muted = mute;
Ok(())
}
pub fn rate(&self) -> SampleRate {
self.rate
}
pub fn codec(&mut self) -> &mut Codec {
&mut self.codec
}
pub async fn shutdown(mut self) -> Result<(), Error> {
self.codec.set_dac_mute(true).await?;
self.codec.set_mode(Mode::Off).await?;
Ok(()) }
fn restart(&mut self) -> Result<(), Error> {
let (tx, buf) = match core::mem::replace(&mut self.tx, Stream::Poisoned) {
Stream::Running(t) => t.stop(),
Stream::Stopped(tx, buf) => (tx, buf),
Stream::Poisoned => return Err(Error::Dma(DmaError::DescriptorError)),
};
match tx.write(buf) {
Ok(t) => {
self.tx = Stream::Running(t);
Ok(())
}
Err((e, tx, buf)) => {
self.tx = Stream::Stopped(tx, buf);
Err(Error::I2s(e))
}
}
}
}
fn as_bytes(samples: &[i16]) -> &[u8] {
unsafe { core::slice::from_raw_parts(samples.as_ptr().cast(), samples.len() * 2) }
}
fn as_bytes_mut(samples: &mut [i16], len: usize) -> &mut [u8] {
debug_assert!(len <= samples.len() * 2);
unsafe { core::slice::from_raw_parts_mut(samples.as_mut_ptr().cast(), len) }
}