Patch for /dev/dsp to make ioctl SNDCTL_DSP_RESET respond immediately
Gerd Spalink
Gerd.Spalink@t-online.de
Sun Apr 11 21:00:00 GMT 2004
Hello,
This patch makes the device /dev/dsp respond more quickly to
the ioctl SNDCTL_DSP_RESET. Thanks to Eran Tromer for the hint.
There are more fixes in this patch to enhance compatibility with OSS.
I have also adapted the code for the testsuite again.
Please look at the ChangeLogs below.
Gerd
ChangeLog for winsup/cygwin:
2004-04-11 Gerd Spalink <Gerd.Spalink@t-online.de>
* fhandler_dsp.cc (fhandler_dev_dsp::Audio_out::stop): Add optional boolean
argument so that playing can be stopped without playing pending buffers.
(fhandler_dev_dsp::ioctl): Stop playback immediately for SNDCTL_DSP_RESET.
Do not reset audio parameters in this case.
Add support for ioctl SNDCTL_DSP_GETISPACE.
(fhandler_dev_dsp::Audio_out::emptyblocks): Now returns the number of
completely empty blocks.
(fhandler_dev_dsp::Audio_out::buf_info): p->fragments is now the number of
completely empty blocks. This conforms with the OSS specification.
(fhandler_dev_dsp::Audio_out::parsewav): Ignore wave headers that are not
aligned on four byte boundary.
(fhandler_dev_dsp::Audio_in::buf_info): New, needed for SNDCTL_DSP_GETISPACE.
ChangeLog for winsup/testsuite:
2004-04-11 Gerd Spalink <Gerd.Spalink@t-online.de>
* winsup.api/devdsp.c (forkrectest): Move synchronization with child
so that test passes also under high CPU load.
(forkplaytest): Ditto.
(abortplaytest): New function to test ioctl code SNDCTL_DSP_RESET.
Index: fhandler_dsp.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_dsp.cc,v
retrieving revision 1.34
diff -u -p -r1.34 fhandler_dsp.cc
--- fhandler_dsp.cc 10 Apr 2004 13:45:09 -0000 1.34
+++ fhandler_dsp.cc 11 Apr 2004 20:25:07 -0000
@@ -113,7 +113,7 @@ class fhandler_dev_dsp::Audio_out: publi
bool query (int rate, int bits, int channels);
bool start (int rate, int bits, int channels);
- void stop ();
+ void stop (bool immediately = false);
bool write (const char *pSampleData, int nBytes);
void buf_info (audio_buf_info *p, int rate, int bits, int channels);
void callback_sampledone (WAVEHDR *pHdr);
@@ -152,6 +152,7 @@ public:
bool start (int rate, int bits, int channels);
void stop ();
bool read (char *pSampleData, int &nBytes);
+ void buf_info (audio_buf_info *p, int rate, int bits, int channels);
void callback_blockfull (WAVEHDR *pHdr);
private:
@@ -418,7 +419,7 @@ fhandler_dev_dsp::Audio_out::start (int
}
void
-fhandler_dev_dsp::Audio_out::stop ()
+fhandler_dev_dsp::Audio_out::stop (bool immediately)
{
MMRESULT rc;
WAVEHDR *pHdr;
@@ -428,8 +429,11 @@ fhandler_dev_dsp::Audio_out::stop ()
GetCurrentProcessId (), getOwner ());
if (getOwner () && !denyAccess ())
{
- sendcurrent (); // force out last block whatever size..
- waitforallsent (); // block till finished..
+ if (!immediately)
+ {
+ sendcurrent (); // force out last block whatever size..
+ waitforallsent (); // block till finished..
+ }
rc = waveOutReset (dev_);
debug_printf ("waveOutReset rc=%d", rc);
@@ -507,7 +511,7 @@ fhandler_dev_dsp::Audio_out::write (cons
return true;
}
-// return number of (partially) empty blocks back.
+// return number of (completely) empty blocks back.
int
fhandler_dev_dsp::Audio_out::emptyblocks ()
{
@@ -516,8 +520,6 @@ fhandler_dev_dsp::Audio_out::emptyblocks
n = Qisr2app_->query ();
unlock ();
n += Qapp2app_->query ();
- if (pHdr_ != NULL)
- n++;
return n;
}
@@ -531,8 +533,8 @@ fhandler_dev_dsp::Audio_out::buf_info (a
{
p->fragments = emptyblocks ();
if (pHdr_ != NULL)
- p->bytes = p->fragsize - bufferIndex_ +
- p->fragsize * (p->fragments - 1);
+ p->bytes = (int)pHdr_->dwUser - bufferIndex_
+ + p->fragsize * p->fragments;
else
p->bytes = p->fragsize * p->fragments;
}
@@ -685,7 +687,9 @@ fhandler_dev_dsp::Audio_out::parsewav (c
const char *end = pData + nBytes;
const char *pDat;
int skip = 0;
-
+ // Check alignment first: A lot of the code below depends on it
+ if (((int)pData & 0x3) != 0)
+ return false;
if (!(pData[0] == 'R' && pData[1] == 'I'
&& pData[2] == 'F' && pData[3] == 'F'))
return false;
@@ -971,6 +975,31 @@ fhandler_dev_dsp::Audio_in::waitfordata
bufferIndex_ = 0;
}
+void
+fhandler_dev_dsp::Audio_in::buf_info (audio_buf_info *p,
+ int rate, int bits, int channels)
+{
+ p->fragstotal = MAX_BLOCKS;
+ p->fragsize = blockSize (rate, bits, channels);
+ if (getOwner ())
+ {
+ lock ();
+ p->fragments = Qisr2app_->query ();
+ unlock ();
+ p->fragments += Qapp2app_->query ();
+ if (pHdr_ != NULL)
+ p->bytes = pHdr_->dwBytesRecorded - bufferIndex_
+ + p->fragsize * p->fragments;
+ else
+ p->bytes = p->fragsize * p->fragments;
+ }
+ else
+ {
+ p->fragments = 0;
+ p->bytes = 0;
+ }
+}
+
// This is called on an interrupt so use locking..
void
fhandler_dev_dsp::Audio_in::callback_blockfull (WAVEHDR *pHdr)
@@ -1214,22 +1243,12 @@ fhandler_dev_dsp::ioctl (unsigned int cm
if (audio_out_)
{
RETURN_ERROR_WHEN_BUSY (audio_out_);
- audioformat_ = AFMT_U8;
- audiofreq_ = 8000;
- audiobits_ = 8;
- audiochannels_ = 1;
- audio_out_->stop ();
- audio_out_->setformat (audioformat_);
+ audio_out_->stop (true);
}
if (audio_in_)
{
RETURN_ERROR_WHEN_BUSY (audio_in_);
- audioformat_ = AFMT_U8;
- audiofreq_ = 8000;
- audiobits_ = 8;
- audiochannels_ = 1;
audio_in_->stop ();
- audio_in_->setformat (audioformat_);
}
return 0;
break;
@@ -1409,6 +1428,20 @@ fhandler_dev_dsp::ioctl (unsigned int cm
{
RETURN_ERROR_WHEN_BUSY (audio_out_);
audio_out_->buf_info (p, audiofreq_, audiobits_, audiochannels_);
+ debug_printf ("ptr=%p frags=%d fragsize=%d bytes=%d",
+ ptr, p->fragments, p->fragsize, p->bytes);
+ }
+ return 0;
+ }
+ break;
+
+ CASE (SNDCTL_DSP_GETISPACE)
+ {
+ audio_buf_info *p = (audio_buf_info *) ptr;
+ if (audio_in_)
+ {
+ RETURN_ERROR_WHEN_BUSY (audio_in_);
+ audio_in_->buf_info (p, audiofreq_, audiobits_, audiochannels_);
debug_printf ("ptr=%p frags=%d fragsize=%d bytes=%d",
ptr, p->fragments, p->fragsize, p->bytes);
}
Index: devdsp.c
===================================================================
RCS file: /cvs/src/src/winsup/testsuite/winsup.api/devdsp.c,v
retrieving revision 1.2
diff -u -p -r1.2 devdsp.c
--- devdsp.c 5 Apr 2004 08:30:13 -0000 1.2
+++ devdsp.c 11 Apr 2004 20:08:44 -0000
@@ -36,7 +36,7 @@ static const char wavfile_okay[] =
/* Globals required by libltp */
const char *TCID = "devdsp"; /* set test case identifier */
-int TST_TOTAL = 34;
+int TST_TOTAL = 35;
/* Prototypes */
void sinegen (void *wave, int rate, int bits, int len, int stride);
@@ -53,6 +53,7 @@ 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);
@@ -80,6 +81,7 @@ main (int argc, char *argv[])
monitortest ();
forkplaytest ();
forkrectest ();
+ abortplaytest ();
playwavtest ();
tst_exit ();
/* NOTREACHED */
@@ -247,11 +249,10 @@ forkrectest (void)
if (pid)
{
tst_resm (TINFO, "forked, child PID=%d", pid);
- sleep (1);
+ syncwithchild (pid, 0);
tst_resm (TINFO, "parent records..");
rectest (fd, 22050, 1, 16);
tst_resm (TINFO, "parent done");
- syncwithchild (pid, 0);
}
else
{ /* child */
@@ -273,10 +274,10 @@ forkrectest (void)
if (pid)
{
tst_resm (TINFO, "forked, child PID=%d", pid);
+ syncwithchild (pid, TFAIL); /* expecting error exit */
tst_resm (TINFO, "parent records again ..");
rectest (fd, 22050, 1, 16);
tst_resm (TINFO, "parent done");
- syncwithchild (pid, TFAIL); /* expecting error exit */
}
else
{ /* child */
@@ -315,11 +316,10 @@ forkplaytest (void)
if (pid)
{
tst_resm (TINFO, "forked, child PID=%d", pid);
- sleep (1);
+ syncwithchild (pid, 0);
tst_resm (TINFO, "parent plays..");
playtest (fd, 22050, 0, 8);
tst_resm (TINFO, "parent done");
- syncwithchild (pid, 0);
}
else
{ /* child */
@@ -341,10 +341,10 @@ forkplaytest (void)
if (pid)
{
tst_resm (TINFO, "forked, child PID=%d", pid);
+ syncwithchild (pid, TFAIL); /* expected failure */
tst_resm (TINFO, "parent plays again..");
playtest (fd, 22050, 0, 8);
tst_resm (TINFO, "parent done");
- syncwithchild (pid, TFAIL); /* expected failure */
}
else
{ /* child */
@@ -601,6 +601,39 @@ sinegenb (int freq, int samprate, unsign
value += stride;
phase += incr;
}
+}
+
+void
+abortplaytest (void)
+{
+ int audio;
+ int size = sizeof (wavfile_okay);
+ int n;
+ int ioctl_par = 0;
+
+ 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
More information about the Cygwin-patches
mailing list