2
* Purpose: A sample program for using mmap()
3
* Copyright (C) 4Front Technologies, 2002-2004. Released under GPLv2/CDDL.
6
* This is a simple program which demonstrates use of mmapped DMA buffer
7
* of the sound driver directly from application program.
9
* This program tries to open a file called "smpl" in the current directory and
10
* play it. If present this file must be a "raw" audio file recorded with
11
* the same sample rate and format as this program uses. There is no checking
12
* for the format in this program.
14
* {!notice This program needs some fine tuning. At this moment it doesn't
15
* perform adequate error checkings.}
26
#include <sys/types.h>
28
#include <soundcard.h>
30
#include <sys/ioctl.h>
36
static int sinebuf[48] = {
37
0, 4276, 8480, 12539, 16383, 19947, 23169, 25995,
38
28377, 30272, 31650, 32486, 32767, 32486, 31650, 30272,
39
28377, 25995, 23169, 19947, 16383, 12539, 8480, 4276,
40
0, -4276, -8480, -12539, -16383, -19947, -23169, -25995,
41
-28377, -30272, -31650, -32486, -32767, -32486, -31650, -30272,
42
-28377, -25995, -23169, -19947, -16383, -12539, -8480, -4276
47
produce_output (short *op, int offs, int len)
53
for (i = 0; i < len; i++)
55
int v = sinebuf[sinep];
56
sinep = (sinep + 1) % 48;
58
*op++ = v; /* Left channel */
59
*op++ = v; /* Right channel */
64
main (int argc, char *argv[])
67
int sz, fsz, num_samples;
69
struct audio_buf_info info;
77
* This program must use O_RDWR in some operating systems like Linux.
78
* However in some other operating systems it may need to be O_WRONLY.
80
* {!code /dev/dsp_mmap} is the default device for mmap applications.
83
if ((fd = open ("/dev/dsp_mmap", O_RDWR, 0)) == -1)
85
perror ("/dev/dsp_mmap");
90
if (ioctl (fd, SNDCTL_ENGINEINFO, &ai) != -1)
92
printf ("Using audio device %s (engine %d)\n", ai.name, ai.dev);
95
* Disable cooked mode to permit mmap() with some devices.
96
* Don't do any error checking since usually this call will fail.
97
* There is no need to care about the return value.
99
* Cooked mode must be disabled before setting the sample rate and format.
102
ioctl (fd, SNDCTL_DSP_COOKEDMODE, &tmp); /* Don't check the error return */
105
* Set up the sample format. We will use AFMT_S16_LE because it's the most
106
* common audio file format. AFMT_S16_NE is better in programs that
107
* generate the audio signal themselves.
111
if (ioctl (fd, SNDCTL_DSP_SETFMT, &tmp) == -1)
113
perror ("SNDCTL_DSP_SETFMT");
118
* Check the format returned by the driver.
120
* This program will simply refuse to work if it doesn't get the format it
121
* supports. Playing with incompatible formats will cause terrible noise so
122
* it must be avoided.
124
if (tmp != AFMT_S16_LE)
127
"Error: The device doesn't support the requested sample format\n");
132
* Set the number of channels and the sample rate. We do not care about the
133
* returned values. They will just be reported to the user.
135
* {!notice Real applications must be prepared to support sampling rates
136
* between 8 kHz and 192 kHz (at least). Equally well the number of channels
137
* may be between 1 and 16 (or even more).}
139
* Two channels and 48 kHz is the most likely combination that works.
141
tmp = 2; /* Stereo */
142
if (ioctl (fd, SNDCTL_DSP_CHANNELS, &tmp) == -1)
144
perror ("SNDCTL_DSP_CHANNELS");
148
printf ("Number of channels is %d\n", tmp);
150
tmp = 44100; /* 48000 is the most recommended rate */
151
if (ioctl (fd, SNDCTL_DSP_SPEED, &tmp) == -1)
153
perror ("SNDCTL_DSP_SPEED");
157
printf ("Sample rate set to %d\n", tmp);
159
if (ioctl (fd, SNDCTL_DSP_GETCAPS, &caps) == -1)
162
fprintf (stderr, "Sorry but your sound driver is too old\n");
166
if (!(caps & PCM_CAP_TRIGGER))
168
fprintf (stderr, "Sorry but your soundcard can't do this (TRIGGER)\n");
172
if (!(caps & PCM_CAP_MMAP))
174
fprintf (stderr, "Sorry but your soundcard can't do this (MMAP)\n");
179
* Compute total size of the buffer. It's important to use this value
183
if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
185
perror ("GETOSPACE");
189
sz = info.fragstotal * info.fragsize;
195
* IMPORTANT NOTE!!!!!!!!!!!
197
* Full duplex audio devices have separate input and output buffers.
198
* It is not possible to map both of them at the same mmap() call. The buffer
199
* is selected based on the prot argument in the following way:
201
* - PROT_READ (alone) selects the input buffer.
202
* - PROT_WRITE (alone) selects the output buffer.
203
* - PROT_WRITE|PROT_READ together select the output buffer. This combination
204
* is required in BSD to make the buffer accessible. With just PROT_WRITE
205
* every attempt to access the returned buffer will result in segmentation/bus
206
* error. PROT_READ|PROT_WRITE is also permitted in Linux with OSS version
207
* 3.8-beta16 and later (earlier versions don't accept it).
209
* Non duplex devices have just one buffer. When an application wants to do both
210
* input and output it's recommended that the device is closed and re-opened when
211
* switching between modes. PROT_READ|PROT_WRITE can be used to open the buffer
212
* for both input and output (with OSS 3.8-beta16 and later) but the result may be
217
mmap (NULL, sz, PROT_WRITE, MAP_FILE | MAP_SHARED, fd,
218
0)) == (caddr_t) - 1)
220
perror ("mmap (write)");
223
printf ("mmap (out) returned %08lx\n", (long) buf);
227
* op contains now a pointer to the DMA buffer. Preload some audio data.
230
num_samples = sz / 4;
231
produce_output ((short *) op, 0, num_samples);
235
* Then it's time to start the engine. The driver doesn't allow read() and/or
236
* write() when the buffer is mapped. So the only way to start operation is
237
* to togle device's enable bits. First set them off. Setting them on enables
238
* recording and/or playback.
242
ioctl (fd, SNDCTL_DSP_SETTRIGGER, &tmp);
243
printf ("Trigger set to %08x\n", tmp);
246
* It might be usefull to write some data to the buffer before starting.
249
tmp = PCM_ENABLE_OUTPUT;
250
ioctl (fd, SNDCTL_DSP_SETTRIGGER, &tmp);
251
printf ("Trigger set to %08x\n", tmp);
254
* The machine is up and running now. Use SNDCTL_DSP_GETOPTR to get the
257
* NOTE! The driver empties each buffer fragmen after they have been
258
* played. This prevents looping sound if there are some performance problems
259
* in the application side. For similar reasons it recommended that the
260
* application uses some amout of play ahead. It can rewrite the unplayed
261
* data later if necessary.
268
if (ioctl (fd, SNDCTL_DSP_GETOPTR, &ci) == -1)
270
perror ("SNDCTL_DSP_GETOPTR");
274
device_p = ci.ptr / 4;
276
if (device_p < app_p)
278
produce_output ((short *) op, app_p, num_samples - app_p);
282
if (device_p > app_p)
284
produce_output ((short *) op, app_p, device_p - app_p);