[Patch]: fhandler_dsp.cc

Christopher Faylor cgf-no-personal-reply-please@cygwin.com
Sat Aug 21 13:54:00 GMT 2004


On Mon, Aug 16, 2004 at 11:04:00PM -0400, Pierre A. Humblet wrote:
>Following Gerd's comments, here is an updated patch that also improves 
>the internal error handling. It follows Gerd's approach.
>
>He has not answered my previous e-mail but he has indicated he would
>be in vacation for two weeks, so this is not unexpected.
> 
>I have also verified that the code passes Gerd's new nasty dup test.
>I think we are good to go for now.

If Gerd is on vacation and he has previously commented on your patch
favorably, I think it makes sense to check this in and tweak things
later, if there are problems.  I'd like to get a 1.5.11 released and if
this helps things then we probably want it.

cgf

>2004-08-17  Pierre Humblet <pierre.humblet@ieee.org>
>
>	* fhandler.h (fhandler_dev_dsp:~fhandler_dev_dsp): Delete.
>	(fhandler_dev_dsp::open_count): Delete.		   
>	(fhandler_dev_dsp::close_audio_in): New method declaration.
>	(fhandler_dev_dsp::close_audio_in): Ditto.
>	* fhandler_dsp.cc: Add and edit debug_printf throughout.
>	(fhandler_dev_dsp::Audio::denyAccess): Delete.
>	(fhandler_dev_dsp::Audio::fork_fixup): Ditto.
>	(fhandler_dev_dsp::Audio::getOwner): Ditto.
>	(fhandler_dev_dsp::Audio::clearOwner): Ditto.
>	(fhandler_dev_dsp::Audio::owner_): Ditto.
>	(fhandler_dev_dsp::Audio::setformat): Ditto, rename to setconvert.
>	(fhandler_dev_dsp::Audio::lock): Ditto, move to queue.
>	(fhandler_dev_dsp::Audio::unlock): Ditto.
>	(fhandler_dev_dsp::Audio::lock_): Ditto.
>	(fhandler_dev_dsp::Audio::bufferIndex_): New member, from Audio_out
>	and Audio_in.
>	(fhandler_dev_dsp::Audio::pHdr_): Ditto.
>	(fhandler_dev_dsp::Audio::wavehdr_): Ditto.
>	(fhandler_dev_dsp::Audio::bigwavebuffer_): ditto.
>	(fhandler_dev_dsp::Audio::Qisr2app_): Ditto.
>	(fhandler_dev_dsp::Audio::setconvert): New method, from old setformat.
>	(fhandler_dev_dsp::Audio::queue::lock): New method.
>	(fhandler_dev_dsp::Audio::queue::unlock): Ditto.
>	(fhandler_dev_dsp::Audio::queue::dellock): Ditto.
>	(fhandler_dev_dsp::Audio::queue::isvalid): Ditto.
>	(fhandler_dev_dsp::Audio::queue::lock_): New member.
>	(fhandler_dev_dsp::Audio::queue::depth1_): Delete.
>	(fhandler_dev_dsp::Audio_out::fork_fixup): New method.
>	(fhandler_dev_dsp::Audio_out::isvalid): New method.
>	(fhandler_dev_dsp::Audio_out::start): Remove arguments.
>	(fhandler_dev_dsp::Audio_out::parsewav): Change arguments and set 
>	internal state.
>	(fhandler_dev_dsp::Audio_out::emptyblocks): Delete.
>	(fhandler_dev_dsp::Audio_out::Qapp2app_): Ditto.
>	(fhandler_dev_dsp::Audio_out::Qisr2app_): Ditto, move to Audio.
>	(fhandler_dev_dsp::Audio_out::bufferIndex_): Ditto.
>	(fhandler_dev_dsp::Audio_out::pHdr_): Ditto.
>	(fhandler_dev_dsp::Audio_out::wavehdr_): Ditto.
>	(fhandler_dev_dsp::Audio_out::bigwavefuffer_): Ditto.
>	(fhandler_dev_dsp::Audio_out::freq_): New member.
>	(fhandler_dev_dsp::Audio_out::bits_): New member.
>	(fhandler_dev_dsp::Audio_out::channels_): New member.
>	(fhandler_dev_dsp::Audio_in::fork_fixup): New method.
>	(fhandler_dev_dsp::Audio_in::isvalid): New method.
>	(fhandler_dev_dsp::Audio_in::Qapp2app_): Delete.
>	(fhandler_dev_dsp::Audio_in::Qisr2app_): Ditto, move to Audio.
>	(fhandler_dev_dsp::Audio_in::bufferIndex_): Ditto.
>	(fhandler_dev_dsp::Audio_in::pHdr_): Ditto.
>	(fhandler_dev_dsp::Audio_in::wavehdr_): Ditto.
>	(fhandler_dev_dsp::Audio_in::bigwavefuffer_): Ditto.
>	(fhandler_dev_dsp::Audio::queue::queue): Simplify.
>	(fhandler_dev_dsp::Audio::queue::send): Use lock.
>	(fhandler_dev_dsp::Audio::queue::query): Do not use depth1_.
>	(fhandler_dev_dsp::Audio::queue::recv): Ditto.
>	(fhandler_dev_dsp::Audio::Audio): Adapt to new class members.
>	(fhandler_dev_dsp::Audio::~Audio): Ditto
>	(fhandler_dev_dsp::Audio_out::start): Reorganize.
>	(fhandler_dev_dsp::Audio_out::stop): Simplify.
>	(fhandler_dev_dsp::Audio_out::init): Reset the queue and clear flag.
>	(fhandler_dev_dsp::Audio_out::write): Reorganize to allocate audio_out.
>	(fhandler_dev_dsp::Audio_out::buf_info): Use appropriate block size.
>	(fhandler_dev_dsp::Audio_out::callback_sampledone): Do not use lock.
>	(fhandler_dev_dsp::Audio_out::waitforspace): Simplify.
>	(fhandler_dev_dsp::Audio_out::waitforallsent):Ditto.
>	(fhandler_dev_dsp::Audio_out::sendcurrent): Reorganize.
>	Clear flag before requeuing.
>	(fhandler_dev_dsp::Audio_out::parsewav): 
>	(fhandler_dev_dsp::Audio_in::start): Reorganize.
>	(fhandler_dev_dsp::Audio_in::stop): Simplify.
>	(fhandler_dev_dsp::Audio_in::queueblock): Ditto.
>	Requeue header in case of error.
>	(fhandler_dev_dsp::Audio_in::init): Reset the queue and clear flag.
>	(fhandler_dev_dsp::Audio_in::waitfordata): Simplify.
>	Do not UnprepareHeader if the flag is zero.
>	(fhandler_dev_dsp::Audio_in::buf_info): Ditto.
>	(fhandler_dev_dsp::Audio_in::callback_blockfull): Do not use lock.
>	(fhandler_dev_dsp::open_count): Delete.
>	(fhandler_dev_dsp::open): Only check existence, do not allocate
>	anything. Set flags appropriately. Create archetype.
>	(fhandler_dev_dsp::write): Call archetype as needed. Create audio_out.
>	(fhandler_dev_dsp::read): Call archetype as needed. Create audio_in.
>	(fhandler_dev_dsp::close): Call archetype as needed. 
>	Call close_audio_in and close_audio_out.
>	(fhandler_dev_dsp::close_audio_in): New function.
>	(fhandler_dev_dsp::close_audio_out): New function.
>	(fhandler_dev_dsp::dup): Use archetypes.
>	(fhandler_dev_dsp::ioctl): Call archetype as needed. Reorganize for
>	new structures.
>	(fhandler_dev_dsp::fixup_after_fork): Call archetype as needed.
>	(fhandler_dev_dsp::fixup_after_exec): Call archetype as needed.
>	Clear audio_in and audio_out.

