In my opinion, we shouldn't use atomics at all, but ok.
This switches the mpv code to use C11 stdatomic.h, and for compilers
that don't support stdatomic.h yet, we emulate the subset used by mpv
using the builtins commonly provided by gcc and clang.
This supersedes an earlier similar attempt by Kovensky. That attempt
unfortunately relied on a big copypasted freebsd header (which also
depended on much more highly compiler-specific functionality, defined
reserved symbols, etc.), so it had to be NIH'ed.
Some issues:
- C11 says default initialization of atomics "produces a valid state",
but it's not sure whether the stored value is really 0. But we rely on
this.
- I'm pretty sure our use of the __atomic... builtins is/was incorrect.
We don't use atomic load/store intrinsics, and access stuff directly.
- Our wrapper actually does stricter typechecking than the stdatomic.h
implementation by gcc 4.9. We make the atomic types incompatible with
normal types by wrapping them into structs. (The FreeBSD wrapper does
the same.)
- I couldn't test on MinGW.
Use the time as returned by mp_time_us() for mpthread_cond_timedwait(),
instead of calculating the struct timespec value based on a timeout.
This (probably) makes it easier to wait for a specific deadline.
This didn't quite work. The main issue was that get_space tries to be
clever to reduce overall buffering, so it will cause the playloop to
decode and queue only as much audio as is needed to refill the AO in
reasonable time. Also, even if ignoring the problem, the logic of the
previous commit was slightly broken. (This required a few retries,
because I couldn't reproduce the issue on my own machine.)
When the audio buffer went low, but could not be refilled yet, it could
happen that the AO playback thread and the decode thread could enter a
wakeup feedback loop, causing up to 100% CPU usage doing nothing. This
happened because the decoder thread would wake up the AO thread when
writing 0 bytes of newly decoded data, and the AO thread in reaction
wakes up the decoder thread after writing 0 bytes to the AO buffer.
Fix this by waking up the decoder thread only if data was actually
played or queued. (This will still cause some redundant wakeups, but
will eventually settle down, reducing CPU usage close to ideal.)
I don't think this is really a very good idea because it is conceptually
incorrect but other prominent multimedia programs use this approach
(VLC and xbmc), and it seems to make the conversion more robust in certain
cases.
For example it has been reported, that configuring a receiver that can output
7.1 to output 5.1, will make CoreAudio report 8 channel descriptions, and the
last 2 descriptions will be tagged kAudioChannelLabel_Unknown.
Fixes#737
The code was falling back to the full waveext chmap_sel when less than 2
channels were detected. This new code is slightly more correct since it only
fills the chmap_sel with the stereo or mono chmap in the fallback case.
CoreAudio supports 3 kinds of layouts: bitmap based, tag based, and speaker
description based (using either channel labels or positional data).
Previously we tried to convert everything to bitmap based channel layouts,
but it turns out description based ones are the most generic and there are
built-in CoreAudio APIs to perform the conversion in this direction.
Moreover description based layouts support waveext extensions (like SDL and
SDR), and are easier to map to mp_chmaps.
The comment says that it wakes up the main thread if 50% has been
played, but in reality the value was 0.74/2 => 37.5%. Correct this. This
probably changes little, because it's a very fuzzy heuristic in the
first place.
Also move down the min_wait calculation to where it's actually used.
For some reason, the buffered_audio variable was used to "cache" the
ao_get_delay() result. But I can't really see any reason why this should
be done, and it just seems to complicate everything.
One reason might be that the value should be checked only if the AO
buffers have been recently filled (as otherwise the delay could go low
and trigger an accidental EOF condition), but this didn't work anyway,
since buffered_audio is set from ao_get_delay() anyway at a later point
if it was unset. And in both cases, the value is used _after_ filling
the audio buffers anyway.
Simplify it. Also, move the audio EOF condition to a separate function.
(Note that ao_eof_reached() probably could/should whether the last
ao_play() call had AOPLAY_FINAL_CHUNK set to avoid accidental EOF on
underflows, but for now let's keep the code equivalent.)
This was reported with PulseAudio 2.1. Apparently it still has problems
with reporting the correct delay. Since ao_pulse.c still has our custom
get_delay implementation, there's a possibility that this is our fault,
but this seems unlikely, because it's full of workarounds for issues
like this. It's also possible that this problem doesn't exist on
PulseAudio 5.0 anymore (I didn't explicitly retest it).
The check is general and works for all push based AOs. For pull based
AOs, this can't happen as pull.c implements all the logic correctly.
This should probably be an AO function, but since the playloop still has
some strange stuff (using the buffered_audio variable instead of calling
ao_get_delay() directly), just leave it and make it more explicit.
Same change as in e2184fcb, but this time for pull based AOs. This is
slightly controversial, because it will make a fast syscall from e.g.
ao_jack. And according to JackAudio developers, syscalls are evil and
will destroy realtime operation. But I don't think this is an issue at
all.
Still avoid locking a mutex. I'm not sure what jackaudio does in the
worst case - but if they set the jackaudio thread (and only this thread)
to realtime, we might run into deadlock situations due to priority
inversion and such. I'm not quite sure whether this can happen, but I'll
readily follow the cargo cult if it makes hack happy.
I'm not quite sure why ao_pulse needs this. It was broken when a thread
to fill audio buffers was added to AO - the pulseaudio callback was
waking up the playback thread, not the audio thread. But nobody noticed,
so it can't be very important. In any case, this change makes it wake up
the audio thread instead (which in turn wakes up the playback thread if
needed).
And also add a function ao_need_data(), which AO drivers can call if
their audio buffer runs low.
This change intends to make it easier for the playback thread: instead
of making the playback thread calculate a timeout at which the audio
buffer should be refilled, make the push.c audio thread wakeup the core
instead.
ao_need_data() is going to be used by ao_pulse, and we need to
workaround a stupid situation with pulseaudio causing a deadlock because
its callback still holds the internal pulseaudio lock.
For AOs that don't call ao_need_data(), the deadline is calculated by
the buffer fill status and latency, as before.
Also fix a format string mistake in a log call using it.
I wonder if this code shouldn't use FormatMessage, but it looks kind
of involved [1], so: no, thanks.
[1] http://support.microsoft.com/kb/256348/en-us
The volume controls in mpv now affect the session's volume (the
application's volume in the mixer). Since we do not request a
non-persistent session, the volume and mute status persist across mpv
invocations and system reboots.
In exclusive mode, WASAPI doesn't have access to a mixer so the endpoint
(sound card)'s master volume is modified instead. Since by definition
mpv is the only thing outputting audio in exclusive mode, this causes no
conflict, and ao_wasapi restores the last user-set volume when it's
uninitialized.
Due to the COM Single-Threaded Apartment model, the thread owning the
objects will still do all the actual method calls (in the form of
message dispatches), but at least this will be COM's problem rather than
having to set up several handles and adding extra code to the event
thread.
Since the event thread still needs to own the WASAPI handles to avoid
waiting on another thread to dispatch the messages, the init and uninit
code still has to run in the thread.
This also removes a broken drain implementation and removes unused
headers from each of the files split from the original ao_wasapi.c.
ao_wasapi.c was almost entirely init code mixed with option code and
occasionally actual audio handling code. Split most things to
ao_wasapi_utils.c and keep the audio handling code in ao_wasapi.c.
Gets rid of the internal ring buffer and get_buffer. Corrects an
implementation error in thread_reset.
There is still a possible race condition on reset, and a few refactors
left to do. If feasible, the thread that handles everything
WASAPI-related will be made to only handle feed events.
Assume obtained.samples contains the number of samples the SDL audio
callback will request at once. Then make sure ao.c will set the buffer
size at least to 3 times that value (or more).
Might help with bad SDL audio backends like ESD, which supposedly uses a
500ms buffer.
In general, we don't need to have a large hw audio buffer size anymore,
because we can quickly fill it from the soft buffer.
Note that this probably doesn't change much anyway. On my system (dmix
enabled), the buffer size is only 170ms, and ALSA won't give more. Even
when using a hardware device the buffer size seems to be limited to
341ms.
This AO pretended to support volume operations when in spdif passthrough
mode, but actually did nothing. This is wrong: at least the GET
operations must write their argument. Signal that volume is unsupported
instead.
This was probably a hack to prevent insertion of volume filters or so,
but it didn't work anyway, while recovering after failed volume filter
insertion does work, so this is not needed at all.
Since the addition of the AO feed thread, 200ms of latency (MIN_BUFFER)
was added to all push-based AOs. This is not so nice, because even AOs
with relatively small buffering (e.g. ao_alsa on my system with ~170ms
of buffer size), the additional latency becomes noticable when e.g.
toggling mute with softvol.
Fix this by trying to keep not only 200ms minimum buffer, but also 200ms
maximum buffer. In other words, never buffer beyond 200ms in total. Do
this by estimating the AO's buffer fill status using get_space and the
initially known AO buffer size (the get_space return value on
initialization, before any audio was played). We limit the maximum
amount of data written to the soft buffer so that soft buffer size and
audio buffer size equal to 200ms (MIN_BUFFER).
To avoid weird problems with weird AOs, we buffer beyond MIN_BUFFER if
the AO's get_space requests more data than that, and as long as the soft
buffer is large enough.
Note that this is just a hack to improve the latency. When the audio
chain gains the ability to refilter data, this won't be needed anymore,
and instead we can introduce some sort of buffer replacement function in
order to update data in the soft buffer.
It is possible to have ao->reset() called between ao->pause() and
ao->resume() when seeking during the pause. If the underlying PCM
supports pausing, resuming an already reset PCM will produce an error.
Avoid that by explicitly checking PCM state before calling
snd_pcm_pause().
Signed-off-by: wm4 <wm4@nowhere>
The uint64_t math would cause overflow at long enough system uptimes
(...such as 3 days), and any precision error given by the double math will
be under one milisecond.
One strange issue is that we apparently can't stop the audio API on
audio reset (ao_driver.reset). We could use SDL_PauseAudio, but that
doesn't specify whether remaining audio is dropped. We also could use
SDL_LockAudio, but holding that over a long time will probably be bad,
and it probably doesn't drop audio. This means we simply play silence
after a reset, instead of stopping the callback completely. (The
existing code ran into an underrun in this situation.)
The delay estimation works about the same. We simply assume that the
callback is locked to audio timing (like ao_jack), and that 1 callback
corresponds to 1 period. It seems this (removed) code fragment assumes
there 1 one period size delay:
// delay subcomponent: remaining audio from the next played buffer, as
// provided by the callback
buffer_interval += callback_interval;
so we explicitly do that too.
Until now, this was always conflated with uninit. This was ugly, and
also many AOs emulated this manually (or just ignored it). Make draining
an explicit operation, so AOs which support it can provide it, and for
all others generic code will emulate it.
For ao_wasapi, we keep it simple and basically disable the internal
draining implementation (maybe it should be restored later).
Tested on Linux only.
Same deal as with the previous commit. We don't lose any functionality,
except for waiting "properly" on audio end, instead of waiting using the
delay estimate.