[MPlayer-dev-eng] [PATCH] Add audio support for sndio API.

Brad Smith brad at comstyle.com
Thu Jun 21 02:58:50 CEST 2012


---
 Makefile              |    2 +
 configure             |   26 ++++
 libao2/ao_sndio.c     |  343 +++++++++++++++++++++++++++++++++++++++++++++++++
 libao2/audio_out.c    |    4 +
 stream/ai_sndio.c     |   66 ++++++++++
 stream/audio_in.c     |   58 +++++++++
 stream/audio_in.h     |   19 +++
 stream/tvi_bsdbt848.c |  155 +++++++++++++++++++++-
 8 files changed, 665 insertions(+), 8 deletions(-)
 create mode 100644 libao2/ao_sndio.c
 create mode 100644 stream/ai_sndio.c

diff --git a/Makefile b/Makefile
index 940d43b..cbff1a3 100644
--- a/Makefile
+++ b/Makefile
@@ -35,6 +35,7 @@ OS_FEATURE-$(VSSCANF)                += osdep/vsscanf.c
 # conditional source declarations
 SRCS_AUDIO_INPUT-$(ALSA)             += stream/ai_alsa.c
 SRCS_AUDIO_INPUT-$(OSS)              += stream/ai_oss.c
+SRCS_AUDIO_INPUT-$(SNDIO)            += stream/ai_sndio.c
 SRCS_COMMON-$(AUDIO_INPUT)           += $(SRCS_AUDIO_INPUT-yes)
 SRCS_COMMON-$(BITMAP_FONT)           += sub/font_load.c
 SRCS_COMMON-$(CDDA)                  += stream/stream_cdda.c \
@@ -592,6 +593,7 @@ SRCS_MPLAYER-$(QUARTZ)        += libvo/vo_quartz.c libvo/osx_common.c
 SRCS_MPLAYER-$(S3FB)          += libvo/vo_s3fb.c
 SRCS_MPLAYER-$(SDL)           += libao2/ao_sdl.c libvo/vo_sdl.c libvo/sdl_common.c
 SRCS_MPLAYER-$(SGIAUDIO)      += libao2/ao_sgi.c
+SRCS_MPLAYER-$(SNDIO)         += libao2/ao_sndio.c
 SRCS_MPLAYER-$(SUNAUDIO)      += libao2/ao_sun.c
 SRCS_MPLAYER-$(SVGA)          += libvo/vo_svga.c
 SRCS_MPLAYER-$(TDFXFB)        += libvo/vo_tdfxfb.c
diff --git a/configure b/configure
index 1079193..8a9770c 100755
--- a/configure
+++ b/configure
@@ -536,6 +536,7 @@ Audio output:
   --disable-openal       disable OpenAL audio output [autodetect]
   --disable-nas          disable NAS audio output [autodetect]
   --disable-sgiaudio     disable SGI audio output [autodetect]
+  --disable-sndio        disable sndio audio output [autodetect]
   --disable-sunaudio     disable Sun audio output [autodetect]
   --disable-kai          disable KAI audio output [autodetect]
   --disable-dart         disable DART audio output [autodetect]
@@ -780,6 +781,7 @@ _vm=auto
 _xf86keysym=auto
 _mlib=no #broken, thus disabled
 _sgiaudio=auto
+_sndio=auto
 _sunaudio=auto
 _alsa=auto
 _fastmemcpy=yes
@@ -1205,6 +1207,8 @@ for ac_option do
   --disable-xf86keysym) _xf86keysym=no  ;;
   --enable-mlib)        _mlib=yes       ;;
   --disable-mlib)       _mlib=no        ;;
+  --enable-sndio)       _sndio=yes      ;;
+  --disable-sndio)      _sndio=no       ;;
   --enable-sunaudio)    _sunaudio=yes   ;;
   --disable-sunaudio)   _sunaudio=no    ;;
   --enable-sgiaudio)    _sgiaudio=yes   ;;
@@ -5578,6 +5582,26 @@ fi
 echores "$_alsa"
 
 
