diff options
Diffstat (limited to 'libao2')
-rw-r--r-- | libao2/ao_ivtv.c | 161 | ||||
-rw-r--r-- | libao2/ao_mpegpes.c | 336 | ||||
-rw-r--r-- | libao2/ao_nas.c | 646 | ||||
-rw-r--r-- | libao2/ao_sdl.c | 319 | ||||
-rw-r--r-- | libao2/ao_sun.c | 692 | ||||
-rw-r--r-- | libao2/ao_win32.c | 326 | ||||
-rw-r--r-- | libao2/audio_out.c | 33 |
7 files changed, 0 insertions, 2513 deletions
diff --git a/libao2/ao_ivtv.c b/libao2/ao_ivtv.c deleted file mode 100644 index e05537cbd8..0000000000 --- a/libao2/ao_ivtv.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * audio output for WinTV PVR-150/250/350 (a.k.a IVTV) cards - * through Connexant hardware MPEG decoder - * See http://ivtvdriver.org/index.php/Main_Page for more details on the - * cards supported by the ivtv driver. - * - * WARNING: You need to force -ac hwmpa for audio output to work. - * - * Copyright (C) 2006 Benjamin Zores - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <inttypes.h> - -#include "config.h" - -#include "mp_msg.h" - -#include "audio_out.h" -#include "audio_out_internal.h" -#include "libaf/af_format.h" -#include "libmpdemux/mpeg_packetizer.h" -#include "libvo/vo_ivtv.h" - -#define MPEG_AUDIO_ID 0x1C0 - -static int freq = 0; - -static const ao_info_t info = -{ - "IVTV MPEG Audio Decoder output", - "ivtv", - "Benjamin Zores", - "" -}; - -LIBAO_EXTERN(ivtv) - -/* to set/get/query special features/parameters */ -static int -control (int cmd,void *arg) -{ - return CONTROL_UNKNOWN; -} - -/* open & setup audio device */ -static int -init (int rate, int channels, int format, int flags) -{ - if (ivtv_fd < 0) - return 0; - - if (format != AF_FORMAT_MPEG2) - { - mp_msg (MSGT_AO, MSGL_FATAL, - "AO: [ivtv] can only handle MPEG audio streams.\n"); - return 0; - } - - ao_data.outburst = 2048; - ao_data.samplerate = rate; - ao_data.channels = channels; - ao_data.format = AF_FORMAT_MPEG2; - ao_data.buffersize = 2048; - ao_data.bps = rate * 2 * 2; - ao_data.brokenpts = 0; - freq = rate; - - /* check for supported audio rate */ - if (rate != 32000 || rate != 41000 || rate != 48000) - { - mp_tmsg (MSGT_AO, MSGL_ERR, "[AO MPEGPES] %d Hz not supported, try to resample.\n", rate); - rate = 48000; - } - - return 1; -} - -/* close audio device */ -static void -uninit (int immed) -{ - /* nothing to do */ -} - -/* stop playing and empty buffers (for seeking/pause) */ -static void -reset (void) -{ - /* nothing to do */ -} - -/* stop playing, keep buffers (for pause) */ -static void -audio_pause (void) -{ - reset (); -} - -/* resume playing, after audio_pause() */ -static void -audio_resume (void) -{ - /* nothing to do */ -} - -/* how many bytes can be played without blocking */ -static int -get_space (void) -{ - extern int vo_pts; - float x; - int y; - - x = (float) (vo_pts - ao_data.brokenpts) / 90000.0; - if (x <= 0) - return 0; - - y = freq * 4 * x; - y /= ao_data.outburst; - y *= ao_data.outburst; - - if (y > 32000) - y = 32000; - - return y; -} - -/* number of bytes played */ -static int -play (void *data, int len, int flags) -{ - if (ao_data.format != AF_FORMAT_MPEG2) - return 0; - - send_mpeg_pes_packet (data, len, MPEG_AUDIO_ID, ao_data.brokenpts, 2, ivtv_write); - - return len; -} - -/* delay in seconds between first and last sample in buffer */ -static float -get_delay (void) -{ - return 0.0; -} diff --git a/libao2/ao_mpegpes.c b/libao2/ao_mpegpes.c deleted file mode 100644 index fe3f20fc85..0000000000 --- a/libao2/ao_mpegpes.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * MPEG-PES audio output driver - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <inttypes.h> -#include <errno.h> - -#include "config.h" - -#include "audio_out.h" -#include "audio_out_internal.h" - -#include "libaf/af_format.h" -#include "libmpdemux/mpeg_packetizer.h" -#include "subopt-helper.h" - -#include "mp_msg.h" - -#ifdef CONFIG_DVB -#include <poll.h> -#include <sys/ioctl.h> -#include <linux/dvb/audio.h> -audio_mixer_t dvb_mixer={255,255}; -#endif - -#define true 1 -#define false 0 - -extern int vo_mpegpes_fd; -int ao_mpegpes_fd = -1; - -#include <errno.h> - -static const ao_info_t info = -{ -#ifdef CONFIG_DVB - "DVB audio output", -#else - "MPEG-PES audio output", -#endif - "mpegpes", - "A'rpi", - "" -}; - -LIBAO_EXTERN(mpegpes) - - -// to set/get/query special features/parameters -static int control(int cmd,void *arg){ -#ifdef CONFIG_DVB - switch(cmd){ - case AOCONTROL_GET_VOLUME: - if(ao_mpegpes_fd >= 0){ - ((ao_control_vol_t*)(arg))->left=dvb_mixer.volume_left/2.56; - ((ao_control_vol_t*)(arg))->right=dvb_mixer.volume_right/2.56; - return CONTROL_OK; - } - return CONTROL_ERROR; - case AOCONTROL_SET_VOLUME: - if(ao_mpegpes_fd >= 0){ - dvb_mixer.volume_left=((ao_control_vol_t*)(arg))->left*2.56; - dvb_mixer.volume_right=((ao_control_vol_t*)(arg))->right*2.56; - if(dvb_mixer.volume_left>255) dvb_mixer.volume_left=255; - if(dvb_mixer.volume_right>255) dvb_mixer.volume_right=255; - // printf("Setting DVB volume: %d ; %d \n",dvb_mixer.volume_left,dvb_mixer.volume_right); - if ( (ioctl(vo_mpegpes_fd,AUDIO_SET_MIXER, &dvb_mixer) < 0)){ - mp_tmsg(MSGT_AO, MSGL_ERR, "[AO MPEGPES] DVB audio set mixer failed: %s.\n", - strerror(errno)); - return CONTROL_ERROR; - } - return CONTROL_OK; - } - return CONTROL_ERROR; - } -#endif - return CONTROL_UNKNOWN; -} - -static int freq=0; -static int freq_id=0; - -#ifdef CONFIG_DVB -static int init_device(int card) -{ - char ao_file[30]; - sprintf(ao_file, "/dev/dvb/adapter%d/audio0", card); - mp_msg(MSGT_VO,MSGL_INFO, "Opening %s\n", ao_file); - if((ao_mpegpes_fd = open(ao_file,O_RDWR|O_NONBLOCK)) < 0) - { - mp_msg(MSGT_VO, MSGL_ERR, "DVB AUDIO DEVICE: %s\n", strerror(errno)); - return -1; - } - if( (ioctl(ao_mpegpes_fd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY) < 0)) - { - mp_msg(MSGT_VO, MSGL_ERR, "DVB AUDIO SELECT SOURCE: %s\n", strerror(errno)); - goto fail; - } - if((ioctl(ao_mpegpes_fd, AUDIO_PLAY) < 0)) - { - mp_msg(MSGT_VO, MSGL_ERR, "DVB AUDIO PLAY: %s\n", strerror(errno)); - goto fail; - } - if((ioctl(ao_mpegpes_fd, AUDIO_SET_AV_SYNC, true) < 0)) - { - mp_msg(MSGT_VO, MSGL_ERR, "DVB AUDIO SET AV SYNC: %s\n", strerror(errno)); - goto fail; - } - //FIXME: in vo_mpegpes audio was initialized as MUTEd - if((ioctl(ao_mpegpes_fd, AUDIO_SET_MUTE, false) < 0)) - { - mp_msg(MSGT_VO, MSGL_ERR, "DVB AUDIO SET MUTE: %s\n", strerror(errno)); - goto fail; - } - return ao_mpegpes_fd; -fail: - close(ao_mpegpes_fd); - ao_mpegpes_fd = -1; - return -1; -} -#endif - -static int preinit(const char *arg) -{ - int card = -1; - char *ao_file = NULL; - - const opt_t subopts[] = { - {"card", OPT_ARG_INT, &card, NULL}, - {"file", OPT_ARG_MSTRZ, &ao_file, NULL}, - {NULL} - }; - - if(subopt_parse(ao_subdevice, subopts) != 0) - { - mp_msg(MSGT_VO, MSGL_ERR, "AO_MPEGPES, Unrecognized options\n"); - return -1; - } - if(card==-1) - { - //search the first usable card - int n; - char file[30]; - for(n=0; n<4; n++) - { - sprintf(file, "/dev/dvb/adapter%d/audio0", n); - if(access(file, F_OK | W_OK)==0) - { - card = n+1; - break; - } - } - } - if((card < 1) || (card > 4)) - { - mp_msg(MSGT_VO, MSGL_ERR, "DVB card number must be between 1 and 4\n"); - return -1; - } - card--; - -#ifdef CONFIG_DVB - if(!ao_file) - return init_device(card); -#else - if(!ao_file) - return vo_mpegpes_fd; //video fd -#endif - - ao_mpegpes_fd = open(ao_file, O_WRONLY | O_CREAT, 0666); - if(ao_mpegpes_fd < 0) - { - mp_msg(MSGT_VO, MSGL_ERR, "ao_mpegpes: %s\n", strerror(errno)); - return -1; - } - return ao_mpegpes_fd; -} - -static int my_ao_write(const unsigned char* data,int len){ - int orig_len = len; -#ifdef CONFIG_DVB -#define NFD 1 - struct pollfd pfd[NFD]; - - pfd[0].fd = ao_mpegpes_fd; - pfd[0].events = POLLOUT; - - while(len>0){ - if(poll(pfd,NFD,1)){ - if(pfd[0].revents & POLLOUT){ - int ret = write(ao_mpegpes_fd, data, len); - if(ret<=0){ - mp_msg(MSGT_VO, MSGL_ERR, "ao_mpegpes write: %s\n", strerror(errno)); - usleep(0); - } else { - len-=ret; - data+=ret; - } - } else usleep(1000); - } - } - -#else - if(ao_mpegpes_fd < 0) return 0; // no file - write(ao_mpegpes_fd, data, len); // write to file -#endif - return orig_len; -} - - -// open & setup audio device -// return: 1=success 0=fail -static int init(int rate,int channels,int format,int flags){ - if(preinit(NULL)<0) return 0; - - ao_data.channels=2; - ao_data.outburst=2000; - switch(format){ - case AF_FORMAT_S16_BE: - case AF_FORMAT_MPEG2: - case AF_FORMAT_AC3_BE: - ao_data.format=format; - break; - case AF_FORMAT_AC3_LE: - ao_data.format=AF_FORMAT_AC3_BE; - break; - default: - ao_data.format=AF_FORMAT_S16_BE; - } - - switch(rate){ - case 48000: freq_id=0;break; - case 96000: freq_id=1;break; - case 44100: freq_id=2;break; - case 32000: freq_id=3;break; - default: - mp_tmsg(MSGT_AO, MSGL_ERR, "[AO MPEGPES] %d Hz not supported, try to resample.\n", rate); -#if 0 - if(rate>48000) rate=96000; else - if(rate>44100) rate=48000; else - if(rate>32000) rate=44100; else - rate=32000; - goto retry; -#else - rate=48000; freq_id=0; -#endif - } - - ao_data.bps=rate*2*2; - freq=ao_data.samplerate=rate; - - return 1; -} - -// close audio device -static void uninit(int immed){ - if (ao_mpegpes_fd >= 0) - close(ao_mpegpes_fd); - ao_mpegpes_fd = -1; -} - -// stop playing and empty buffers (for seeking/pause) -static void reset(void){ - -} - -// stop playing, keep buffers (for pause) -static void audio_pause(void) -{ - // for now, just call reset(); - reset(); -} - -// resume playing, after audio_pause() -static void audio_resume(void) -{ -} - -extern int vo_pts; - -// return: how many bytes can be played without blocking -static int get_space(void){ - float x=(float)(vo_pts-ao_data.brokenpts)/90000.0; - int y; - //FIXME: is it correct? - if(vo_mpegpes_fd < 0) return 32000; //not using -vo mpegpes -// printf("vo_pts: %5.3f ao_pts: %5.3f\n",vo_pts/90000.0,ao_data.brokenpts/90000.0); - if(x<=0) return 0; - y=freq*4*x;y/=ao_data.outburst;y*=ao_data.outburst; - if(y>32000) y=32000; -// printf("diff: %5.3f -> %d \n",x,y); - return y; -} - -// 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){ -// printf("\nao_mpegpes: play(%d) freq=%d\n",len,freq_id); - if(ao_data.format==AF_FORMAT_MPEG2) - send_mpeg_pes_packet (data, len, 0x1C0, ao_data.brokenpts, 1, my_ao_write); - else { -// if(len>2000) len=2000; -// printf("ao_mpegpes: len=%d \n",len); - send_mpeg_lpcm_packet(data, len, 0xA0, ao_data.brokenpts, freq_id, my_ao_write); - } - return len; -} - -// return: delay in seconds between first and last sample in buffer -static float get_delay(void){ - - return 0.0; -} diff --git a/libao2/ao_nas.c b/libao2/ao_nas.c deleted file mode 100644 index d3274df9a5..0000000000 --- a/libao2/ao_nas.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * NAS audio output driver - * - * copyright (c) 2001 Tobias Diedrich <ranma@gmx.at> - * - * Based on the libaudiooss parts rewritten by me, which were - * originally based on the NAS output plugin for XMMS. - * - * XMMS plugin by Willem Monsuwe - * adapted for libaudiooss by Jon Trulson - * further modified by Erik Inge Bolsø - * largely rewritten and used for this ao driver by Tobias Diedrich - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* - * Theory of operation: - * - * The NAS consists of two parts, a server daemon and a client. - * We setup the server to use a buffer of size bytes_per_second - * with a low watermark of buffer_size - NAS_FRAG_SIZE. - * Upon starting the flow the server will generate a buffer underrun - * event and the event handler will fill the buffer for the first time. - * Now the server will generate a lowwater event when the server buffer - * falls below the low watermark value. The event handler gets called - * again and refills the buffer by the number of bytes requested by the - * server (usually a multiple of 4096). To prevent stuttering on - * startup (start of playing, seeks, unpausing) the client buffer should - * be bigger than the server buffer. (For debugging we also do some - * accounting of what we think how much of the server buffer is filled) - */ - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <pthread.h> -#include <limits.h> -#include <audio/audiolib.h> - -#include "config.h" -#include "mp_msg.h" - -#include "audio_out.h" -#include "audio_out_internal.h" -#include "libaf/af_format.h" - -/* NAS_FRAG_SIZE must be a power-of-two value */ -#define NAS_FRAG_SIZE 4096 - -static const char * const nas_event_types[] = { - "Undefined", - "Undefined", - "ElementNotify", - "GrabNotify", - "MonitorNotify", - "BucketNotify", - "DeviceNotify" -}; - -static const char * const nas_elementnotify_kinds[] = { - "LowWater", - "HighWater", - "State", - "Unknown" -}; - -static const char * const nas_states[] = { - "Stop", - "Start", - "Pause", - "Any" -}; - -static const char * const nas_reasons[] = { - "User", - "Underrun", - "Overrun", - "EOF", - "Watermark", - "Hardware", - "Any" -}; - -static const char* nas_reason(unsigned int reason) -{ - if (reason > 6) reason = 6; - return nas_reasons[reason]; -} - -static const char* nas_elementnotify_kind(unsigned int kind) -{ - if (kind > 2) kind = 3; - return nas_elementnotify_kinds[kind]; -} - -static const char* nas_event_type(unsigned int type) { - if (type > 6) type = 0; - return nas_event_types[type]; -} - -static const char* nas_state(unsigned int state) { - if (state>3) state = 3; - return nas_states[state]; -} - -static const ao_info_t info = -{ - "NAS audio output", - "nas", - "Tobias Diedrich <ranma+mplayer@tdiedrich.de>", - "" -}; - -struct ao_nas_data { - AuServer *aud; - AuFlowID flow; - AuDeviceID dev; - AuFixedPoint gain; - - unsigned int state; - int expect_underrun; - - char *client_buffer; - char *server_buffer; - unsigned int client_buffer_size; - unsigned int client_buffer_used; - unsigned int server_buffer_size; - unsigned int server_buffer_used; - pthread_mutex_t buffer_mutex; - - pthread_t event_thread; - int stop_thread; -}; - -static struct ao_nas_data *nas_data; - -LIBAO_EXTERN(nas) - -static void nas_print_error(AuServer *aud, const char *prefix, AuStatus as) -{ - char s[100]; - AuGetErrorText(aud, as, s, 100); - mp_msg(MSGT_AO, MSGL_ERR, "ao_nas: %s: returned status %d (%s)\n", prefix, as, s); -} - -static int nas_readBuffer(struct ao_nas_data *nas_data, unsigned int num) -{ - AuStatus as; - - pthread_mutex_lock(&nas_data->buffer_mutex); - mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: nas_readBuffer(): num=%d client=%d/%d server=%d/%d\n", - num, - nas_data->client_buffer_used, nas_data->client_buffer_size, - nas_data->server_buffer_used, nas_data->server_buffer_size); - - if (nas_data->client_buffer_used == 0) { - mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: buffer is empty, nothing read.\n"); - pthread_mutex_unlock(&nas_data->buffer_mutex); - return 0; - } - if (num > nas_data->client_buffer_used) - num = nas_data->client_buffer_used; - - /* - * It is not appropriate to call AuWriteElement() here because the - * buffer is locked and delays writing to the network will cause - * other threads to block waiting for buffer_mutex. Instead the - * data is copied to "server_buffer" and written to the network - * outside of the locked section of code. - * - * (Note: Rather than these two buffers, a single circular buffer - * could eliminate the memcpy/memmove steps.) - */ - /* make sure we don't overflow the buffer */ - if (num > nas_data->server_buffer_size) - num = nas_data->server_buffer_size; - memcpy(nas_data->server_buffer, nas_data->client_buffer, num); - - nas_data->client_buffer_used -= num; - nas_data->server_buffer_used += num; - memmove(nas_data->client_buffer, nas_data->client_buffer + num, nas_data->client_buffer_used); - pthread_mutex_unlock(&nas_data->buffer_mutex); - - /* - * Now write the new buffer to the network. - */ - AuWriteElement(nas_data->aud, nas_data->flow, 0, num, nas_data->server_buffer, AuFalse, &as); - if (as != AuSuccess) - nas_print_error(nas_data->aud, "nas_readBuffer(): AuWriteElement", as); - - return num; -} - -static int nas_writeBuffer(struct ao_nas_data *nas_data, void *data, unsigned int len) -{ - pthread_mutex_lock(&nas_data->buffer_mutex); - mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: nas_writeBuffer(): len=%d client=%d/%d server=%d/%d\n", - len, nas_data->client_buffer_used, nas_data->client_buffer_size, - nas_data->server_buffer_used, nas_data->server_buffer_size); - - /* make sure we don't overflow the buffer */ - if (len > nas_data->client_buffer_size - nas_data->client_buffer_used) - len = nas_data->client_buffer_size - nas_data->client_buffer_used; - memcpy(nas_data->client_buffer + nas_data->client_buffer_used, data, len); - nas_data->client_buffer_used += len; - - pthread_mutex_unlock(&nas_data->buffer_mutex); - - return len; -} - -static int nas_empty_event_queue(struct ao_nas_data *nas_data) -{ - AuEvent ev; - int result = 0; - - while (AuScanForTypedEvent(nas_data->aud, AuEventsQueuedAfterFlush, - AuTrue, AuEventTypeElementNotify, &ev)) { - AuDispatchEvent(nas_data->aud, &ev); - result = 1; - } - return result; -} - -static void *nas_event_thread_start(void *data) -{ - struct ao_nas_data *nas_data = data; - - do { - mp_msg(MSGT_AO, MSGL_DBG2, - "ao_nas: event thread heartbeat (state=%s)\n", - nas_state(nas_data->state)); - nas_empty_event_queue(nas_data); - usleep(1000); - } while (!nas_data->stop_thread); - - return NULL; -} - -static AuBool nas_error_handler(AuServer* aud, AuErrorEvent* ev) -{ - char s[100]; - AuGetErrorText(aud, ev->error_code, s, 100); - mp_msg(MSGT_AO, MSGL_ERR, "ao_nas: 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); - - return AuTrue; -} - -static AuBool nas_event_handler(AuServer *aud, AuEvent *ev, AuEventHandlerRec *hnd) -{ - AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev; - struct ao_nas_data *nas_data = hnd->data; - - mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: event_handler(): type %s kind %s state %s->%s reason %s numbytes %d expect_underrun %d\n", - nas_event_type(event->type), - nas_elementnotify_kind(event->kind), - nas_state(event->prev_state), - nas_state(event->cur_state), - nas_reason(event->reason), - (int)event->num_bytes, - nas_data->expect_underrun); - - if (event->num_bytes > INT_MAX) { - mp_msg(MSGT_AO, MSGL_ERR, "ao_nas: num_bytes > 2GB, server buggy?\n"); - } - - if (event->num_bytes > nas_data->server_buffer_used) - event->num_bytes = nas_data->server_buffer_used; - nas_data->server_buffer_used -= event->num_bytes; - - switch (event->reason) { - case AuReasonWatermark: - nas_readBuffer(nas_data, event->num_bytes); - break; - case AuReasonUnderrun: - // buffer underrun -> refill buffer - nas_data->server_buffer_used = 0; - if (nas_data->expect_underrun) { - nas_data->expect_underrun = 0; - } else { - static int hint = 1; - mp_msg(MSGT_AO, MSGL_WARN, - "ao_nas: Buffer underrun.\n"); - if (hint) { - hint = 0; - mp_msg(MSGT_AO, MSGL_HINT, - "Possible reasons are:\n" - "1) Network congestion.\n" - "2) Your NAS server is too slow.\n" - "Try renicing your nasd to e.g. -15.\n"); - } - } - if (nas_readBuffer(nas_data, - nas_data->server_buffer_size - - nas_data->server_buffer_used) != 0) { - event->cur_state = AuStateStart; - break; - } - mp_msg(MSGT_AO, MSGL_DBG2, - "ao_nas: Can't refill buffer, stopping flow.\n"); - AuStopFlow(aud, nas_data->flow, NULL); - break; - default: - break; - } - nas_data->state=event->cur_state; - return AuTrue; -} - -static AuDeviceID nas_find_device(AuServer *aud, 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 int nas_aformat_to_auformat(unsigned int *format) -{ - switch (*format) { - case AF_FORMAT_U8: - return AuFormatLinearUnsigned8; - case AF_FORMAT_S8: - return AuFormatLinearSigned8; - case AF_FORMAT_U16_LE: - return AuFormatLinearUnsigned16LSB; - case AF_FORMAT_U16_BE: - return AuFormatLinearUnsigned16MSB; - case AF_FORMAT_S16_LE: - return AuFormatLinearSigned16LSB; - case AF_FORMAT_S16_BE: - return AuFormatLinearSigned16MSB; - case AF_FORMAT_MU_LAW: - return AuFormatULAW8; - default: - *format=AF_FORMAT_S16_NE; - return nas_aformat_to_auformat(format); - } -} - -// to set/get/query special features/parameters -static int control(int cmd, void *arg) -{ - AuElementParameters aep; - AuStatus as; - int retval = CONTROL_UNKNOWN; - - ao_control_vol_t *vol = (ao_control_vol_t *)arg; - - switch (cmd) { - case AOCONTROL_GET_VOLUME: - - vol->right = (float)nas_data->gain/AU_FIXED_POINT_SCALE*50; - vol->left = vol->right; - - mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: AOCONTROL_GET_VOLUME: %.2f\n", vol->right); - retval = CONTROL_OK; - break; - - case AOCONTROL_SET_VOLUME: - /* - * kn: we should have vol->left == vol->right but i don't - * know if something can change it outside of ao_nas - * so i take the mean of both values. - */ - nas_data->gain = AU_FIXED_POINT_SCALE*((vol->left+vol->right)/2)/50; - mp_msg(MSGT_AO, MSGL_DBG2, "ao_nas: AOCONTROL_SET_VOLUME: %.2f\n", (vol->left+vol->right)/2); - - aep.parameters[AuParmsMultiplyConstantConstant]=nas_data->gain; - aep.flow = nas_data->flow; - aep.element_num = 1; - aep.num_parameters = AuParmsMultiplyConstant; - - AuSetElementParameters(nas_data->aud, 1, &aep, &as); - if (as != AuSuccess) { - nas_print_error(nas_data->aud, - "control(): AuSetElementParameters", as); - retval = CONTROL_ERROR; - } else retval = CONTROL_OK; - break; - }; - - return retval; -} - -// 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 = nas_aformat_to_auformat(&format); - int bytes_per_sample = channels * AuSizeofFormat(auformat); - int buffer_size; - char *server; - - (void)flags; /* shut up 'unused parameter' warning */ - - global_ao->no_persistent_volume = true; - - nas_data=malloc(sizeof(struct ao_nas_data)); - memset(nas_data, 0, sizeof(struct ao_nas_data)); - - mp_msg(MSGT_AO, MSGL_V, "ao2: %d Hz %d chans %s\n",rate,channels, - af_fmt2str_short(format)); - - ao_data.format = format; - ao_data.samplerate = rate; - ao_data.channels = channels; - ao_data.outburst = NAS_FRAG_SIZE; - ao_data.bps = rate * bytes_per_sample; - buffer_size = ao_data.bps; /* buffer 1 second */ - /* - * round up to multiple of NAS_FRAG_SIZE - * divide by 3 first because of 2:1 split - */ - buffer_size = (buffer_size/3 + NAS_FRAG_SIZE-1) & ~(NAS_FRAG_SIZE-1); - ao_data.buffersize = buffer_size*3; - - nas_data->client_buffer_size = buffer_size*2; - nas_data->client_buffer = malloc(nas_data->client_buffer_size); - nas_data->server_buffer_size = buffer_size; - nas_data->server_buffer = malloc(nas_data->server_buffer_size); - - if (!bytes_per_sample) { - mp_msg(MSGT_AO, MSGL_ERR, "ao_nas: init(): Zero bytes per sample -> nosound\n"); - return 0; - } - - if (!(server = getenv("AUDIOSERVER")) && - !(server = getenv("DISPLAY"))) { - mp_msg(MSGT_AO, MSGL_ERR, "ao_nas: init(): AUDIOSERVER environment variable not set -> nosound\n"); - return 0; - } - - mp_msg(MSGT_AO, MSGL_V, "ao_nas: init(): Using audioserver %s\n", server); - - nas_data->aud = AuOpenServer(server, 0, NULL, 0, NULL, NULL); - if (!nas_data->aud) { - mp_msg(MSGT_AO, MSGL_ERR, "ao_nas: init(): Can't open nas audio server -> nosound\n"); - return 0; - } - - while (channels>0) { - nas_data->dev = nas_find_device(nas_data->aud, channels); - if (nas_data->dev != AuNone && - ((nas_data->flow = AuCreateFlow(nas_data->aud, NULL)) != 0)) - break; - channels--; - } - - if (nas_data->flow == 0) { - mp_msg(MSGT_AO, MSGL_ERR, "ao_nas: init(): Can't find a suitable output device -> nosound\n"); - AuCloseServer(nas_data->aud); - nas_data->aud = 0; - return 0; - } - - AuMakeElementImportClient(elms, rate, auformat, channels, AuTrue, - buffer_size / bytes_per_sample, - (buffer_size - NAS_FRAG_SIZE) / - bytes_per_sample, 0, NULL); - nas_data->gain = AuFixedPointFromFraction(1, 1); - AuMakeElementMultiplyConstant(elms+1, 0, nas_data->gain); - AuMakeElementExportDevice(elms+2, 1, nas_data->dev, rate, - AuUnlimitedSamples, 0, NULL); - AuSetElements(nas_data->aud, nas_data->flow, AuTrue, sizeof(elms)/sizeof(*elms), elms, &as); - if (as != AuSuccess) { - nas_print_error(nas_data->aud, "init(): AuSetElements", as); - AuCloseServer(nas_data->aud); - nas_data->aud = 0; - return 0; - } - AuRegisterEventHandler(nas_data->aud, AuEventHandlerIDMask | - AuEventHandlerTypeMask, - AuEventTypeElementNotify, nas_data->flow, - nas_event_handler, (AuPointer) nas_data); - AuSetErrorHandler(nas_data->aud, nas_error_handler); - nas_data->state=AuStateStop; - nas_data->expect_underrun=0; - - pthread_mutex_init(&nas_data->buffer_mutex, NULL); - pthread_create(&nas_data->event_thread, NULL, &nas_event_thread_start, nas_data); - - return 1; -} - -// close audio device -static void uninit(int immed){ - - mp_msg(MSGT_AO, MSGL_DBG3, "ao_nas: uninit()\n"); - - nas_data->expect_underrun = 1; - if (!immed) - while (nas_data->state != AuStateStop) usleep(1000); - nas_data->stop_thread = 1; - pthread_join(nas_data->event_thread, NULL); - AuCloseServer(nas_data->aud); - nas_data->aud = 0; - free(nas_data->client_buffer); - free(nas_data->server_buffer); -} - -// stop playing and empty buffers (for seeking/pause) -static void reset(void){ - AuStatus as; - - mp_msg(MSGT_AO, MSGL_DBG3, "ao_nas: reset()\n"); - - pthread_mutex_lock(&nas_data->buffer_mutex); - nas_data->client_buffer_used = 0; - pthread_mutex_unlock(&nas_data->buffer_mutex); - while (nas_data->state != AuStateStop) { - AuStopFlow(nas_data->aud, nas_data->flow, &as); - if (as != AuSuccess) - nas_print_error(nas_data->aud, "reset(): AuStopFlow", as); - usleep(1000); - } -} - -// stop playing, keep buffers (for pause) -static void audio_pause(void) -{ - AuStatus as; - mp_msg(MSGT_AO, MSGL_DBG3, "ao_nas: audio_pause()\n"); - - AuStopFlow(nas_data->aud, nas_data->flow, &as); -} - -// resume playing, after audio_pause() -static void audio_resume(void) -{ - AuStatus as; - - mp_msg(MSGT_AO, MSGL_DBG3, "ao_nas: audio_resume()\n"); - - AuStartFlow(nas_data->aud, nas_data->flow, &as); - if (as != AuSuccess) - nas_print_error(nas_data->aud, - "play(): AuStartFlow", as); -} - - -// return: how many bytes can be played without blocking -static int get_space(void) -{ - int result; - - mp_msg(MSGT_AO, MSGL_DBG3, "ao_nas: get_space()\n"); - - pthread_mutex_lock(&nas_data->buffer_mutex); - result = nas_data->client_buffer_size - nas_data->client_buffer_used; - pthread_mutex_unlock(&nas_data->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) -{ - int written, maxbursts = 0, playbursts = 0; - AuStatus as; - - mp_msg(MSGT_AO, MSGL_DBG3, - "ao_nas: play(%p, %d, %d)\n", - data, len, flags); - - if (len == 0) - return 0; - - if (!(flags & AOPLAY_FINAL_CHUNK)) { - pthread_mutex_lock(&nas_data->buffer_mutex); - maxbursts = (nas_data->client_buffer_size - - nas_data->client_buffer_used) / ao_data.outburst; - playbursts = len / ao_data.outburst; - len = (playbursts > maxbursts ? maxbursts : playbursts) * - ao_data.outburst; - pthread_mutex_unlock(&nas_data->buffer_mutex); - } - - /* - * If AOPLAY_FINAL_CHUNK is set, we did not actually check len fits - * into the available buffer space, but mplayer.c shouldn't give us - * more to play than we report to i |