summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-03-09 00:12:53 +0100
committerwm4 <wm4@nowhere>2014-03-09 01:27:41 +0100
commite5e86083329f25342f1a7ec30efcaaa6cee0aec9 (patch)
tree5fb94366a2d353402a6453d09547ee2586fc6a34 /audio
parenta477481aabaa16f1ed15af456125160bc8face5a (diff)
downloadmpv-e5e86083329f25342f1a7ec30efcaaa6cee0aec9.tar.bz2
mpv-e5e86083329f25342f1a7ec30efcaaa6cee0aec9.tar.xz
ao_jack: use new pull API helpers
This removes the ringbuffer management from the code, and uses the generic code added with the previous commit. The result should be pretty much the same. The "estimate" sub-option goes away. This estimation is now always active. The new code for delay estimation is slightly different, and follows the claim of the jack framework that callbacks are timed exactly.
Diffstat (limited to 'audio')
-rw-r--r--audio/out/ao_jack.c212
1 files changed, 16 insertions, 196 deletions
diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c
index 5b142f2d06..b3cd3fd6ef 100644
--- a/audio/out/ao_jack.c
+++ b/audio/out/ao_jack.c
@@ -37,116 +37,36 @@
#include "osdep/timer.h"
#include "options/m_option.h"
-#include "misc/ring.h"
-
#include <jack/jack.h>
-//! size of one chunk, if this is too small MPlayer will start to "stutter"
-//! after a short time of playback
-#define CHUNK_SIZE (8 * 1024)
-//! number of "virtual" chunks the buffer consists of
-#define NUM_CHUNKS 8
-
-struct port_ring {
- jack_port_t *port;
- struct mp_ring *ring;
-};
-
struct priv {
jack_client_t *client;
float jack_latency;
char *cfg_port;
char *cfg_client_name;
- int estimate;
int connect;
int autostart;
int stdlayout;
int last_chunk;
- volatile int paused;
- volatile int underrun;
- volatile float callback_interval;
- volatile float callback_time;
- volatile float last_ok_time; // last time real audio was played
int num_ports;
- struct port_ring ports[MP_NUM_CHANNELS];
+ jack_port_t *ports[MP_NUM_CHANNELS];
};
-/**
- * \brief fill the buffers with silence
- * \param bufs num_bufs float buffers, each will contain the data of one channel
- * \param cnt number of samples in each buffer
- * \param num_bufs number of buffers
- */
-static void
-silence(float *buf, jack_nframes_t nframes)
-{
- memset(buf, 0, nframes * sizeof(*buf));
-}
-
-static int
-process_port(struct ao *ao, struct port_ring *pr, jack_nframes_t nframes)
-{
- struct priv *p = ao->priv;
- int buffered;
- float *buf;
-
- buf = jack_port_get_buffer(pr->port, nframes);
-
- if (p->paused || p->underrun) {
- silence(buf, nframes);
- return 0;
- }
-
- buffered = mp_ring_buffered(pr->ring) / sizeof(float);
- if (buffered < nframes) {
- mp_ring_read(pr->ring, (void *) buf, buffered * sizeof(float));
- silence(&buf[buffered], nframes - buffered);
- return 1;
- }
-
- mp_ring_read(pr->ring, (void *) buf, nframes * sizeof(float));
- return 0;
-}
-
-/**
- * \brief JACK Callback function
- * \param nframes number of frames to fill into buffers
- * \param arg unused
- * \return currently always 0
- *
- * Write silence into buffers if paused or an underrun occured
- */
-static int
-process(jack_nframes_t nframes, void *arg)
+static int process(jack_nframes_t nframes, void *arg)
{
struct ao *ao = arg;
struct priv *p = ao->priv;
- int i, underrun;
- underrun = 0;
+ void *buffers[MP_NUM_CHANNELS];
- for (i = 0; i < p->num_ports; i++) {
- if (process_port(ao, &p->ports[i], nframes))
- underrun = 1;
- }
-
- float now = mp_time_us() / 1000000.0;
+ for (int i = 0; i < p->num_ports; i++)
+ buffers[i] = jack_port_get_buffer(p->ports[i], nframes);
- if (underrun)
- p->underrun = 1;
+ int64_t end_time = mp_time_us();
+ end_time += (p->jack_latency + nframes / (double)ao->samplerate) * 1000000.0;
- if (!p->underrun)
- p->last_ok_time = now;
-
- if (p->estimate) {
- float diff = p->callback_time + p->callback_interval - now;
- if ((diff > -0.002) && (diff < 0.002))
- p->callback_time += p->callback_interval;
- else
- p->callback_time = now;
- p->callback_interval = (float)nframes / (float)ao->samplerate;
- }
+ ao_read_data(ao, buffers, nframes, end_time);
return 0;
}
@@ -172,8 +92,9 @@ connect_to_outports(struct ao *ao)
}
for (i = 0; i < p->num_ports && matching_ports[i]; i++) {
- if (jack_connect(p->client, jack_port_name(p->ports[i].port),
- matching_ports[i])) {
+ if (jack_connect(p->client, jack_port_name(p->ports[i]),
+ matching_ports[i]))
+ {
MP_FATAL(ao, "connecting failed\n");
goto err_connect;
}
@@ -192,23 +113,18 @@ static int
create_ports(struct ao *ao, int nports)
{
struct priv *p = ao->priv;
- struct port_ring *pr;
char pname[30];
int i;
for (i = 0; i < nports; i++) {
- pr = &p->ports[i];
-
snprintf(pname, sizeof(pname), "out_%d", i);
- pr->port = jack_port_register(p->client, pname, JACK_DEFAULT_AUDIO_TYPE,
- JackPortIsOutput, 0);
+ p->ports[i] = jack_port_register(p->client, pname, JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
- if (!pr->port) {
+ if (!p->ports[i]) {
MP_FATAL(ao, "not enough ports available\n");
goto err_port_register;
}
-
- pr->ring = mp_ring_new(p, NUM_CHUNKS * CHUNK_SIZE);
}
p->num_ports = nports;
@@ -269,11 +185,10 @@ static int init(struct ao *ao)
goto err_connect;
jack_latency_range_t jack_latency_range;
- jack_port_get_latency_range(p->ports[0].port, JackPlaybackLatency,
+ jack_port_get_latency_range(p->ports[0], JackPlaybackLatency,
&jack_latency_range);
p->jack_latency = (float)(jack_latency_range.max + jack_get_buffer_size(p->client))
/ (float)ao->samplerate;
- p->callback_interval = 0;
if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, p->num_ports))
goto err_chmap_sel_get_def;
@@ -291,104 +206,17 @@ err_chmap:
return -1;
}
-static float get_delay(struct ao *ao)
-{
- struct priv *p = ao->priv;
- int buffered = mp_ring_buffered(p->ports[0].ring); // could be less
- float in_jack = p->jack_latency;
- float now = mp_time_us() / 1000000.0;
-
- if (p->estimate && p->callback_interval > 0) {
- float elapsed = mp_time_us() / 1000000.0 - p->callback_time;
- in_jack += p->callback_interval - elapsed;
- }
-
- if (p->underrun && !buffered && p->last_chunk) {
- // Report correct buffer drainage, when our buffer is empty, but jack
- // and/or the audio device still have some audio to play.
- // Assumes audio clock goes at about the same speed as the system time.
- in_jack += p->last_ok_time - now;
- }
-
- if (in_jack < 0)
- in_jack = 0;
-
- return (float)buffered / (float)ao->bps + in_jack;
-}
-
-/**
- * \brief stop playing and empty buffers (for seeking/pause)
- */
-static void reset(struct ao *ao)
-{
- struct priv *p = ao->priv;
- int i;
- p->paused = 1;
-
- for (i = 0; i < p->num_ports; i++)
- mp_ring_reset(p->ports[i].ring);
-
- p->paused = 0;
-}
-
// close audio device
static void uninit(struct ao *ao, bool immed)
{
struct priv *p = ao->priv;
if (!immed)
- mp_sleep_us(get_delay(ao) * 1000 * 1000);
+ ao_wait_drain(ao);
- mp_sleep_us(100 * 1000);
jack_client_close(p->client);
}
-/**
- * \brief stop playing, keep buffers (for pause)
- */
-static void audio_pause(struct ao *ao)
-{
- struct priv *p = ao->priv;
- p->paused = 1;
-}
-
-/**
- * \brief resume playing, after audio_pause()
- */
-static void audio_resume(struct ao *ao)
-{
- struct priv *p = ao->priv;
- p->paused = 0;
-}
-
-static int get_space(struct ao *ao)
-{
- struct priv *p = ao->priv;
- return mp_ring_available(p->ports[0].ring) / ao->sstride;
-}
-
-/**
- * \brief write data into buffer and reset underrun flag
- */
-static int play(struct ao *ao, void **data, int samples, int flags)
-{
- struct priv *p = ao->priv;
- struct port_ring *pr;
- int i, len, ret;
-
- len = samples * ao->sstride;
- ret = 0;
-
- for (i = 0; i < p->num_ports; i++) {
- pr = &p->ports[i];
- ret = mp_ring_write(pr->ring, data[i], len);
- }
-
- p->underrun = 0;
- p->last_chunk = flags & AOPLAY_FINAL_CHUNK;
- return ret / ao->sstride;
-}
-
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_jack = {
@@ -396,22 +224,14 @@ const struct ao_driver audio_out_jack = {
.name = "jack",
.init = init,
.uninit = uninit,
- .get_space = get_space,
- .play = play,
- .get_delay = get_delay,
- .pause = audio_pause,
- .resume = audio_resume,
- .reset = reset,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.cfg_client_name = "mpv",
- .estimate = 1,
.connect = 1,
},
.options = (const struct m_option[]) {
OPT_STRING("port", cfg_port, 0),
OPT_STRING("name", cfg_client_name, 0),
- OPT_FLAG("estimate", estimate, 0),
OPT_FLAG("autostart", autostart, 0),
OPT_FLAG("connect", connect, 0),
OPT_CHOICE("std-channel-layout", stdlayout, 0,