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;
}
}