+echocheck "sndio audio"
+if test "$_sndio" = auto ; then
+  cat > $TMPC << EOF
+#include <sndio.h>
+int main(void) { struct sio_par par; sio_initpar(&par); return 0; }
+EOF
+  _sndio=no
+  cc_check -lsndio && _sndio=yes
+fi
+if test "$_sndio" = yes ; then
+  def_sndio='#define CONFIG_SNDIO_AUDIO 1'
+  _aomodules="sndio $_aomodules"
+  extra_ldflags="$extra_ldflags -lsndio"
+else
+  def_sndio='#undef CONFIG_SNDIO_AUDIO'
+  _noaomodules="sndio $_noaomodules"
+fi
+echores "$_sndio"
+
+
 echocheck "Sun audio"
 if test "$_sunaudio" = auto ; then
   cat > $TMPC << EOF
@@ -8153,6 +8177,7 @@ SDL = $_sdl
 SPEEX = $_speex
 STREAM_CACHE = $_stream_cache
 SGIAUDIO = $_sgiaudio
+SNDIO = $_sndio
 SUNAUDIO = $_sunaudio
 SVGA = $_svga
 TDFXFB = $_tdfxfb
@@ -8547,6 +8572,7 @@ $def_ossaudio_devdsp
 $def_ossaudio_devmixer
 $def_pulse
 $def_sgiaudio
+$def_sndio
 $def_sunaudio
 $def_win32waveout
 
