обновление
This commit is contained in:
81
src/audio.rs
Normal file
81
src/audio.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
use rodio::{Decoder, OutputStream, OutputStreamBuilder, Sink};
|
||||
|
||||
pub struct AudioPlayer {
|
||||
_stream: OutputStream,
|
||||
sink: Sink,
|
||||
paused_pos: Option<Duration>,
|
||||
}
|
||||
|
||||
impl AudioPlayer {
|
||||
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let stream_handle = OutputStreamBuilder::open_default_stream()?;
|
||||
let sink = Sink::connect_new(&stream_handle.mixer());
|
||||
sink.set_volume(1.0);
|
||||
Ok(Self { _stream: stream_handle, sink, paused_pos: None })
|
||||
}
|
||||
|
||||
pub fn play(&mut self, path: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
|
||||
self.sink.stop();
|
||||
self.paused_pos = None;
|
||||
let file = BufReader::new(File::open(path)?);
|
||||
let source = Decoder::new(file)?;
|
||||
self.sink.append(source);
|
||||
self.sink.play();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn position(&self) -> Duration {
|
||||
if self.sink.is_paused() {
|
||||
self.paused_pos.unwrap_or_else(|| self.sink.get_pos())
|
||||
} else {
|
||||
self.sink.get_pos()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_pause(&mut self) {
|
||||
if self.sink.is_paused() {
|
||||
self.sink.play();
|
||||
self.paused_pos = None;
|
||||
} else {
|
||||
self.paused_pos = Some(self.sink.get_pos());
|
||||
self.sink.pause();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
self.sink.stop();
|
||||
self.paused_pos = None;
|
||||
}
|
||||
|
||||
pub fn is_finished(&self) -> bool {
|
||||
self.sink.empty()
|
||||
}
|
||||
|
||||
pub fn volume(&self) -> f32 {
|
||||
self.sink.volume()
|
||||
}
|
||||
|
||||
pub fn change_volume(&mut self, delta: f32) {
|
||||
let v = (self.sink.volume() + delta).clamp(0.0, 2.0);
|
||||
self.sink.set_volume(v);
|
||||
}
|
||||
|
||||
pub fn seek_by(&mut self, delta: i64, total: Duration) -> Result<Duration, Box<dyn std::error::Error>> {
|
||||
let current = self.position();
|
||||
let new_secs = (current.as_secs() as i64 + delta).max(0) as u64;
|
||||
let mut new_pos = Duration::from_secs(new_secs);
|
||||
if !total.is_zero() && new_pos >= total {
|
||||
new_pos = total.saturating_sub(Duration::from_millis(100));
|
||||
}
|
||||
self.sink.try_seek(new_pos)?;
|
||||
if self.sink.is_paused() {
|
||||
self.paused_pos = Some(new_pos);
|
||||
}
|
||||
Ok(new_pos)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user