C Recording from FreeBSD sound subsystem

I am trying to implement a basic example to record a few seconds of audio in FreeBSD, which uses a modified OSS version.
Following the sample files included in the FreeBSD source code and the OSS programming guide I have prepared the following sample program:

Code:
#include <sys/soundcard.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>

#define MAX_FILENAME_LENGTH 1024
#define MAX_SECONDS_TO_RECORD 3600                      // UP TO 1 HOUR RECORDING
#define MAX_BUFFER_LENGTH 8000*MAX_SECONDS_TO_RECORD

int main(int argc, char *argv[]) {

        unsigned char buffer[MAX_BUFFER_LENGTH];        // BUFFER TO STORE AUDIO
        char dspfile[MAX_FILENAME_LENGTH];              // /dev/dsp FILENAME
        int fd;                                         // /dev/dsp FILE DESCRIPTOR
        unsigned int seconds_to_record;                 // NUMBER OF SECONDS TO RECORD
        unsigned long samples_to_record;                // NUMBER OF SAMPLES TO RECORD
        unsigned long samples_recorded;                 // NUMBER OF SAMPLES RECORDED
        int format;                                     // FORMAT
        int channels;                                   // CHANNELS (1=MONO 2=STEREO)
        int sampling_rate;                              // SAMPLING RATE
        int error;                                      // AUX VARIABLE ERROR

        // STEP 1: READ /dev/dsp PARAMETER
        if(argc!=3) {
                fprintf(stderr, "ERROR: Incorrect number of arguments.\n");
                fprintf(stderr, "USAGE: %s /dev/dsp seconds\n", argv[0]);
                exit(1);
        } else if( strlen(argv[1]) >= MAX_FILENAME_LENGTH ) {
                fprintf(stderr, "ERROR: /dev/dsp filename parameter too long. Maximum size is %d.\n", MAX_FILENAME_LENGTH);
                exit(1);
        } else {
                strncpy(dspfile, argv[1], MAX_FILENAME_LENGTH);
                sscanf(argv[2], "%u", &seconds_to_record);
        }
        if( seconds_to_record >= MAX_SECONDS_TO_RECORD) {
                fprintf(stderr, "ERROR: Too many seconds requested. Maximum recording time is %u.\n", MAX_SECONDS_TO_RECORD);
                exit(1);
        }

        // STEP 2: OPEN FILE
        fd = open(dspfile, O_RDWR);
        if(fd==-1) {
                fprintf(stderr, "ERROR: Can not open /dev/dsp file %s. Error code %d %s\n", dspfile, errno, strerror(errno));
                exit(1);
        }

        // STEP 3: CONFIGURE MONO, 8 BITS UNSIGNED SAMPLES, 8KHz SAMPLING RATE
        channels = 1;
        error = ioctl(fd, SNDCTL_DSP_CHANNELS, &channels);
        if(error==-1) {
                fprintf(stderr, "ERROR: Can not configure 1 channel. Error code %d %s\n", errno, strerror(errno));
                exit(-1);
        }
        format = AFMT_U8;
        error = ioctl(fd, SNDCTL_DSP_SETFMT, &format);
        if(error==-1) {
                fprintf(stderr, "ERROR: Can not configure audio format. Error code %d %s\n", errno, strerror(errno));
                exit(-1);
        }
        sampling_rate = 8000;
        error = ioctl(fd, SNDCTL_DSP_SPEED, &sampling_rate);
        if(error==-1) {
                fprintf(stderr, "ERROR: Can not configure sampling rate. Error code %d %s\n", errno, strerror(errno));
                exit(-1);
        }

        // STEP 4: RECORD N SAMPLES CORRESPONDING TO THE REQUESTED NUMBER OF SECONDS TO RECORD
        samples_to_record = seconds_to_record * 8000;
        samples_recorded = 0;
        while(samples_to_record > 0) {
                ssize_t samples_read = read(fd, buffer + samples_recorded, samples_to_record);
                samples_to_record -= (unsigned long)samples_read;
                samples_recorded += (unsigned long)samples_read;
                write(STDOUT_FILENO, buffer + samples_recorded, samples_read);
        }

        // STEP 5: CLOSE FILE
        if(close(fd)==-1) {
                fprintf(stderr, "ERROR: Can not close /dev/dsp file %s. Error code %d %s\n", dspfile, errno, strerror(errno));
                exit(1);
        }

        // DISENGAGE
        return(0);

}

But I get a 24000 bytes empty file when I try to record 3 seconds, so it seems like the samples come with all 0 values.

Doing the following works:

Code:
cat /dev/dsp > test.raw
cat test.raw > /dev/dsp

Doing cat /dev/dsp also works -characteres are seen on the terminal window-.
So it seems that I am missing something wrong or I am missing one step.
 
Which command line do you use to invoke your program ?
I have tried both:

./myprogram /dev/dsp 3

and

./myprogram /dev/dsp0.0 3

(where dsp0.0 corresponds to the actual device selected via sysctl hw.snd.default_unit=x and 3 specifies to record 3 seconds).
 
Back
Top