diff --git a/libao2/ao_sndio.c b/libao2/ao_sndio.c
new file mode 100644
index 0000000..bb06a08
--- /dev/null
+++ b/libao2/ao_sndio.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2008 Alexandre Ratchov <alex at caoua.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <poll.h>
+#include <errno.h>
+#include <sndio.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "mixer.h"
+#include "help_mp.h"
+
+#include "libaf/af_format.h"
+
+#include "audio_out.h"
+#include "audio_out_internal.h"
+
+static ao_info_t info = {
+	"sndio audio output",
+	"sndio",
+	"Alexandre Ratchov <alex at caoua.org>",
+	""
+};
+
+LIBAO_EXTERN(sndio)
+
+static struct sio_hdl *hdl = NULL;
+static struct sio_par par;
+static int delay, vol, havevol;
+#define SILENCE_NMAX 0x1000
+static char silence[SILENCE_NMAX];
+
+/*
+ * misc parameters (volume, etc...)
+ */
+static int control(int cmd, void *arg)
+{
+	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;
+}
+
+/*
+ * call-back invoked to notify of the hardware position
+ */
+static void movecb(void *addr, int delta)
+{
+	delay -= delta * (int)(par.bps * par.pchan);
+}
+
+/*
+ * call-back invoked to notify about volume changes
+ */
+static void volcb(void *addr, unsigned newvol)
+{
+	vol = newvol;
+}
+
+/*
+ * open device and setup parameters
+ * return: 1 = success, 0 = failure
+ */
+static int init(int rate, int channels, int format, int flags)
+{
+	int bpf;
+	int ac3 = 0;
+
+	hdl = sio_open(NULL, SIO_PLAY, 0);
+	if (hdl == NULL) {
+		mp_msg(MSGT_AO, MSGL_ERR, "ao2: can't open sndio\n");
+		return 0;
+	}
+	sio_initpar(&par);
+	switch (format) {
+	case AF_FORMAT_U8:
+		par.bits = 8;
+		par.sig = 0;
+		break;
+	case AF_FORMAT_S8:
+		par.bits = 8;
+		par.sig = 1;
+		break;
+	case AF_FORMAT_U16_LE:
+		par.bits = 16;
+		par.sig = 0;
+		par.le = 1;
+		break;
+	case AF_FORMAT_S16_LE:
+		par.bits = 16;
+		par.sig = 1;
+		par.le = 1;
+		break;
+	case AF_FORMAT_U16_BE:
+		par.bits = 16;
+		par.sig = 0;
+		par.le = 0;
+		break;
+	case AF_FORMAT_S16_BE:
+		par.bits = 16;
+		par.sig = 1;
+		par.le = 0;
+		break;
+	case AF_FORMAT_U24_LE:
+		par.bits = 24;
+		par.bps = 3;
+		par.sig = 0;
+		par.le = 1;
+		break;
+	case AF_FORMAT_S24_LE:
+		par.bits = 24;
+		par.bps = 3;
+		par.sig = 1;
+		par.le = 1;
+		break;
+	case AF_FORMAT_U24_BE:
+		par.bits = 24;
+		par.bps = 3;
+		par.sig = 0;
+		par.le = 0;
+		break;
+	case AF_FORMAT_S24_BE:
+		par.bits = 24;
+		par.bps = 3;
+		par.sig = 1;
+		par.le = 0;
+		break;
+	case AF_FORMAT_U32_LE:
+		par.bits = 32;
+		par.sig = 0;
+		par.le = 1;
+		break;
+	case AF_FORMAT_U32_BE:
+		par.bits = 32;
+		par.sig = 0;
+		par.le = 0;
+		break;
+	case AF_FORMAT_S32_LE:
+		par.bits = 32;
+		par.sig = 1;
+		par.le = 1;
+		break;
+	case AF_FORMAT_S32_BE:
+		par.bits = 32;
+		par.sig = 1;
+		par.le = 0;
+		break;
+	case AF_FORMAT_AC3_BE:
+	case AF_FORMAT_AC3_LE:
+		par.bits = 16;
+		par.sig = 1;
+		par.le = SIO_LE_NATIVE;
+		ac3 = 1;
+		break;
+	default:
+		mp_msg(MSGT_AO, MSGL_V, "ao2: unsupported format\n");
+		par.bits = 16;
+		par.sig = 1;
+		par.le = SIO_LE_NATIVE;
+	}
+	par.rate = rate;
+	par.pchan = channels;
+	par.appbufsz = par.rate * 250 / 1000;	/* 250ms buffer */
+	par.round = par.rate * 10 / 1000;	/*  10ms block size */
+	if (!sio_setpar(hdl, &par)) {
+		mp_msg(MSGT_AO, MSGL_ERR, "ao2: couldn't set params\n");
+		return 0;
+	}
+	if (!sio_getpar(hdl, &par)) {
+		mp_msg(MSGT_AO, MSGL_ERR, "ao2: couldn't get params\n");
+		return 0;
+	}
+	if (par.bits == 8 && par.bps == 1) {
+		format = par.sig ? AF_FORMAT_S8 : AF_FORMAT_U8;	
+	} else if (par.bits == 16 && par.bps == 2) {
+		format = par.sig ? 
+		    (par.le ? AF_FORMAT_S16_LE : AF_FORMAT_S16_BE) :
+		    (par.le ? AF_FORMAT_U16_LE : AF_FORMAT_U16_BE);
+	} else if ((par.bits == 24 || par.msb) && par.bps == 3) {
+		format = par.sig ? 
+		    (par.le ? AF_FORMAT_S24_LE : AF_FORMAT_S24_BE) :
+		    (par.le ? AF_FORMAT_U24_LE : AF_FORMAT_U24_BE);
+	} else if ((par.bits == 32 || par.msb) && par.bps == 4) {
+		format = par.sig ? 
+		    (par.le ? AF_FORMAT_S32_LE : AF_FORMAT_S32_BE) :
+		    (par.le ? AF_FORMAT_U32_LE : AF_FORMAT_U32_BE);
+	} else {
+		mp_msg(MSGT_AO, MSGL_ERR, "ao2: couldn't set format\n");
+		return 0;
+	}
+
+	bpf = par.bps * par.pchan;
+	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);
+	delay = 0;
+	if (!sio_start(hdl)) {
+		mp_msg(MSGT_AO, MSGL_ERR, "ao2: init: couldn't start\n");
+	}
+	if (ao_data.samplerate != rate) {
+		/* apparently mplayer rounds a little when resampling.
+		 * anyway, it doesn't write quite a full buffer on the first
+		 * write, which means libsndio never actually starts up
+		 * because it's trying to fill the buffer.  this is
+		 * enough for everything I have come across.
+		 */
+		sio_write(hdl, silence, 8 * bpf);
+		delay += 8 * bpf;
+	}
+	return 1;
+}
+
+/*
+ * close device
+ */
+static void uninit(int immed)
+{
+	if (hdl)
+		sio_close(hdl);
+}
+
+/*
+ * stop playing and empty buffers (for seeking/pause)
+ */
+static void reset(void)
+{
+	if (!sio_stop(hdl)) {
+		mp_msg(MSGT_AO, MSGL_ERR, "ao2: reset: couldn't stop\n");
+	}
+	delay = 0;
+	if (!sio_start(hdl)) {
+		mp_msg(MSGT_AO, MSGL_ERR, "ao2: reset: couldn't start\n");
+	}
+}
+
+/*
+ * how many bytes can be played without blocking
+ */
+static int get_space(void)
+{
+	struct pollfd pfd;
+	int bufused, revents, n;
+
+	/*
+	 * call poll() and sio_revents(), so the
+	 * delay counter is updated
+	 */
+	n = sio_pollfd(hdl, &pfd, POLLOUT);
+	while (poll(&pfd, n, 0) < 0 && errno == EINTR)
+		; /* nothing */
+	revents = sio_revents(hdl, &pfd);
+	return par.bufsz * par.pchan * par.bps - delay;
+}
+
+/*
+ * play given number of bytes until sio_write() blocks
+ */
+static int play(void *data, int len, int flags)
+{
+	int n;
+
+	n = sio_write(hdl, data, len);
+	delay += n;
+	if (flags & AOPLAY_FINAL_CHUNK)
+		reset();
+	return n;
+}
+
+/*
+ * return: delay in seconds between first and last sample in buffer
+ */
+static float get_delay(void)
+{
+	return (float)delay / (par.bps * par.pchan * par.rate);
+}
+
+/*
+ * stop playing, keep buffers (for pause)
+ */
+static void audio_pause(void)
+{
+	reset();
+}
+
+/*
+ * resume playing, after audio_pause()
+ */
+static void audio_resume(void)
+{
+	int n, count, todo;
+
+	/*
+	 * we want to start with buffers full, because mplayer uses
+	 * get_space() pointer as clock, which would cause video to
+	 * accelerate while 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)
+			count = SILENCE_NMAX;
+		n = sio_write(hdl, silence, count);
+		if (n == 0)
+			break;
+		todo -= n;
+		delay += n;
+	}
+}
diff --git a/libao2/audio_out.c b/libao2/audio_out.c
index 6021ae1..0e02dd2 100644
--- a/libao2/audio_out.c
+++ b/libao2/audio_out.c
@@ -42,6 +42,7 @@ extern const ao_functions_t audio_out_null;
 extern const ao_functions_t audio_out_alsa;
 extern const ao_functions_t audio_out_nas;
 extern const ao_functions_t audio_out_sdl;
+extern const ao_functions_t audio_out_sndio;
 extern const ao_functions_t audio_out_sun;
 extern const ao_functions_t audio_out_sgi;
 extern const ao_functions_t audio_out_win32;
@@ -82,6 +83,9 @@ const ao_functions_t* const audio_out_drivers[] =
 #ifdef CONFIG_SGI_AUDIO
         &audio_out_sgi,
 #endif
+#ifdef CONFIG_SNDIO_AUDIO
+        &audio_out_sndio,
+#endif
 #ifdef CONFIG_SUN_AUDIO
         &audio_out_sun,
 #endif
diff --git a/stream/ai_sndio.c b/stream/ai_sndio.c
new file mode 100644
index 0000000..b45a9ae
--- /dev/null
+++ b/stream/ai_sndio.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2008 Jacob Meuser <jakemsr at sdf.lonestar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "config.h"
+
+#include <sndio.h>
+#include "audio_in.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+int ai_sndio_setup(audio_in_t *ai)
+{
+    struct sio_par par;
+
+    sio_initpar(&par);
+
+    par.bits = 16;
+    par.sig = 1;
+    par.le = 1;
+    par.rchan = ai->req_channels;
+    par.rate = ai->req_samplerate;
+    par.appbufsz = ai->req_samplerate;	/* 1 sec */
+
+   if (!sio_setpar(ai->sndio.hdl, &par) || !sio_getpar(ai->sndio.hdl, &par)) {
+	mp_msg(MSGT_TV, MSGL_ERR, "could not configure sndio audio");
+	return -1;
+    }
+
+    ai->channels = par.rchan;
+    ai->samplerate = par.rate;
+    ai->samplesize = par.bits;
+    ai->bytes_per_sample = par.bps;
+    ai->blocksize = par.round * par.bps;
+
+    return 0;
+}
+
+int ai_sndio_init(audio_in_t *ai)
+{
+    int err;
+
+    if ((ai->sndio.hdl = sio_open(ai->sndio.device, SIO_REC, 0)) == NULL) {
+	mp_msg(MSGT_TV, MSGL_ERR, "could not open sndio audio");
+	return -1;
+    }
+
+    err = ai_sndio_setup(ai);
+
+    return err;
+}
diff --git a/stream/audio_in.c b/stream/audio_in.c
index a05ccb1..3e30725 100644
--- a/stream/audio_in.c
+++ b/stream/audio_in.c
@@ -54,6 +54,12 @@ int audio_in_init(audio_in_t *ai, int type)
 	ai->oss.device = strdup("/dev/dsp");
 	return 0;
 #endif
