Commit Graph

16 Commits

Author SHA1 Message Date
Zaggy1024
7405376938 LibMedia: Prevent conflicts between AudioMixingSink resume and set_time
If a set_time()'s callbacks were still pending, but a resume() went
through, the audio timing could get a bit confused. Instead, check if
m_temporary_time is set before resuming, since that would indicate that
the set_time() callbacks will call resume() when the time is stable
again.

Also, multiple set_time() calls will now only start one set of tasks,
and m_temporary_time is used to store the time passed to the last call.
Thus, set_time() doesn't conflict with itself, but no calls to
set_time() are ignored still.
2026-02-23 07:27:31 +01:00
Federico Tedin
f256597d55 LibMedia: Avoid crashing when PlaybackStream can't be created 2026-01-25 18:14:15 -06:00
Zaggy1024
65c0be66e4 LibMedia: Implement audio conversion in AudioDataProvider 2025-12-13 08:58:26 +01:00
Zaggy1024
c75284591f LibMedia: Make PlaybackStream use the output's sample specification
Instead of specifying the sample rate, channel count/map, etc. to the
PlaybackStream, we'll now use the output device's sample specification
whenever possible. If necessary, the stream will fall back to sane
default.

This hugely simplifies AudioMixingSink, since it no longer has to take
care of reinitializing the stream with a new sample specification when
it encounters a track with a higher sample rate or more channels. We
wouldn't be likely to benefit from this anyway, since it turns out that
at least Windows's virtual surround doesn't work through WASAPI at all,
and WASAPI likely wouldn't support downmixing.

This commit breaks playback of audio files that don't match the system
default audio device's sample rate and channel count. The next commit
introduces a converter into the pipeline to allow mixing of any sample
specification.
2025-12-13 08:58:26 +01:00
Zaggy1024
5c9a34d84a LibMedia: Only use floats for audio data callbacks
We were already assuming that our streams were using floats, we may as
well hardcode this. If we ever encounter a platform API that doesn't
support or convert from float, we can always bring this back.

Also, since we don't support big-endian systems, remove that check in
PulseAudioWrappers.
2025-12-13 08:58:26 +01:00
Zaggy1024
875ea17160 LibMedia: Skip blocks in AudioMixingSink when they aren't playable
If the sample rate or channel count doesn't match, we were previously
getting stuck permanently here. This wouldn't really be an issue in
practice since the stream is being shut down in those cases anyway, but
it's incorrect behavior.
2025-12-13 08:58:26 +01:00
Zaggy1024
aca776aa00 LibMedia: Factor out the audio data callback in AudioMixingSink 2025-12-13 08:58:26 +01:00
Zaggy1024
a87ea9d096 LibMedia: Have the sinks start the data providers
This will allow us to start the audio data providers after their sample
specification conversion is set up in a future commit.
2025-12-13 08:58:26 +01:00
Zaggy1024
564e607f7a LibMedia: Clear pending audio data when re-enabling an audio track
Without removing the current block, we end up playing no audio until
its timestamp is reached, after we shift the next block forward if its
timestamp is less than the previous block's end time. This would mean
that re-enabling an audio track after a seek backwards would result in
a delay in its audio resuming.
2025-12-13 08:58:26 +01:00
Zaggy1024
ae5e200dfc LibMedia: Move overlapping audio block correction to the data provider
This prevents PlaybackManager's seek while enabling an audio track from
causing the AudioMixingSink to push audio blocks forward unnecessarily.
Previously, the seek would cause the initial block or blocks to repeat
from the perspective of AudioMixingSink, so it would think that it
needs to shift the first block after the seek forward by a few samples.
By moving this to the AudioDataProvider, we can clear the last sample
index every time the decoder is flushed, ensuring that the block
shifting always makes sense.

By doing this in AudioMixingSink instead of the Decoder
implementations, we avoid having to duplicate this shifting logic
across multiple implementations.

This also fixes an issue where multiple audio blocks occupying the same
timestamp would be skipped while seeking, causing a significant break
in audio.
2025-11-17 16:51:18 +01:00
Zaggy1024
7e325d64f5 LibMedia: Use [from/to]_time_units in FFmpegDemuxer and AudioMixingSink 2025-11-17 16:51:18 +01:00
Zaggy1024
7845b22c5f LibMedia: Stop recursively locking in AudioMixingSink initialization
We already hold a lock in deferred_create_playback_stream, so we can
just skip taking a lock in create_playback_stream.
2025-11-03 16:39:24 -06:00
Zaggy1024
7745d9209d LibMedia: Sync AudioMixingSink::set_time onto the stream thread
With the previous setup setting the time directly on the main thread,
the following could occur:

- HTMLMediaElement temporarily pauses playback to begin a seek.
- AudioMixingSink starts an audio task to drain audio and suspend.
- HTMLMediaElement starts PlaybackManager seeking to a new position.
- AudioDataProvider completes the seek to the new position.
- The PlaybackManager tells AudioMixingSink to set the media time,
  which it does so synchronously on the main thread.
- At this point, the time provider corresponds to the new position.
- The pause completes, and a deferred invocation sets media time to
  its old position again.

This would result in the timeline showing the wrong position after a
seek on rare occasions.

Instead, always queue up a drain and suspend when setting the sink's
media time. This ensures that updating the time always occurs after the
pause has completed.

Also, since setting the time is asynchronous now, we need to store the
target time until the seeking drain completes. Otherwise, we still
briefly see the previous playback position after a seek.
2025-10-27 17:28:49 -07:00
Zaggy1024
8d9a493b1b LibMedia+LibWeb: Implement media volume/muting 2025-10-27 17:28:49 -07:00
Zaggy1024
e176249db8 LibMedia: Use AudioMixingSink as a time provider when it is available 2025-10-27 17:28:49 -07:00
Zaggy1024
0ff330c906 LibMedia: Play audio through PlaybackManager using Providers/Sinks
This commit implements the functionality to play back audio through
PlaybackManager.

To decode the audio data, AudioDataProviders are created for each track
in the provided media data. These providers will fill their audio block
queue, then sit idle until their corresponding tracks are enabled.

In order to output the audio, one AudioMixingSink is created which
manages a PlaybackStream which requests audio blocks from multiple
AudioDataProviders and mixes them into one buffer with sample-perfect
precision.
2025-10-27 17:28:49 -07:00