use crate::alsa::{Error, Pcm, Result};
use crate::libc as c;
use crate::unix::errno;
use crate::unix::poll;
use crate::unix::AsyncPoll;
use audio_core as core;
use std::marker;
pub struct AsyncWriter<'a, T> {
pcm: &'a mut Pcm,
poll_handle: AsyncPoll,
pollfd: c::pollfd,
channels: usize,
_marker: marker::PhantomData<T>,
}
impl<'a, T> AsyncWriter<'a, T> {
pub(super) unsafe fn new(pcm: &'a mut Pcm, pollfd: c::pollfd, channels: usize) -> Result<Self> {
Ok(Self {
pcm,
poll_handle: AsyncPoll::new(pollfd)?,
pollfd,
channels,
_marker: marker::PhantomData,
})
}
pub async fn write_interleaved<B>(&mut self, mut buf: B) -> Result<()>
where
B: core::ReadBuf + core::ExactSizeBuf + core::AsInterleaved<T>,
{
if buf.channels() != self.channels {
return Err(Error::ChannelsMismatch {
actual: buf.channels(),
expected: self.channels,
});
}
while buf.has_remaining() {
self.pcm.tag.ensure_on_thread();
let frames = buf.frames() as usize;
unsafe {
let result = {
let ptr = buf.as_interleaved().as_ptr() as *const c::c_void;
self.pcm.write_interleaved_unchecked(ptr, frames as u64)
};
let written = match result {
Ok(written) => written as usize,
Err(Error::Sys(errno::EWOULDBLOCK)) => {
loop {
let guard = self.poll_handle.returned_events().await;
self.pollfd.revents = guard.events();
let mut fds = [self.pollfd];
let flags = self.pcm.poll_descriptors_revents(&mut fds)?;
if flags == poll::PollFlags::POLLOUT {
break;
}
drop(guard);
}
continue;
}
Err(e) => return Err(e),
};
buf.advance(written);
}
}
Ok(())
}
}
unsafe impl<T> Send for AsyncWriter<'_, T> {}