+#ifdef CONFIG_SNDIO_AUDIO
+    case AUDIO_IN_SNDIO:
+	ai->sndio.hdl = NULL;
+	ai->sndio.device = strdup("default");
+	return 0;
+#endif
     default:
 	return -1;
     }
@@ -75,6 +81,12 @@ int audio_in_setup(audio_in_t *ai)
 	ai->setup = 1;
 	return 0;
 #endif
+#ifdef CONFIG_SNDIO_AUDIO
+    case AUDIO_IN_SNDIO:
+	if (ai_sndio_init(ai) < 0) return -1;
+	ai->setup = 1;
+	return 0;
+#endif
     default:
 	return -1;
     }
@@ -97,6 +109,13 @@ int audio_in_set_samplerate(audio_in_t *ai, int rate)
 	if (ai_oss_set_samplerate(ai) < 0) return -1;
 	return ai->samplerate;
 #endif
+#ifdef CONFIG_SNDIO_AUDIO
+    case AUDIO_IN_SNDIO:
+	ai->req_samplerate = rate;
+	if (!ai->setup) return 0;
+	if (ai_sndio_setup(ai) < 0) return -1;
+	return ai->samplerate;
+#endif
     default:
 	return -1;
     }
@@ -119,6 +138,13 @@ int audio_in_set_channels(audio_in_t *ai, int channels)
 	if (ai_oss_set_channels(ai) < 0) return -1;
 	return ai->channels;
 #endif
