2014-03-08 23:04:37 +00:00
|
|
|
/*
|
|
|
|
* This file is part of mpv.
|
|
|
|
*
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* mpv is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2014-03-08 23:04:37 +00:00
|
|
|
*
|
|
|
|
* mpv is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* GNU Lesser General Public License for more details.
|
2014-03-08 23:04:37 +00:00
|
|
|
*
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2014-03-08 23:04:37 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <inttypes.h>
|
2014-05-29 21:57:11 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
2014-03-08 23:04:37 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
2014-05-29 21:57:11 +00:00
|
|
|
#include "osdep/io.h"
|
|
|
|
|
2014-03-08 23:04:37 +00:00
|
|
|
#include "ao.h"
|
|
|
|
#include "internal.h"
|
|
|
|
#include "audio/format.h"
|
|
|
|
|
|
|
|
#include "common/msg.h"
|
|
|
|
#include "common/common.h"
|
|
|
|
|
2014-04-15 20:38:16 +00:00
|
|
|
#include "input/input.h"
|
|
|
|
|
2014-03-08 23:04:37 +00:00
|
|
|
#include "osdep/threads.h"
|
2014-04-17 20:50:49 +00:00
|
|
|
#include "osdep/timer.h"
|
2016-09-07 09:26:25 +00:00
|
|
|
#include "osdep/atomic.h"
|
2014-03-08 23:04:37 +00:00
|
|
|
|
|
|
|
#include "audio/audio.h"
|
|
|
|
#include "audio/audio_buffer.h"
|
|
|
|
|
|
|
|
struct ao_push_state {
|
|
|
|
pthread_t thread;
|
|
|
|
pthread_mutex_t lock;
|
|
|
|
pthread_cond_t wakeup;
|
|
|
|
|
2014-04-15 20:38:16 +00:00
|
|
|
// --- protected by lock
|
|
|
|
|
2014-03-08 23:04:37 +00:00
|
|
|
struct mp_audio_buffer *buffer;
|
|
|
|
|
|
|
|
bool terminate;
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
bool wait_on_ao;
|
2014-09-05 20:21:06 +00:00
|
|
|
bool still_playing;
|
2014-05-29 21:56:48 +00:00
|
|
|
bool need_wakeup;
|
|
|
|
bool paused;
|
2014-03-08 23:04:37 +00:00
|
|
|
|
|
|
|
// Whether the current buffer contains the complete audio.
|
|
|
|
bool final_chunk;
|
2014-04-17 20:50:49 +00:00
|
|
|
double expected_end_time;
|
2014-05-29 21:57:11 +00:00
|
|
|
|
|
|
|
int wakeup_pipe[2];
|
2014-03-08 23:04:37 +00:00
|
|
|
};
|
|
|
|
|
2014-05-29 21:56:48 +00:00
|
|
|
// lock must be held
|
2014-04-15 20:38:16 +00:00
|
|
|
static void wakeup_playthread(struct ao *ao)
|
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
2014-05-29 21:56:48 +00:00
|
|
|
if (ao->driver->wakeup)
|
|
|
|
ao->driver->wakeup(ao);
|
2014-04-15 20:38:16 +00:00
|
|
|
p->need_wakeup = true;
|
|
|
|
pthread_cond_signal(&p->wakeup);
|
|
|
|
}
|
|
|
|
|
2014-03-08 23:04:37 +00:00
|
|
|
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
|
|
|
|
{
|
|
|
|
int r = CONTROL_UNKNOWN;
|
|
|
|
if (ao->driver->control) {
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
pthread_mutex_lock(&p->lock);
|
|
|
|
r = ao->driver->control(ao, cmd, arg);
|
|
|
|
pthread_mutex_unlock(&p->lock);
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-09-05 20:21:06 +00:00
|
|
|
static double unlocked_get_delay(struct ao *ao)
|
2014-03-08 23:04:37 +00:00
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
double driver_delay = 0;
|
|
|
|
if (ao->driver->get_delay)
|
|
|
|
driver_delay = ao->driver->get_delay(ao);
|
2014-10-10 11:18:53 +00:00
|
|
|
return driver_delay + mp_audio_buffer_seconds(p->buffer);
|
2014-03-08 23:04:37 +00:00
|
|
|
}
|
|
|
|
|
2014-11-09 10:45:04 +00:00
|
|
|
static double get_delay(struct ao *ao)
|
2014-09-05 20:21:06 +00:00
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
pthread_mutex_lock(&p->lock);
|
2014-11-09 10:45:04 +00:00
|
|
|
double delay = unlocked_get_delay(ao);
|
2014-09-05 20:21:06 +00:00
|
|
|
pthread_mutex_unlock(&p->lock);
|
|
|
|
return delay;
|
|
|
|
}
|
|
|
|
|
2014-03-08 23:04:37 +00:00
|
|
|
static void reset(struct ao *ao)
|
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
pthread_mutex_lock(&p->lock);
|
|
|
|
if (ao->driver->reset)
|
|
|
|
ao->driver->reset(ao);
|
|
|
|
mp_audio_buffer_clear(p->buffer);
|
2014-05-29 21:56:48 +00:00
|
|
|
p->paused = false;
|
2014-09-06 14:25:27 +00:00
|
|
|
if (p->still_playing)
|
|
|
|
wakeup_playthread(ao);
|
2014-09-05 20:21:06 +00:00
|
|
|
p->still_playing = false;
|
2014-03-08 23:04:37 +00:00
|
|
|
pthread_mutex_unlock(&p->lock);
|
|
|
|
}
|
|
|
|
|
2014-05-29 21:57:11 +00:00
|
|
|
static void audio_pause(struct ao *ao)
|
2014-03-08 23:04:37 +00:00
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
pthread_mutex_lock(&p->lock);
|
|
|
|
if (ao->driver->pause)
|
|
|
|
ao->driver->pause(ao);
|
2014-05-29 21:56:48 +00:00
|
|
|
p->paused = true;
|
2014-04-15 20:38:16 +00:00
|
|
|
wakeup_playthread(ao);
|
2014-03-08 23:04:37 +00:00
|
|
|
pthread_mutex_unlock(&p->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void resume(struct ao *ao)
|
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
pthread_mutex_lock(&p->lock);
|
|
|
|
if (ao->driver->resume)
|
|
|
|
ao->driver->resume(ao);
|
2014-05-29 21:56:48 +00:00
|
|
|
p->paused = false;
|
2014-04-17 20:50:49 +00:00
|
|
|
p->expected_end_time = 0;
|
2014-04-15 20:38:16 +00:00
|
|
|
wakeup_playthread(ao);
|
2014-03-08 23:04:37 +00:00
|
|
|
pthread_mutex_unlock(&p->lock);
|
|
|
|
}
|
|
|
|
|
2014-03-08 23:49:39 +00:00
|
|
|
static void drain(struct ao *ao)
|
|
|
|
{
|
2014-05-30 00:14:45 +00:00
|
|
|
struct ao_push_state *p = ao->api_priv;
|
audio: apply an upper bound timeout when draining
This helps with shitty APIs and even shittier drivers (I'm looking at
you, ALSA). Sometimes they won't send proper wakeups. This can be fine
during playback, when for example playing video, because mpv still will
wakeup the AO outside of its own wakeup mechanisms when sending new data
to it. But when draining, it entirely relies on the driver's wakeup
mechanism. So when the driver wakeup mechanism didn't work, it could
hard freeze while waiting for the audio thread to play the rest of the
data.
Avoid this by waiting for an upper bound. We set this upper bound at the
total mpv audio buffer size plus 1 second. We don't use the get_delay
value, because the audio API could return crap for it, and we're being
paranoid here. I couldn't confirm whether this works correctly, because
my driver issue fixed itself.
(In the case that happened to me, the driver somehow stopped getting
interrupts. aplay froze instead of playing audio, and playing audio-only
files resulted in a chop party. Video worked, for reasons mentioned
above, but drainign froze hard. The driver problem was solved when
closing all audio output streams in the system. Might have been a dmix
related problem too.)
2016-06-12 19:05:10 +00:00
|
|
|
double maxbuffer = ao->buffer / (double)ao->samplerate + 1;
|
2014-05-30 00:14:45 +00:00
|
|
|
|
2014-10-04 22:31:20 +00:00
|
|
|
MP_VERBOSE(ao, "draining...\n");
|
|
|
|
|
2014-05-30 00:14:45 +00:00
|
|
|
pthread_mutex_lock(&p->lock);
|
2014-10-04 22:31:20 +00:00
|
|
|
if (p->paused)
|
|
|
|
goto done;
|
|
|
|
|
2014-05-30 00:14:45 +00:00
|
|
|
p->final_chunk = true;
|
|
|
|
wakeup_playthread(ao);
|
audio: apply an upper bound timeout when draining
This helps with shitty APIs and even shittier drivers (I'm looking at
you, ALSA). Sometimes they won't send proper wakeups. This can be fine
during playback, when for example playing video, because mpv still will
wakeup the AO outside of its own wakeup mechanisms when sending new data
to it. But when draining, it entirely relies on the driver's wakeup
mechanism. So when the driver wakeup mechanism didn't work, it could
hard freeze while waiting for the audio thread to play the rest of the
data.
Avoid this by waiting for an upper bound. We set this upper bound at the
total mpv audio buffer size plus 1 second. We don't use the get_delay
value, because the audio API could return crap for it, and we're being
paranoid here. I couldn't confirm whether this works correctly, because
my driver issue fixed itself.
(In the case that happened to me, the driver somehow stopped getting
interrupts. aplay froze instead of playing audio, and playing audio-only
files resulted in a chop party. Video worked, for reasons mentioned
above, but drainign froze hard. The driver problem was solved when
closing all audio output streams in the system. Might have been a dmix
related problem too.)
2016-06-12 19:05:10 +00:00
|
|
|
|
|
|
|
// Wait until everything is done. Since the audio API (especially ALSA)
|
|
|
|
// can't be trusted to do this right, and we're hard-blocking here, apply
|
|
|
|
// an upper bound timeout.
|
|
|
|
struct timespec until = mp_rel_time_to_timespec(maxbuffer);
|
|
|
|
while (p->still_playing && mp_audio_buffer_samples(p->buffer) > 0) {
|
|
|
|
if (pthread_cond_timedwait(&p->wakeup, &p->lock, &until)) {
|
|
|
|
MP_WARN(ao, "Draining is taking too long, aborting.\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
2014-05-30 00:14:45 +00:00
|
|
|
|
2014-10-04 22:31:20 +00:00
|
|
|
if (ao->driver->drain) {
|
|
|
|
ao->driver->drain(ao);
|
|
|
|
} else {
|
2014-10-05 21:05:54 +00:00
|
|
|
double time = unlocked_get_delay(ao);
|
audio: apply an upper bound timeout when draining
This helps with shitty APIs and even shittier drivers (I'm looking at
you, ALSA). Sometimes they won't send proper wakeups. This can be fine
during playback, when for example playing video, because mpv still will
wakeup the AO outside of its own wakeup mechanisms when sending new data
to it. But when draining, it entirely relies on the driver's wakeup
mechanism. So when the driver wakeup mechanism didn't work, it could
hard freeze while waiting for the audio thread to play the rest of the
data.
Avoid this by waiting for an upper bound. We set this upper bound at the
total mpv audio buffer size plus 1 second. We don't use the get_delay
value, because the audio API could return crap for it, and we're being
paranoid here. I couldn't confirm whether this works correctly, because
my driver issue fixed itself.
(In the case that happened to me, the driver somehow stopped getting
interrupts. aplay froze instead of playing audio, and playing audio-only
files resulted in a chop party. Video worked, for reasons mentioned
above, but drainign froze hard. The driver problem was solved when
closing all audio output streams in the system. Might have been a dmix
related problem too.)
2016-06-12 19:05:10 +00:00
|
|
|
mp_sleep_us(MPMIN(time, maxbuffer) * 1e6);
|
2014-10-04 22:13:00 +00:00
|
|
|
}
|
2014-10-04 22:31:20 +00:00
|
|
|
|
|
|
|
done:
|
|
|
|
pthread_mutex_unlock(&p->lock);
|
|
|
|
|
2014-07-13 18:06:33 +00:00
|
|
|
reset(ao);
|
2014-03-08 23:49:39 +00:00
|
|
|
}
|
2014-03-08 23:04:37 +00:00
|
|
|
|
2014-05-11 18:51:49 +00:00
|
|
|
static int unlocked_get_space(struct ao *ao)
|
2014-03-08 23:04:37 +00:00
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
audio/out: reduce amount of audio buffering
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.
2014-03-10 00:13:40 +00:00
|
|
|
int space = mp_audio_buffer_get_write_available(p->buffer);
|
|
|
|
if (ao->driver->get_space) {
|
2016-10-04 17:31:17 +00:00
|
|
|
int align = af_format_sample_alignment(ao->format);
|
audio/out: reduce amount of audio buffering
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.
2014-03-10 00:13:40 +00:00
|
|
|
// The following code attempts to keep the total buffered audio to
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
// ao->buffer in order to improve latency.
|
audio/out: reduce amount of audio buffering
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.
2014-03-10 00:13:40 +00:00
|
|
|
int device_space = ao->driver->get_space(ao);
|
|
|
|
int device_buffered = ao->device_buffer - device_space;
|
|
|
|
int soft_buffered = mp_audio_buffer_samples(p->buffer);
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
// The extra margin helps avoiding too many wakeups if the AO is fully
|
|
|
|
// byte based and doesn't do proper chunked processing.
|
|
|
|
int min_buffer = ao->buffer + 64;
|
|
|
|
int missing = min_buffer - device_buffered - soft_buffered;
|
2016-10-04 17:31:17 +00:00
|
|
|
missing = (missing + align - 1) / align * align;
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
// But always keep the device's buffer filled as much as we can.
|
|
|
|
int device_missing = device_space - soft_buffered;
|
|
|
|
missing = MPMAX(missing, device_missing);
|
audio/out: reduce amount of audio buffering
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.
2014-03-10 00:13:40 +00:00
|
|
|
space = MPMIN(space, missing);
|
|
|
|
space = MPMAX(0, space);
|
|
|
|
}
|
2014-05-11 18:51:49 +00:00
|
|
|
return space;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_space(struct ao *ao)
|
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
pthread_mutex_lock(&p->lock);
|
|
|
|
int space = unlocked_get_space(ao);
|
2014-03-08 23:04:37 +00:00
|
|
|
pthread_mutex_unlock(&p->lock);
|
audio/out: reduce amount of audio buffering
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.
2014-03-10 00:13:40 +00:00
|
|
|
return space;
|
2014-03-08 23:04:37 +00:00
|
|
|
}
|
|
|
|
|
2014-09-05 20:21:06 +00:00
|
|
|
static bool get_eof(struct ao *ao)
|
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
pthread_mutex_lock(&p->lock);
|
|
|
|
bool eof = !p->still_playing;
|
|
|
|
pthread_mutex_unlock(&p->lock);
|
|
|
|
return eof;
|
|
|
|
}
|
|
|
|
|
2014-03-08 23:04:37 +00:00
|
|
|
static int play(struct ao *ao, void **data, int samples, int flags)
|
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&p->lock);
|
|
|
|
|
|
|
|
int write_samples = mp_audio_buffer_get_write_available(p->buffer);
|
|
|
|
write_samples = MPMIN(write_samples, samples);
|
|
|
|
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
MP_TRACE(ao, "samples=%d flags=%d r=%d\n", samples, flags, write_samples);
|
|
|
|
|
2014-05-29 21:56:48 +00:00
|
|
|
if (write_samples < samples)
|
|
|
|
flags = flags & ~AOPLAY_FINAL_CHUNK;
|
|
|
|
bool is_final = flags & AOPLAY_FINAL_CHUNK;
|
|
|
|
|
2014-03-08 23:04:37 +00:00
|
|
|
struct mp_audio audio;
|
|
|
|
mp_audio_buffer_get_format(p->buffer, &audio);
|
|
|
|
for (int n = 0; n < ao->num_planes; n++)
|
|
|
|
audio.planes[n] = data[n];
|
|
|
|
audio.samples = write_samples;
|
|
|
|
mp_audio_buffer_append(p->buffer, &audio);
|
|
|
|
|
2014-05-29 21:56:48 +00:00
|
|
|
bool got_data = write_samples > 0 || p->paused || p->final_chunk != is_final;
|
2014-03-08 23:04:37 +00:00
|
|
|
|
2014-05-29 21:56:48 +00:00
|
|
|
p->final_chunk = is_final;
|
|
|
|
p->paused = false;
|
2014-10-14 20:07:04 +00:00
|
|
|
if (got_data) {
|
|
|
|
p->still_playing = true;
|
|
|
|
p->expected_end_time = 0;
|
|
|
|
}
|
2014-05-29 21:56:48 +00:00
|
|
|
|
|
|
|
// If we don't have new data, the decoder thread basically promises it
|
|
|
|
// will send new data as soon as it's available.
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
if (got_data)
|
2014-05-29 21:56:48 +00:00
|
|
|
wakeup_playthread(ao);
|
2014-03-08 23:04:37 +00:00
|
|
|
pthread_mutex_unlock(&p->lock);
|
|
|
|
return write_samples;
|
|
|
|
}
|
|
|
|
|
|
|
|
// called locked
|
2014-05-29 21:56:48 +00:00
|
|
|
static void ao_play_data(struct ao *ao)
|
2014-03-08 23:04:37 +00:00
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
struct mp_audio data;
|
|
|
|
mp_audio_buffer_peek(p->buffer, &data);
|
|
|
|
int max = data.samples;
|
2014-05-29 21:56:48 +00:00
|
|
|
int space = ao->driver->get_space(ao);
|
|
|
|
space = MPMAX(space, 0);
|
2014-03-08 23:04:37 +00:00
|
|
|
if (data.samples > space)
|
|
|
|
data.samples = space;
|
|
|
|
int flags = 0;
|
|
|
|
if (p->final_chunk && data.samples == max)
|
|
|
|
flags |= AOPLAY_FINAL_CHUNK;
|
2014-05-29 21:56:48 +00:00
|
|
|
MP_STATS(ao, "start ao fill");
|
|
|
|
int r = 0;
|
|
|
|
if (data.samples)
|
|
|
|
r = ao->driver->play(ao, data.planes, data.samples, flags);
|
|
|
|
MP_STATS(ao, "end ao fill");
|
2014-03-08 23:04:37 +00:00
|
|
|
if (r > data.samples) {
|
2014-05-11 14:26:23 +00:00
|
|
|
MP_WARN(ao, "Audio device returned non-sense value.\n");
|
2014-03-08 23:04:37 +00:00
|
|
|
r = data.samples;
|
|
|
|
}
|
2014-05-30 00:14:38 +00:00
|
|
|
r = MPMAX(r, 0);
|
|
|
|
// Probably can't copy the rest of the buffer due to period alignment.
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
bool stuck_eof = r <= 0 && space >= max && data.samples > 0;
|
|
|
|
if ((flags & AOPLAY_FINAL_CHUNK) && stuck_eof) {
|
2014-05-30 00:14:38 +00:00
|
|
|
MP_ERR(ao, "Audio output driver seems to ignore AOPLAY_FINAL_CHUNK.\n");
|
|
|
|
r = max;
|
|
|
|
}
|
|
|
|
mp_audio_buffer_skip(p->buffer, r);
|
2014-10-10 11:18:53 +00:00
|
|
|
if (r > 0)
|
|
|
|
p->expected_end_time = 0;
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
// Nothing written, but more input data than space - this must mean the
|
|
|
|
// AO's get_space() doesn't do period alignment correctly.
|
|
|
|
bool stuck = r == 0 && max >= space && space > 0;
|
|
|
|
if (stuck)
|
|
|
|
MP_ERR(ao, "Audio output is reporting incorrect buffer status.\n");
|
|
|
|
// Wait until space becomes available. Also wait if we actually wrote data,
|
|
|
|
// so the AO wakes us up properly if it needs more data.
|
|
|
|
p->wait_on_ao = space == 0 || r > 0 || stuck;
|
2014-09-05 20:21:06 +00:00
|
|
|
p->still_playing |= r > 0;
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
// If we just filled the AO completely (r == space), don't refill for a
|
|
|
|
// while. Prevents wakeup feedback with byte-granular AOs.
|
|
|
|
int needed = unlocked_get_space(ao);
|
2016-06-12 18:59:11 +00:00
|
|
|
bool more = needed >= (r == space ? ao->device_buffer / 4 : 1) && !stuck &&
|
|
|
|
!(flags & AOPLAY_FINAL_CHUNK);
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
if (more)
|
2016-09-16 12:23:54 +00:00
|
|
|
ao->wakeup_cb(ao->wakeup_ctx); // request more data
|
2016-06-12 18:59:11 +00:00
|
|
|
MP_TRACE(ao, "in=%d flags=%d space=%d r=%d wa/pl=%d/%d needed=%d more=%d\n",
|
|
|
|
max, flags, space, r, p->wait_on_ao, p->still_playing, needed, more);
|
2014-03-08 23:04:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *playthread(void *arg)
|
|
|
|
{
|
|
|
|
struct ao *ao = arg;
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
2014-10-19 21:32:34 +00:00
|
|
|
mpthread_set_name("ao");
|
2014-05-29 21:56:48 +00:00
|
|
|
pthread_mutex_lock(&p->lock);
|
|
|
|
while (!p->terminate) {
|
2014-06-03 13:57:47 +00:00
|
|
|
if (!p->paused)
|
|
|
|
ao_play_data(ao);
|
2014-05-29 21:56:48 +00:00
|
|
|
|
|
|
|
if (!p->need_wakeup) {
|
|
|
|
MP_STATS(ao, "start audio wait");
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
if (!p->wait_on_ao || p->paused) {
|
2014-05-29 21:56:48 +00:00
|
|
|
// Avoid busy waiting, because the audio API will still report
|
|
|
|
// that it needs new data, even if we're not ready yet, or if
|
|
|
|
// get_space() decides that the amount of audio buffered in the
|
|
|
|
// device is enough, and p->buffer can be empty.
|
|
|
|
// The most important part is that the decoder is woken up, so
|
|
|
|
// that the decoder will wake up us in turn.
|
|
|
|
MP_TRACE(ao, "buffer inactive.\n");
|
2014-09-05 20:21:06 +00:00
|
|
|
|
|
|
|
bool was_playing = p->still_playing;
|
|
|
|
double timeout = -1;
|
2014-10-10 11:18:53 +00:00
|
|
|
if (p->still_playing && !p->paused && p->final_chunk &&
|
|
|
|
!mp_audio_buffer_samples(p->buffer))
|
|
|
|
{
|
|
|
|
double now = mp_time_sec();
|
|
|
|
if (!p->expected_end_time)
|
|
|
|
p->expected_end_time = now + unlocked_get_delay(ao);
|
|
|
|
if (p->expected_end_time < now) {
|
2014-09-05 20:21:06 +00:00
|
|
|
p->still_playing = false;
|
2014-10-10 11:18:53 +00:00
|
|
|
} else {
|
|
|
|
timeout = p->expected_end_time - now;
|
|
|
|
}
|
2014-09-05 20:21:06 +00:00
|
|
|
}
|
|
|
|
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
if (was_playing && !p->still_playing)
|
2016-09-16 12:23:54 +00:00
|
|
|
ao->wakeup_cb(ao->wakeup_ctx);
|
2014-10-04 22:31:20 +00:00
|
|
|
pthread_cond_signal(&p->wakeup); // for draining
|
2014-09-05 20:21:06 +00:00
|
|
|
|
|
|
|
if (p->still_playing && timeout > 0) {
|
2015-05-11 21:44:36 +00:00
|
|
|
struct timespec ts = mp_rel_time_to_timespec(timeout);
|
|
|
|
pthread_cond_timedwait(&p->wakeup, &p->lock, &ts);
|
2014-09-05 20:21:06 +00:00
|
|
|
} else {
|
|
|
|
pthread_cond_wait(&p->wakeup, &p->lock);
|
|
|
|
}
|
2014-03-08 23:04:37 +00:00
|
|
|
} else {
|
2014-10-10 11:18:53 +00:00
|
|
|
// Wait until the device wants us to write more data to it.
|
2014-05-29 21:56:48 +00:00
|
|
|
if (!ao->driver->wait || ao->driver->wait(ao, &p->lock) < 0) {
|
|
|
|
// Fallback to guessing.
|
audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).
The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.
This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.
Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)
This commit will probably cause a bunch of regressions again.
2014-09-06 10:59:04 +00:00
|
|
|
double timeout = 0;
|
|
|
|
if (ao->driver->get_delay)
|
|
|
|
timeout = ao->driver->get_delay(ao);
|
|
|
|
timeout *= 0.25; // wake up if 25% played
|
2015-05-11 21:44:36 +00:00
|
|
|
if (!p->need_wakeup) {
|
|
|
|
struct timespec ts = mp_rel_time_to_timespec(timeout);
|
|
|
|
pthread_cond_timedwait(&p->wakeup, &p->lock, &ts);
|
|
|
|
}
|
2014-05-29 21:56:48 +00:00
|
|
|
}
|
2014-03-08 23:04:37 +00:00
|
|
|
}
|
2014-05-29 21:56:48 +00:00
|
|
|
MP_STATS(ao, "end audio wait");
|
2014-03-08 23:04:37 +00:00
|
|
|
}
|
2014-04-15 20:38:16 +00:00
|
|
|
p->need_wakeup = false;
|
2014-03-08 23:04:37 +00:00
|
|
|
}
|
2014-05-29 21:56:48 +00:00
|
|
|
pthread_mutex_unlock(&p->lock);
|
2014-03-08 23:04:37 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-09-27 02:54:17 +00:00
|
|
|
static void destroy_no_thread(struct ao *ao)
|
2014-03-08 23:04:37 +00:00
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
|
2014-03-08 23:49:39 +00:00
|
|
|
ao->driver->uninit(ao);
|
2014-03-08 23:04:37 +00:00
|
|
|
|
2014-05-29 21:57:11 +00:00
|
|
|
for (int n = 0; n < 2; n++)
|
|
|
|
close(p->wakeup_pipe[n]);
|
|
|
|
|
2014-03-08 23:04:37 +00:00
|
|
|
pthread_cond_destroy(&p->wakeup);
|
|
|
|
pthread_mutex_destroy(&p->lock);
|
|
|
|
}
|
|
|
|
|
2014-09-27 02:54:17 +00:00
|
|
|
static void uninit(struct ao *ao)
|
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&p->lock);
|
|
|
|
p->terminate = true;
|
|
|
|
wakeup_playthread(ao);
|
|
|
|
pthread_mutex_unlock(&p->lock);
|
|
|
|
|
|
|
|
pthread_join(p->thread, NULL);
|
|
|
|
|
|
|
|
destroy_no_thread(ao);
|
|
|
|
}
|
|
|
|
|
2014-03-08 23:04:37 +00:00
|
|
|
static int init(struct ao *ao)
|
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
|
|
|
|
pthread_mutex_init(&p->lock, NULL);
|
|
|
|
pthread_cond_init(&p->wakeup, NULL);
|
2014-07-26 18:26:27 +00:00
|
|
|
mp_make_wakeup_pipe(p->wakeup_pipe);
|
2014-03-08 23:04:37 +00:00
|
|
|
|
2014-09-27 02:52:46 +00:00
|
|
|
if (ao->device_buffer <= 0) {
|
|
|
|
MP_FATAL(ao, "Couldn't probe device buffer size.\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2014-03-08 23:04:37 +00:00
|
|
|
p->buffer = mp_audio_buffer_create(ao);
|
|
|
|
mp_audio_buffer_reinit_fmt(p->buffer, ao->format,
|
|
|
|
&ao->channels, ao->samplerate);
|
|
|
|
mp_audio_buffer_preallocate_min(p->buffer, ao->buffer);
|
2014-07-25 12:30:59 +00:00
|
|
|
if (pthread_create(&p->thread, NULL, playthread, ao))
|
|
|
|
goto err;
|
2014-03-08 23:04:37 +00:00
|
|
|
return 0;
|
2014-07-25 12:30:59 +00:00
|
|
|
err:
|
2014-09-27 02:54:17 +00:00
|
|
|
destroy_no_thread(ao);
|
2014-07-25 12:30:59 +00:00
|
|
|
return -1;
|
2014-03-08 23:04:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const struct ao_driver ao_api_push = {
|
|
|
|
.init = init,
|
|
|
|
.control = control,
|
|
|
|
.uninit = uninit,
|
|
|
|
.reset = reset,
|
|
|
|
.get_space = get_space,
|
|
|
|
.play = play,
|
|
|
|
.get_delay = get_delay,
|
2014-05-29 21:57:11 +00:00
|
|
|
.pause = audio_pause,
|
2014-03-08 23:04:37 +00:00
|
|
|
.resume = resume,
|
2014-03-08 23:49:39 +00:00
|
|
|
.drain = drain,
|
2014-09-05 20:21:06 +00:00
|
|
|
.get_eof = get_eof,
|
2014-03-08 23:04:37 +00:00
|
|
|
.priv_size = sizeof(struct ao_push_state),
|
|
|
|
};
|
|
|
|
|
2014-04-15 20:38:16 +00:00
|
|
|
// Must be called locked.
|
2014-03-08 23:04:37 +00:00
|
|
|
int ao_play_silence(struct ao *ao, int samples)
|
|
|
|
{
|
|
|
|
assert(ao->api == &ao_api_push);
|
2015-06-26 21:06:37 +00:00
|
|
|
if (samples <= 0 || !af_fmt_is_pcm(ao->format) || !ao->driver->play)
|
2014-03-08 23:04:37 +00:00
|
|
|
return 0;
|
|
|
|
char *p = talloc_size(NULL, samples * ao->sstride);
|
|
|
|
af_fill_silence(p, samples * ao->sstride, ao->format);
|
|
|
|
void *tmp[MP_NUM_CHANNELS];
|
|
|
|
for (int n = 0; n < MP_NUM_CHANNELS; n++)
|
|
|
|
tmp[n] = p;
|
|
|
|
int r = ao->driver->play(ao, tmp, samples, 0);
|
|
|
|
talloc_free(p);
|
|
|
|
return r;
|
|
|
|
}
|
2014-05-29 21:57:11 +00:00
|
|
|
|
|
|
|
#ifndef __MINGW32__
|
|
|
|
|
|
|
|
#include <poll.h>
|
|
|
|
|
|
|
|
#define MAX_POLL_FDS 20
|
|
|
|
|
|
|
|
// Call poll() for the given fds. This will extend the given fds with the
|
|
|
|
// wakeup pipe, so ao_wakeup_poll() will basically interrupt this function.
|
|
|
|
// Unlocks the lock temporarily.
|
2014-05-30 21:54:11 +00:00
|
|
|
// Returns <0 on error, 0 on success, 1 if the caller should return immediately.
|
2014-05-29 21:57:11 +00:00
|
|
|
int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds,
|
|
|
|
pthread_mutex_t *lock)
|
|
|
|
{
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
assert(ao->api == &ao_api_push);
|
|
|
|
assert(&p->lock == lock);
|
|
|
|
|
2014-11-21 02:50:15 +00:00
|
|
|
if (num_fds >= MAX_POLL_FDS || p->wakeup_pipe[0] < 0)
|
2014-05-29 21:57:11 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
struct pollfd p_fds[MAX_POLL_FDS];
|
|
|
|
memcpy(p_fds, fds, num_fds * sizeof(p_fds[0]));
|
|
|
|
p_fds[num_fds] = (struct pollfd){
|
|
|
|
.fd = p->wakeup_pipe[0],
|
|
|
|
.events = POLLIN,
|
|
|
|
};
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&p->lock);
|
|
|
|
int r = poll(p_fds, num_fds + 1, -1);
|
|
|
|
r = r < 0 ? -errno : 0;
|
|
|
|
pthread_mutex_lock(&p->lock);
|
|
|
|
|
|
|
|
memcpy(fds, p_fds, num_fds * sizeof(fds[0]));
|
2014-05-30 21:54:11 +00:00
|
|
|
bool wakeup = false;
|
2014-05-29 21:57:11 +00:00
|
|
|
if (p_fds[num_fds].revents & POLLIN) {
|
2014-05-30 21:54:11 +00:00
|
|
|
wakeup = true;
|
2016-07-29 01:24:52 +00:00
|
|
|
// might "drown" some wakeups, but that's ok for our use-case
|
|
|
|
mp_flush_wakeup_pipe(p->wakeup_pipe[0]);
|
2014-05-29 21:57:11 +00:00
|
|
|
}
|
2014-05-30 21:54:11 +00:00
|
|
|
return (r >= 0 || r == -EINTR) ? wakeup : -1;
|
2014-05-29 21:57:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ao_wakeup_poll(struct ao *ao)
|
|
|
|
{
|
|
|
|
assert(ao->api == &ao_api_push);
|
|
|
|
struct ao_push_state *p = ao->api_priv;
|
|
|
|
|
2016-06-07 11:39:43 +00:00
|
|
|
(void)write(p->wakeup_pipe[1], &(char){0}, 1);
|
2014-05-29 21:57:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|