6.6 Audio Device

Team-FLY

An audio device (microphone, speaker) is an example of a peripheral device represented by a special file. The device designation for this device on many systems is /dev/audio . The discussion in this section illustrates the nature of special files, but it is specific to Sun systems. The audio device may behave differently on different systems. Note: If you logged in from an ASCII terminal or X-terminal, you cannot use the audio device even if the system has one.

Example 6.24

The following command plays the audio file sample.au on the speaker of a Sun workstation.

 cat sample.au > /dev/audio 

The audio device may support several audio formats, and you may have to set the audio device for the proper format before Example 6.24 works correctly. Audio files typically contain a header giving information about the format of the audio file. Sending the file directly to the audio device, as in this example, may cause the header to be interpreted as audio data. You will probably hear a series of clicks at the beginning of the playback. Many systems have a utility for playing audio. The utility reads the header and uses this information to program the audio device for the correct format. This command utility may be called audioplay or just play .

In this section, we assume that we are using audio files in a fixed format and that the audio device has already been set for that format.

Program 6.16 contains a library of functions for reading and writing from the audio device. None of these library functions pass the file descriptor corresponding to the audio device. Rather, the audio library is treated as an object that calling programs access through the provided interface ( open_audio , close_audio , read_audio and write_audio ).

The open_audio opens /dev/audio for read or write access, using blocking I/O. If the audio device has already been opened, open hangs until the device is closed. If the audio device had been opened with the O_NONBLOCK flag, open would have returned with an error if the device were busy.

The open_audio function attempts to open both the microphone and the speaker. A process that will only record can call open with O_RDONLY; a process that will only play can call open with O_WRONLY . If it is interrupted by a signal, open_audio restarts open .

The speaker can handle data only at a predetermined rate, so write_audio may not send the entire buffer to the speaker in one write function. Similarly, read_audio reads only the data currently available from the microphone and returns the number of bytes actually read. The get_record_buffer_size function uses ioctl to retrieve the size of the blocks that the audio device driver reads from the audio device.

Program 6.16 audiolib.c

The audio device object and its basic operations .

 #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stropts.h> #include <unistd.h> #include <sys/audio.h> #include "restart.h"; #define AUDIO "/dev/audio" static int audio_fd = -1;   /* audio device file descriptor */ int open_audio(void) {    while (((audio_fd = open(AUDIO, O_RDWR)) == -1) && (errno == EINTR)) ;    if (audio_fd == -1)       return -1;    return 0; } void close_audio(void) {    r_close(audio_fd);    audio_fd = -1; } int read_audio(char *buffer, int maxcnt) {    return r_read(audio_fd, buffer, maxcnt); } int write_audio(char *buffer, int maxcnt) {    return r_write(audio_fd, buffer, maxcnt); } int get_record_buffer_size(void) {    audio_info_t myaudio;    if (audio_fd == -1)       return -1;    if (ioctl(audio_fd, AUDIO_GETINFO, &myaudio) == -1)       return -1;    else       return myaudio.record.buffer_size; } 

The ioctl function provides a means of obtaining device status information or setting device control options. The ioctl function has variable syntax. Its first two parameters are an open file descriptor and an integer specifying the type of request. Different requests may require different additional parameters.

  SYNOPSIS  #include <stropts.h>   int ioctl(int fildes, int request, .... /* arg */);  POSIX  

If successful, ioctl returns a value other than “1 that depends on the request value. If unsuccessful , ioctl returns “1 and sets errno . The mandatory errors depend on the value of request . See the man page for ioctl for further information.

The ioctl function provides a means of obtaining device status information or setting device control options. The Sun Solaris operating environment uses the AUDIO_GETINFO request of ioctl to retrieve information about the audio device. The audio_info_t type defined in audioio.h holds configuration information about the audio device.

 typedef struct audio_info {    audio_prinfo_t   play;          /* output status information */    audio_prinfo_t   record;        /* input status information */    uint_t           monitor_gain;  /* input to output mix */    uchar_t          output_muted;  /* nonzero if output muted */    uchar_t _xxx[3];                /* Reserved for future use */    uint_t _yyy[3];                 /* Reserved for future use */ } audio_info_t; 

