| /* devdsp.c: Device tests for /dev/dsp |
| |
| Written by Gerd Spalink (Gerd.Spalink@t-online.de) |
| |
| This file is part of Cygwin. |
| |
| This software is a copyrighted work licensed under the terms of the |
| Cygwin license. Please consult the file "CYGWIN_LICENSE" for |
| details. */ |
| |
| /* Conventions used here: |
| We use the libltp framework |
| 1. Any unexpected behaviour leads to an exit with nonzero exit status |
| 2. Unexpected behaviour from /dev/dsp results in an exit status of TFAIL |
| 3. Unexpected behaviour from OS (malloc, fork, waitpid...) result |
| in an exit status of TBROK */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <sys/ioctl.h> |
| #include <sys/wait.h> |
| #include <sys/types.h> |
| #include <sys/soundcard.h> |
| #include <math.h> |
| #include <errno.h> |
| #include "test.h" /* use libltp framework */ |
| |
| /* Controls if a child can open the device after the parent */ |
| #define CHILD_EXPECT 0 /* 0 or 1 */ |
| |
| static const char wavfile_okay[] = |
| { |
| #include "devdsp_okay.h" /* a sound sample */ |
| }; |
| |
| /* Globals required by libltp */ |
| const char *TCID = "devdsp"; /* set test case identifier */ |
| int TST_TOTAL = 37; |
| |
| /* Prototypes */ |
| void sinegen (void *wave, int rate, int bits, int len, int stride); |
| void sinegenw (int freq, int samprate, short *value, int len, int stride); |
| void sinegenb (int freq, int samprate, unsigned char *value, int len, |
| int stride); |
| void playtest (int fd, int rate, int stereo, int bits); |
| void rectest (int fd, int rate, int stereo, int bits); |
| void rwtest (int fd, int rate, int stereo, int bits); |
| void setpars (int fd, int rate, int stereo, int bits); |
| void forkplaytest (void); |
| void forkrectest (void); |
| void recordingtest (void); |
| void playbacktest (void); |
| void monitortest (void); |
| void ioctltest (void); |
| void abortplaytest (void); |
| void playwavtest (void); |
| void syncwithchild (pid_t pid, int expected_exit_status); |
| void cleanup (void); |
| void dup_test (void); |
| |
| static int expect_child_failure = 0; |
| |
| /* Sampling rates we want to test */ |
| static const int rates[] = { 44100, 22050, 8000 }; |
| |
| /* Combinations of stereo/bits we want to test */ |
| struct sb |
| { |
| int stereo; |
| int bits; |
| }; |
| static const struct sb sblut[] = { {0, 8}, {0, 16}, {1, 8}, {1, 16} }; |
| |
| int |
| main (int argc, char *argv[]) |
| { |
| /* tst_brkm(TBROK, cleanup, "see if it breaks all right"); */ |
| ioctltest (); |
| playbacktest (); |
| recordingtest (); |
| monitortest (); |
| forkplaytest (); |
| forkrectest (); |
| abortplaytest (); |
| playwavtest (); |
| dup_test (); |
| tst_exit (); |
| /* NOTREACHED */ |
| return 0; |
| } |
| |
| /* test some extra ioctls */ |
| void |
| ioctltest (void) |
| { |
| int audio1; |
| int ioctl_par; |
| int channels; |
| |
| tst_resm (TINFO, "Running %s", __FUNCTION__); |
| audio1 = open ("/dev/dsp", O_WRONLY); |
| if (audio1 < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "open W: %s", strerror (errno)); |
| } |
| setpars (audio1, 44100, 1, 16); |
| |
| channels = ioctl_par = 1; |
| while (ioctl (audio1, SNDCTL_DSP_CHANNELS, &ioctl_par) == 0) |
| { |
| channels++; |
| ioctl_par = channels; |
| } |
| if (channels == ioctl_par) |
| tst_resm (TFAIL, "Max channels=%d failed", ioctl_par); |
| else |
| tst_resm (TPASS, "Max channels=%d failed, OK=%d", channels, ioctl_par); |
| |
| /* Note: block size may depend on parameters */ |
| if (ioctl (audio1, SNDCTL_DSP_GETBLKSIZE, &ioctl_par) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl GETBLKSIZE: %s", strerror (errno)); |
| } |
| tst_resm (TPASS, "ioctl get buffer size=%d", ioctl_par); |
| if (ioctl (audio1, SNDCTL_DSP_GETFMTS, &ioctl_par) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl GETFMTS: %s", strerror (errno)); |
| } |
| tst_resm (TPASS, "ioctl get formats=%08x", ioctl_par); |
| if (ioctl (audio1, SNDCTL_DSP_GETCAPS, &ioctl_par) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl GETCAPS: %s", strerror (errno)); |
| } |
| tst_resm (TPASS, "ioctl get caps=%08x", ioctl_par); |
| if (close (audio1) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| } |
| |
| /* test write / play */ |
| void |
| playbacktest (void) |
| { |
| int audio1, audio2; |
| int rate, k; |
| |
| tst_resm (TINFO, "Running %s", __FUNCTION__); |
| audio1 = open ("/dev/dsp", O_WRONLY); |
| if (audio1 < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Error open /dev/dsp W: %s", |
| strerror (errno)); |
| } |
| audio2 = open ("/dev/dsp", O_WRONLY); |
| if (audio2 >= 0) |
| { |
| tst_brkm (TFAIL, cleanup, |
| "Second open /dev/dsp W succeeded, but is expected to fail"); |
| } |
| else if (errno != EBUSY) |
| { |
| tst_brkm (TFAIL, cleanup, "Expected EBUSY here, exit: %s", |
| strerror (errno)); |
| } |
| for (rate = 0; rate < sizeof (rates) / sizeof (int); rate++) |
| for (k = 0; k < sizeof (sblut) / sizeof (struct sb); k++) |
| { |
| playtest (audio1, rates[rate], sblut[k].stereo, sblut[k].bits); |
| tst_resm (TPASS, "Play bits=%2d stereo=%d rate=%5d", |
| sblut[k].bits, sblut[k].stereo, rates[rate]); |
| } |
| if (close (audio1) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| } |
| |
| /* test read / record */ |
| void |
| recordingtest (void) |
| { |
| int audio1, audio2; |
| int rate, k; |
| |
| /* test read / record */ |
| tst_resm (TINFO, "Running %s", __FUNCTION__); |
| audio1 = open ("/dev/dsp", O_RDONLY); |
| if (audio1 < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Error open /dev/dsp R: %s", |
| strerror (errno)); |
| } |
| audio2 = open ("/dev/dsp", O_RDONLY); |
| if (audio2 >= 0) |
| { |
| tst_brkm (TFAIL, cleanup, |
| "Second open /dev/dsp R succeeded, but is expected to fail"); |
| } |
| else if (errno != EBUSY) |
| { |
| tst_brkm (TFAIL, cleanup, "Expected EBUSY here, exit: %s", |
| strerror (errno)); |
| } |
| for (rate = 0; rate < sizeof (rates) / sizeof (int); rate++) |
| for (k = 0; k < sizeof (sblut) / sizeof (struct sb); k++) |
| { |
| rectest (audio1, rates[rate], sblut[k].stereo, sblut[k].bits); |
| tst_resm (TPASS, "Record bits=%2d stereo=%d rate=%5d", |
| sblut[k].bits, sblut[k].stereo, rates[rate]); |
| } |
| if (close (audio1) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| } |
| |
| /* simultaneous read/write */ |
| void |
| monitortest (void) |
| { |
| int fd; |
| |
| tst_resm (TINFO, "Running %s", __FUNCTION__); |
| fd = open ("/dev/dsp", O_RDWR); |
| if (fd < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "open RW: %s", strerror (errno)); |
| } |
| rwtest (fd, 44100, 1, 16); |
| tst_resm (TPASS, "Record+Play rate=44100, stereo, 16 bits"); |
| if (close (fd) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| } |
| |
| void |
| forkrectest (void) |
| { |
| int pid; |
| int fd; |
| |
| tst_resm (TINFO, "Running %s", __FUNCTION__); |
| fd = open ("/dev/dsp", O_RDONLY); |
| if (fd < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Error open /dev/dsp R: %s", |
| strerror (errno)); |
| } |
| pid = fork (); |
| if (pid < 0) |
| { |
| tst_brkm (TBROK, cleanup, "Fork failed: %s", strerror (errno)); |
| } |
| if (pid) |
| { |
| tst_resm (TINFO, "forked, child PID=%d", pid); |
| syncwithchild (pid, 0); |
| tst_resm (TINFO, "parent records.."); |
| rectest (fd, 22050, 1, 16); |
| tst_resm (TINFO, "parent done"); |
| } |
| else |
| { /* child */ |
| tst_resm (TINFO, "child records.."); |
| rectest (fd, 44100, 1, 16); |
| tst_resm (TINFO, "child done"); |
| fflush (stdout); |
| exit (0); /* implicit close */ |
| } |
| tst_resm (TPASS, "child records after fork"); |
| /* fork again, but now we have done a read before, |
| * so the child is expected to fail |
| */ |
| pid = fork (); |
| if (pid < 0) |
| { |
| tst_brkm (TBROK, cleanup, "Fork failed: %s", strerror (errno)); |
| } |
| if (pid) |
| { |
| tst_resm (TINFO, "forked, child PID=%d", pid); |
| syncwithchild (pid, CHILD_EXPECT?TFAIL:0); /* expecting error exit */ |
| tst_resm (TINFO, "parent records again .."); |
| rectest (fd, 22050, 1, 16); |
| tst_resm (TINFO, "parent done"); |
| } |
| else |
| { /* child */ |
| expect_child_failure = CHILD_EXPECT; |
| tst_resm (TINFO, "child trying to record %s", |
| CHILD_EXPECT?"(should fail)..":""); |
| rectest (fd, 44100, 1, 16); |
| /* NOTREACHED */ |
| tst_resm (TINFO, "child done"); |
| fflush (stdout); |
| exit (0); /* implicit close */ |
| } |
| if (close (fd) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| tst_resm (TPASS, "child tries to record while parent is already recording"); |
| } |
| |
| void |
| forkplaytest (void) |
| { |
| int pid; |
| int fd; |
| |
| tst_resm (TINFO, "Running %s", __FUNCTION__); |
| fd = open ("/dev/dsp", O_WRONLY); |
| if (fd < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Error open /dev/dsp R: %s", |
| strerror (errno)); |
| } |
| pid = fork (); |
| if (pid < 0) |
| { |
| tst_brkm (TBROK, cleanup, "Fork failed: %s", strerror (errno)); |
| } |
| if (pid) |
| { |
| tst_resm (TINFO, "forked, child PID=%d", pid); |
| syncwithchild (pid, 0); |
| tst_resm (TINFO, "parent plays.."); |
| playtest (fd, 22050, 0, 8); |
| tst_resm (TINFO, "parent done"); |
| } |
| else |
| { /* child */ |
| tst_resm (TINFO, "child plays.."); |
| playtest (fd, 44100, 1, 16); |
| tst_resm (TINFO, "child done"); |
| fflush (stdout); |
| exit (0); /* implicit close */ |
| } |
| tst_resm (TPASS, "child plays after fork"); |
| /* fork again, but now we have done a write before, |
| * so the child is expected to fail |
| */ |
| pid = fork (); |
| if (pid < 0) |
| { |
| tst_brkm (TBROK, cleanup, "Fork failed"); |
| } |
| if (pid) |
| { |
| tst_resm (TINFO, "forked, child PID=%d", pid); |
| syncwithchild (pid, CHILD_EXPECT?TFAIL:0); /* expected failure */ |
| tst_resm (TINFO, "parent plays again.."); |
| playtest (fd, 22050, 0, 8); |
| tst_resm (TINFO, "parent done"); |
| } |
| else |
| { /* child */ |
| expect_child_failure = CHILD_EXPECT; |
| tst_resm (TINFO, "child trying to play %s", |
| CHILD_EXPECT?"(should fail)..":""); |
| playtest (fd, 44100, 1, 16); |
| /* NOTREACHED */ |
| tst_resm (TINFO, "child done"); |
| fflush (stdout); |
| exit (0); /* implicit close */ |
| } |
| if (close (fd) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| tst_resm (TPASS, "child tries to play while parent is already playing"); |
| } |
| |
| void |
| playtest (int fd, int rate, int stereo, int bits) |
| { /* Play sine waves, always 0.25 sec */ |
| void *wave; |
| int n, c, b; |
| int size; |
| if (stereo) |
| c = 2; |
| else |
| c = 1; |
| if (bits == 8) |
| b = 1; |
| else |
| b = 2; |
| size = rate / 4 * c * b; |
| |
| wave = malloc (size); |
| if (wave == NULL) |
| { |
| tst_brkm (TBROK, cleanup, "Malloc failed, exit"); |
| } |
| setpars (fd, rate, stereo, bits); |
| sinegen (wave, rate, bits, rate / 4, c); |
| |
| if ((n = write (fd, wave, size)) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "write: %s", strerror (errno)); |
| } |
| if (n != size) |
| { |
| tst_brkm (TFAIL, cleanup, "Wrote %d, expected %d; exit", n, size); |
| } |
| free (wave); |
| } |
| |
| void |
| rectest (int fd, int rate, int stereo, int bits) |
| { |
| void *wave; |
| int n, c, b; |
| int size; |
| if (stereo) |
| c = 2; |
| else |
| c = 1; |
| if (bits == 8) |
| b = 1; |
| else |
| b = 2; |
| size = rate / 4 * c * b; |
| |
| wave = malloc (size); |
| if (wave == NULL) |
| { |
| tst_brkm (TBROK, cleanup, "Malloc failed, exit"); |
| } |
| setpars (fd, rate, stereo, bits); |
| if ((n = read (fd, wave, size)) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "read: %s", strerror (errno)); |
| } |
| if (n != size) |
| { |
| tst_brkm (TFAIL, cleanup, "Read n=%d (%d expected); exit", n, size); |
| } |
| if ((n = read (fd, wave, size)) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "read: %s", strerror (errno)); |
| } |
| if (n != size) |
| { |
| tst_brkm (TFAIL, cleanup, "Read n=%d (%d expected); exit", n, size); |
| } |
| free (wave); |
| } |
| |
| void |
| rwtest (int fd, int rate, int stereo, int bits) |
| { |
| int pid; |
| void *wave; |
| int n, c, b; |
| int size; |
| if (stereo) |
| c = 2; |
| else |
| c = 1; |
| if (bits == 8) |
| b = 1; |
| else |
| b = 2; |
| size = rate / 4 * c * b; |
| |
| wave = malloc (size); |
| if (wave == NULL) |
| { |
| tst_brkm (TBROK, cleanup, "Malloc failed, exit"); |
| } |
| setpars (fd, rate, stereo, bits); |
| pid = fork (); |
| if (pid < 0) |
| { |
| tst_brkm (TBROK, cleanup, "Fork failed: %s", strerror (errno)); |
| } |
| if (pid) |
| { |
| tst_resm (TINFO, "forked, child PID=%d parent records", pid); |
| if ((n = read (fd, wave, size)) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "read: %s", strerror (errno)); |
| } |
| if (n != size) |
| { |
| tst_brkm (TFAIL, cleanup, "Read n=%d (%d expected)", n, size); |
| } |
| free (wave); |
| syncwithchild (pid, 0); |
| } |
| else |
| { /* child */ |
| tst_resm (TINFO, "child plays"); |
| sinegen (wave, rate, bits, rate / 4, c); |
| if ((n = write (fd, wave, size)) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "child write: %s", strerror (errno)); |
| } |
| if (n != size) |
| { |
| tst_brkm (TFAIL, cleanup, "child write n=%d OK (%d expected)", n, |
| size); |
| } |
| free (wave); |
| exit (0); |
| } |
| } |
| |
| void |
| setpars (int fd, int rate, int stereo, int bits) |
| { |
| int ioctl_par = 0; |
| |
| if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &bits) < 0) |
| { |
| if (expect_child_failure) |
| { /* Note: Don't print this to stderr because we expect failures here |
| * for the some cases after fork() |
| */ |
| tst_resm (TINFO, "ioctl SNDCTL_DSP_SAMPLESIZE: %s", |
| strerror (errno)); |
| exit (TFAIL); |
| } |
| else |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl SNDCTL_DSP_SAMPLESIZE: %s", |
| strerror (errno)); |
| } |
| } |
| if (ioctl (fd, SNDCTL_DSP_STEREO, &stereo) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl SNDCTL_DSP_STEREO: %s", |
| strerror (errno)); |
| } |
| if (ioctl (fd, SNDCTL_DSP_SPEED, &rate) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl SNDCTL_DSP_SPEED: %s", |
| strerror (errno)); |
| } |
| if (ioctl (fd, SNDCTL_DSP_SYNC, &ioctl_par) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl SNDCTL_DSP_SYNC: %s", |
| strerror (errno)); |
| } |
| } |
| |
| void |
| syncwithchild (pid_t pid, int expected_exit_status) |
| { |
| int status; |
| |
| if (waitpid (pid, &status, 0) != pid) |
| { |
| tst_brkm (TBROK, cleanup, "Wait for child: %s", strerror (errno)); |
| } |
| if (!WIFEXITED (status)) |
| { |
| tst_brkm (TBROK, cleanup, "Child had abnormal exit"); |
| } |
| if (WEXITSTATUS (status) != expected_exit_status) |
| { |
| tst_brkm (TFAIL, cleanup, "Child had exit status %d != %d", |
| WEXITSTATUS (status), expected_exit_status); |
| } |
| } |
| |
| void |
| sinegen (void *wave, int rate, int bits, int len, int stride) |
| { |
| if (bits == 8) |
| { |
| sinegenb (1000, rate, (unsigned char *) wave, len, stride); |
| if (stride == 2) |
| sinegenb (800, rate, (unsigned char *) wave + 1, len, stride); |
| } |
| else |
| { |
| sinegenw (1000, rate, (short *) wave, len, stride); |
| if (stride == 2) |
| sinegenw (800, rate, (short *) wave + 1, len, stride); |
| } |
| } |
| |
| void |
| sinegenw (int freq, int samprate, short *value, int len, int stride) |
| { |
| double phase, incr; |
| |
| phase = 0.0; |
| incr = M_PI * 2.0 * (double) freq / (double) samprate; |
| while (len-- > 0) |
| { |
| *value = (short) floor (0.5 + 6553 * sin (phase)); |
| value += stride; |
| phase += incr; |
| } |
| } |
| |
| void |
| sinegenb (int freq, int samprate, unsigned char *value, int len, int stride) |
| { |
| double phase, incr; |
| |
| phase = 0.0; |
| incr = M_PI * 2.0 * (double) freq / (double) samprate; |
| while (len-- > 0) |
| { |
| *value = (unsigned char) floor (128.5 + 26 * sin (phase)); |
| value += stride; |
| phase += incr; |
| } |
| } |
| |
| void |
| abortplaytest (void) |
| { |
| int audio; |
| int size = sizeof (wavfile_okay); |
| int n; |
| int ioctl_par = 0; |
| |
| tst_resm (TINFO, "Running %s", __FUNCTION__); |
| audio = open ("/dev/dsp", O_WRONLY); |
| if (audio < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Error open /dev/dsp W: %s", |
| strerror (errno)); |
| } |
| if ((n = write (audio, wavfile_okay, size)) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "write: %s", strerror (errno)); |
| } |
| if (n != size) |
| { |
| tst_brkm (TFAIL, cleanup, "Wrote %d, expected %d; exit", n, size); |
| } |
| if (ioctl (audio, SNDCTL_DSP_RESET, &ioctl_par) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl DSP_RESET: %s", strerror (errno)); |
| } |
| if (close (audio) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| tst_resm (TPASS, "Playwav + ioctl DSP_RESET=%d", ioctl_par); |
| } |
| |
| void |
| playwavtest (void) |
| { |
| int audio; |
| int size = sizeof (wavfile_okay); |
| int n; |
| |
| tst_resm (TINFO, "Running %s", __FUNCTION__); |
| audio = open ("/dev/dsp", O_WRONLY); |
| if (audio < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Error open /dev/dsp W: %s", |
| strerror (errno)); |
| } |
| if ((n = write (audio, wavfile_okay, size)) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "write: %s", strerror (errno)); |
| } |
| if (n != size) |
| { |
| tst_brkm (TFAIL, cleanup, "Wrote %d, expected %d; exit", n, size); |
| } |
| if (close (audio) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| tst_resm (TPASS, "Set parameters from wave file header"); |
| } |
| |
| void dup_test (void) |
| { |
| int audio, fd, n; |
| int bits1, bits2; |
| int size = sizeof (wavfile_okay); |
| int header = 44; |
| const char *okay = wavfile_okay + header; |
| |
| tst_resm (TINFO, "Running %s", __FUNCTION__); |
| audio = open ("/dev/dsp", O_WRONLY); |
| if (audio < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Error open /dev/dsp W: %s", |
| strerror (errno)); |
| } |
| /* write header once to set parameters correctly */ |
| n = write (audio, wavfile_okay, header); |
| if (n != header) |
| { |
| tst_brkm (TFAIL, cleanup, "Wrote %d, expected %d; exit", n, header); |
| } |
| size = size - header; |
| /* dup / close */ |
| for (fd = audio+1; fd <= audio+5; fd++) |
| if (dup2 (fd-1, fd) != -1) |
| { |
| if (fd-2 >= audio) |
| if (close (fd-2) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| if ((n = write (fd, okay, size)) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "write: %s", strerror (errno)); |
| } |
| if (n != size) |
| { |
| tst_brkm (TFAIL, cleanup, "Wrote %d, expected %d; exit", n, size); |
| } |
| } |
| else |
| tst_brkm (TFAIL, cleanup, "dup: %s", strerror (errno)); |
| |
| for (fd = audio+4; fd <= audio+5; fd++) |
| if (close (fd) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| tst_resm (TPASS, "Write to duped fd"); |
| |
| audio = open ("/dev/dsp", O_WRONLY); |
| if (audio < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Error open /dev/dsp W: %s", |
| strerror (errno)); |
| } |
| fd = audio + 1; |
| if (dup2 (audio, fd) == -1) |
| { |
| tst_brkm (TFAIL, cleanup, "dup: %s", strerror (errno)); |
| } |
| bits1 = AFMT_U8; |
| if (ioctl (audio, SNDCTL_DSP_SAMPLESIZE, &bits1) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl: %s", strerror (errno)); |
| } |
| bits1 = AFMT_S16_LE; |
| if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &bits1) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl: %s", strerror (errno)); |
| } |
| bits1 = AFMT_QUERY; |
| if (ioctl (audio, SNDCTL_DSP_SAMPLESIZE, &bits1) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl: %s", strerror (errno)); |
| } |
| bits2 = AFMT_QUERY; |
| if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &bits2) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "ioctl: %s", strerror (errno)); |
| } |
| if (bits1 != AFMT_S16_LE || bits2 != AFMT_S16_LE) |
| { |
| tst_brkm (TFAIL, cleanup, "Inconsistent state of duped fd: %d %d %d", |
| AFMT_S16_LE,bits1,bits2); |
| } |
| if (close (audio) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| if (close (fd) < 0) |
| { |
| tst_brkm (TFAIL, cleanup, "Close audio: %s", strerror (errno)); |
| } |
| tst_resm (TPASS, "Parameter change to duped fd"); |
| } |
| void |
| cleanup (void) |
| { |
| } |