summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-03-09 00:17:18 +0100
committerwm4 <wm4@nowhere>2014-03-09 01:27:41 +0100
commit2f03dc259960c9cb282e8f371d9f68266afea49c (patch)
treecd3cb608983ef5bf5acfde5a103587cd38dd167e /audio
parente5e86083329f25342f1a7ec30efcaaa6cee0aec9 (diff)
downloadmpv-2f03dc259960c9cb282e8f371d9f68266afea49c.tar.bz2
mpv-2f03dc259960c9cb282e8f371d9f68266afea49c.tar.xz
ao_portaudio: use new pull API helpers
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.
Diffstat (limited to 'audio')
-rw-r--r--audio/out/ao_portaudio.c160
1 files changed, 13 insertions, 147 deletions
diff --git a/audio/out/ao_portaudio.c b/audio/out/ao_portaudio.c
index c3ba343485..135c9224f1 100644
--- a/audio/out/ao_portaudio.c
+++ b/audio/out/ao_portaudio.c
@@ -20,7 +20,6 @@
#include <string.h>
#include <stdlib.h>
#include <assert.h>
-#include <pthread.h>
#include <libavutil/common.h>
#include <portaudio.h>
@@ -29,22 +28,12 @@
#include "options/m_option.h"
#include "audio/format.h"
#include "common/msg.h"
-#include "misc/ring.h"
+#include "osdep/timer.h"
#include "ao.h"
#include "internal.h"
struct priv {
PaStream *stream;
- int framelen;
-
- pthread_mutex_t ring_mutex;
-
- // following variables are protected by ring_mutex
- struct mp_ring *ring;
- double play_time; // time when last packet returned to PA is on speaker
- // 0 is N/A (0 is not a valid PA time value)
- int play_silence; // play this many bytes of silence, before real data
- bool play_remaining;// play what's left in the buffer, then stop stream
// Options
char *cfg_device;
@@ -81,12 +70,6 @@ static bool check_pa_ret(struct mp_log *log, int ret)
#define CHECK_PA_RET(ret) check_pa_ret(ao->log, (ret))
-static int seconds_to_bytes(struct ao *ao, double seconds)
-{
- return af_fmt_seconds_to_bytes(ao->format, seconds, ao->channels.num,
- ao->samplerate);
-}
-
static int to_int(const char *s, int return_on_error)
{
char *endptr;
@@ -142,11 +125,6 @@ static int validate_device_opt(struct mp_log *log, const m_option_t *opt,
return 0;
}
-static void fill_silence(unsigned char *ptr, int len)
-{
- memset(ptr, 0, len);
-}
-
static int stream_callback(const void *input,
void *output_v,
unsigned long frameCount,
@@ -155,42 +133,17 @@ static int stream_callback(const void *input,
void *userData)
{
struct ao *ao = userData;
- struct priv *priv = ao->priv;
- int res = paContinue;
- unsigned char *output = output_v;
- int len_bytes = frameCount * priv->framelen;
-
- pthread_mutex_lock(&priv->ring_mutex);
// NOTE: PA + ALSA in dmix mode seems to pretend that there is no latency
// (outputBufferDacTime == currentTime)
- priv->play_time = timeInfo->outputBufferDacTime
- + len_bytes / (float)ao->bps;
-
- if (priv->play_silence > 0) {
- int bytes = FFMIN(priv->play_silence, len_bytes);
- fill_silence(output, bytes);
- priv->play_silence -= bytes;
- len_bytes -= bytes;
- output += bytes;
- }
- int read = mp_ring_read(priv->ring, output, len_bytes);
- len_bytes -= read;
- output += read;
-
- if (len_bytes > 0) {
- if (priv->play_remaining) {
- res = paComplete;
- priv->play_remaining = false;
- } else {
- MP_ERR(ao, "Buffer underflow!\n");
- }
- fill_silence(output, len_bytes);
- }
+ double play_time = timeInfo->outputBufferDacTime
+ + frameCount / (float)ao->samplerate;
+ double latency = play_time - timeInfo->currentTime;
+ int64_t end = mp_time_us() + MPMAX(0, latency * 1000000.0);
- pthread_mutex_unlock(&priv->ring_mutex);
+ ao_read_data(ao, &output_v, frameCount, end);
- return res;
+ return paContinue;
}
static void uninit(struct ao *ao, bool cut_audio)
@@ -199,18 +152,13 @@ static void uninit(struct ao *ao, bool cut_audio)
if (priv->stream) {
if (!cut_audio && Pa_IsStreamActive(priv->stream) == 1) {
- pthread_mutex_lock(&priv->ring_mutex);
-
- priv->play_remaining = true;
-
- pthread_mutex_unlock(&priv->ring_mutex);
+ ao_wait_drain(ao);
CHECK_PA_RET(Pa_StopStream(priv->stream));
}
CHECK_PA_RET(Pa_CloseStream(priv->stream));
}
- pthread_mutex_destroy(&priv->ring_mutex);
Pa_Terminate();
}
@@ -221,8 +169,6 @@ static int init(struct ao *ao)
if (!CHECK_PA_RET(Pa_Initialize()))
return -1;
- pthread_mutex_init(&priv->ring_mutex, NULL);
-
int pa_device = Pa_GetDefaultOutputDevice();
if (priv->cfg_device && priv->cfg_device[0])
pa_device = find_device(ao->log, priv->cfg_device);
@@ -261,8 +207,8 @@ static int init(struct ao *ao)
ao->format = fmt->mp_format;
sp.sampleFormat = fmt->pa_format;
- priv->framelen = ao->channels.num * (af_fmt2bits(ao->format) / 8);
- ao->bps = ao->samplerate * priv->framelen;
+ int framelen = ao->channels.num * (af_fmt2bits(ao->format) / 8);
+ ao->bps = ao->samplerate * framelen;
if (!CHECK_PA_RET(Pa_IsFormatSupported(NULL, &sp, ao->samplerate)))
goto error_exit;
@@ -271,8 +217,6 @@ static int init(struct ao *ao)
stream_callback, ao)))
goto error_exit;
- priv->ring = mp_ring_new(priv, seconds_to_bytes(ao, 0.5));
-
return 0;
error_exit:
@@ -280,95 +224,20 @@ error_exit:
return -1;
}
-static int play(struct ao *ao, void **data, int samples, int flags)
-{
- struct priv *priv = ao->priv;
-
- pthread_mutex_lock(&priv->ring_mutex);
-
- int write_len = mp_ring_write(priv->ring, data[0], samples * ao->sstride);
- if (flags & AOPLAY_FINAL_CHUNK)
- priv->play_remaining = true;
-
- pthread_mutex_unlock(&priv->ring_mutex);
-
- if (Pa_IsStreamStopped(priv->stream) == 1)
- CHECK_PA_RET(Pa_StartStream(priv->stream));
-
- return write_len / ao->sstride;
-}
-
-static int get_space(struct ao *ao)
-{
- struct priv *priv = ao->priv;
-
- pthread_mutex_lock(&priv->ring_mutex);
-
- int free = mp_ring_available(priv->ring);
-
- pthread_mutex_unlock(&priv->ring_mutex);
-
- return free / ao->sstride;
-}
-
-static float get_delay(struct ao *ao)
-{
- struct priv *priv = ao->priv;
-
- double stream_time = Pa_GetStreamTime(priv->stream);
-
- pthread_mutex_lock(&priv->ring_mutex);
-
- float frame_time = priv->play_time ? priv->play_time - stream_time : 0;
- float buffer_latency = (mp_ring_buffered(priv->ring) + priv->play_silence)
- / (float)ao->bps;
-
- pthread_mutex_unlock(&priv->ring_mutex);
-
- return buffer_latency + frame_time;
-}
-
static void reset(struct ao *ao)
{
struct priv *priv = ao->priv;
if (Pa_IsStreamStopped(priv->stream) != 1)
CHECK_PA_RET(Pa_AbortStream(priv->stream));
-
- pthread_mutex_lock(&priv->ring_mutex);
-
- mp_ring_reset(priv->ring);
- priv->play_remaining = false;
- priv->play_time = 0;
- priv->play_silence = 0;
-
- pthread_mutex_unlock(&priv->ring_mutex);
-}
-
-static void pause(struct ao *ao)
-{
- struct priv *priv = ao->priv;
-
- CHECK_PA_RET(Pa_AbortStream(priv->stream));
-
- double stream_time = Pa_GetStreamTime(priv->stream);
-
- pthread_mutex_lock(&priv->ring_mutex);
-
- // When playback resumes, replace the lost audio (due to dropping the
- // portaudio/driver/hardware internal buffers) with silence.
- float frame_time = priv->play_time ? priv->play_time - stream_time : 0;
- priv->play_silence += seconds_to_bytes(ao, FFMAX(frame_time, 0));
- priv->play_time = 0;
-
- pthread_mutex_unlock(&priv->ring_mutex);
}
static void resume(struct ao *ao)
{
struct priv *priv = ao->priv;
- CHECK_PA_RET(Pa_StartStream(priv->stream));
+ if (Pa_IsStreamStopped(priv->stream) == 1)
+ CHECK_PA_RET(Pa_StartStream(priv->stream));
}
#define OPT_BASE_STRUCT struct priv
@@ -379,10 +248,7 @@ const struct ao_driver audio_out_portaudio = {
.init = init,
.uninit = uninit,
.reset = reset,
- .get_space = get_space,
- .play = play,
- .get_delay = get_delay,
- .pause = pause,
+ .pause = reset,
.resume = resume,
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]) {