+#ifdef CONFIG_SNDIO_AUDIO
+    case AUDIO_IN_SNDIO:
+	ai->req_channels = channels;
+	if (!ai->setup) return 0;
+	if (ai_sndio_setup(ai) < 0) return -1;
+	return ai->channels;
+#endif
     default:
 	return -1;
     }
@@ -147,6 +173,12 @@ int audio_in_set_device(audio_in_t *ai, char *device)
 	ai->oss.device = strdup(device);
 	return 0;
 #endif
+#ifdef CONFIG_SNDIO_AUDIO
+    case AUDIO_IN_SNDIO:
+	if (ai->sndio.device) free(ai->sndio.device);
+	ai->sndio.device = strdup(device);
+	return 0;
+#endif
     default:
 	return -1;
     }
@@ -172,6 +204,13 @@ int audio_in_uninit(audio_in_t *ai)
 	    ai->setup = 0;
 	    return 0;
 #endif
+#ifdef CONFIG_SNDIO_AUDIO
+	case AUDIO_IN_SNDIO:
+	    if (ai->sndio.hdl)
+	        sio_close(ai->sndio.hdl);
+	    ai->setup = 0;
+	    return 0;
+#endif
 	}
     }
     return -1;
@@ -188,6 +227,12 @@ int audio_in_start_capture(audio_in_t *ai)
     case AUDIO_IN_OSS:
 	return 0;
 #endif
+#ifdef CONFIG_SNDIO_AUDIO
+    case AUDIO_IN_SNDIO:
+	if (!sio_start(ai->sndio.hdl))
+	    return -1;
+	return 0;
+#endif
     default:
 	return -1;
     }
@@ -231,6 +276,19 @@ int audio_in_read_chunk(audio_in_t *ai, unsigned char *buffer)
 	}
 	return ret;
 #endif
