Mercurial > mplayer.hg
changeset 3276:e279cc05f189
-ao NAS support by Tobias Diedrich <ranma@gmx.at>
author | arpi |
---|---|
date | Mon, 03 Dec 2001 01:13:48 +0000 |
parents | 38344371432f |
children | 9d4a7b4afba2 |
files | DOCS/German/sound.html DOCS/sound.html Makefile configure libao2/ao_nas.c libao2/audio_out.c |
diffstat | 6 files changed, 366 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/DOCS/German/sound.html Mon Dec 03 01:09:36 2001 +0000 +++ b/DOCS/German/sound.html Mon Dec 03 01:13:48 2001 +0000 @@ -14,6 +14,7 @@ <TR><TD> </TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>oss</TD><TD> </TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>OSS (ioctl) Treiber</TD></TR> <TR><TD></TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>sdl</TD><TD></TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>SDL Treiber (unterstützt Up-/Downsampling, <B>ESD</B>, <B>ARTS</B> usw.)</TD></TR> +<TR><TD></TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>nas</TD><TD></TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>NAS (Network Audio System) Treiber</TD></TR> <TR><TD></TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>alsa5</TD><TD></TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>ALSA 0.5 Treiber</TD></TR> <TR><TD></TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>alsa9</TD><TD></TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>ALSA 0.9 Treiber (funkioniert, macht aber Probleme -> verwende OSS)</TD></TR> <TR><TD></TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>sun</TD><TD></TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>SUN Audio-Treiber (/dev/audio) für BSD und Solaris8 Anwender</TD></TR>
--- a/DOCS/sound.html Mon Dec 03 01:09:36 2001 +0000 +++ b/DOCS/sound.html Mon Dec 03 01:13:48 2001 +0000 @@ -14,6 +14,7 @@ <TR><TD> </TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>oss</TD><TD> </TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>OSS (ioctl) driver</TD></TR> <TR><TD></TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>sdl</TD><TD></TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>SDL driver (supports up/downsampling, <B>ESD</B>, <B>ARTS</B> etc)</TD></TR> +<TR><TD></TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>nas</TD><TD></TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>NAS (Network Audio System) driver</TD></TR> <TR><TD></TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>alsa5</TD><TD></TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>native ALSA 0.5 driver</TD></TR> <TR><TD></TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>alsa9</TD><TD></TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>native ALSA 0.9 driver (works, but has problems -> use OSS)</TD></TR> <TR><TD></TD><TD VALIGN=top><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>sun</TD><TD></TD><TD><FONT face="Verdana, Arial, Helvetica, sans-serif" size=2>SUN audio driver (/dev/audio) for BSD and Solaris8 users</TD></TR>
--- a/Makefile Mon Dec 03 01:09:36 2001 +0000 +++ b/Makefile Mon Dec 03 01:13:48 2001 +0000 @@ -34,7 +34,7 @@ VO_LIBS = -Llibvo2 -lvo2 $(X_LIB) $(DXR3_LIB) $(GGI_LIB) $(MLIB_LIB) $(PNG_LIB) $(SDL_LIB) $(SVGA_LIB) endif -A_LIBS = -Lmp3lib -lMP3 -Llibac3 -lac3 $(ALSA_LIB) $(MAD_LIB) $(VORBIS_LIB) $(SGIAUDIO_LIB) +A_LIBS = -Lmp3lib -lMP3 -Llibac3 -lac3 $(ALSA_LIB) $(NAS_LIB) $(MAD_LIB) $(VORBIS_LIB) $(SGIAUDIO_LIB) OSDEP_LIBS = -Llinux -losdep PP_LIBS = -Lpostproc -lpostproc
--- a/configure Mon Dec 03 01:09:36 2001 +0000 +++ b/configure Mon Dec 03 01:13:48 2001 +0000 @@ -646,6 +646,7 @@ _dga=auto # 1 2 no auto _xv=auto _sdl=auto +_nas=auto _png=auto _gl=auto _ggi=auto @@ -714,6 +715,8 @@ --disable-xv) _xv=no ;; --enable-sdl) _sdl=yes ;; --disable-sdl) _sdl=no ;; + --enable-nas) _nas=yes ;; + --disable-nas) _nas=no ;; --enable-png) _png=yes ;; --disable-png) _png=no ;; --enable-gl) _gl=yes ;; @@ -1768,6 +1771,24 @@ fi echores "$_sdl (with $_sdlconfig)" +echocheck "NAS" +if test "$_nas" = auto || test "$_nas" = yes ; then + cat > $TMPC << EOF +#include <audio/audiolib.h> +int main(void) { return 0; } +EOF + _nas=no + cc_check -laudio -lX11 -lXt -L$_x11libdir && _nas=yes +fi +if test "$_nas" = yes ; then + _def_nas='#define HAVE_NAS 1' + _ld_nas="-laudio -lX11 -lXt -L$_x11libdir" + _aosrc="$_aosrc ao_nas.c" + _aomodules="nas $_aomodules" +else + _def_nas='#undef HAVE_NAS' +fi +echores "$_nas" echocheck "DXR3/H+" if test "$_dxr3" = auto ; then @@ -2598,6 +2619,7 @@ # audio output ALSA_LIB = $_ld_alsa +NAS_LIB = $_ld_nas MAD_LIB = $_ld_mad VORBIS_LIB = $_ld_vorbis SGIAUDIO_LIB = $_ld_sgiaudio @@ -2779,6 +2801,8 @@ $_def_alsa9 $_def_sunaudio $_def_sgiaudio +$_def_nas + /* Enable fast OSD/SUB renderer (looks ugly, but uses less CPU power) */ #undef FAST_OSD
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libao2/ao_nas.c Mon Dec 03 01:13:48 2001 +0000 @@ -0,0 +1,333 @@ +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <audio/audiolib.h> + +#include "audio_out.h" +#include "audio_out_internal.h" +#include "afmt.h" + +#define FRAG_SIZE 4096 +#define FRAG_COUNT 8 +#define BUFFER_SIZE FRAG_SIZE * FRAG_COUNT + +#define NAS_DEBUG 0 + +#if NAS_DEBUG == 1 +#define DPRINTF(format, args...) fprintf(stderr, format, ## args); \ + fflush(stderr) +#else +#define DPRINTF(format, args...) +#endif + +static ao_info_t info = +{ + "NAS audio output", + "nas", + "Tobias Diedrich", + "" +}; + +static AuServer* aud; +static AuFlowID flow; +static AuDeviceID dev; + +static void *client_buffer; +static int client_buffer_size = BUFFER_SIZE; +static int client_buffer_used; +static int server_buffer_size = BUFFER_SIZE; +static int server_buffer_used; +static pthread_mutex_t buffer_mutex = PTHREAD_MUTEX_INITIALIZER; + +pthread_t event_thread; +static int stop_thread; + +LIBAO_EXTERN(nas) + +static void wait_for_event() +{ + AuEvent ev; + + AuNextEvent(aud, AuTrue, &ev); + AuDispatchEvent(aud, &ev); +} + +static int readBuffer(int num) +{ + pthread_mutex_lock(&buffer_mutex); + DPRINTF("readBuffer(): num=%d client=%d/%d server=%d/%d\n", + num, + client_buffer_used, client_buffer_size, + server_buffer_used, server_buffer_size); + + if (client_buffer_used == 0) { + DPRINTF("buffer is empty, nothing read.\n"); + pthread_mutex_unlock(&buffer_mutex); + return 0; + } + if (client_buffer_used < num) + num = client_buffer_used; + + AuWriteElement(aud, flow, 0, num, client_buffer, AuFalse, NULL); + client_buffer_used -= num; + server_buffer_used += num; + memmove(client_buffer, client_buffer + num, client_buffer_used); + pthread_mutex_unlock(&buffer_mutex); + + return num; +} + +static void writeBuffer(void *data, int len) +{ + pthread_mutex_lock(&buffer_mutex); + DPRINTF("writeBuffer(): len=%d client=%d/%d server=%d/%d\n", + len, client_buffer_used, client_buffer_size, + server_buffer_used, server_buffer_size); + + memcpy(client_buffer + client_buffer_used, data, len); + client_buffer_used += len; + + pthread_mutex_unlock(&buffer_mutex); + if (server_buffer_used < server_buffer_size) + readBuffer(server_buffer_size - server_buffer_used); +} + + +static void *event_thread_start(void *data) +{ + while (!stop_thread) { + wait_for_event(); + } +} + +static AuBool event_handler(AuServer *aud, AuEvent *ev, AuEventHandlerRec *hnd) +{ + switch (ev->type) { + case AuEventTypeElementNotify: { + AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev; + DPRINTF("event_handler(): kind %d state %d->%d reason %d numbytes %d\n", + event->kind, + event->prev_state, + event->cur_state, + event->reason, + event->num_bytes); + + switch (event->kind) { + case AuElementNotifyKindLowWater: + server_buffer_used -= event->num_bytes; + readBuffer(event->num_bytes); + break; + case AuElementNotifyKindState: + if ((event->cur_state == AuStatePause) && + (event->reason != AuReasonUser)) { + // buffer underrun -> refill buffer + server_buffer_used = 0; + readBuffer(server_buffer_size - server_buffer_used); + } + } + } + } + return AuTrue; +} + +static AuBool error_handler(AuServer* aud, AuErrorEvent* ev) +{ + char s[100]; + AuGetErrorText(aud, ev->error_code, s, 100); + fprintf(stderr,"libaudiooss: error [%s]\n" + "error_code: %d\n" + "request_code: %d\n" + "minor_code: %d\n", + s, + ev->error_code, + ev->request_code, + ev->minor_code); + fflush(stderr); + + return AuTrue; +} + +static AuDeviceID find_device(int nch) +{ + int i; + for (i = 0; i < AuServerNumDevices(aud); i++) { + AuDeviceAttributes *dev = AuServerDevice(aud, i); + if ((AuDeviceKind(dev) == AuComponentKindPhysicalOutput) && + AuDeviceNumTracks(dev) == nch) { + return AuDeviceIdentifier(dev); + } + } + return AuNone; +} + +static unsigned char aformat_to_auformat(unsigned int format) +{ + switch (format) { + case AFMT_U8: return AuFormatLinearUnsigned8; + case AFMT_S8: return AuFormatLinearSigned8; + case AFMT_U16_LE: return AuFormatLinearUnsigned16LSB; + case AFMT_U16_BE: return AuFormatLinearUnsigned16MSB; + case AFMT_S16_LE: return AuFormatLinearSigned16LSB; + case AFMT_S16_BE: return AuFormatLinearSigned16MSB; + case AFMT_MU_LAW: return AuFormatULAW8; + default: return 0; + } +} + +// to set/get/query special features/parameters +static int control(int cmd,int arg){ + return -1; +} + +// open & setup audio device +// return: 1=success 0=fail +static int init(int rate,int channels,int format,int flags) +{ + AuElement elms[3]; + AuStatus as; + unsigned char auformat = aformat_to_auformat(format); + int bytes_per_sample; + char *server; + + printf("ao2: %d Hz %d chans %s\n",rate,channels, + audio_out_format_name(format)); + + if (!auformat) { + printf("Unsupported format -> nosound\n"); + return 0; + } + + client_buffer = malloc(BUFFER_SIZE); + bytes_per_sample = channels * AuSizeofFormat(auformat); + + ao_data.samplerate = rate; + ao_data.channels = channels; + ao_data.buffersize = BUFFER_SIZE * 2; + ao_data.outburst = FRAG_SIZE; + ao_data.bps = rate * bytes_per_sample; + + if (!bytes_per_sample) { + printf("Zero bytes per sample -> nosound\n"); + return 0; + } + + if (!(server = getenv("AUDIOSERVER"))) + server = getenv("DISPLAY"); + + if (!server) // default to tcp/localhost:8000 + server = "tcp/localhost:8000"; + + printf("Using audioserver %s\n", server); + + aud = AuOpenServer(server, 0, NULL, 0, NULL, NULL); + if (!aud){ + printf("Can't open nas audio server -> nosound\n"); + return 0; + } + + dev = find_device(channels); + if ((dev == AuNone) || (!(flow = AuCreateFlow(aud, NULL)))) { + printf("Can't find a device serving that many channels -> nosound\n"); + AuCloseServer(aud); + aud = 0; + return 0; + } + + AuMakeElementImportClient(elms, rate, auformat, channels, AuTrue, + BUFFER_SIZE / bytes_per_sample, + (BUFFER_SIZE - FRAG_SIZE) / bytes_per_sample, + 0, NULL); + AuMakeElementExportDevice(elms+1, 0, dev, rate, + AuUnlimitedSamples, 0, NULL); + AuSetElements(aud, flow, AuTrue, 2, elms, &as); + if (as != AuSuccess) + printf("AuSetElements returned status %d!\n", as); + AuRegisterEventHandler(aud, AuEventHandlerIDMask | + AuEventHandlerTypeMask, + AuEventTypeElementNotify, flow, + event_handler, (AuPointer) NULL); + AuSetErrorHandler(aud, error_handler); + AuStartFlow(aud, flow, &as); + if (as != AuSuccess) + printf("AuSetElements returned status %d!\n", as); + + /* + * Wait for first buffer underrun event + * + * For some weird reason we get a buffer underrun event if we + * don't fill the server buffer fast enough after staring the + * flow. So we just wait for it to happen to be in a sane state. + */ + wait_for_event(); + + pthread_create(&event_thread, NULL, &event_thread_start, NULL); + + return 1; +} + +// close audio device +static void uninit(){ + stop_thread = 1; + pthread_join(event_thread, NULL); + AuStopFlow(aud, flow, NULL); + AuCloseServer(aud); + aud = 0; + free(client_buffer); +} + +// stop playing and empty buffers (for seeking/pause) +static void reset(){ + pthread_mutex_lock(&buffer_mutex); + client_buffer_used = 0; + pthread_mutex_unlock(&buffer_mutex); + while (server_buffer_used > 0) { + usleep(1000); +// DPRINTF("used=%d\n", server_buffer_used); + } +} + +// stop playing, keep buffers (for pause) +static void audio_pause() +{ + // for now, just call reset(); + reset(); +} + +// resume playing, after audio_pause() +static void audio_resume() +{ +} + +// return: how many bytes can be played without blocking +static int get_space() +{ + int result; + + pthread_mutex_lock(&buffer_mutex); + result = client_buffer_size - client_buffer_used; + pthread_mutex_unlock(&buffer_mutex); + + return result; +} + +// plays 'len' bytes of 'data' +// it should round it down to outburst*n +// return: number of bytes played +static int play(void* data,int len,int flags){ + writeBuffer(data, len); +// printf("ao_nas: wrote %d bytes of audio data\n", len); + return len; +} + +// return: delay in seconds between first and last sample in buffer +static float get_delay() +{ + float result; + + pthread_mutex_lock(&buffer_mutex); + result = ((float)(client_buffer_used + server_buffer_used)) / + (float)ao_data.bps; + pthread_mutex_unlock(&buffer_mutex); + + return result; +}
--- a/libao2/audio_out.c Mon Dec 03 01:09:36 2001 +0000 +++ b/libao2/audio_out.c Mon Dec 03 01:13:48 2001 +0000 @@ -22,6 +22,9 @@ #ifdef HAVE_ESD extern ao_functions_t audio_out_esd; #endif +#ifdef HAVE_NAS +extern ao_functions_t audio_out_nas; +#endif #ifdef HAVE_SDL extern ao_functions_t audio_out_sdl; #endif @@ -60,6 +63,9 @@ #ifdef HAVE_ESD &audio_out_esd, #endif +#ifdef HAVE_NAS + &audio_out_nas, +#endif #ifdef HAVE_SDL &audio_out_sdl, #endif