* 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.
This commit is contained in:
Corinna Vinschen 2011-05-04 11:41:22 +00:00
parent 307b0a5d4b
commit 5152a53ade
2 changed files with 119 additions and 25 deletions

View File

@ -1,3 +1,27 @@
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> 2011-05-04 Christopher Faylor <me.cygwin2011@cgf.cx>
* thread.h (pthread::static_cancel_self): Mark as noreturn. * thread.h (pthread::static_cancel_self): Mark as noreturn.

View File

@ -1,6 +1,6 @@
/* 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, 2008 Red Hat, Inc Copyright 2001, 2002, 2003, 2004, 2008, 2011 Red Hat, Inc
Written by Andy Younger (andy@snoogie.demon.co.uk) Written by Andy Younger (andy@snoogie.demon.co.uk)
Extended by Gerd Spalink (Gerd.Spalink@t-online.de) Extended by Gerd Spalink (Gerd.Spalink@t-online.de)
@ -20,6 +20,7 @@ details. */
#include "fhandler.h" #include "fhandler.h"
#include "dtable.h" #include "dtable.h"
#include "cygheap.h" #include "cygheap.h"
#include "sigproc.h"
/*------------------------------------------------------------------------ /*------------------------------------------------------------------------
Simple encapsulation of the win32 audio device. Simple encapsulation of the win32 audio device.
@ -49,7 +50,7 @@ details. */
class fhandler_dev_dsp::Audio class fhandler_dev_dsp::Audio
{ // This class contains functionality common to Audio_in and Audio_out { // This class contains functionality common to Audio_in and Audio_out
public: public:
Audio (); Audio (fhandler_dev_dsp *my_fh);
~Audio (); ~Audio ();
class queue; class queue;
@ -74,6 +75,8 @@ class fhandler_dev_dsp::Audio
char *bigwavebuffer_; // audio samples only char *bigwavebuffer_; // audio samples only
// Member variables below must be locked // Member variables below must be locked
queue *Qisr2app_; // blocks passed from wave callback queue *Qisr2app_; // blocks passed from wave callback
fhandler_dev_dsp *fh;
}; };
class fhandler_dev_dsp::Audio::queue class fhandler_dev_dsp::Audio::queue
@ -104,11 +107,13 @@ static void CALLBACK waveOut_callback (HWAVEOUT hWave, UINT msg, DWORD instance,
class fhandler_dev_dsp::Audio_out: public Audio class fhandler_dev_dsp::Audio_out: public Audio
{ {
public: public:
Audio_out (fhandler_dev_dsp *my_fh) : Audio (my_fh) {}
void fork_fixup (HANDLE parent); void fork_fixup (HANDLE parent);
bool query (int rate, int bits, int channels); bool query (int rate, int bits, int channels);
bool start (); bool start ();
void stop (bool immediately = false); 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 buf_info (audio_buf_info *p, int rate, int bits, int channels);
void callback_sampledone (WAVEHDR *pHdr); void callback_sampledone (WAVEHDR *pHdr);
bool parsewav (const char *&pData, int &nBytes, bool parsewav (const char *&pData, int &nBytes,
@ -117,7 +122,7 @@ class fhandler_dev_dsp::Audio_out: public Audio
private: private:
void init (unsigned blockSize); void init (unsigned blockSize);
void waitforallsent (); void waitforallsent ();
void waitforspace (); bool waitforspace ();
bool sendcurrent (); bool sendcurrent ();
enum { MAX_BLOCKS = 12 }; enum { MAX_BLOCKS = 12 };
@ -135,6 +140,8 @@ static void CALLBACK waveIn_callback (HWAVEIN hWave, UINT msg, DWORD instance,
class fhandler_dev_dsp::Audio_in: public Audio class fhandler_dev_dsp::Audio_in: public Audio
{ {
public: public:
Audio_in (fhandler_dev_dsp *my_fh) : Audio (my_fh) {}
void fork_fixup (HANDLE parent); void fork_fixup (HANDLE parent);
bool query (int rate, int bits, int channels); bool query (int rate, int bits, int channels);
bool start (int rate, int bits, int channels); bool start (int rate, int bits, int channels);
@ -146,7 +153,7 @@ public:
private: private:
bool init (unsigned blockSize); bool init (unsigned blockSize);
bool queueblock (WAVEHDR *pHdr); 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_; HWAVEIN dev_;
}; };
@ -222,11 +229,12 @@ fhandler_dev_dsp::Audio::queue::query ()
} }
// Audio class implements functionality need for both read and write // 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; bigwavebuffer_ = NULL;
Qisr2app_ = new queue (MAX_BLOCKS); Qisr2app_ = new queue (MAX_BLOCKS);
convert_ = &fhandler_dev_dsp::Audio::convert_none; convert_ = &fhandler_dev_dsp::Audio::convert_none;
fh = my_fh;
} }
fhandler_dev_dsp::Audio::~Audio () fhandler_dev_dsp::Audio::~Audio ()
@ -452,18 +460,24 @@ fhandler_dev_dsp::Audio_out::init (unsigned blockSize)
pHdr_ = NULL; pHdr_ = NULL;
} }
bool int
fhandler_dev_dsp::Audio_out::write (const char *pSampleData, int nBytes) 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 { // 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_; 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 { // all data fits into the current block, with some space left
memcpy (&pHdr_->lpData[bufferIndex_], pSampleData, nBytes); memcpy (&pHdr_->lpData[bufferIndex_], pSampleData, bytes_to_write);
bufferIndex_ += nBytes; bufferIndex_ += bytes_to_write;
break; break;
} }
else else
@ -472,10 +486,10 @@ fhandler_dev_dsp::Audio_out::write (const char *pSampleData, int nBytes)
bufferIndex_ += sizeleft; bufferIndex_ += sizeleft;
sendcurrent (); sendcurrent ();
pSampleData += sizeleft; pSampleData += sizeleft;
nBytes -= sizeleft; bytes_to_write -= sizeleft;
} }
} }
return true; return nBytes - bytes_to_write;
} }
void void
@ -511,18 +525,39 @@ fhandler_dev_dsp::Audio_out::callback_sampledone (WAVEHDR *pHdr)
Qisr2app_->send (pHdr); Qisr2app_->send (pHdr);
} }
void bool
fhandler_dev_dsp::Audio_out::waitforspace () fhandler_dev_dsp::Audio_out::waitforspace ()
{ {
WAVEHDR *pHdr; WAVEHDR *pHdr;
MMRESULT rc = WAVERR_STILLPLAYING; MMRESULT rc = WAVERR_STILLPLAYING;
if (pHdr_ != NULL) if (pHdr_ != NULL)
return; return true;
while (!Qisr2app_->recv (&pHdr)) 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"); 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) if (pHdr->dwFlags)
{ {
@ -533,6 +568,7 @@ fhandler_dev_dsp::Audio_out::waitforspace ()
} }
pHdr_ = pHdr; pHdr_ = pHdr;
bufferIndex_ = 0; bufferIndex_ = 0;
return true;
} }
void void
@ -830,7 +866,13 @@ fhandler_dev_dsp::Audio_in::read (char *pSampleData, int &nBytes)
debug_printf ("pSampleData=%08x nBytes=%d", pSampleData, bytes_to_read); debug_printf ("pSampleData=%08x nBytes=%d", pSampleData, bytes_to_read);
while (bytes_to_read != 0) while (bytes_to_read != 0)
{ // Block till next sound has been read { // 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 // Handle gathering our blocks into smaller or larger buffer
int sizeleft = pHdr_->dwBytesRecorded - bufferIndex_; int sizeleft = pHdr_->dwBytesRecorded - bufferIndex_;
@ -863,18 +905,39 @@ fhandler_dev_dsp::Audio_in::read (char *pSampleData, int &nBytes)
return true; return true;
} }
void bool
fhandler_dev_dsp::Audio_in::waitfordata () fhandler_dev_dsp::Audio_in::waitfordata ()
{ {
WAVEHDR *pHdr; WAVEHDR *pHdr;
MMRESULT rc; MMRESULT rc;
if (pHdr_ != NULL) if (pHdr_ != NULL)
return; return true;
while (!Qisr2app_->recv (&pHdr)) 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"); 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 */ if (pHdr->dwFlags) /* Zero if queued following error in queueblock */
{ {
@ -885,6 +948,7 @@ fhandler_dev_dsp::Audio_in::waitfordata ()
} }
pHdr_ = pHdr; pHdr_ = pHdr;
bufferIndex_ = 0; bufferIndex_ = 0;
return true;
} }
void void
@ -1012,7 +1076,7 @@ fhandler_dev_dsp::write (const void *ptr, size_t len)
else if (IS_WRITE ()) else if (IS_WRITE ())
{ {
debug_printf ("Allocating"); debug_printf ("Allocating");
if (!(audio_out_ = new Audio_out)) if (!(audio_out_ = new Audio_out (this)))
return -1; return -1;
/* check for wave file & get parameters & skip header if possible. */ /* check for wave file & get parameters & skip header if possible. */
@ -1036,8 +1100,14 @@ fhandler_dev_dsp::write (const void *ptr, size_t len)
return -1; return -1;
} }
audio_out_->write (ptr_s, len_s); int written = audio_out_->write (ptr_s, len_s);
return len; if (written < 0)
{
if (len - len_s > 0)
return len - len_s;
return -1;
}
return len - len_s + written;
} }
void __stdcall void __stdcall
@ -1052,7 +1122,7 @@ fhandler_dev_dsp::read (void *ptr, size_t& len)
else if (IS_READ ()) else if (IS_READ ())
{ {
debug_printf ("Allocating"); debug_printf ("Allocating");
if (!(audio_in_ = new Audio_in)) if (!(audio_in_ = new Audio_in (this)))
{ {
len = (size_t)-1; len = (size_t)-1;
return; return;