+#ifdef CONFIG_SNDIO_AUDIO
+    case AUDIO_IN_SNDIO:
+	ret = sio_read(ai->sndio.hdl, buffer, ai->blocksize);
+	if (ret != ai->blocksize) {
+	    if (ret < 0) {
+		mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio, strerror(errno));
+	    } else {
+		mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_NotEnoughSamples);
+	    }
+	    return -1;
+	}
+	return ret;
+#endif
     default:
 	return -1;
     }
diff --git a/stream/audio_in.h b/stream/audio_in.h
index 31688e7..41b40c7 100644
--- a/stream/audio_in.h
+++ b/stream/audio_in.h
@@ -21,6 +21,7 @@
 
 #define AUDIO_IN_ALSA 1
 #define AUDIO_IN_OSS 2
+#define AUDIO_IN_SNDIO 3
 
 #include "config.h"
 
@@ -45,6 +46,16 @@ typedef struct {
 } ai_oss_t;
 #endif
 
+#ifdef CONFIG_SNDIO_AUDIO
+#include <sndio.h>
+
+typedef struct {
+    char *device;
+
+    struct sio_hdl *hdl;
+} ai_sndio_t;
+#endif
+
 typedef struct
 {
     int type;
@@ -67,6 +78,9 @@ typedef struct
 #ifdef CONFIG_OSS_AUDIO
     ai_oss_t oss;
 #endif
+#ifdef CONFIG_SNDIO_AUDIO
+    ai_sndio_t sndio;
+#endif
 } audio_in_t;
 
 int audio_in_init(audio_in_t *ai, int type);
@@ -90,4 +104,9 @@ int ai_oss_set_channels(audio_in_t *ai);
 int ai_oss_init(audio_in_t *ai);
 #endif
 
+#ifdef CONFIG_SNDIO_AUDIO
+int ai_sndio_setup(audio_in_t *ai);
+int ai_sndio_init(audio_in_t *ai);
+#endif
+
 #endif /* MPLAYER_AUDIO_IN_H */
diff --git a/stream/tvi_bsdbt848.c b/stream/tvi_bsdbt848.c
index 3da47fa..6f1f81d 100644
--- a/stream/tvi_bsdbt848.c
+++ b/stream/tvi_bsdbt848.c
@@ -54,9 +54,10 @@
 #include <signal.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/ioctl.h>
 
 #include <sys/param.h>
-#ifdef CONFIG_SUN_AUDIO
+#if defined(CONFIG_SUN_AUDIO) && !defined(CONFIG_SNDIO_AUDIO)
 #include <sys/audioio.h>
 #endif
 
@@ -68,6 +69,9 @@
 #include IOCTL_BT848_H_NAME
 #endif
 
+#ifdef CONFIG_SNDIO_AUDIO
+#include <sndio.h>
+#else
 #ifdef HAVE_SYS_SOUNDCARD_H
 #include <sys/soundcard.h>
 #else
@@ -77,6 +81,7 @@
 #include <machine/soundcard.h>
 #endif
 #endif
+#endif
 
 #include "libaf/af_format.h"
 #include "libmpcodecs/img_format.h"
