69 lines
1.7 KiB
Rust
69 lines
1.7 KiB
Rust
use crate::stream::Stream;
|
|
use librespot::playback::audio_backend::{Sink, SinkAsBytes, SinkError, SinkResult};
|
|
use librespot::playback::convert::Converter;
|
|
use librespot::playback::decoder::AudioPacket;
|
|
use std::io::Write;
|
|
use tokio::sync::mpsc::UnboundedSender;
|
|
|
|
pub enum SinkEvent {
|
|
Start,
|
|
Stop,
|
|
}
|
|
|
|
pub struct StreamSink {
|
|
stream: Stream,
|
|
sender: UnboundedSender<SinkEvent>,
|
|
}
|
|
|
|
impl StreamSink {
|
|
pub fn new(stream: Stream, sender: UnboundedSender<SinkEvent>) -> Self {
|
|
Self { stream, sender }
|
|
}
|
|
}
|
|
|
|
impl Sink for StreamSink {
|
|
fn start(&mut self) -> SinkResult<()> {
|
|
if let Err(_why) = self.sender.send(SinkEvent::Start) {
|
|
// WARNING: Returning an error causes librespot-playback to exit the process with status 1
|
|
|
|
// return Err(SinkError::ConnectionRefused(_why.to_string()));
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn stop(&mut self) -> SinkResult<()> {
|
|
if let Err(_why) = self.sender.send(SinkEvent::Stop) {
|
|
// WARNING: Returning an error causes librespot-playback to exit the process with status 1
|
|
|
|
// return Err(SinkError::ConnectionRefused(_why.to_string()));
|
|
}
|
|
|
|
self.stream.flush().ok();
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn write(&mut self, packet: AudioPacket, converter: &mut Converter) -> SinkResult<()> {
|
|
use zerocopy::AsBytes;
|
|
|
|
let AudioPacket::Samples(samples) = packet else {
|
|
return Ok(());
|
|
};
|
|
|
|
self.write_bytes(converter.f64_to_f32(&samples).as_bytes())?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl SinkAsBytes for StreamSink {
|
|
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
|
self.stream
|
|
.write_all(data)
|
|
.map_err(|why| SinkError::OnWrite(why.to_string()))?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|