Below is an update of mplayer sndio backend: - use sndiod volume knob if available, rather than chaining two soft volume knobs (consumes less CPU) - stop audio during pause, consumes less CPU - remove unnecessary checks - honour AOPLAY_FINAL_CHUNK flag, fixes playback of very short files
comments? ok? -- Alexandre Index: Makefile =================================================================== RCS file: /cvs/ports/x11/mplayer/Makefile,v retrieving revision 1.197 diff -u -p -r1.197 Makefile --- Makefile 30 Dec 2011 17:40:40 -0000 1.197 +++ Makefile 24 Jan 2012 22:21:08 -0000 @@ -13,7 +13,7 @@ SUBST_VARS += PREFIX CONFDIR # Distfiles must be hand-rolled, see README N = mplayer DISTNAME = mplayer-${V} -REVISION = 11 +REVISION = 12 CATEGORIES = x11 multimedia Index: files/ao_sndio.c =================================================================== RCS file: /cvs/ports/x11/mplayer/files/ao_sndio.c,v retrieving revision 1.6 diff -u -p -r1.6 ao_sndio.c --- files/ao_sndio.c 8 Nov 2010 21:25:44 -0000 1.6 +++ files/ao_sndio.c 24 Jan 2012 22:21:08 -0000 @@ -40,7 +40,7 @@ LIBAO_EXTERN(sndio) static struct sio_hdl *hdl = NULL; static struct sio_par par; -static long long realpos = 0, playpos = 0; +static int delay, vol, havevol; #define SILENCE_NMAX 0x1000 static char silence[SILENCE_NMAX]; @@ -49,7 +49,21 @@ static char silence[SILENCE_NMAX]; */ static int control(int cmd, void *arg) { - return CONTROL_FALSE; + ao_control_vol_t *ctl = arg; + + if (!havevol) + return CONTROL_FALSE; + switch (cmd) { + case AOCONTROL_GET_VOLUME: + ctl->left = ctl->right = vol * 100 / SIO_MAXVOL; + break; + case AOCONTROL_SET_VOLUME: + sio_setvol(hdl, ctl->left * SIO_MAXVOL / 100); + break; + default: + return CONTROL_UNKNOWN; + } + return CONTROL_OK; } /* @@ -57,7 +71,15 @@ static int control(int cmd, void *arg) */ static void movecb(void *addr, int delta) { - realpos += delta * (int)(par.bps * par.pchan); + delay -= delta * (int)(par.bps * par.pchan); +} + +/* + * call-back invoked to notify about volume changes + */ +static void volcb(void *addr, unsigned newvol) +{ + vol = newvol; } /* @@ -74,7 +96,6 @@ static int init(int rate, int channels, mp_msg(MSGT_AO, MSGL_ERR, "ao2: can't open sndio\n"); return 0; } - sio_initpar(&par); switch (format) { case AF_FORMAT_U8: @@ -194,24 +215,22 @@ static int init(int rate, int channels, } bpf = par.bps * par.pchan; - ao_data.samplerate = par.rate; ao_data.channels = par.pchan; ao_data.format = ac3 ? AF_FORMAT_AC3_NE : format; ao_data.bps = bpf * par.rate; ao_data.buffersize = par.appbufsz * bpf; ao_data.outburst = par.round * bpf; + /* avoid resampling for close rates */ + if ((par.rate >= rate * 0.97) && (par.rate <= rate * 1.03)) + ao_data.samplerate = rate; + else + ao_data.samplerate = par.rate; + havevol = sio_onvol(hdl, volcb, NULL); sio_onmove(hdl, movecb, NULL); - realpos = playpos = 0; + delay = 0; if (!sio_start(hdl)) { mp_msg(MSGT_AO, MSGL_ERR, "ao2: init: couldn't start\n"); } - - /* avoid resampling for close rates */ - if ((ao_data.samplerate >= rate * 0.97) && - (ao_data.samplerate <= rate * 1.03)) { - ao_data.samplerate = rate; - } - if (ao_data.samplerate != rate) { /* apparently mplayer rounds a little when resampling. * anyway, it doesn't write quite a full buffer on the first @@ -220,8 +239,8 @@ static int init(int rate, int channels, * enough for everything I have come across. */ sio_write(hdl, silence, 8 * bpf); + delay += 8 * bpf; } - return 1; } @@ -237,11 +256,12 @@ static void uninit(int immed) /* * stop playing and empty buffers (for seeking/pause) */ -static void reset(void) { +static void reset(void) +{ if (!sio_stop(hdl)) { mp_msg(MSGT_AO, MSGL_ERR, "ao2: reset: couldn't stop\n"); } - realpos = playpos = 0; + delay = 0; if (!sio_start(hdl)) { mp_msg(MSGT_AO, MSGL_ERR, "ao2: reset: couldn't start\n"); } @@ -253,19 +273,17 @@ static void reset(void) { static int get_space(void) { struct pollfd pfd; - int bufused, space, revents, n; + int bufused, revents, n; /* * call poll() and sio_revents(), so the - * playpos and realpos counters are updated + * delay counter is updated */ n = sio_pollfd(hdl, &pfd, POLLOUT); while (poll(&pfd, n, 0) < 0 && errno == EINTR) ; /* nothing */ revents = sio_revents(hdl, &pfd); - bufused = (realpos < 0) ? playpos : playpos - realpos; - space = par.bufsz * par.pchan * par.bps - bufused; - return space; + return par.bufsz * par.pchan * par.bps - delay; } /* @@ -276,7 +294,9 @@ static int play(void *data, int len, int int n; n = sio_write(hdl, data, len); - playpos += n; + delay += n; + if (flags & AOPLAY_FINAL_CHUNK) + reset(); return n; } @@ -285,9 +305,7 @@ static int play(void *data, int len, int */ static float get_delay(void) { - int bufused; - bufused = (realpos < 0) ? playpos : playpos - realpos; - return (float)bufused / (par.bps * par.pchan * par.rate); + return (float)delay / (par.bps * par.pchan * par.rate); } /* @@ -295,7 +313,7 @@ static float get_delay(void) */ static void audio_pause(void) { - /* libsndio stops automatically if no data is available */ + reset(); } /* @@ -305,13 +323,13 @@ static void audio_resume(void) { int n, count, todo; - todo = par.appbufsz * par.pchan * par.bps; - /* - * libsndio starts automatically if enough data is available; - * however we want to start with buffers full, because video - * would accelerate during buffers are filled + * we want to start with buffers full, because mplayer uses + * get_space() pointer as clock, which would cause video to + * accelerate during buffers are filled. Remove this when not + * necessary anymore. */ + todo = par.bufsz * par.pchan * par.bps; while (todo > 0) { count = todo; if (count > SILENCE_NMAX) @@ -320,6 +338,6 @@ static void audio_resume(void) if (n == 0) break; todo -= n; - realpos -= n; + delay += n; } }