@@ -106,7 +111,13 @@ typedef struct priv {
 /* Audio */
     char *dspdev;
     int dspready;
+#ifdef CONFIG_SNDIO_AUDIO
+    struct sio_hdl *hdl;
+    struct sio_par par;
+    int round, appbufsz; /* sizes in bytes */
+#else
     int dspfd;
+#endif
     int dspsamplesize;
     int dspstereo;
     int dspspeed;
@@ -114,6 +125,9 @@ typedef struct priv {
     int dspframesize;
     int dsprate;
     long long dspbytesread;
+#ifdef CONFIG_SNDIO_AUDIO
+    long long realpos;
+#endif
 
 /* Video */
     char *btdev;
@@ -163,6 +177,15 @@ static priv_t *G_private=NULL;
 
 static int getinput(int innumber);
 
+#ifdef CONFIG_SNDIO_AUDIO
+void movecb(void *addr, int delta)
+{
+    priv_t *priv = addr;
+
+    priv->realpos += delta * priv->dspsamplesize/8 * (priv->dspstereo+1);
+}
+#endif
+
 static void processframe(int signal)
 {
 struct timeval curtime;
@@ -223,7 +246,9 @@ static tvi_handle_t *tvi_init_bsdbt848(tv_param_t* tv_param)
 
     /* set audio device name */
     if (!tv_param->adevice)
-#ifdef CONFIG_SUN_AUDIO
+#ifdef CONFIG_SNDIO_AUDIO
+        priv->dspdev = NULL;
+#elif defined(CONFIG_SUN_AUDIO)
         priv->dspdev = strdup("/dev/sound");
 #else
         priv->dspdev = strdup("/dev/dsp");
@@ -332,12 +357,39 @@ static int control(priv_t *priv, int cmd, void *arg)
         {
         int dspspeed = *(int *)arg;
 
+#ifdef CONFIG_SNDIO_AUDIO
+        if (!sio_stop(priv->hdl))
+            {
+            mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848InvalidAudioRate, "sio_stop failed");
+            return TVI_CONTROL_FALSE;
+            }
+        sio_initpar(&priv->par);
+        priv->par.rate = dspspeed;
+        priv->par.round = 4096 / (priv->dspsamplesize/8 * (priv->dspstereo + 1));
+        if(!sio_setpar(priv->hdl, &priv->par) || !sio_getpar(priv->hdl, &priv->par))
+            {
+            mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848InvalidAudioRate, "sio_[s|g]etpar failed");
+            return TVI_CONTROL_FALSE;
+            }
+        priv->round = priv->par.round * priv->par.bps * priv->par.rchan;
+        priv->appbufsz = priv->par.appbufsz * priv->par.bps * priv->par.rchan;
+        if(priv->par.rate != dspspeed)
+            {
+            mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848InvalidAudioRate, "returned rate != requested rate");
+            return TVI_CONTROL_FALSE;
+            }
+        if (!sio_start(priv->hdl))
+            {
+            mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848InvalidAudioRate, "sio_start failed");
+            return TVI_CONTROL_FALSE;
+            }
+#else
            if(ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &dspspeed) == -1)
             {
             mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848InvalidAudioRate, strerror(errno));
             return TVI_CONTROL_FALSE;
             }
-
+#endif
         priv->dspspeed = dspspeed;
 
         priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/
@@ -646,12 +698,76 @@ priv->dspready = TRUE;
 priv->dspsamplesize = 16;
 priv->dspstereo = 1;
 priv->dspspeed = 44100;
+#ifndef CONFIG_SNDIO_AUDIO
 priv->dspfmt = AFMT_S16_LE;
+#endif
 priv->dspbytesread = 0;
 priv->dsprate = priv->dspspeed * priv->dspsamplesize/8*(priv->dspstereo+1);
 priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/priv->fps *
                      (priv->dspstereo+1);
 
+#ifdef CONFIG_SNDIO_AUDIO
+
+if((priv->hdl = sio_open(priv->dspdev, SIO_REC, 0)) == NULL)
+    {
+    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848ErrorOpeningDspDev, "sio_open failed");
+    priv->dspready = FALSE;
+    }
+
+sio_initpar(&priv->par);
+priv->par.rchan = priv->dspstereo + 1;
+priv->par.rate = priv->dspspeed;
+priv->par.bits = priv->dspsamplesize;
+priv->par.sig = 1;
+//priv->par.round = FRAGSIZE / (priv->dspsamplesize/8 * (priv->dspstereo + 1));
+priv->par.round = priv->dspspeed / 100; /* 10 ms */
+priv->par.appbufsz = priv->dspspeed / 4; /* 250 ms */
+
+if(priv->dspready && (!sio_setpar(priv->hdl, &priv->par) || !sio_getpar(priv->hdl, &priv->par)))
+    {
+    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848ErrorConfiguringDsp, "sio_[s|g]etpar failed");
+    priv->dspready = FALSE;
+    }
+
+priv->round = priv->par.round * priv->par.bps * priv->par.rchan;
+priv->appbufsz = priv->par.appbufsz * priv->par.bps * priv->par.rchan;
+
+if(priv->par.rchan != priv->dspstereo + 1)
+    {
+    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848ErrorConfiguringDsp, "returned channels != requested channels");
+    priv->dspready = FALSE;
+    }
+if (priv->par.bits != priv->dspsamplesize || priv->par.sig != 1 || priv->par.le != SIO_LE_NATIVE)
+    {
+    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848ErrorConfiguringDsp, "returned format != requested format");
+    priv->dspready = FALSE;
+    }
+if(priv->par.rate != priv->dspspeed)
+    {
+    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848ErrorConfiguringDsp, "returned rate != requested rate");
+    // this may be overridden later with command line options, so it's not necessarily a problem
+    //priv->dspready = FALSE;
+    }
+
+priv->realpos = 0;
+
+if(priv->dspready == TRUE)
+    {
+    sio_onmove(priv->hdl, movecb, priv);
+    if(!sio_start(priv->hdl))
+        {
+        mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848ErrorConfiguringDsp, "sio_start failed");
+        priv->dspready = FALSE;
+        }
+    }
+
+if(priv->dspready == FALSE)
+    {
+    sio_close(priv->hdl);
+    }
+
+#else
+
 if((priv->dspfd = open (priv->dspdev, O_RDONLY, 0)) < 0)
     {
     mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848ErrorOpeningDspDev, strerror(errno));
