Audio sink seek adopted (#18971)

Adopted #13869 

# Objective

Fixes #9076 

## Solution

Using `rodio`'s `try_seek`

## Testing

@ivanstepanovftw added a `seek` system using `AudioSink` to the
`audio_control.rs` example. I got it working with .mp3 files, but rodio
doesn't support seeking for .ogg and .flac files, so I removed it from
the commit (since the assets folder only has .ogg files). Another thing
to note is that `try_seek` fails when using `PlaybackMode::Loop`, as
`rodio::source::buffered::Buffered` doesn't support `try_seek`. I
haven't tested `SpatialAudioSink`.

## Notes

I copied the docs for `try_seek` verbatim from `rodio`, and re-exported
`rodio::source::SeekError`. I'm not completely confident in those
decisions, please let me know if I'm doing anything wrong.

</details>

---------

Co-authored-by: Ivan Stepanov <ivanstepanovftw@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
Co-authored-by: François Mockers <mockersf@gmail.com>
This commit is contained in:
Taj Holliday 2025-05-03 11:29:38 +00:00 committed by GitHub
parent cd67bac544
commit 2affecdb07
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,10 +1,11 @@
use crate::Volume;
use bevy_ecs::component::Component;
use bevy_math::Vec3;
use bevy_transform::prelude::Transform;
use core::time::Duration;
pub use rodio::source::SeekError;
use rodio::{Sink, SpatialSink};
use crate::Volume;
/// Common interactions with an audio sink.
pub trait AudioSinkPlayback {
/// Gets the volume of the sound as a [`Volume`].
@ -41,6 +42,26 @@ pub trait AudioSinkPlayback {
/// No effect if not paused.
fn play(&self);
/// Attempts to seek to a given position in the current source.
///
/// This blocks between 0 and ~5 milliseconds.
///
/// As long as the duration of the source is known, seek is guaranteed to saturate
/// at the end of the source. For example given a source that reports a total duration
/// of 42 seconds calling `try_seek()` with 60 seconds as argument will seek to
/// 42 seconds.
///
/// # Errors
/// This function will return [`SeekError::NotSupported`] if one of the underlying
/// sources does not support seeking.
///
/// It will return an error if an implementation ran
/// into one during the seek.
///
/// When seeking beyond the end of a source, this
/// function might return an error if the duration of the source is not known.
fn try_seek(&self, pos: Duration) -> Result<(), SeekError>;
/// Pauses playback of this sink.
///
/// No effect if already paused.
@ -160,6 +181,10 @@ impl AudioSinkPlayback for AudioSink {
self.sink.play();
}
fn try_seek(&self, pos: Duration) -> Result<(), SeekError> {
self.sink.try_seek(pos)
}
fn pause(&self) {
self.sink.pause();
}
@ -256,6 +281,10 @@ impl AudioSinkPlayback for SpatialAudioSink {
self.sink.play();
}
fn try_seek(&self, pos: Duration) -> Result<(), SeekError> {
self.sink.try_seek(pos)
}
fn pause(&self) {
self.sink.pause();
}