/*
    Just a simple example how to use OSS to play 16-bit stereo 44100 kHz
    samples. Use as you wish.

    - Marq/Fit 2000
 */

#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/soundcard.h>

int main(int argc,char *argv[])
{
    int handle,
        tmp,
        child;

    long    length;

    unsigned char   *sampledata;

    FILE    *fp;

    /* Read the sample given in command line. I won't explain it any
       further... */
    fp=fopen(argv[1],"rb");
    if(fp==NULL)
        return(EXIT_FAILURE);

    fseek(fp,0,SEEK_END);
    length=ftell(fp);
    fseek(fp,0,SEEK_SET);

    sampledata=malloc(length);
    if(sampledata==NULL)
        return(EXIT_FAILURE);

    fread(sampledata,1,length,fp);
    fclose(fp);

    /* 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
    */
    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 fork a child
       process that runs in the background and handles the audio writing. */

    if(!(child=fork())) /* Child process runs in this if-clause */
    {
        while(1)
        {
            /* Keep writing bytes to the device. Note that write handles
               bytes, not samples. */
            write(handle,(void *)sampledata,length);
        }
    }

    /* The main program continues here. Insert your megademo here ;v) */
    getchar();

    /* Kill the child process and close device */
    kill(child,SIGKILL);
    close(handle);

    return(EXIT_SUCCESS);
}

/* EOS */
