+2011-05-04 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler_dsp.cc (fhandler_dev_dsp::Audio): Add fh member.
+ (fhandler_dev_dsp::Audio_out::Audio_out): Take pointer to encapsulating
+ fhandler_dev_dsp as parameter.
+ (fhandler_dev_dsp::Audio_in::Audio_in): Ditto.
+ (fhandler_dev_dsp::Audio::Audio): Take pointer to encapsulating
+ fhandler_dev_dsp as parameter and store in fh.
+ (fhandler_dev_dsp::Audio_out::write): Change return type to int and
+ return number of bytes written. Return -1 if waitforspace returns false
+ and no bytes have been written so far.
+ (fhandler_dev_dsp::Audio_out::waitforspace): Change return type to bool.
+ Handle O_NONBLOCK. Make waiting loop interruptible and cancelable.
+ Return false in any of these cases, otherwise true.
+ (fhandler_dev_dsp::Audio_in::read): Set returned nBytes to -1 if
+ waitfordata returns false and nothing has been read so far.
+ (fhandler_dev_dsp::Audio_in::waitfordata): Change return type to bool.
+ Handle O_NONBLOCK. Make waiting loop interruptible and cancelable.
+ Return false in any of these cases, otherwise true.
+ (fhandler_dev_dsp::write): Call Audio_out constructor with this as
+ parameter.
+ (fhandler_dev_dsp::read): Call Audio_in constructor with this as
+ parameter.
+
2011-05-04 Christopher Faylor <me.cygwin2011@cgf.cx>
* thread.h (pthread::static_cancel_self): Mark as noreturn.
/* Fhandler_dev_dsp: code to emulate OSS sound model /dev/dsp
- Copyright 2001, 2002, 2003, 2004, 2008 Red Hat, Inc
+ Copyright 2001, 2002, 2003, 2004, 2008, 2011 Red Hat, Inc
Written by Andy Younger (andy@snoogie.demon.co.uk)
Extended by Gerd Spalink (Gerd.Spalink@t-online.de)
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
+#include "sigproc.h"
/*------------------------------------------------------------------------
Simple encapsulation of the win32 audio device.
class fhandler_dev_dsp::Audio
{ // This class contains functionality common to Audio_in and Audio_out
public:
- Audio ();
+ Audio (fhandler_dev_dsp *my_fh);
~Audio ();
class queue;
char *bigwavebuffer_; // audio samples only
// Member variables below must be locked
queue *Qisr2app_; // blocks passed from wave callback
+
+ fhandler_dev_dsp *fh;
};
class fhandler_dev_dsp::Audio::queue
class fhandler_dev_dsp::Audio_out: public Audio
{
public:
+ Audio_out (fhandler_dev_dsp *my_fh) : Audio (my_fh) {}
+
void fork_fixup (HANDLE parent);
bool query (int rate, int bits, int channels);
bool start ();
void stop (bool immediately = false);
- bool write (const char *pSampleData, int nBytes);
+ int 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,
private:
void init (unsigned blockSize);
void waitforallsent ();
- void waitforspace ();
+ bool waitforspace ();
bool sendcurrent ();
enum { MAX_BLOCKS = 12 };
class fhandler_dev_dsp::Audio_in: public Audio
{
public:
+ Audio_in (fhandler_dev_dsp *my_fh) : Audio (my_fh) {}
+
void fork_fixup (HANDLE parent);
bool query (int rate, int bits, int channels);
bool start (int rate, int bits, int channels);
private:
bool init (unsigned blockSize);
bool queueblock (WAVEHDR *pHdr);
- void waitfordata (); // blocks until we have a good pHdr_
+ bool waitfordata (); // blocks until we have a good pHdr_ unless O_NONBLOCK
HWAVEIN dev_;
};
}
// Audio class implements functionality need for both read and write
-fhandler_dev_dsp::Audio::Audio ()
+fhandler_dev_dsp::Audio::Audio (fhandler_dev_dsp *my_fh)
{
bigwavebuffer_ = NULL;
Qisr2app_ = new queue (MAX_BLOCKS);
convert_ = &fhandler_dev_dsp::Audio::convert_none;
+ fh = my_fh;
}
fhandler_dev_dsp::Audio::~Audio ()
pHdr_ = NULL;
}
-bool
+int
fhandler_dev_dsp::Audio_out::write (const char *pSampleData, int nBytes)
{
- while (nBytes != 0)
+ int bytes_to_write = nBytes;
+ while (bytes_to_write != 0)
{ // Block if all blocks used until at least one is free
- waitforspace ();
+ if (!waitforspace ())
+ {
+ if (bytes_to_write != nBytes)
+ break;
+ return -1;
+ }
int sizeleft = (int)pHdr_->dwUser - bufferIndex_;
- if (nBytes < sizeleft)
+ if (bytes_to_write < sizeleft)
{ // all data fits into the current block, with some space left
- memcpy (&pHdr_->lpData[bufferIndex_], pSampleData, nBytes);
- bufferIndex_ += nBytes;
+ memcpy (&pHdr_->lpData[bufferIndex_], pSampleData, bytes_to_write);
+ bufferIndex_ += bytes_to_write;
break;
}
else
bufferIndex_ += sizeleft;
sendcurrent ();
pSampleData += sizeleft;
- nBytes -= sizeleft;
+ bytes_to_write -= sizeleft;
}
}
- return true;
+ return nBytes - bytes_to_write;
}
void
Qisr2app_->send (pHdr);
}
-void
+bool
fhandler_dev_dsp::Audio_out::waitforspace ()
{
WAVEHDR *pHdr;
MMRESULT rc = WAVERR_STILLPLAYING;
if (pHdr_ != NULL)
- return;
+ return true;
while (!Qisr2app_->recv (&pHdr))
{
+ if (fh->is_nonblocking ())
+ {
+ set_errno (EAGAIN);
+ return false;
+ }
+ HANDLE w4[2] = { signal_arrived, pthread::get_cancel_event () };
+ DWORD cnt = w4[1] ? 2 : 1;
debug_printf ("100ms");
- Sleep (100);
+ switch (WaitForMultipleObjects (cnt, w4, FALSE, 100))
+ {
+ case WAIT_OBJECT_0:
+ if (!_my_tls.call_signal_handler ())
+ {
+ set_errno (EINTR);
+ return false;
+ }
+ break;
+ case WAIT_OBJECT_0 + 1:
+ pthread::static_cancel_self ();
+ /*NOTREACHED*/
+ default:
+ break;
+ }
}
if (pHdr->dwFlags)
{
}
pHdr_ = pHdr;
bufferIndex_ = 0;
+ return true;
}
void
debug_printf ("pSampleData=%08x nBytes=%d", pSampleData, bytes_to_read);
while (bytes_to_read != 0)
{ // Block till next sound has been read
- waitfordata ();
+ if (!waitfordata ())
+ {
+ if (nBytes)
+ return true;
+ nBytes = -1;
+ return false;
+ }
// Handle gathering our blocks into smaller or larger buffer
int sizeleft = pHdr_->dwBytesRecorded - bufferIndex_;
return true;
}
-void
+bool
fhandler_dev_dsp::Audio_in::waitfordata ()
{
WAVEHDR *pHdr;
MMRESULT rc;
if (pHdr_ != NULL)
- return;
+ return true;
while (!Qisr2app_->recv (&pHdr))
{
+ if (fh->is_nonblocking ())
+ {
+ set_errno (EAGAIN);
+ return false;
+ }
+ HANDLE w4[2] = { signal_arrived, pthread::get_cancel_event () };
+ DWORD cnt = w4[1] ? 2 : 1;
debug_printf ("100ms");
- Sleep (100);
+ switch (WaitForMultipleObjects (cnt, w4, FALSE, 100))
+ {
+ case WAIT_OBJECT_0:
+ if (!_my_tls.call_signal_handler ())
+ {
+ set_errno (EINTR);
+ return false;
+ }
+ break;
+ case WAIT_OBJECT_0 + 1:
+ pthread::static_cancel_self ();
+ /*NOTREACHED*/
+ default:
+ break;
+ }
}
if (pHdr->dwFlags) /* Zero if queued following error in queueblock */
{
}
pHdr_ = pHdr;
bufferIndex_ = 0;
+ return true;
}
void
else if (IS_WRITE ())
{
debug_printf ("Allocating");
- if (!(audio_out_ = new Audio_out))
+ if (!(audio_out_ = new Audio_out (this)))
return -1;
/* check for wave file & get parameters & skip header if possible. */
return -1;
}
- audio_out_->write (ptr_s, len_s);
- return len;
+ int written = audio_out_->write (ptr_s, len_s);
+ if (written < 0)
+ {
+ if (len - len_s > 0)
+ return len - len_s;
+ return -1;
+ }
+ return len - len_s + written;
}
void __stdcall
else if (IS_READ ())
{
debug_printf ("Allocating");
- if (!(audio_in_ = new Audio_in))
+ if (!(audio_in_ = new Audio_in (this)))
{
len = (size_t)-1;
return;