The audio_prinfo_t member of the preceding structure is defined as follows .

 struct audio_prinfo {    /* The following values describe the audio data encoding */    uint_t   sample_rate;  /* samples per second */    uint_t   channels;     /* number of interleaved channels */    uint_t   precision;    /* number of bits per sample */    uint_t   encoding;     /* data encoding method */    /* The following values control audio device configuration */    uint_t   gain;         /* volume level */    uint_t   port;         /* selected I/O port */    uint_t   avail_ports;  /* available I/O ports */    uint_t   _xxx[2];      /* reserved for future use */    uint_t   buffer_size;  /* I/O buffer size */    /* The following values describe the current device state */    uint_t   samples;      /* number of samples converted */    uint_t   eof;          /* end-of-file counter (play only) */    uchar_t  pause;        /* nonzero if paused, zero to resume */    uchar_t  error;        /* nonzero if overflow/underflow */    uchar_t  waiting;      /* nonzero if a process wants access */    uchar_t  balance;      /* stereo channel balance */    ushort_t minordev;    /* The following values are read-only device state flags */    uchar_t  open;         /* nonzero if open access granted */    uchar_t  active;       /* nonzero if I/O active */ } audio_prinfo_t; 

The buffer_size member of the audio_prinfo_t structure specifies how large a chunk of audio data the device driver accumulates before passing the data to a read request. The buffer_size for play specifies how large a chunk the device driver accumulates before sending the data to the speaker. Audio tends to sound better if the program sends and receives chunks that match the corresponding buffer_size settings. Use ioctl to determine these sizes in an audio application program. The get_record_buffer_size function in Program 6.16 returns the appropriate block size to use when reading from the microphone, or “1 if an error occurs.

Program 6.17 reads from the microphone and writes to the speaker. Terminate the program by entering Ctrl-C from the keyboard. It is best to use headphones when trying this program to avoid feedback caused by a microphone and speaker in close proximity. The audiolib.h header file contains the following audio function prototypes .

 int open_audio(void); void close_audio(void); int read_audio(char *buffer, int maxcnt); int write_audio(char *buffer, int length); 
Program 6.17 audiocopy.c

A simple program that reads from the microphone and sends the results to the speaker .

 #include <stdio.h> #include <stdlib.h> #include "audiolib.h" #define BUFSIZE 1024 int main (void) {    char buffer[BUFSIZE];    int bytesread;    if (open_audio() == -1) {       perror("Failed to open audio");       return 1;    }    for( ; ; ) {       if ((bytesread = read_audio(buffer, BUFSIZE)) == -1) {           perror("Failed to read microphone");           break;       } else if (write_audio(buffer, bytesread) == -1) {           perror("Failed to write to speaker");           break;       }    }    close_audio();    return 1; } 

The implementation of Program 6.16 opens the audio device for blocking I/O. Nonblocking reads are complicated by the fact that read can return “1 either if there is an error or if the audio device is not ready with the data. The latter case has an errno value of EAGAIN and should not be treated as an error. The primary reason for opening the audio device in nonblocking mode is so that open does not hang when the device is already open. An alternative is to open the audio device in nonblocking mode and then to use fcntl to change the mode to blocking.

Example 6.25 nonblockingaudio.c

The following program opens the audio device for nonblocking I/O. It then reads BLKSIZE bytes from the audio device into a buffer. It does nothing with the audio that is read in other than display the number of bytes read.

 #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "restart.h" #define AUDIO_DEVICE "/dev/audio" #define BLKSIZE 1024 int main(void) {    int audiofd;    char *bp;    char buffer[BLKSIZE];    unsigned bytesneeded;    int bytesread;    if ((audiofd = open(AUDIO_DEVICE, O_NONBLOCK  O_RDWR)) == -1) {       perror("Failed to open audio device");       return 1;     }    bp = buffer;    bytesneeded = BLKSIZE;    while(bytesneeded != 0) {       bytesread = r_read(audiofd, bp, bytesneeded);       if ((bytesread == -1) && (errno != EAGAIN))          break;       if (bytesread > 0) {          bp += bytesread;          bytesneeded -= bytesread;       }    }    fprintf(stderr, "%d bytes read\n", BLKSIZE - bytesneeded);    return 0; } 

In testing audio programs, keep in mind that the audio device is closed when the program exits. If the audio buffer still holds data that has not yet reached the speakers , that data may be lost. The draining of a device after a close is system dependent, so read the man page before deciding how to handle the situation.

Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net