/*************************************************************************** oss.c - description ------------------- begin : Wed May 15 2002 copyright : (C) 2002 by Pete Bernert email : BlackDove@addcom.de ***************************************************************************/ /*************************************************************************** * * * This program 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. See also the license.txt file for * * additional informations. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include "out.h" //////////////////////////////////////////////////////////////////////// // oss globals //////////////////////////////////////////////////////////////////////// #define OSS_MODE_STEREO 1 #define OSS_MODE_MONO 0 #define OSS_SPEED_44100 44100 #define FRAGMENT_SHIFT 12 #define FRAGMENT_SIZE (1 << FRAGMENT_SHIFT) static int oss_audio_fd = -1; extern int errno; //////////////////////////////////////////////////////////////////////// // SETUP SOUND //////////////////////////////////////////////////////////////////////// static int oss_init(void) { int pspeed=44100; int pstereo; int format; int myfrag; int oss_speed, oss_stereo; pstereo = OSS_MODE_STEREO; oss_speed = pspeed; oss_stereo = pstereo; if((oss_audio_fd=open("/dev/dsp",O_WRONLY,0))==-1) { printf("OSS device not available\n"); return -1; } if(ioctl(oss_audio_fd,SNDCTL_DSP_RESET,0)==-1) { printf("Sound reset failed\n"); return -1; } // we use 64 fragments with 1024 bytes each // rearmed: now using 10*4096 for better latency myfrag = (10<<16) | FRAGMENT_SHIFT; if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFRAGMENT,&myfrag)==-1) { printf("Sound set fragment failed!\n"); return -1; } format = AFMT_S16_NE; if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFMT,&format) == -1) { printf("Sound format not supported!\n"); return -1; } if(format!=AFMT_S16_NE) { printf("Sound format not supported!\n"); return -1; } if(ioctl(oss_audio_fd,SNDCTL_DSP_STEREO,&oss_stereo)==-1 || !oss_stereo) { printf("Stereo mode not supported!\n"); return -1; } if(ioctl(oss_audio_fd,SNDCTL_DSP_SPEED,&oss_speed)==-1) { printf("Sound frequency not supported\n"); return -1; } if(oss_speed!=pspeed) { printf("Sound frequency not supported\n"); return -1; } return 0; } //////////////////////////////////////////////////////////////////////// // REMOVE SOUND //////////////////////////////////////////////////////////////////////// static void oss_finish(void) { if(oss_audio_fd != -1 ) { close(oss_audio_fd); oss_audio_fd = -1; } } //////////////////////////////////////////////////////////////////////// // GET BUFFERED STATUS //////////////////////////////////////////////////////////////////////// static int oss_busy(void) { audio_buf_info info; unsigned long l; if(oss_audio_fd == -1) return 1; if(ioctl(oss_audio_fd,SNDCTL_DSP_GETOSPACE,&info)==-1) l=0; else { if(info.fragments<(info.fragstotal>>1)) // can we write in at least the half of fragments? l=1; // -> no? wait else l=0; // -> else go on } return l; } //////////////////////////////////////////////////////////////////////// // FEED SOUND DATA //////////////////////////////////////////////////////////////////////// static void oss_feed(void *buf, int bytes) { audio_buf_info info; char sbuf[4096]; if(oss_audio_fd == -1) return; if(ioctl(oss_audio_fd,SNDCTL_DSP_GETOSPACE,&info)==0) { // for fast forward if(bytes > info.fragments * FRAGMENT_SIZE) bytes = info.fragments * FRAGMENT_SIZE; if(bytes == 0) return; if(info.fragments==info.fragstotal) { memset(sbuf, 0, sizeof(sbuf)); write(oss_audio_fd, sbuf, sizeof(sbuf)); write(oss_audio_fd, sbuf, sizeof(sbuf)); write(oss_audio_fd, sbuf, sizeof(sbuf)); } } write(oss_audio_fd, buf, bytes); } void out_register_oss(struct out_driver *drv) { drv->name = "oss"; drv->init = oss_init; drv->finish = oss_finish; drv->busy = oss_busy; drv->feed = oss_feed; }