>Index: fhandler.h
>===================================================================
>RCS file: /cvs/src/src/winsup/cygwin/fhandler.h,v
>retrieving revision 1.210
>diff -u -p -r1.210 fhandler.h
>--- fhandler.h	15 Jul 2004 14:56:05 -0000	1.210
>+++ fhandler.h	14 Aug 2004 03:30:18 -0000
>@@ -1069,12 +1069,10 @@ class fhandler_dev_dsp: public fhandler_
>   int audiofreq_;
>   int audiobits_;
>   int audiochannels_;
>-  static int open_count; // per process
>   Audio_out *audio_out_;
>   Audio_in  *audio_in_;
>  public:
>   fhandler_dev_dsp ();
>-  ~fhandler_dev_dsp();
>
>   int open (int flags, mode_t mode = 0);
>   int write (const void *ptr, size_t len);
>@@ -1086,6 +1084,9 @@ class fhandler_dev_dsp: public fhandler_
>   void dump (void);
>   void fixup_after_fork (HANDLE parent);
>   void fixup_after_exec ();
>+ private:
>+  void close_audio_in ();
>+  void close_audio_out (bool immediately = false);
> };
>
> class fhandler_virtual : public fhandler_base
>Index: fhandler_dsp.cc
>===================================================================
>RCS file: /cvs/src/src/winsup/cygwin/fhandler_dsp.cc,v
>retrieving revision 1.38
>diff -u -p -r1.38 fhandler_dsp.cc
>--- fhandler_dsp.cc	19 Jul 2004 13:13:48 -0000	1.38
>+++ fhandler_dsp.cc	16 Aug 2004 23:47:11 -0000
>@@ -1,4 +1,4 @@
>-/* fhandler_dev_dsp: code to emulate OSS sound model /dev/dsp
>+/* Fhandler_dev_dsp: code to emulate OSS sound model /dev/dsp
>
>    Copyright 2001, 2002, 2003, 2004 Red Hat, Inc
>
>@@ -21,12 +21,14 @@ details. */
> #include "security.h"
> #include "path.h"
> #include "fhandler.h"
>+#include "dtable.h"
>+#include "cygheap.h"
>
> /*------------------------------------------------------------------------
>   Simple encapsulation of the win32 audio device.
>
>   Implementation Notes
>-  1. Audio buffers are created dynamically just before the first read or
>+  1. Audio structures are malloced just before the first read or
>      write to /dev/dsp. The actual buffer size is determined at that time,
>      such that one buffer holds about 125ms of audio data.
>      At the time of this writing, 12 buffers are allocated,
>@@ -35,38 +37,28 @@ details. */
>      but for this implementation only returns meaningful results if
>      sampling rate, number of channels and number of bits per sample
>      are not changed afterwards.
>+     The audio structures are freed when the device is reset or closed,
>+     and they are not passed to exec'ed processes.
>+     The dev_ member is cleared after a fork. This forces the child
>+     to reopen the audio device._
>
>-  2. Every open call creates a new instance of the handler. To cope
>-     with the fact that only a single wave device exists, the static
>-     variable open_count tracks opens for one process. After a
>+  2. Every open call creates a new instance of the handler. After a
>      successful open, every subsequent open from the same process
>      to the device fails with EBUSY.
>-     If different processes open the audio device simultaneously,
>-     the results are unpredictable - usually the first one wins.
>-
>-  3. The wave device is reserved within a process from the time that
>-     the first read or write call has been successful until /dev/dsp
>-     has been closed by that process. During this reservation period
>-     child processes that use the same file descriptor cannot
>-     do read, write or ioctls that change the device properties.
>-     This means that a parent can open the device, do some ioctl,
>-     spawn children, and any one of them can do the data read/write
>+     The structures are shared between duped handles, but not with
>+     children. They only inherit the settings from the parent.
>  */
>
> class fhandler_dev_dsp::Audio
> { // This class contains functionality common to Audio_in and Audio_out
>  public:
>    Audio ();
>-  ~Audio ();
>+   ~Audio ();
>
>   class queue;
>
>-  bool denyAccess ();
>-  void fork_fixup (HANDLE parent);
>-  inline DWORD getOwner () { return owner_; }
>-  void setOwner () { owner_ = GetCurrentProcessId (); }
>-  inline void clearOwner () { owner_ = 0L; }
>-  void setformat (int format);
>+  bool isvalid ();
>+  void setconvert (int format);
>   void convert_none (unsigned char *buffer, int size_bytes) { }
>   void convert_U8_S8 (unsigned char *buffer, int size_bytes);
>   void convert_S16LE_U16LE (unsigned char *buffer, int size_bytes);
>@@ -75,14 +67,16 @@ class fhandler_dev_dsp::Audio
>   void fillFormat (WAVEFORMATEX * format,
> 		   int rate, int bits, int channels);
>   unsigned blockSize (int rate, int bits, int channels);
>-
>   void (fhandler_dev_dsp::Audio::*convert_)
>     (unsigned char *buffer, int size_bytes);
>-  inline void lock () { EnterCriticalSection (&lock_); }
>-  inline void unlock () { LeaveCriticalSection (&lock_); }
>- private:
>-  DWORD owner_; /* Process ID when wave operation started, else 0 */
>-  CRITICAL_SECTION lock_;
>+
>+  enum { MAX_BLOCKS = 12 };
>+  int bufferIndex_;  // offset into pHdr_->lpData
>+  WAVEHDR *pHdr_;    // data to be filled by write
>+  WAVEHDR wavehdr_[MAX_BLOCKS];
>+  char *bigwavebuffer_; // audio samples only
>+  // Member variables below must be locked
>+  queue *Qisr2app_; // blocks passed from wave callback
> };
>
> class fhandler_dev_dsp::Audio::queue
>@@ -93,12 +87,17 @@ class fhandler_dev_dsp::Audio::queue
>
>   bool send (WAVEHDR *);  // queue an item, returns true if successful
>   bool recv (WAVEHDR **); // retrieve an item, returns true if successful
>-  int query ();		  // return number of items queued
>-
>+  void reset ();
>+  int query (); // return number of items queued
>+  inline void lock () { EnterCriticalSection (&lock_); }
>+  inline void unlock () { LeaveCriticalSection (&lock_); }
>+  inline void dellock () { debug_printf ("Deleting Critical Section"); DeleteCriticalSection (&lock_); }
>+  bool isvalid () { return storage_; }
>  private:
>+  CRITICAL_SECTION lock_;
>   int head_;
>   int tail_;
>-  int depth_, depth1_;
>+  int depth_;
>   WAVEHDR **storage_;
> };
>
>@@ -108,35 +107,29 @@ static void CALLBACK waveOut_callback (H
> class fhandler_dev_dsp::Audio_out: public Audio
> {
>  public:
>-   Audio_out ();
>-  ~Audio_out ();
>-
>+  void fork_fixup (HANDLE parent);
>   bool query (int rate, int bits, int channels);
>-  bool start (int rate, int bits, int channels);
>+  bool start ();
>   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);
>   bool parsewav (const char *&pData, int &nBytes,
>-		 int &rate, int &bits, int &channels);
>+		 int rate, int bits, int channels);
>
>  private:
>   void init (unsigned blockSize);
>   void waitforallsent ();
>   void waitforspace ();
>   bool sendcurrent ();
>-  int emptyblocks ();
>
>   enum { MAX_BLOCKS = 12 };
>-  queue *Qapp2app_;  // empty and unprepared blocks
>   HWAVEOUT dev_;     // The wave device
>-  int bufferIndex_;  // offset into pHdr_->lpData
>-  WAVEHDR *pHdr_;    // data to be filled by write
>-  WAVEHDR wavehdr_[MAX_BLOCKS];
>-  char *bigwavebuffer_; // audio samples only
>-
>-  // Member variables below must be locked
>-  queue *Qisr2app_; // empty blocks passed from wave callback
>+  /* Private copies of audiofreq_, audiobits_, audiochannels_,
>+     possibly set from wave file */
>+  int freq_;
>+  int bits_;
>+  int channels_;
> };
>
> static void CALLBACK waveIn_callback (HWAVEIN hWave, UINT msg, DWORD instance,
>@@ -145,9 +138,7 @@ static void CALLBACK waveIn_callback (HW
> class fhandler_dev_dsp::Audio_in: public Audio
> {
> public:
>-   Audio_in ();
>-  ~Audio_in ();
>-
>+  void fork_fixup (HANDLE parent);
>   bool query (int rate, int bits, int channels);
>   bool start (int rate, int bits, int channels);
>   void stop ();
>@@ -160,16 +151,7 @@ private:
>   bool queueblock (WAVEHDR *pHdr);
>   void waitfordata (); // blocks until we have a good pHdr_
>
>-  enum { MAX_BLOCKS = 12 }; // read ahead of 1.5 seconds
>-  queue *Qapp2app_;    // filled and unprepared blocks
>   HWAVEIN dev_;
>-  int bufferIndex_;    // offset into pHdr_->lpData
>-  WAVEHDR *pHdr_;      // successfully recorded data
>-  WAVEHDR wavehdr_[MAX_BLOCKS];
>-  char *bigwavebuffer_; // audio samples
>-
>-  // Member variables below must be locked
>-  queue *Qisr2app_; // filled blocks passed from wave callback
> };
>
> /* --------------------------------------------------------------------
>@@ -178,13 +160,10 @@ private:
> // Simple fixed length FIFO queue implementation for audio buffer management
> fhandler_dev_dsp::Audio::queue::queue (int depth)
> {
>-  head_ = 0;
>-  tail_ = 0;
>-  depth_ = depth;
>-  depth1_ = depth + 1;
>   // allow space for one extra object in the queue
>   // so we can distinguish full and empty status
>-  storage_ = new WAVEHDR *[depth1_];
>+  depth_ = depth;
>+  storage_ = new WAVEHDR *[depth_ + 1];
> }
>
> fhandler_dev_dsp::Audio::queue::~queue ()
>@@ -192,28 +171,48 @@ fhandler_dev_dsp::Audio::queue::~queue (
>   delete[] storage_;
> }
>
>+void
>+fhandler_dev_dsp::Audio::queue::reset ()
>+ {
>+   /* When starting, after reset and after fork */
>+   head_ = tail_ = 0;
>+   debug_printf ("InitializeCriticalSection");
>+   memset (&lock_, 0, sizeof (lock_));
>+   InitializeCriticalSection (&lock_);
>+ }
>+
> bool
> fhandler_dev_dsp::Audio::queue::send (WAVEHDR *x)
> {
>+  bool res = false;
>+  lock ();
>   if (query () == depth_)
>-    return false;
>-  storage_[tail_] = x;
>-  tail_++;
>-  if (tail_ == depth1_)
>-    tail_ = 0;
>-  return true;
>+    system_printf ("Queue overflow");
>+  else
>+    {
>+      storage_[tail_] = x;
>+      if (++tail_ > depth_)
>+	tail_ = 0;
>+      res = true;
>+    }
>+  unlock ();
>+  return res;
> }
>
> bool
> fhandler_dev_dsp::Audio::queue::recv (WAVEHDR **x)
> {
>-  if (query () == 0)
>-    return false;
>-  *x = storage_[head_];
>-  head_++;
>-  if (head_ == depth1_)
>-    head_ = 0;
>-  return true;
>+  bool res = false;
>+  lock ();
>+  if (query () != 0)
>+    {
>+      *x = storage_[head_];
>+      if (++head_ > depth_)
>+	head_ = 0;
>+      res = true;
>+    }
>+  unlock ();
>+  return res;
> }
>
> int
>@@ -221,40 +220,33 @@ fhandler_dev_dsp::Audio::queue::query ()
> {
>   int n = tail_ - head_;
>   if (n < 0)
>-    n += depth1_;
>+    n += depth_ + 1;
>   return n;
> }
>
> // Audio class implements functionality need for both read and write
> fhandler_dev_dsp::Audio::Audio ()
> {
>-  InitializeCriticalSection (&lock_);
>+  bigwavebuffer_ = NULL;
>+  Qisr2app_ = new queue (MAX_BLOCKS);
>   convert_ = &fhandler_dev_dsp::Audio::convert_none;
>-  owner_ = 0L;
> }
>
> fhandler_dev_dsp::Audio::~Audio ()
> {
>-  DeleteCriticalSection (&lock_);
>+  debug_printf("");
>+  delete Qisr2app_;
>+  delete[] bigwavebuffer_;
> }
>
>-void
>-fhandler_dev_dsp::Audio::fork_fixup (HANDLE parent)
>-{
>-  debug_printf ("parent=0x%08x", parent);
>-  InitializeCriticalSection (&lock_);
>-}
>-
>-bool
>-fhandler_dev_dsp::Audio::denyAccess ()
>-{
>-  if (owner_ == 0L)
>-    return false;
>-  return (GetCurrentProcessId () != owner_);
>+inline bool
>+fhandler_dev_dsp::Audio::isvalid ()
>+{
>+  return bigwavebuffer_ && Qisr2app_ && Qisr2app_->isvalid ();
> }
>
> void
>-fhandler_dev_dsp::Audio::setformat (int format)
>+fhandler_dev_dsp::Audio::setconvert (int format)
> {
>   switch (format)
>     {
>@@ -361,19 +353,16 @@ fhandler_dev_dsp::Audio::blockSize (int
> }
>
> //=======================================================================
>-fhandler_dev_dsp::Audio_out::Audio_out (): Audio ()
>+void
>+fhandler_dev_dsp::Audio_out::fork_fixup (HANDLE parent)
> {
>-  bigwavebuffer_ = NULL;
>-  Qisr2app_ = new queue (MAX_BLOCKS);
>-  Qapp2app_ = new queue (MAX_BLOCKS);
>+  /* Null dev_.
>+     It will be necessary to reset the queue, open the device
>+     and create a lock when writing */
>+  debug_printf ("parent=0x%08x", parent);
>+  dev_ = NULL;
> }
>
>-fhandler_dev_dsp::Audio_out::~Audio_out ()
>-{
>-  stop ();
>-  delete Qapp2app_;
>-  delete Qisr2app_;
>-}
>
> bool
> fhandler_dev_dsp::Audio_out::query (int rate, int bits, int channels)
>@@ -383,37 +372,34 @@ fhandler_dev_dsp::Audio_out::query (int
>
>   fillFormat (&format, rate, bits, channels);
>   rc = waveOutOpen (NULL, WAVE_MAPPER, &format, 0L, 0L, WAVE_FORMAT_QUERY);
>-  debug_printf ("freq=%d bits=%d channels=%d %s", rate, bits, channels,
>-		(rc != MMSYSERR_NOERROR) ? "FAIL" : "OK");
>+  debug_printf ("%d = waveOutOpen (freq=%d bits=%d channels=%d)", rc, rate, bits, channels);
>   return (rc == MMSYSERR_NOERROR);
> }
>
> bool
>-fhandler_dev_dsp::Audio_out::start (int rate, int bits, int channels)
>+fhandler_dev_dsp::Audio_out::start ()
> {
>   WAVEFORMATEX format;
>   MMRESULT rc;
>-  unsigned bSize = blockSize (rate, bits, channels);
>-  bigwavebuffer_ = new char[MAX_BLOCKS * bSize];
>-  if (bigwavebuffer_ == NULL)
>-    return false;
>+  unsigned bSize = blockSize (freq_, bits_, channels_);
>+
>+  if (dev_)
>+    return true;
>+
>+  /* In case of fork bigwavebuffer may already exist */
>+  if (!bigwavebuffer_)
>+    bigwavebuffer_ = new char[MAX_BLOCKS * bSize];
>
>-  int nDevices = waveOutGetNumDevs ();
>-  debug_printf ("number devices=%d, blocksize=%d", nDevices, bSize);
>-  if (nDevices <= 0)
>+  if (!isvalid ())
>     return false;
>
>-  fillFormat (&format, rate, bits, channels);
>+  fillFormat (&format, freq_, bits_, channels_);
>   rc = waveOutOpen (&dev_, WAVE_MAPPER, &format, (DWORD) waveOut_callback,
> 		     (DWORD) this, CALLBACK_FUNCTION);
>   if (rc == MMSYSERR_NOERROR)
>-    {
>-      setOwner ();
>-      init (bSize);
>-    }
>+    init (bSize);
>
>-  debug_printf ("freq=%d bits=%d channels=%d %s", rate, bits, channels,
>-		(rc != MMSYSERR_NOERROR) ? "FAIL" : "OK");
>+  debug_printf ("%d = waveOutOpen (freq=%d bits=%d channels=%d)", rc, freq_, bits_, channels_);
>
>   return (rc == MMSYSERR_NOERROR);
> }
>@@ -423,11 +409,9 @@ fhandler_dev_dsp::Audio_out::stop (bool
> {
>   MMRESULT rc;
>   WAVEHDR *pHdr;
>-  bool gotblock;
>
>-  debug_printf ("dev_=%08x pid=%d owner=%d", (int)dev_,
>-		GetCurrentProcessId (), getOwner ());
>-  if (getOwner () && !denyAccess ())
>+  debug_printf ("dev_=%08x", (int)dev_);
>+  if (dev_)
>     {
>       if (!immediately)
> 	{
>@@ -436,33 +420,17 @@ fhandler_dev_dsp::Audio_out::stop (bool
> 	}
>
>       rc = waveOutReset (dev_);
>-      debug_printf ("waveOutReset rc=%d", rc);
>-      do
>+      debug_printf ("%d = waveOutReset ()", rc);
>+      while (Qisr2app_->recv (&pHdr))
> 	{
>-	  lock ();
>-	  gotblock = Qisr2app_->recv (&pHdr);
>-	  unlock ();
>-	  if (gotblock)
>-	    {
>-	      rc = waveOutUnprepareHeader (dev_, pHdr, sizeof (WAVEHDR));
>-	      debug_printf ("waveOutUnprepareHeader Block 0x%08x %s", pHdr,
>-			    (rc != MMSYSERR_NOERROR) ? "FAIL" : "OK");
>-	    }
>+	  rc = waveOutUnprepareHeader (dev_, pHdr, sizeof (WAVEHDR));
>+	  debug_printf ("%d = waveOutUnprepareHeader (0x%08x)", rc, pHdr);
> 	}
>-      while (gotblock);
>-      while (Qapp2app_->recv (&pHdr))
>-	/* flush queue */;
>
>       rc = waveOutClose (dev_);
>-      debug_printf ("waveOutClose rc=%d", rc);
>+      debug_printf ("%d = waveOutClose ()", rc);
>
>-      clearOwner ();
>-    }
>-
>-  if (bigwavebuffer_)
>-    {
>-      delete[] bigwavebuffer_;
>-      bigwavebuffer_ = NULL;
>+      Qisr2app_->dellock ();
>     }
> }
>
>@@ -472,13 +440,15 @@ fhandler_dev_dsp::Audio_out::init (unsig
>   int i;
>
>   // internally queue all of our buffer for later use by write
>+  Qisr2app_->reset ();
>   for (i = 0; i < MAX_BLOCKS; i++)
>     {
>       wavehdr_[i].lpData = &bigwavebuffer_[i * blockSize];
>       wavehdr_[i].dwUser = (int) blockSize;
>-      if (!Qapp2app_->send (&wavehdr_[i]))
>+      wavehdr_[i].dwFlags = 0;
>+      if (!Qisr2app_->send (&wavehdr_[i]))
> 	{
>-	  debug_printf ("Internal Error i=%d", i);
>+	  system_printf ("Internal Error i=%d", i);
> 	  break; // should not happen
> 	}
>     }
>@@ -511,27 +481,17 @@ fhandler_dev_dsp::Audio_out::write (cons
>   return true;
> }
>
>-// return number of (completely) empty blocks back.
>-int
>-fhandler_dev_dsp::Audio_out::emptyblocks ()
>-{
>-  int n;
>-  lock ();
>-  n = Qisr2app_->query ();
>-  unlock ();
>-  n += Qapp2app_->query ();
>-  return n;
>-}
>-
> void
> fhandler_dev_dsp::Audio_out::buf_info (audio_buf_info *p,
> 				       int rate, int bits, int channels)
> {
>   p->fragstotal = MAX_BLOCKS;
>-  p->fragsize = blockSize (rate, bits, channels);
>-  if (getOwner ())
>+  if (this && dev_)
>     {
>-      p->fragments = emptyblocks ();
>+      /* If the device is running we use the internal values,
>+	 possibly set from the wave file. */
>+      p->fragsize = blockSize (freq_, bits_, channels_);
>+      p->fragments = Qisr2app_->query ();
>       if (pHdr_ != NULL)
> 	p->bytes = (int)pHdr_->dwUser - bufferIndex_
> 	  + p->fragsize * p->fragments;
>@@ -540,6 +500,7 @@ fhandler_dev_dsp::Audio_out::buf_info (a
>     }
>   else
>     {
>+      p->fragsize = blockSize (rate, bits, channels);
>       p->fragments = MAX_BLOCKS;
>       p->bytes = p->fragsize * p->fragments;
>     }
>@@ -547,51 +508,31 @@ fhandler_dev_dsp::Audio_out::buf_info (a
>
> /* This is called on an interupt so use locking.. Note Qisr2app_
>    is used so we should wrap all references to it in locks. */
>-void
>+inline void
> fhandler_dev_dsp::Audio_out::callback_sampledone (WAVEHDR *pHdr)
> {
>-  lock ();
>   Qisr2app_->send (pHdr);
>-  unlock ();
> }
>
> void
> fhandler_dev_dsp::Audio_out::waitforspace ()
> {
>   WAVEHDR *pHdr;
>-  bool gotblock;
>   MMRESULT rc = WAVERR_STILLPLAYING;
>
>   if (pHdr_ != NULL)
>     return;
>-  while (Qapp2app_->recv (&pHdr) == false)
>+  while (!Qisr2app_->recv (&pHdr))
>     {
>-      lock ();
>-      gotblock = Qisr2app_->recv (&pHdr);
>-      unlock ();
>-      if (gotblock)
>-	{
>-	  if ((pHdr->dwFlags & WHDR_DONE)
>-	      && ((rc = waveOutUnprepareHeader (dev_, pHdr, sizeof (WAVEHDR)))
>-	       == MMSYSERR_NOERROR))
>-	    {
>-	      Qapp2app_->send (pHdr);
>-	    }
>-	  else
>-	    {
>-	      debug_printf ("error UnprepareHeader 0x%08x, rc=%d, 100ms",
>-			    pHdr, rc);
>-	      lock ();
>-	      Qisr2app_->send (pHdr);
>-	      unlock ();
>-	      Sleep (100);
>-	    }
>-	}
>-      else
>-	{
>-	  debug_printf ("100ms");
>-	  Sleep (100);
>-	}
>+      debug_printf ("100ms");
>+      Sleep (100);
>+    }
>+  if (pHdr->dwFlags)
>+    {
>+      /* Errors are ignored here. They will probbaly cause a failure
>+	 in the subsequent PrepareHeader */
>+      rc = waveOutUnprepareHeader (dev_, pHdr, sizeof (WAVEHDR));
>+      debug_printf ("%d = waveOutUnprepareHeader (0x%08x)", rc, pHdr);
>     }
>   pHdr_ = pHdr;
>   bufferIndex_ = 0;
>@@ -600,10 +541,9 @@ fhandler_dev_dsp::Audio_out::waitforspac
> void
> fhandler_dev_dsp::Audio_out::waitforallsent ()
> {
>-  while (emptyblocks () != MAX_BLOCKS)
>+  while (Qisr2app_->query () != MAX_BLOCKS)
>     {
>-      debug_printf ("100ms Qisr=%d Qapp=%d",
>-		    Qisr2app_->query (), Qapp2app_->query ());
>+      debug_printf ("%d blocks in Qisr2app", Qisr2app_->query ());
>       Sleep (100);
>     }
> }
>@@ -613,6 +553,9 @@ bool
> fhandler_dev_dsp::Audio_out::sendcurrent ()
> {
>   WAVEHDR *pHdr = pHdr_;
>+  MMRESULT rc;
>+  debug_printf ("pHdr=0x%08x bytes=%d", pHdr, bufferIndex_);
>+
>   if (pHdr_ == NULL)
>     return false;
>   pHdr_ = NULL;
>@@ -622,27 +565,19 @@ fhandler_dev_dsp::Audio_out::sendcurrent
>
>   // Send internal buffer out to the soundcard
>   pHdr->dwBufferLength = bufferIndex_;
>-  pHdr->dwFlags = 0;
>-  if (waveOutPrepareHeader (dev_, pHdr, sizeof (WAVEHDR)) == MMSYSERR_NOERROR)
>-    {
>-      if (waveOutWrite (dev_, pHdr, sizeof (WAVEHDR)) == MMSYSERR_NOERROR)
>-	{
>-	  debug_printf ("waveOutWrite bytes=%d", bufferIndex_);
>-	  return true;
>-	}
>-      else
>-	{
>-	  debug_printf ("waveOutWrite failed");
>-	  lock ();
>-	  Qisr2app_->send (pHdr);
>-	  unlock ();
>-	}
>-    }
>-  else
>+  rc = waveOutPrepareHeader (dev_, pHdr, sizeof (WAVEHDR));
>+  debug_printf ("%d = waveOutPrepareHeader (0x%08x)", rc, pHdr);
>+  if (rc == MMSYSERR_NOERROR)
>     {
>-      debug_printf ("waveOutPrepareHeader failed");
>-      Qapp2app_->send (pHdr);
>+      rc = waveOutWrite (dev_, pHdr, sizeof (WAVEHDR));
>+      debug_printf ("%d = waveOutWrite (0x%08x)", rc, pHdr);
>     }
>+  if (rc == MMSYSERR_NOERROR)
>+    return true;
>+
>+  /* FIXME: Should we return an error instead ?*/
>+  pHdr->dwFlags = 0; /* avoid calling UnprepareHeader again */
>+  Qisr2app_->send (pHdr);
>   return false;
> }
>
>@@ -681,12 +616,19 @@ struct wavformat
>
> bool
> fhandler_dev_dsp::Audio_out::parsewav (const char * &pData, int &nBytes,
>-				       int &rate, int &bits, int &channels)
>+				       int dev_freq, int dev_bits, int dev_channels)
> {
>   int len;
>   const char *end = pData + nBytes;
>   const char *pDat;
>   int skip = 0;
>+
>+  /* Start with default values from the device handler */
>+  freq_ = dev_freq;
>+  bits_ = dev_bits;
>+  channels_ = dev_channels;
>+  setconvert (bits_ == 8 ? AFMT_U8 : AFMT_S16_LE);
>+
>   // Check alignment first: A lot of the code below depends on it
>   if (((int)pData & 0x3) != 0)
>     return false;
>@@ -719,9 +661,9 @@ fhandler_dev_dsp::Audio_out::parsewav (c
> 	      if (query (format->dwSamplesPerSec, format->wBitsPerSample,
> 			 format->wChannels))
> 		{ // return the parameters we found
>-		  rate = format->dwSamplesPerSec;
>-		  bits = format->wBitsPerSample;
>-		  channels = format->wChannels;
>+		  freq_ = format->dwSamplesPerSec;
>+		  bits_ = format->wBitsPerSample;
>+		  channels_ = format->wChannels;
> 		}
> 	    }
> 	}
>@@ -734,6 +676,7 @@ fhandler_dev_dsp::Audio_out::parsewav (c
> 	      debug_printf ("Discard %d bytes wave header", skip);
> 	      pData += skip;
> 	      nBytes -= skip;
>+	      setconvert (bits_ == 8 ? AFMT_U8 : AFMT_S16_LE);
> 	      return true;
> 	    }
> 	}
>@@ -750,9 +693,7 @@ fhandler_dev_dsp::Audio_out::parsewav (c
>    for reception and start the wave-in device.
>    We manage queues of pointers to WAVEHDR
>    When a block has been filled, the callback puts the corresponding
>-   WAVEHDR pointer into a queue. We need a second queue to distinguish
>-   blocks with data from blocks that have been unprepared and are ready
>-   to be used by read().
>+   WAVEHDR pointer into a queue.
>    The function read() blocks (polled, sigh) until at least one good buffer
>    has arrived, then the data is copied into the buffer provided to read().
>    After a buffer has been fully used by read(), it is queued again
>@@ -760,18 +701,14 @@ fhandler_dev_dsp::Audio_out::parsewav (c
>    The function read() iterates until all data requested has been
>    received, there is no way to interrupt it */
>
>-fhandler_dev_dsp::Audio_in::Audio_in () : Audio ()
>-{
>-  bigwavebuffer_ = NULL;
>-  Qisr2app_ = new queue (MAX_BLOCKS);
>-  Qapp2app_ = new queue (MAX_BLOCKS);
>-}
>-
>-fhandler_dev_dsp::Audio_in::~Audio_in ()
>+void
>+fhandler_dev_dsp::Audio_in::fork_fixup (HANDLE parent)
> {
>-  stop ();
>-  delete Qapp2app_;
>-  delete Qisr2app_;
>+  /* Null dev_.
>+     It will be necessary to reset the queue, open the device
>+     and create a lock when reading */
>+  debug_printf ("parent=0x%08x", parent);
>+  dev_ = NULL;
> }
>
> bool
>@@ -782,8 +719,7 @@ fhandler_dev_dsp::Audio_in::query (int r
>
>   fillFormat (&format, rate, bits, channels);
>   rc = waveInOpen (NULL, WAVE_MAPPER, &format, 0L, 0L, WAVE_FORMAT_QUERY);
>-  debug_printf ("freq=%d bits=%d channels=%d %s", rate, bits, channels,
>-		(rc != MMSYSERR_NOERROR) ? "FAIL" : "OK");
>+  debug_printf ("%d = waveInOpen (freq=%d bits=%d channels=%d)", rc, rate, bits, channels);
>   return (rc == MMSYSERR_NOERROR);
> }
>
>@@ -793,31 +729,27 @@ fhandler_dev_dsp::Audio_in::start (int r
>   WAVEFORMATEX format;
>   MMRESULT rc;
>   unsigned bSize = blockSize (rate, bits, channels);
>-  bigwavebuffer_ = new char[MAX_BLOCKS * bSize];
>-  if (bigwavebuffer_ == NULL)
>-    return false;
>
>-  int nDevices = waveInGetNumDevs ();
>-  debug_printf ("number devices=%d, blocksize=%d", nDevices, bSize);
>-  if (nDevices <= 0)
>+  if (dev_)
>+    return true;
>+
>+  /* In case of fork bigwavebuffer may already exist */
>+  if (!bigwavebuffer_)
>+    bigwavebuffer_ = new char[MAX_BLOCKS * bSize];
>+
>+  if (!isvalid ())
>     return false;
>
>   fillFormat (&format, rate, bits, channels);
>   rc = waveInOpen (&dev_, WAVE_MAPPER, &format, (DWORD) waveIn_callback,
> 		   (DWORD) this, CALLBACK_FUNCTION);
>+  debug_printf ("%d = waveInOpen (rate=%d bits=%d channels=%d)", rc, rate, bits, channels);
>+
>   if (rc == MMSYSERR_NOERROR)
>     {
>-      setOwner ();
>       if (!init (bSize))
>-	{
>-	  stop ();
>-	  return false;
>-	}
>+	return false;
>     }
>-
>-  debug_printf ("freq=%d bits=%d channels=%d %s", rate, bits, channels,
>-		(rc != MMSYSERR_NOERROR) ? "FAIL" : "OK");
>-
>   return (rc == MMSYSERR_NOERROR);
> }
>
>@@ -826,45 +758,27 @@ fhandler_dev_dsp::Audio_in::stop ()
> {
>   MMRESULT rc;
>   WAVEHDR *pHdr;
>-  bool gotblock;
>
>-  debug_printf ("dev_=%08x pid=%d owner=%d", (int)dev_,
>-		GetCurrentProcessId (), getOwner ());
>-  if (getOwner () && !denyAccess ())
>+  debug_printf ("dev_=%08x", (int)dev_);
>+  if (dev_)
>     {
>-      rc = waveInReset (dev_);
>       /* Note that waveInReset calls our callback for all incomplete buffers.
> 	 Since all the win32 wave functions appear to use a common lock,
> 	 we must not call into the wave API from the callback.
> 	 Otherwise we end up in a deadlock. */
>-      debug_printf ("waveInReset rc=%d", rc);
>+      rc = waveInReset (dev_);
>+      debug_printf ("%d = waveInReset ()", rc);
>
>-      do
>+      while (Qisr2app_->recv (&pHdr))
> 	{
>-	  lock ();
>-	  gotblock = Qisr2app_->recv (&pHdr);
>-	  unlock ();
>-	  if (gotblock)
>-	    {
>-	      rc = waveInUnprepareHeader (dev_, pHdr, sizeof (WAVEHDR));
>-	      debug_printf ("waveInUnprepareHeader Block 0x%08x %s", pHdr,
>-			    (rc != MMSYSERR_NOERROR) ? "FAIL" : "OK");
>-	    }
>+	  rc = waveInUnprepareHeader (dev_, pHdr, sizeof (WAVEHDR));
>+	  debug_printf ("%d = waveInUnprepareHeader (0x%08x)", rc, pHdr);
> 	}
>-      while (gotblock);
>-      while (Qapp2app_->recv (&pHdr))
>-	/* flush queue */;
>
>       rc = waveInClose (dev_);
>-      debug_printf ("waveInClose rc=%d", rc);
>+      debug_printf ("%d = waveInClose ()", rc);
>
>-      clearOwner ();
>-    }
>-
>-  if (bigwavebuffer_)
>-    {
>-      delete[] bigwavebuffer_;
>-      bigwavebuffer_ = NULL;
>+      Qisr2app_->dellock ();
>     }
> }
>
>@@ -872,13 +786,21 @@ bool
> fhandler_dev_dsp::Audio_in::queueblock (WAVEHDR *pHdr)
> {
>   MMRESULT rc;
>-  pHdr->dwFlags = 0;
>   rc = waveInPrepareHeader (dev_, pHdr, sizeof (WAVEHDR));
>+  debug_printf ("%d = waveInPrepareHeader (0x%08x)", rc, pHdr);
>   if (rc == MMSYSERR_NOERROR)
>-    rc = waveInAddBuffer (dev_, pHdr, sizeof (WAVEHDR));
>-  debug_printf ("waveInAddBuffer Block 0x%08x %s", pHdr,
>-		(rc != MMSYSERR_NOERROR) ? "FAIL" : "OK");
>-  return (rc == MMSYSERR_NOERROR);
>+    {
>+      rc = waveInAddBuffer (dev_, pHdr, sizeof (WAVEHDR));
>+      debug_printf ("%d = waveInAddBuffer (0x%08x)", rc, pHdr);
>+    }
>+  if (rc == MMSYSERR_NOERROR)
>+    return true;
>+
>+  /* FIXME: Should the calling function return an error instead ?*/
>+  pHdr->dwFlags = 0;  /* avoid calling UnprepareHeader again */
>+  pHdr->dwBytesRecorded = 0;  /* no data will have been read */
>+  Qisr2app_->send (pHdr);
>+  return false;
> }
>
> bool
>@@ -888,17 +810,18 @@ fhandler_dev_dsp::Audio_in::init (unsign
>   int i;
>
>   // try to queue all of our buffer for reception
>+  Qisr2app_->reset ();
>   for (i = 0; i < MAX_BLOCKS; i++)
>     {
>       wavehdr_[i].lpData = &bigwavebuffer_[i * blockSize];
>       wavehdr_[i].dwBufferLength = blockSize;
>+      wavehdr_[i].dwFlags = 0;
>       if (!queueblock (&wavehdr_[i]))
> 	break;
>     }
>   pHdr_ = NULL;
>   rc = waveInStart (dev_);
>-  debug_printf ("waveInStart=%d %s queued=%d",
>-		rc, (rc != MMSYSERR_NOERROR) ? "FAIL" : "OK", i);
>+  debug_printf ("%d = waveInStart (), queued=%d", rc, i);
>   return (rc == MMSYSERR_NOERROR);
> }
>
>@@ -947,29 +870,21 @@ void
> fhandler_dev_dsp::Audio_in::waitfordata ()
> {
>   WAVEHDR *pHdr;
>-  bool gotblock;
>   MMRESULT rc;
>
>   if (pHdr_ != NULL)
>     return;
>-  while (Qapp2app_->recv (&pHdr) == false)
>+  while (!Qisr2app_->recv (&pHdr))
>     {
>-      lock ();
>-      gotblock = Qisr2app_->recv (&pHdr);
>-      unlock ();
>-      if (gotblock)
>-	{
>-	  rc = waveInUnprepareHeader (dev_, pHdr, sizeof (WAVEHDR));
>-	  if (rc == MMSYSERR_NOERROR)
>-	    Qapp2app_->send (pHdr);
>-	  else
>-	    debug_printf ("error UnprepareHeader 0x%08x", pHdr);
>-	}
>-      else
>-	{
>-	  debug_printf ("100ms");
>-	  Sleep (100);
>-	}
>+      debug_printf ("100ms");
>+      Sleep (100);
>+    }
>+  if (pHdr->dwFlags) /* Zero if queued following error in queueblock */
>+    {
>+      /* Errors are ignored here. They will probbaly cause a failure
>+         in the subsequent PrepareHeader */
>+      rc = waveInUnprepareHeader (dev_, pHdr, sizeof (WAVEHDR));
>+      debug_printf ("%d = waveInUnprepareHeader (0x%08x)", rc, pHdr);
>     }
>   pHdr_ = pHdr;
>   bufferIndex_ = 0;
>@@ -981,12 +896,9 @@ fhandler_dev_dsp::Audio_in::buf_info (au
> {
>   p->fragstotal = MAX_BLOCKS;
>   p->fragsize = blockSize (rate, bits, channels);
>-  if (getOwner ())
>+  if (this && dev_)
>     {
>-      lock ();
>       p->fragments = Qisr2app_->query ();
>-      unlock ();
>-      p->fragments += Qapp2app_->query ();
>       if (pHdr_ != NULL)
> 	p->bytes = pHdr_->dwBytesRecorded - bufferIndex_
> 	  + p->fragsize * p->fragments;
>@@ -1000,13 +912,10 @@ fhandler_dev_dsp::Audio_in::buf_info (au
>     }
> }
>
>-// This is called on an interrupt so use locking..
>-void
>+inline void
> fhandler_dev_dsp::Audio_in::callback_blockfull (WAVEHDR *pHdr)
> {
>-  lock ();
>   Qisr2app_->send (pHdr);
>-  unlock ();
> }
>
> static void CALLBACK
>@@ -1024,10 +933,7 @@ waveIn_callback (HWAVEIN hWave, UINT msg
>
> /* ------------------------------------------------------------------------
>    /dev/dsp handler
>-   ------------------------------------------------------------------------
>-   instances of the handler statics */
>-int fhandler_dev_dsp::open_count = 0;
>-
>+   ------------------------------------------------------------------------ */
> fhandler_dev_dsp::fhandler_dev_dsp ():
>   fhandler_base ()
> {
>@@ -1036,21 +942,16 @@ fhandler_dev_dsp::fhandler_dev_dsp ():
>   audio_out_ = NULL;
> }
>
>-fhandler_dev_dsp::~fhandler_dev_dsp ()
>-{
>-  close ();
>-  debug_printf ("0x%08x end", (int)this);
>-}
>-
> int
> fhandler_dev_dsp::open (int flags, mode_t mode)
> {
>-  open_count++;
>-  if (open_count > 1)
>+  if (cygheap->fdtab.find_archetype (pc.dev))
>     {
>       set_errno (EBUSY);
>       return 0;
>     }
>+  int err = 0;
>+  UINT num_in = 0, num_out = 0;
>   set_flags ((flags & ~O_TEXT) | O_BINARY);
>   // Work out initial sample format & frequency, /dev/dsp defaults
>   audioformat_ = AFMT_U8;
>@@ -1059,102 +960,84 @@ fhandler_dev_dsp::open (int flags, mode_
>   audiochannels_ = 1;
>   switch (flags & O_ACCMODE)
>     {
>+    case O_RDWR:
>+      if ((num_in = waveInGetNumDevs ()) == 0)
>+	err = ENXIO;
>+      /* Fall through */
>     case O_WRONLY:
>-      audio_out_ = new Audio_out;
>-      if (!audio_out_->query (audiofreq_, audiobits_, audiochannels_))
>-	{
>-	  delete audio_out_;
>-	  audio_out_ = NULL;
>-	}
>+      if ((num_out = waveOutGetNumDevs ()) == 0)
>+	err = ENXIO;
>       break;
>     case O_RDONLY:
>-      audio_in_ = new Audio_in;
>-      if (!audio_in_->query (audiofreq_, audiobits_, audiochannels_))
>-	{
>-	  delete audio_in_;
>-	  audio_in_ = NULL;
>-	}
>-      break;
>-    case O_RDWR:
>-      audio_out_ = new Audio_out;
>-      if (audio_out_->query (audiofreq_, audiobits_, audiochannels_))
>-	{
>-	  audio_in_ = new Audio_in;
>-	  if (!audio_in_->query (audiofreq_, audiobits_, audiochannels_))
>-	    {
>-	      delete audio_in_;
>-	      audio_in_ = NULL;
>-	      audio_out_->stop ();
>-	      delete audio_out_;
>-	      audio_out_ = NULL;
>-	    }
>-	}
>-      else
>-	{
>-	  delete audio_out_;
>-	  audio_out_ = NULL;
>-	}
>+      if ((num_in = waveInGetNumDevs ()) == 0)
>+	err = ENXIO;
>       break;
>     default:
>-      set_errno (EINVAL);
>-      return 0;
>-    } // switch (flags & O_ACCMODE)
>-  int rc;
>-  if (audio_in_ || audio_out_)
>-    { /* All tried query () succeeded */
>-      rc = 1;
>+      err = EINVAL;
>+    }
>+
>+  if (!err)
>+    {
>       set_open_status ();
>       need_fork_fixup (true);
>-      close_on_exec (true);
>+      nohandle (true);
>+
>+      // FIXME: Do this better someday
>+      fhandler_dev_dsp *arch = (fhandler_dev_dsp *) cmalloc (HEAP_ARCHETYPES, sizeof (*this));
>+      archetype = arch;
>+      *((fhandler_dev_dsp **) cygheap->fdtab.add_archetype ()) = arch;
>+      *arch = *this;
>+      archetype->usecount = 1;
>     }
>   else
>-    { /* One of the tried query () failed */
>-      rc = 0;
>-      set_errno (EIO);
>-    }
>-  debug_printf ("ACCMODE=0x%08x audio_in=%08x audio_out=%08x, rc=%d",
>-		flags & O_ACCMODE, (int)audio_in_, (int)audio_out_, rc);
>-  return rc;
>+    set_errno (err);
>+
>+  debug_printf ("ACCMODE=0x%08x audio_in=%d audio_out=%d, err=%d",
>+		flags & O_ACCMODE, num_in, num_out, err);
>+  return !err;
> }
>
>-#define RETURN_ERROR_WHEN_BUSY(audio)\
>-  if ((audio)->denyAccess ())    \
>-    {\
>-      set_errno (EBUSY);\
>-      return -1;\
>-    }
>+#define IS_WRITE() ((get_flags() & O_ACCMODE) != O_RDONLY)
>+#define IS_READ() ((get_flags() & O_ACCMODE) != O_WRONLY)
>
> int
> fhandler_dev_dsp::write (const void *ptr, size_t len)
> {
>+  debug_printf ("ptr=%08x len=%d", ptr, len);
>+  if ((fhandler_dev_dsp *) archetype != this)
>+    return ((fhandler_dev_dsp *)archetype)->write(ptr, len);
>+
>   int len_s = len;
>   const char *ptr_s = static_cast <const char *> (ptr);
>
>-  debug_printf ("ptr=%08x len=%d", ptr, len);
>   if (!audio_out_)
>+    if (IS_WRITE ())
>+      {
>+	debug_printf ("Allocating");
>+	if (!(audio_out_ = new Audio_out))
>+	  return -1;
>+
>+	/* check for wave file & get parameters & skip header if possible. */
>+
>+	if (audio_out_->parsewav (ptr_s, len_s,
>+				  audiofreq_, audiobits_, audiochannels_))
>+	  debug_printf ("=> ptr_s=%08x len_s=%d", ptr_s, len_s);
>+      }
>+    else
>+      {
>+	set_errno (EBADF); // device was opened for read?
>+	return -1;
>+      }
>+
>+  /* Open audio device properly with callbacks.
>+     Private parameters were set in call to parsewav.
>+     This is a no-op when there are successive writes in the same process */
>+  if (!audio_out_->start ())
>     {
>-      set_errno (EACCES); // device was opened for read?
>+      set_errno (EIO);
>       return -1;
>     }
>-  RETURN_ERROR_WHEN_BUSY (audio_out_);
>-  if (audio_out_->getOwner () == 0L)
>-    { // No owner yet, lets do it
>-      // check for wave file & get parameters & skip header if possible.
>-      if (audio_out_->parsewav (ptr_s, len_s,
>-				audiofreq_, audiobits_, audiochannels_))
>-	{ // update our format conversion
>-	  debug_printf ("=> ptr_s=%08x len_s=%d", ptr_s, len_s);
>-	  audioformat_ = ((audiobits_ == 8) ? AFMT_U8 : AFMT_S16_LE);
>-	  audio_out_->setformat (audioformat_);
>-	}
>-      // Open audio device properly with callbacks.
>-      if (!audio_out_->start (audiofreq_, audiobits_, audiochannels_))
>-	{
>-	  set_errno (EIO);
>-	  return -1;
>-	}
>-    }
>-
>+
>   audio_out_->write (ptr_s, len_s);
>   return len;
> }
>@@ -1163,28 +1046,36 @@ void __stdcall
> fhandler_dev_dsp::read (void *ptr, size_t& len)
> {
>   debug_printf ("ptr=%08x len=%d", ptr, len);
>+  if ((fhandler_dev_dsp *) archetype != this)
>+    return ((fhandler_dev_dsp *)archetype)->read(ptr, len);
>+
>   if (!audio_in_)
>+    if (IS_READ ())
>+      {
>+	debug_printf ("Allocating");
>+	if (!(audio_in_ = new Audio_in))
>+	  {
>+	    len = (size_t)-1;
>+	    return;
>+	  }
>+	audio_in_->setconvert (audioformat_);
>+      }
>+    else
>+      {
>+	len = (size_t)-1;
>+	set_errno (EBADF); // device was opened for write?
>+	return;
>+      }
>+
>+  /* Open audio device properly with callbacks.
>+     This is a noop when there are successive reads in the same process */
>+  if (!audio_in_->start (audiofreq_, audiobits_, audiochannels_))
>     {
>       len = (size_t)-1;
>-      set_errno (EACCES); // device was opened for write?
>-      return;
>-    }
>-  if (audio_in_->denyAccess ())
>-    {
>-      len = (size_t)-1;
>-      set_errno (EBUSY);
>+      set_errno (EIO);
>       return;
>     }
>-  if (audio_in_->getOwner () == 0L)
>-    { // No owner yet. Let's take it
>-      // Open audio device properly with callbacks.
>-      if (!audio_in_->start (audiofreq_, audiobits_, audiochannels_))
>-	{
>-	  len = (size_t)-1;
>-	  set_errno (EIO);
>-	  return;
>-	}
>-    }
>+
>   audio_in_->read ((char *)ptr, (int&)len);
>   return;
> }
>@@ -1195,28 +1086,41 @@ fhandler_dev_dsp::lseek (_off64_t offset
>   return 0;
> }
>
>-int
>-fhandler_dev_dsp::close (void)
>+void
>+fhandler_dev_dsp::close_audio_in ()
> {
>-  debug_printf ("audio_in=%08x audio_out=%08x",
>-		(int)audio_in_, (int)audio_out_);
>   if (audio_in_)
>     {
>+      audio_in_->stop ();
>       delete audio_in_;
>       audio_in_ = NULL;
>     }
>+}
>+
>+void
>+fhandler_dev_dsp::close_audio_out (bool immediately)
>+{
>   if (audio_out_)
>     {
>-      if (exit_state != ES_NOT_EXITING)
>-       { // emergency close due to call to exit() or Ctrl-C:
>-	 // do not wait for all pending audio to be played
>-	 audio_out_->stop (true);
>-       }
>+      audio_out_->stop (immediately);
>       delete audio_out_;
>       audio_out_ = NULL;
>     }
>-  if (open_count > 0)
>-    open_count--;
>+}
>+
>+int
>+fhandler_dev_dsp::close (void)
>+{
>+  debug_printf ("audio_in=%08x audio_out=%08x",
>+		(int)audio_in_, (int)audio_out_);
>+  if ((fhandler_dev_dsp *) archetype != this)
>+    return ((fhandler_dev_dsp *)archetype)->close ();
>+
>+  if (--usecount == 0)
>+    {
>+      close_audio_in ();
>+      close_audio_out (exit_state != ES_NOT_EXITING);
>+    }
>   return 0;
> }
>
>@@ -1224,55 +1128,45 @@ int
> fhandler_dev_dsp::dup (fhandler_base * child)
> {
>   debug_printf ("");
>-  fhandler_dev_dsp *fhc = (fhandler_dev_dsp *) child;
>-
>-  fhc->set_flags (get_flags ());
>-  fhc->audiochannels_ = audiochannels_;
>-  fhc->audiobits_ = audiobits_;
>-  fhc->audiofreq_ = audiofreq_;
>-  fhc->audioformat_ = audioformat_;
>+  child->archetype = archetype;
>+  archetype->usecount++;
>   return 0;
> }
>
> int
> fhandler_dev_dsp::ioctl (unsigned int cmd, void *ptr)
> {
>-  int *intptr = (int *) ptr;
>   debug_printf ("audio_in=%08x audio_out=%08x",
> 		(int)audio_in_, (int)audio_out_);
>+  if ((fhandler_dev_dsp *) archetype != this)
>+    return ((fhandler_dev_dsp *)archetype)->ioctl(cmd, ptr);
>+
>+  int *intptr = (int *) ptr;
>   switch (cmd)
>     {
> #define CASE(a) case a : debug_printf ("/dev/dsp: ioctl %s", #a);
>
>       CASE (SNDCTL_DSP_RESET)
>-	if (audio_out_)
>-	  {
>-	    RETURN_ERROR_WHEN_BUSY (audio_out_);
>-	    audio_out_->stop (true);
>-	  }
>-	if (audio_in_)
>-	  {
>-	    RETURN_ERROR_WHEN_BUSY (audio_in_);
>-	    audio_in_->stop ();
>-	  }
>-	return 0;
>+	close_audio_in ();
>+	close_audio_out (true);
>+        return 0;
> 	break;
>
>       CASE (SNDCTL_DSP_GETBLKSIZE)
>-	if (audio_out_)
>+	/* This is valid even if audio_X is NULL */
>+	if (IS_WRITE ())
> 	  {
> 	    *intptr = audio_out_->blockSize (audiofreq_,
> 					     audiobits_,
> 					     audiochannels_);
> 	  }
> 	else
>-	  { // I am very sure that audio_in_ is valid
>+	  { // I am very sure that IS_READ is valid
> 	    *intptr = audio_in_->blockSize (audiofreq_,
> 					    audiobits_,
> 					    audiochannels_);
> 	  }
> 	return 0;
>-	break;
>
>       CASE (SNDCTL_DSP_SETFMT)
>       {
>@@ -1296,11 +1190,9 @@ fhandler_dev_dsp::ioctl (unsigned int cm
> 	  default:
> 	    nBits = 0;
> 	  }
>-	if (nBits && audio_out_)
>+	if (nBits && IS_WRITE ())
> 	  {
>-	    RETURN_ERROR_WHEN_BUSY (audio_out_);
>-	    audio_out_->stop ();
>-	    audio_out_->setformat (*intptr);
>+	    close_audio_out ();
> 	    if (audio_out_->query (audiofreq_, nBits, audiochannels_))
> 	      {
> 		audiobits_ = nBits;
>@@ -1312,11 +1204,9 @@ fhandler_dev_dsp::ioctl (unsigned int cm
> 		return -1;
> 	      }
> 	  }
>-	if (nBits && audio_in_)
>+	if (nBits && IS_READ ())
> 	  {
>-	    RETURN_ERROR_WHEN_BUSY (audio_in_);
>-	    audio_in_->stop ();
>-	    audio_in_->setformat (*intptr);
>+	    close_audio_in ();
> 	    if (audio_in_->query (audiofreq_, nBits, audiochannels_))
> 	      {
> 		audiobits_ = nBits;
>@@ -1330,14 +1220,11 @@ fhandler_dev_dsp::ioctl (unsigned int cm
> 	  }
> 	return 0;
>       }
>-      break;
>
>       CASE (SNDCTL_DSP_SPEED)
>-      {
>-	if (audio_out_)
>+	if (IS_WRITE ())
> 	  {
>-	    RETURN_ERROR_WHEN_BUSY (audio_out_);
>-	    audio_out_->stop ();
>+	    close_audio_out ();
> 	    if (audio_out_->query (*intptr, audiobits_, audiochannels_))
> 	      audiofreq_ = *intptr;
> 	    else
>@@ -1346,10 +1233,9 @@ fhandler_dev_dsp::ioctl (unsigned int cm
> 		return -1;
> 	      }
> 	  }
>-	if (audio_in_)
>+	if (IS_READ ())
> 	  {
>-	    RETURN_ERROR_WHEN_BUSY (audio_in_);
>-	    audio_in_->stop ();
>+	    close_audio_in ();
> 	    if (audio_in_->query (*intptr, audiobits_, audiochannels_))
> 	      audiofreq_ = *intptr;
> 	    else
>@@ -1359,49 +1245,22 @@ fhandler_dev_dsp::ioctl (unsigned int cm
> 	      }
> 	  }
> 	return 0;
>-      }
>-      break;
>
>       CASE (SNDCTL_DSP_STEREO)
>       {
> 	int nChannels = *intptr + 1;
>-
>-	if (audio_out_)
>-	  {
>-	    RETURN_ERROR_WHEN_BUSY (audio_out_);
>-	    audio_out_->stop ();
>-	    if (audio_out_->query (audiofreq_, audiobits_, nChannels))
>-	      audiochannels_ = nChannels;
>-	    else
>-	      {
>-		*intptr = audiochannels_ - 1;
>-		return -1;
>-	      }
>-	  }
>-	if (audio_in_)
>-	  {
>-	    RETURN_ERROR_WHEN_BUSY (audio_in_);
>-	    audio_in_->stop ();
>-	    if (audio_in_->query (audiofreq_, audiobits_, nChannels))
>-	      audiochannels_ = nChannels;
>-	    else
>-	      {
>-		*intptr = audiochannels_ - 1;
>-		return -1;
>-	      }
>-	  }
>-	return 0;
>+	int res = ioctl (SNDCTL_DSP_CHANNELS, &nChannels);
>+	*intptr = nChannels - 1;
>+	return res;
>       }
>-      break;
>
>       CASE (SNDCTL_DSP_CHANNELS)
>       {
> 	int nChannels = *intptr;
>
>-	if (audio_out_)
>+	if (IS_WRITE ())
> 	  {
>-	    RETURN_ERROR_WHEN_BUSY (audio_out_);
>-	    audio_out_->stop ();
>+	    close_audio_out ();
> 	    if (audio_out_->query (audiofreq_, audiobits_, nChannels))
> 	      audiochannels_ = nChannels;
> 	    else
>@@ -1410,10 +1269,9 @@ fhandler_dev_dsp::ioctl (unsigned int cm
> 		return -1;
> 	      }
> 	  }
>-	if (audio_in_)
>+	if (IS_READ ())
> 	  {
>-	    RETURN_ERROR_WHEN_BUSY (audio_in_);
>-	    audio_in_->stop ();
>+	    close_audio_in ();
> 	    if (audio_in_->query (audiofreq_, audiobits_, nChannels))
> 	      audiochannels_ = nChannels;
> 	    else
>@@ -1424,76 +1282,55 @@ fhandler_dev_dsp::ioctl (unsigned int cm
> 	  }
> 	return 0;
>       }
>-      break;
>
>       CASE (SNDCTL_DSP_GETOSPACE)
>       {
>-	audio_buf_info *p = (audio_buf_info *) ptr;
>-	if (audio_out_)
>+	if (!IS_WRITE ())
> 	  {
>-	    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);
>+	    set_errno(EBADF);
>+	    return -1;
> 	  }
>+	audio_buf_info *p = (audio_buf_info *) ptr;
>+	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_)
>+	if (!IS_READ ())
> 	  {
>-	    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);
>+	    set_errno(EBADF);
>+	    return -1;
> 	  }
>+	audio_buf_info *p = (audio_buf_info *) ptr;
>+	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);
> 	return 0;
>       }
>-      break;
>
>       CASE (SNDCTL_DSP_SETFRAGMENT)
>-      {
> 	// Fake!! esound & mikmod require this on non PowerPC platforms.
> 	//
> 	return 0;
>-      }
>-      break;
>
>       CASE (SNDCTL_DSP_GETFMTS)
>-      {
> 	*intptr = AFMT_S16_LE | AFMT_U8; // only native formats returned here
> 	return 0;
>-      }
>-      break;
>
>       CASE (SNDCTL_DSP_GETCAPS)
>-      {
> 	*intptr = DSP_CAP_BATCH | DSP_CAP_DUPLEX;
> 	return 0;
>-      }
>-      break;
>
>       CASE (SNDCTL_DSP_POST)
>       CASE (SNDCTL_DSP_SYNC)
>-      {
>-	if (audio_out_)
>-	  {
>-	    // Stop audio out device
>-	    RETURN_ERROR_WHEN_BUSY (audio_out_);
>-	    audio_out_->stop ();
>-	  }
>-	if (audio_in_)
>-	  {
>-	    // Stop audio in device
>-	    RETURN_ERROR_WHEN_BUSY (audio_in_);
>-	    audio_in_->stop ();
>-	  }
>+	// Stop audio out device
>+	close_audio_out ();
>+        // Stop audio in device
>+        close_audio_in ();
> 	return 0;
>-      }
>-      break;
>
>     default:
>       debug_printf ("/dev/dsp: ioctl 0x%08x not handled yet! FIXME:", cmd);
>@@ -1516,7 +1353,10 @@ fhandler_dev_dsp::fixup_after_fork (HAND
> { // called from new child process
>   debug_printf ("audio_in=%08x audio_out=%08x",
> 		(int)audio_in_, (int)audio_out_);
>-  if (audio_in_ )
>+  if (archetype != this)
>+    return ((fhandler_dev_dsp *)archetype)->fixup_after_fork (parent);
>+
>+  if (audio_in_)
>     audio_in_ ->fork_fixup (parent);
>   if (audio_out_)
>     audio_out_->fork_fixup (parent);
>@@ -1527,6 +1367,9 @@ fhandler_dev_dsp::fixup_after_exec ()
> {
>   debug_printf ("audio_in=%08x audio_out=%08x",
> 		(int)audio_in_, (int)audio_out_);
>-}
>-
>+  if (archetype != this)
>+    return ((fhandler_dev_dsp *)archetype)->fixup_after_exec ();
>
>+  audio_in_ = NULL;
>+  audio_out_ = NULL;
>+}



More information about the Cygwin-patches mailing list