@@ -677,6 +793,8 @@ if((priv->dspready == TRUE) &&
     priv->dspready = FALSE;
     }
 
+#endif
+
 return 1;
 }
 
@@ -701,7 +819,9 @@ if(ioctl(priv->btfd, METEORSSIGNAL, &marg) < 0)
     return 0;
     }
 
+#ifndef CONFIG_SNDIO_AUDIO
 read(priv->dspfd, &tmp, 2);
+#endif
 
 gettimeofday(&curtime, NULL);
 
@@ -740,10 +860,15 @@ if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0 )
     return 0;
     }
 
-close(priv->btfd);
+#ifdef CONFIG_SNDIO_AUDIO
+sio_close(priv->hdl);
+priv->hdl = NULL;
+#else
 close(priv->dspfd);
-
 priv->dspfd = -1;
+#endif
+
+close(priv->btfd);
 priv->btfd = -1;
 
 priv->dspready = priv->videoready = FALSE;
@@ -823,13 +948,21 @@ gettimeofday(&curtime, NULL);
 
 /* Get exactly one frame of audio, which forces video sync to audio.. */
 
+#ifdef CONFIG_SNDIO_AUDIO
+bytesread=sio_read(priv->hdl, buffer, len);
+#else
 bytesread=read(priv->dspfd, buffer, len);
+#endif
 
 while(bytesread < len)
     {
+#ifdef CONFIG_SNDIO_AUDIO
+    ret=sio_read(priv->hdl, &buffer[bytesread], len-bytesread);
+    if(ret == 0)
+#else
     ret=read(priv->dspfd, &buffer[bytesread], len-bytesread);
-
     if(ret == -1)
+#endif
         {
         mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848ErrorReadingAudio, strerror(errno));
         return 0;
@@ -862,13 +995,19 @@ return priv->dspbytesread * 1.0 / priv->dsprate;
 static int get_audio_framesize(priv_t *priv)
 {
 int bytesavail;
-#ifdef CONFIG_SUN_AUDIO
+#if defined(CONFIG_SUN_AUDIO) && !defined(CONFIG_SNDIO_AUDIO)
 struct audio_info auinf;
 #endif
 
 if(priv->dspready == FALSE) return 0;
 
-#ifdef CONFIG_SUN_AUDIO
+#ifdef CONFIG_SNDIO_AUDIO
+bytesavail = priv->realpos - priv->dspbytesread;
+if(bytesavail > priv->appbufsz)
+    bytesavail = priv->appbufsz;
+if(bytesavail < priv->round)
+    bytesavail = priv->round;
+#elif defined(CONFIG_SUN_AUDIO)
 if(ioctl(priv->dspfd, AUDIO_GETINFO, &auinf) < 0)
     {
     mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_Bt848IoctlFailed, "AUDIO_GETINFO", strerror(errno));
-- 
1.7.6


-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.



More information about the MPlayer-dev-eng mailing list