6.6 Audio DeviceAn 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.24The following command plays the audio file sample.au on the speaker of a Sun workstation.
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.cThe audio device object and its basic operations.
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.
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.
The audio_prinfo_t member of the preceding structure is defined as follows.
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.
Program 6.17 audiocopy.cA simple program that reads from the microphone and sends the results to the speaker.
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.cThe 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.
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. |