determine_codec_params() warns when it cannot determine a codec profile.
Some passthrough formats use fixed output parameters and do not require
the probed profile or sample rate making the warning misleading.
Warn only when a value used to configure the selected passthrough format
is missing: the profile for DTS-HD, or the sample rate for core DTS and
AC-3.
Signed-off-by: Nathan Lucas <[email protected]>
The spdif decoder uses avformat/spdifenc. Some spdifenc paths keep
muxer state across packets, such as partial TrueHD MAT frames. After a
seek, that state belongs to the old stream position and can cause the
next packet to be muxed with stale timing or buffering state.
On decoder reset, discard the current spdif muxer context. The next
usable input packet will recreate the muxer through the existing
initialization path.
Cache codec parameters from the initial probe so recreating the muxer
does not probe a partial packet after a seek or replace known values
with fallbacks.
A fresh TrueHD spdif muxer needs a TrueHD major sync before it can begin
muxing the stream. Startup or post-seek playback may begin on a TrueHD
access unit that does not have major sync, so drop TrueHD packets until
a major sync access unit is seen. This also gives the downstream decoder
a clean restart point after seeks. Warn periodically if no major sync
has been found.
Partially addresses: https://trac.ffmpeg.org/ticket/9569
Signed-off-by: Nathan Lucas <[email protected]>
When wait_for_init_done times out, init_state remains INIT_STATE_NONE.
The original check only handled INIT_STATE_ERROR, allowing init() to
return 0 (success) even though the stream was never properly initialized.
This could lead to an infinite reload loop when the partially initialized
stream later enters an error state.
Fix by checking for INIT_STATE_SUCCESS instead of INIT_STATE_ERROR,
so that any state other than SUCCESS (including NONE due to timeout)
is correctly treated as a failure.
Implement `lavfi-tempo` audio filter, which uses `atempo` or `ascale`
form libavfilter for setting the tempo.
Users (myself included) seem to be always looking for alternative tempo
scalers to try, and this provides a faster implementation (or two), and
may prove useful beyond performance/speed.
`atempo` is picked as a default, and as a fall-back if `ascale` is not
available.
Signed-off-by: Mohammad AlSaleh <[email protected]>
pw_time.queued is reported in bytes, while the code here expects it in
nframes.
Note that this doesn't matter at all, because pw_time.queued is always 0
for us since we use it as a pull-based AO. This would be a latent bug if
we ever switched to push model.
Drop the swr_set_channel_mapping() + transpose_order() + reorder_in[]
plumbing. Instead, build the swr input channel layout directly from the
mpv chmap as AV_CHANNEL_ORDER_CUSTOM, so the labels in the layout already
match the positions of the channels in the input data.
For all unknown map, we return all UNSPEC, so the swr expands to default
layout for this channel number.
loop_start starts a thread which immediately acquires the thread loop
lock. Locking the loop before loop_start can therefore deadlock the
newly created thread during initialization.
Locking the thread loop before loop_start was always incorrect, but
Pipewire commit fb49e0795c28* made the issue visible by switching
pw_thread_loop_lock to the underlying SPA loop lock.
To fix this, we just avoid starting the loop until after we're connected
to the server.
* https://github.com/PipeWire/pipewire/commit/fb49e0795c28c892116b03369785ba86c27c968d
PA_SUBSCRIPTION_MASK_SINK is a pa_subscription_mask constant used when
registering with pa_context_subscribe(), not a
pa_subscription_event_type mask. Masking the event type with it would
never match PA_SUBSCRIPTION_EVENT_NEW or PA_SUBSCRIPTION_EVENT_REMOVE,
causing hotplug events to be silently dropped.
Fixes: e01750020d
The retry path in wasapi_thread_init() used MP_TIME_US_TO_NS, giving a
total budget of ~15 us before MP_FATAL killed the audio thread. The
resulting log line "Retrying in 1000 ns" makes the unit confusion
obvious.
In practice AUDCLNT_E_DEVICE_INVALIDATED is most often hit right after
the system resumes from sleep, or when the default endpoint changes,
where the audio endpoint typically needs hundreds of milliseconds to
come back. The current budget never covers that window, so the first
playback after wake-up permanently fell back to "no audio" until the
user manually restarted playback.
Switch the retry schedule to milliseconds: start at 1 ms (~one Windows
timer tick, effectively an immediate yield), multiply by 10 each
iteration, and cap at 1 s -- i.e. 1/10/100/1000 ms, 4 retries, ~1.1 s
total. Use MP_TIME_NS_TO_MS for the warning so the unit in the log
matches reality.
This fixes multiple overflows when passing huge values. Which causes
either invalid memory accesses when memory allocations are wrong size or
huge allocations leading to OOM.
Reported by: Trail of Bits
With `node.always-process` mpv will force pipewire to continuously keep
driving the source node, even when paused, which causes a relatively
significant increase in power consumption due to frequent CPU wakeups.
I have tested mpv with this option disabled, both for music and video,
pausing and seeking around in various ways and could not notice any
problems with this option disabled. And with it disabled pipewire
properly becomes idle a couple seconds after video/audio is paused.
Pipewire documentation suggests that this option is largely useful for
JACK clients, which `mpv` isn't. Using GitHub-wide search it seems like
the other two notable uses of this property are really just SDL and
OpenAL. All other applications I use work well without this property
being set as well.
Note that this change does not affect the output devices differently as
far as I can tell. Both with and without `always-process` pipewire will
suspend the output device after some idle time and in case
`always-process` is enabled, it will redirect `mpv` to `Dummy-Driver`
instead.
This adds option `--audio-set-media-role` to configure whether mpv
should set media roles to supported audio APIs or not. Disabled by
default.
By default, WirePlumber restores the volume of each application to
whatever the last application with the same media role used. This is
completely insane behavior, and I couldn’t find any way for a user to
opt out of it on my end. The `state-stream.lua` script responsible for
this mess only uses media.role if the property is present, so the only
reliable workaround is simply not to set one at all.
This WirePlumber behavior is inherited from PulseAudio, which also
exhibits the same behavior to this day.
This commit also mirrors the same change made to ao_pulse in 2015:
b7325b2f64
See also: https://gitlab.freedesktop.org/pipewire/wireplumber/-/issues/489
Since the option system now handles all the path expansion
automatically, these recent changes can be reverted for simplicity.
This reverts commit be15be3a83.
0ab3184526 introduced most of the stuff
being removed here. The idea is that when doing encoding the core should
wait until everything is initialized. This is true, but the old
implementation is overly complicated and confusing. What we need is for
both the AO to be initialized and the VO to be reconfigured for encoding
to start. Because of the way initialization works, the VO reconfig
always happens first. Changing the order in playloop would of course
break this assumption, but we can trust that nobody would arbitrarily do
that. So all that needs to be done here is that write_video should wait
until the AO is up before pushing frames. And that only applies in
encoding mode and if there is a selected audio stream in the first
place. This is a simple check.
With that in place, all of this extra junk can be dropped. We don't need
special booleans or events for the simple task of making sure the AO and
VO are both up.
There's no good explanation, but I can no longer reproduce the issue
described in the commit. The code as is can cause a "File descriptor in
bad state" message when looping or advancing in a playlist because it
jumps a bit too early to the eof part. Perhaps something in alsa somehow
changed, but the non-gapless audio freezing thing doesn't happen
anymore. The audio state correctly updates on play/pause without these
lines. Since this is known to cause problems elsewhere, just revert it
for now. If the alsa problem crops up again in the future, we can
revisit it then.
This reverts commit d33e54250e.
There's several path-related options that do not handle common shortcuts
(like ~/). Fix this by using mp_get_user_path where appropriate which
expands the path so users get more intuitive behavior. Fixes#15598.
When the monitor goes to sleep, the OpenAL context was not properly
handled, resulting in a null pointer dereference and a crash. This
fix ensures that the OpenAL context is created and set correctly,
avoiding crashes under these conditions.
Fixes: #15648
The server's protocol version is not available until a connection is
properly established. Currently the value of `PA_INVALID_INDEX` is printed
due to calling `pa_context_get_server_protocol_version()` before connecting.
Fix this by doing the call after the connection has been set up.
Fixes: f744aadb77 ("ao_pulse: dump library version etc.")
The problem here is likely ao_alsa specific and has the same symptons as
what the previous commit fixed (audio not playing when the file changes
but the details are a bit different here and the sample rate does not
matter. When using gapless audio (the default), the core player
immediately marks the audio status as EOF after it starts draining and
allows the remaining audio buffers to play while it marches on. This
works fine. When not using gapless audio, it doesn't immediately set EOF
and instead waits for the audio to finish playing before it does
anything else. The problem is that ao_is_playing is always true so the
core waits forever thinking audio is still playing when it actually
isn't.
ao_play_data is what is in charge of setting the mp_pcm_state with it
calling out to the backend for additional help. Unfortunately, this
doesn't work for alsa because it's too dumb to signal the desired states
in this edge case so we have to help it a bit. The main thing to notice
here is that even though we can get EOF from a frame, there can still be
additional valid samples that compe after it. So we can't just
immediately quit after EOF is seen. The approach here is to simply save
if we got eof sometime in the past, wait until we get no more samples,
mark state.playing as false and then jump over to the eof code. This
will set p->playing to false as desired which allows the core code to
set EOF and finally we can go through the reset logic and actually play
audio for the next file.