/* A bit more complicated example how to use OSS to play mixed 16-bit stereo 44100 kHz data. This time we install a signal handler and a pipe for inter-process communication. Threads might be better, but this approach works with all Unixes. Also included is the use of gettimeofday() to get the most precise timing for your demo/game. Press 'q' and enter to exit the program. - Marq/Fit 2000 You may use the source as you wish. */ #include #include #include #include #include #include #include #include /* Needed only for gettimeofday() */ #define BUFFER 1024 /* Bytes to mix at a time */ int comm_pipe[2]; /* The pipe used for inter-process communication */ void signal_handler(int param); /* Our signal handler */ int main() { int handle, tmp, child; char sampledata[BUFFER]; struct sigaction old_handler, /* Structs for signal handler */ new_handler; /* Open the device for writing */ handle=open("/dev/dsp",O_WRONLY); if(handle==-1) return(EXIT_FAILURE); /* Set sound parameters. If you set them in a different order I can't promise it will work. ioctl() calls return -1 if the operation failed completely. If the parameter you passed to an ioctl() is modified, the device can't do something you asked. Didn't bother to check them... */ /* Set fragment length (don't do if you don't care about latency). Small values give a small latency but will sound bad if the app won't get enough CPU time. (2<<16) - We want two fragments 13 - The size of fragment is 2^13 = 8192 bytes (very small) */ tmp=(2<<16)+13; ioctl(handle,SNDCTL_DSP_SETFRAGMENT,&tmp); /* Set output format. Some usual values are: AFMT_S16_LE - 16-bit signed AFMT_U8 - 8-bit unsigned */ tmp=AFMT_S16_LE; ioctl(handle,SNDCTL_DSP_SETFMT,&tmp); /* Set number of channels. 0=mono, 1=stereo */ tmp=1; ioctl(handle,SNDCTL_DSP_STEREO,&tmp); /* Set playing frequency. 44100, 22050 and 11025 are safe bets. */ tmp=44100; ioctl(handle,SNDCTL_DSP_SPEED,&tmp); /* OK. Now the device should be initialised. Let's create a pipe for communication. */ pipe(comm_pipe); /* Install a new handler for SIGCHLD signal. */ new_handler.sa_handler=signal_handler; new_handler.sa_flags=0; sigaction(SIGCHLD,&new_handler,&old_handler); /* Now fork a child process that runs in the background and handles the audio writing. */ if(!(child=fork())) /* Child process runs in this if-clause */ { /* Child closes the output pipe. We don't need it. */ close(comm_pipe[1]); while(1) { /* Notify main process that we need sample data */ kill(getppid(),SIGCHLD); /* Read audio data through pipe from the main process */ read(comm_pipe[0],sampledata,BUFFER); /* Play the read audio data. Blocks until all bytes are in the OSS's buffer. */ write(handle,(void *)sampledata,BUFFER); } } /* Main program closes the input pipe. We don't need it. */ close(comm_pipe[0]); /* The main program continues here. Insert your megademo here ;v) */ while(getchar()!='q') ; /* Kill the child process and close device */ kill(child,SIGKILL); close(handle); /* Restore the old signal handler. Not really necessary since our program would exit anyway. */ sigaction(SIGCHLD,&old_handler,&new_handler); return(EXIT_SUCCESS); } /* Our signal handler. Gets called when the child process sends a signal with kill() ie. new sample data must be mixed. */ void signal_handler(int param) { char mixbuffer[BUFFER]; int n; struct timeval system_time; /* Needed only for gettimeofday() */ struct timezone system_timezone; /* Put just some crap to the mixing buffer. We might as well mix some .mod or .mp3 here. By mixing small fragments you'll get better latency. */ for(n=0;n