[Patch]: fhandler_dsp.cc

Pierre A. Humblet pierre@phumblet.no-ip.org
Tue Aug 17 03:08:00 GMT 2004


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.

Pierre


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.
-------------- next part --------------
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