Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2004-08-17 13:52:50 +0400
committerCorinna Vinschen <corinna@vinschen.de>2004-08-17 13:52:50 +0400
commit8f663bd642bacc45aad98e3456c7c11ece4cdcd2 (patch)
tree256fa5b66d4ecd85df374df4ec89a2c7132f9ecf /winsup/cygwin/fhandler_dsp.cc
parent86b652f9c8105bc5c22e15c858b7e9ccd993cbc4 (diff)
* 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.
Diffstat (limited to 'winsup/cygwin/fhandler_dsp.cc')
-rw-r--r--winsup/cygwin/fhandler_dsp.cc919
1 files changed, 381 insertions, 538 deletions
diff --git a/winsup/cygwin/fhandler_dsp.cc b/winsup/cygwin/fhandler_dsp.cc
index 85237a403..8c6404308 100644
--- a/winsup/cygwin/fhandler_dsp.cc
+++ b/winsup/cygwin/fhandler_dsp.cc
@@ -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 (HWAVEOUT hWave, UINT msg, DWORD instance,
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 (HWAVEIN hWave, UINT msg, DWORD instance,
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)
+inline bool
+fhandler_dev_dsp::Audio::isvalid ()
{
- debug_printf ("parent=0x%08x", parent);
- InitializeCriticalSection (&lock_);
-}
-
-bool
-fhandler_dev_dsp::Audio::denyAccess ()
-{
- if (owner_ == 0L)
- return false;
- return (GetCurrentProcessId () != owner_);
+ 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 rate, int bits, int channels)
}
//=======================================================================
-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 rate, int bits, int channels)
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 immediately)
{
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 immediately)
}
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);
-
- clearOwner ();
- }
+ debug_printf ("%d = waveOutClose ()", rc);
- if (bigwavebuffer_)
- {
- delete[] bigwavebuffer_;
- bigwavebuffer_ = NULL;
+ Qisr2app_->dellock ();
}
}
@@ -472,13 +440,15 @@ fhandler_dev_dsp::Audio_out::init (unsigned blockSize)
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 (const char *pSampleData, int nBytes)
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 (audio_buf_info *p,
}
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 (audio_buf_info *p,
/* 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::waitforspace ()
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 (const char * &pData, int &nBytes,
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 (const char * &pData, int &nBytes,
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 (const char * &pData, int &nBytes,
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 (const char * &pData, int &nBytes,
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 rate, int bits, int channels)
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 rate, int bits, int channels)
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 (unsigned blockSize)
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 (audio_buf_info *p,
{
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 (audio_buf_info *p,
}
}
-// 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, DWORD instance, DWORD param1,
/* ------------------------------------------------------------------------
/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,101 +960,83 @@ fhandler_dev_dsp::open (int flags, mode_t 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, int whence)
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 cmd, void *ptr)
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 cmd, void *ptr)
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 cmd, void *ptr)
}
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 cmd, void *ptr)
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 cmd, void *ptr)
}
}
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 cmd, void *ptr)
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 cmd, void *ptr)
}
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 (HANDLE parent)
{ // 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;
+}