This echanges the two events hForceFeed/hFeedDone for hResume. This
like the last commit makes things more deterministic.
Importantly, the forcefeed is only done if there is not already a full
buffer yet to be played by the device. This should fix some of the
problems with exclusive mode.
This commit also removes the necessity to have a proxy to the
AudioClient object in the main thread.
fixes#1529
This makes things a bit more deterministic. It ensures that the audio
thread isn't doing anything between IAudioClient_Stop(),
IAudioClient_Reset() and setting the sample_count to 0.
Buffer overfilling on resume is still a problem in exclusive mode (see
next commit).
This commit adds notifications for hot plugging of devices. It also extends
the old behaviour of the `audio-out-detected-device` property which is now
backed by the hotplugging code. This allows clients to be notified when the
actual audio output device changes.
Maybe hotplugging should be supported for ao_coreaudio_exclusive too, but it's
device selection code is a bit fragile.
This requires jumping through multiple hoops on fire. Since the
PulseAudio API is virtually undocumented, I'm not sure if this is
correct either. We only react to sink events, and only to the NEW/REMOVE
events. CHANGE events are ignored, because PulseAudio fires them far too
often - even if the system is completely idle! If pa_sink_info.name can
change, we're in trouble. pa_sink_info.description is not so important,
but it'd also be a bit un-nice if it can change, and we don't update it.
The weird way how the actual AO and the hotplug context share the same
struct (ao) comes in handy here, although context_success_cb() still had
to be duplicated from success_cb() - the unused argument has a different
type.
Not very important for the command line player; but GUI applications
will want to know about this.
This only adds the internal API; support for specific audio outputs
comes later.
This reuses the ao struct as context for the hotplug event listener,
similar to how the "old" device listing API did. This is probably a bit
unclean and confusing. One argument got reusing it is that otherwise
rewriting parts of ao_pulse would be required (because the PulseAudio
API requires so damn much boilerplate). Another is that --ao-defaults is
applied to the hotplug dummy ao struct, which automatically applies such
defaults even to the hotplug context.
Notification works through the property observation mechanism in the
client API. The notification chain is a bit complicated: the AO notifies
the player, which in turn notifies the clients, which in turn will
actually retrieve the device list. (It still has the advantage that it's
slightly cleaner, since the AO stuff doesn't need to know about client
API issues.)
The weird handling of atomic flags in ao.c is because we still don't
require real atomics from the compiler. Otherwise we'd just use atomic
bitwise operations.
This is a small oversight. The client name (as set on command line
options or, more importantly, the client API) was not set when listing
devices e.g. via the "audio-device-list" property.
Might or might not fix#1578.
Also adjust the log level for an unrelated message.
rubberband_available() can return a negative value, which we assigned to
a size_t variable, leading to the frame allocation to fail. This could
spam "Error filtering frame.". (That it spams this instead of exiting
should probably also be considered a bug.)
At least in the realtime mode and in our case, a negative return value
should not have any different meaning from a 0 return value, in
particular because we call rubberband_get_samples_required() or set the
"final" parameter for rubberband_process() to continue/stop processing.
After some testing, I am fairly convinced that these defaults sound
better than the previous settings. This also eliminates some issue
with random crackling and noise.
Also remove the `stretch` option since it has no effect in
realtime mode.
The previous commit on this filter accidentally removed the
RubberBandOptionProcessRealTime option. Without it, the lib prints a
warning and passes the audio through.
Also add the RubberBandOptionSmoothingOn option back. Though for some
reason the output sounds still very wrong.
librubberband exports a big load of options. Normally, the default
settings (whether they're librubberband defaults or our defaults) should
be sufficient, but since I'm not so sure about this, making it
configurable allows others to figure it out for me.
The problem here is that librubberband can buffer an arbitrary amount
of data, but at the same time doesn't provide a way to query how much
data is buffered. So we keep track of this manually, assuming that
librubberband tries to reach the requested time ratio for input and
output (which is probably true).
The disadvantage is that rounding errors could accumulate over time.
(Maybe it should try to round towards keeping the time ratio.)
In theory it could happen that draining on EOF happens incrementally,
and then the unconditional reset could have dropped the remaining
buffered audio.
If "--af=rubberband" is used, librubberband will be used to speed up or
slow down audio with pitch correction.
This still has some problems: the audio delay is not calculated
correctly, so the audio position jitters around by a few milliseconds.
This will probably ruin video timing.
Staring at the code a bit, it turns out that changing speed without
losing state is quite easy. The initialization code is big and
complicated, but most of it is specific only to the configured audio
format, not the speed.
Refactor the code so that changing speed at runtime could work. (It's
not actually used yet - the player code still does a complete reinit.
This will be fixed in the next commit.)
The "if (s->speed_tempo == s->speed_pitch)" looks a bit strange, but
does the same thing as the code did before: speed can be changed only if
exactly one flag is set. If both are set or none, speed can't be
changed.
This code skipped initialization if no speed/pitch change was to be
applied.
It also didn't force conversion of the audio to a supported format,
which is probably the most important case in context of compatibility.
With this change applied, af_scaletempo will always force format
conversion.
To make the change less disruptive, make the filter detach if
unconvertable formats are used. Some users use spdif and also have
"af=scaletempo" in their config, so better not completely break this.
In the case the filter was added with the "speed=both" suboption, the
filter also detached itself in this case; but it's an obscure case, so I
don't care about that.
Previously we let the user use the audio device ID, but this is not persistent
and can change when plugging in new devices. That of course made it quite
worthless for storing it as a user setting for GUIs, or for user scripts.
In theory getting the kAudioDevicePropertyDeviceUID can fail but it doesn't
on any of my devices, so I'm leaving the error reporting quite high and see if
someone complains.
The MSDN documentation for IsFormatSupported says a return code of
AUDCLNT_E_UNSUPPORTED_FORMAT means the function "succeeded but the
specified format is not supported in exclusive mode." This seems to
imply that the format is supported in shared mode, and that's what the
old code assumed, however try_format would incorrectly return success
with some drivers.
The remarks section of the documentation contradicts that assumption. It
says that in shared mode, if the audio engine does not support the
caller-specified format or any similar format, ppClosestMatch is set to
NULL and the function returns AUDCLNT_E_UNSUPPORTED_FORMAT. This is the
same as in exclusive mode, so treat AUDCLNT_E_UNSUPPORTED_FORMAT the
same regardless of opt_exclusive. In shared mode, the format selection
code will fall back to the mix format, which should always be supported.
Apparently, physically disconnecting the audio device (consider USB
audio) breaks the ALSA device handle forever. It will signal ENODEV.
Fortunately, it's easy for us to handle this, and we can just use
existing mechanisms that will make the playback core close and reopen
the AO. Whether the immediate reopening will actually succeeds really is
ALSA's problem, though.
In general, you need to check errno when using strtol(), but as far as I
know, strtol() won't reset errno on success. This has to be done
manually. The code could have failed sporadically if strtol() succeeded,
and errno was already set to one of the checked values.
(This strtol() still isn't fully error checked, but I don't know if it's
intentional, e.g. for parsing a numeric prefix only.)
Before this commit, ao_null was used as last fallback. This doesn't make
too much sense. Why would you decode audio just to discard it? Let audio
initialization fail instead. This also handles the weird but possible
corner-case that ao_null might fail initializing, in which case e.g.
ao_pcm could be autoselected. (This happened once, and had to be fixed
manually.)
This removes the slightly duplicated code for picking the required AO
driver if --audio-device forces one. Now --audio-device reuses the same
code as --ao for this.
As a consequence, ao_alloc_pb() and ao_create() can be merged into
ao_init(). Although the ao_init() argument list, which is already pretty
big, grows by one, it's better than having all these similar sounding
functions around.
Actually, I just wanted to do the change the following commit will do,
but I found this code was more of a mess than it had to be.
Adds about 7 lines of boilerplate per filter. This could be avoided by
providing a different entrypoint (something like af->filter_inplace),
which would basically mirror the old interface exactly for this kind of
filter. But I feel like it would just be a hack to support all those
old, useless filters better. (The ideal solution would be using a
language that can do closures to provide a compat. wrapper, but
whatever.)
af_bs2b has terribly repetitious code for setting up filter functions
for each format (most of them useless, in addition to bs2b being
useless), so I did something terrible with macros.
af_sinesuppress had commented code for float filtering (maybe it was
broken; it has been commented every since it was added in 2006). Remove
this code.
Just to make sure all filters get the correct format. Together wih the
check in af_add_output_frame(), this asserts that
af->prev->fmt_out == af->fmt_in
This also requires setting the "in" pseudo-filter (s->first) formats
correctly. Before this commit, the fmt_in/fmt_out fields weren't used
for this filter.
Commit 5e25a3d2 broke handling of the initial frame (the one decoded
with initial_audio_decode()). It didn't update the pts_offset field,
leading to a shift in timestamps by one audio frame.
Fix by calling the actual decode function in a single place. This
requires slightly more changes than what would be necessary to fix the
bug, but it also somewhat simplifies the data flow.
The goal is switching the whole audio chain to using refcounted frames.
This brings the architecture closer to FFmpeg, enables better
integration with libavfilter, will reduce useless copying somewhat, and
will probably allow better timestamp tracking.
For now, every filter goes through a semi-awful wrapper in
af_do_filter(), though. This will be fixed step by step, and the wrapper
should eventually be removed. Another thing that will have to be done is
improving the timestamp handling and avoiding extra copies for the AO.
Some of the new code is rather similar to the video filter code (the
core filter code basically just has types replaced). Such code
duplication is normally very unwanted, but in this case there's probably
no other choice. On the other hand, this code is pretty simple (even if
somewhat tricky). Maybe there will be unified filter code in the future,
but this is still far away.