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:
Diffstat (limited to 'winsup/cygwin/fhandler_dsp.cc')
-rw-r--r--winsup/cygwin/fhandler_dsp.cc1527
1 files changed, 0 insertions, 1527 deletions
diff --git a/winsup/cygwin/fhandler_dsp.cc b/winsup/cygwin/fhandler_dsp.cc
deleted file mode 100644
index a2ddef4f2..000000000
--- a/winsup/cygwin/fhandler_dsp.cc
+++ /dev/null
@@ -1,1527 +0,0 @@
-/* fhandler_dev_dsp: code to emulate OSS sound model /dev/dsp
-
- Copyright 2001, 2002, 2003, 2004 Red Hat, Inc
-
- Written by Andy Younger (andy@snoogie.demon.co.uk)
- Extended by Gerd Spalink (Gerd.Spalink@t-online.de)
- to support recording from the audio input
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#include "winsup.h"
-#include <stdio.h>
-#include <windows.h>
-#include <sys/soundcard.h>
-#include <mmsystem.h>
-#include "cygerrno.h"
-#include "security.h"
-#include "path.h"
-#include "fhandler.h"
-
-/*------------------------------------------------------------------------
- Simple encapsulation of the win32 audio device.
-
- Implementation Notes
- 1. Audio buffers are created dynamically 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,
- so that up to 1.5 seconds can be buffered within Win32.
- The buffer size can be queried with the ioctl SNDCTL_DSP_GETBLKSIZE,
- but for this implementation only returns meaningful results if
- sampling rate, number of channels and number of bits per sample
- are not changed afterwards.
-
- 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
- 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
- */
-
-class fhandler_dev_dsp::Audio
-{ // This class contains functionality common to Audio_in and Audio_out
- public:
- 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);
- 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);
- void convert_S16LE_U16BE (unsigned char *buffer, int size_bytes);
- void convert_S16LE_S16BE (unsigned char *buffer, int size_bytes);
- 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_;
-};
-
-class fhandler_dev_dsp::Audio::queue
-{ // non-blocking fixed size queues for buffer management
- public:
- queue (int depth = 4);
- ~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
-
- private:
- int head_;
- int tail_;
- int depth_, depth1_;
- WAVEHDR **storage_;
-};
-
-static void CALLBACK waveOut_callback (HWAVEOUT hWave, UINT msg, DWORD instance,
- DWORD param1, DWORD param2);
-
-class fhandler_dev_dsp::Audio_out: public Audio
-{
- public:
- Audio_out ();
- ~Audio_out ();
-
- bool query (int rate, int bits, int channels);
- bool start (int rate, int bits, int channels);
- 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);
-
- 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
-};
-
-static void CALLBACK waveIn_callback (HWAVEIN hWave, UINT msg, DWORD instance,
- DWORD param1, DWORD param2);
-
-class fhandler_dev_dsp::Audio_in: public Audio
-{
-public:
- Audio_in ();
- ~Audio_in ();
-
- bool query (int rate, int bits, int channels);
- bool start (int rate, int bits, int channels);
- void stop ();
- bool read (char *pSampleData, int &nBytes);
- void buf_info (audio_buf_info *p, int rate, int bits, int channels);
- void callback_blockfull (WAVEHDR *pHdr);
-
-private:
- bool init (unsigned blockSize);
- 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
-};
-
-/* --------------------------------------------------------------------
- Implementation */
-
-// 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_];
-}
-
-fhandler_dev_dsp::Audio::queue::~queue ()
-{
- delete[] storage_;
-}
-
-bool
-fhandler_dev_dsp::Audio::queue::send (WAVEHDR *x)
-{
- if (query () == depth_)
- return false;
- storage_[tail_] = x;
- tail_++;
- if (tail_ == depth1_)
- tail_ = 0;
- return true;
-}
-
-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;
-}
-
-int
-fhandler_dev_dsp::Audio::queue::query ()
-{
- int n = tail_ - head_;
- if (n < 0)
- n += depth1_;
- return n;
-}
-
-// Audio class implements functionality need for both read and write
-fhandler_dev_dsp::Audio::Audio ()
-{
- InitializeCriticalSection (&lock_);
- convert_ = &fhandler_dev_dsp::Audio::convert_none;
- owner_ = 0L;
-}
-
-fhandler_dev_dsp::Audio::~Audio ()
-{
- DeleteCriticalSection (&lock_);
-}
-
-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_);
-}
-
-void
-fhandler_dev_dsp::Audio::setformat (int format)
-{
- switch (format)
- {
- case AFMT_S8:
- convert_ = &fhandler_dev_dsp::Audio::convert_U8_S8;
- debug_printf ("U8_S8");
- break;
- case AFMT_U16_LE:
- convert_ = &fhandler_dev_dsp::Audio::convert_S16LE_U16LE;
- debug_printf ("S16LE_U16LE");
- break;
- case AFMT_U16_BE:
- convert_ = &fhandler_dev_dsp::Audio::convert_S16LE_U16BE;
- debug_printf ("S16LE_U16BE");
- break;
- case AFMT_S16_BE:
- convert_ = &fhandler_dev_dsp::Audio::convert_S16LE_S16BE;
- debug_printf ("S16LE_S16BE");
- break;
- default:
- convert_ = &fhandler_dev_dsp::Audio::convert_none;
- debug_printf ("none");
- }
-}
-
-void
-fhandler_dev_dsp::Audio::convert_U8_S8 (unsigned char *buffer,
- int size_bytes)
-{
- while (size_bytes-- > 0)
- {
- *buffer ^= (unsigned char)0x80;
- buffer++;
- }
-}
-
-void
-fhandler_dev_dsp::Audio::convert_S16LE_U16BE (unsigned char *buffer,
- int size_bytes)
-{
- int size_samples = size_bytes / 2;
- unsigned char hi, lo;
- while (size_samples-- > 0)
- {
- hi = buffer[0];
- lo = buffer[1];
- *buffer++ = lo;
- *buffer++ = hi ^ (unsigned char)0x80;
- }
-}
-
-void
-fhandler_dev_dsp::Audio::convert_S16LE_U16LE (unsigned char *buffer,
- int size_bytes)
-{
- int size_samples = size_bytes / 2;
- while (size_samples-- > 0)
- {
- buffer++;
- *buffer ^= (unsigned char)0x80;
- buffer++;
- }
-}
-
-void
-fhandler_dev_dsp::Audio::convert_S16LE_S16BE (unsigned char *buffer,
- int size_bytes)
-{
- int size_samples = size_bytes / 2;
- unsigned char hi, lo;
- while (size_samples-- > 0)
- {
- hi = buffer[0];
- lo = buffer[1];
- *buffer++ = lo;
- *buffer++ = hi;
- }
-}
-
-void
-fhandler_dev_dsp::Audio::fillFormat (WAVEFORMATEX * format,
- int rate, int bits, int channels)
-{
- memset (format, 0, sizeof (*format));
- format->wFormatTag = WAVE_FORMAT_PCM;
- format->wBitsPerSample = bits;
- format->nChannels = channels;
- format->nSamplesPerSec = rate;
- format->nAvgBytesPerSec = format->nSamplesPerSec * format->nChannels
- * (bits / 8);
- format->nBlockAlign = format->nChannels * (bits / 8);
-}
-
-// calculate a good block size
-unsigned
-fhandler_dev_dsp::Audio::blockSize (int rate, int bits, int channels)
-{
- unsigned blockSize;
- blockSize = ((bits / 8) * channels * rate) / 8; // approx 125ms per block
- // round up to multiple of 64
- blockSize += 0x3f;
- blockSize &= ~0x3f;
- return blockSize;
-}
-
-//=======================================================================
-fhandler_dev_dsp::Audio_out::Audio_out (): Audio ()
-{
- bigwavebuffer_ = NULL;
- Qisr2app_ = new queue (MAX_BLOCKS);
- Qapp2app_ = new queue (MAX_BLOCKS);
-}
-
-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)
-{
- WAVEFORMATEX format;
- MMRESULT rc;
-
- 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");
- return (rc == MMSYSERR_NOERROR);
-}
-
-bool
-fhandler_dev_dsp::Audio_out::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 = waveOutGetNumDevs ();
- debug_printf ("number devices=%d, blocksize=%d", nDevices, bSize);
- if (nDevices <= 0)
- return false;
-
- fillFormat (&format, rate, bits, channels);
- rc = waveOutOpen (&dev_, WAVE_MAPPER, &format, (DWORD) waveOut_callback,
- (DWORD) this, CALLBACK_FUNCTION);
- if (rc == MMSYSERR_NOERROR)
- {
- setOwner ();
- init (bSize);
- }
-
- debug_printf ("freq=%d bits=%d channels=%d %s", rate, bits, channels,
- (rc != MMSYSERR_NOERROR) ? "FAIL" : "OK");
-
- return (rc == MMSYSERR_NOERROR);
-}
-
-void
-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 ())
- {
- if (!immediately)
- {
- sendcurrent (); // force out last block whatever size..
- waitforallsent (); // block till finished..
- }
-
- rc = waveOutReset (dev_);
- debug_printf ("waveOutReset rc=%d", rc);
- do
- {
- 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");
- }
- }
- while (gotblock);
- while (Qapp2app_->recv (&pHdr))
- /* flush queue */;
-
- rc = waveOutClose (dev_);
- debug_printf ("waveOutClose rc=%d", rc);
-
- clearOwner ();
-
- if (bigwavebuffer_)
- {
- delete[] bigwavebuffer_;
- bigwavebuffer_ = NULL;
- }
- }
-}
-
-void
-fhandler_dev_dsp::Audio_out::init (unsigned blockSize)
-{
- int i;
-
- // internally queue all of our buffer for later use by write
- for (i = 0; i < MAX_BLOCKS; i++)
- {
- wavehdr_[i].lpData = &bigwavebuffer_[i * blockSize];
- (int)wavehdr_[i].dwUser = blockSize;
- if (!Qapp2app_->send (&wavehdr_[i]))
- {
- debug_printf ("Internal Error i=%d", i);
- break; // should not happen
- }
- }
- pHdr_ = NULL;
-}
-
-bool
-fhandler_dev_dsp::Audio_out::write (const char *pSampleData, int nBytes)
-{
- while (nBytes != 0)
- { // Block if all blocks used until at least one is free
- waitforspace ();
-
- int sizeleft = (int)pHdr_->dwUser - bufferIndex_;
- if (nBytes < sizeleft)
- { // all data fits into the current block, with some space left
- memcpy (&pHdr_->lpData[bufferIndex_], pSampleData, nBytes);
- bufferIndex_ += nBytes;
- break;
- }
- else
- { // data will fill up the current block
- memcpy (&pHdr_->lpData[bufferIndex_], pSampleData, sizeleft);
- bufferIndex_ += sizeleft;
- sendcurrent ();
- pSampleData += sizeleft;
- nBytes -= sizeleft;
- }
- }
- 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 ())
- {
- p->fragments = emptyblocks ();
- if (pHdr_ != NULL)
- p->bytes = (int)pHdr_->dwUser - bufferIndex_
- + p->fragsize * p->fragments;
- else
- p->bytes = p->fragsize * p->fragments;
- }
- else
- {
- p->fragments = MAX_BLOCKS;
- p->bytes = p->fragsize * p->fragments;
- }
-}
-
-/* This is called on an interupt so use locking.. Note Qisr2app_
- is used so we should wrap all references to it in locks. */
-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)
- {
- 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);
- }
- }
- pHdr_ = pHdr;
- bufferIndex_ = 0;
-}
-
-void
-fhandler_dev_dsp::Audio_out::waitforallsent ()
-{
- while (emptyblocks () != MAX_BLOCKS)
- {
- debug_printf ("100ms Qisr=%d Qapp=%d",
- Qisr2app_->query (), Qapp2app_->query ());
- Sleep (100);
- }
-}
-
-// send the block described by pHdr_ and bufferIndex_ to wave device
-bool
-fhandler_dev_dsp::Audio_out::sendcurrent ()
-{
- WAVEHDR *pHdr = pHdr_;
- if (pHdr_ == NULL)
- return false;
- pHdr_ = NULL;
-
- // Sample buffer conversion
- (this->*convert_) ((unsigned char *)pHdr->lpData, bufferIndex_);
-
- // 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
- {
- debug_printf ("waveOutPrepareHeader failed");
- Qapp2app_->send (pHdr);
- }
- return false;
-}
-
-//------------------------------------------------------------------------
-// Call back routine
-static void CALLBACK
-waveOut_callback (HWAVEOUT hWave, UINT msg, DWORD instance, DWORD param1,
- DWORD param2)
-{
- if (msg == WOM_DONE)
- {
- fhandler_dev_dsp::Audio_out *ptr =
- (fhandler_dev_dsp::Audio_out *) instance;
- ptr->callback_sampledone ((WAVEHDR *) param1);
- }
-}
-
-//------------------------------------------------------------------------
-// wav file detection..
-#pragma pack(1)
-struct wavchunk
-{
- char id[4];
- unsigned int len;
-};
-struct wavformat
-{
- unsigned short wFormatTag;
- unsigned short wChannels;
- unsigned int dwSamplesPerSec;
- unsigned int dwAvgBytesPerSec;
- unsigned short wBlockAlign;
- unsigned short wBitsPerSample;
-};
-#pragma pack()
-
-bool
-fhandler_dev_dsp::Audio_out::parsewav (const char * &pData, int &nBytes,
- int &rate, int &bits, int &channels)
-{
- int len;
- const char *end = pData + nBytes;
- const char *pDat;
- int skip = 0;
- // Check alignment first: A lot of the code below depends on it
- if (((int)pData & 0x3) != 0)
- return false;
- if (!(pData[0] == 'R' && pData[1] == 'I'
- && pData[2] == 'F' && pData[3] == 'F'))
- return false;
- if (!(pData[8] == 'W' && pData[9] == 'A'
- && pData[10] == 'V' && pData[11] == 'E'))
- return false;
-
- len = *(int *) &pData[4];
- len -= 12;
- pDat = pData + 12;
- skip = 12;
- while ((len > 0) && (pDat + sizeof (wavchunk) < end))
- { /* We recognize two kinds of wavchunk:
- "fmt " for the PCM parameters (only PCM supported here)
- "data" for the start of PCM data */
- wavchunk * pChunk = (wavchunk *) pDat;
- int blklen = pChunk-> len;
- if (pChunk->id[0] == 'f' && pChunk->id[1] == 'm'
- && pChunk->id[2] == 't' && pChunk->id[3] == ' ')
- {
- wavformat *format = (wavformat *) (pChunk + 1);
- if ((char *) (format + 1) >= end)
- return false;
- // We have found the parameter chunk
- if (format->wFormatTag == 0x0001)
- { // Micr*s*ft PCM; check if parameters work with our device
- if (query (format->dwSamplesPerSec, format->wBitsPerSample,
- format->wChannels))
- { // return the parameters we found
- rate = format->dwSamplesPerSec;
- bits = format->wBitsPerSample;
- channels = format->wChannels;
- }
- }
- }
- else
- {
- if (pChunk->id[0] == 'd' && pChunk->id[1] == 'a'
- && pChunk->id[2] == 't' && pChunk->id[3] == 'a')
- { // throw away all the header & not output it to the soundcard.
- skip += sizeof (wavchunk);
- debug_printf ("Discard %d bytes wave header", skip);
- pData += skip;
- nBytes -= skip;
- return true;
- }
- }
- pDat += blklen + sizeof (wavchunk);
- skip += blklen + sizeof (wavchunk);
- len -= blklen + sizeof (wavchunk);
- }
- return false;
-}
-
-/* ========================================================================
- Buffering concept for Audio_in:
- On the first read, we queue all blocks of our bigwavebuffer
- 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().
- 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
- to the wave-in device immediately.
- 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 ()
-{
- stop ();
- delete Qapp2app_;
- delete Qisr2app_;
-}
-
-bool
-fhandler_dev_dsp::Audio_in::query (int rate, int bits, int channels)
-{
- WAVEFORMATEX format;
- MMRESULT rc;
-
- 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");
- return (rc == MMSYSERR_NOERROR);
-}
-
-bool
-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)
- return false;
-
- fillFormat (&format, rate, bits, channels);
- rc = waveInOpen (&dev_, WAVE_MAPPER, &format, (DWORD) waveIn_callback,
- (DWORD) this, CALLBACK_FUNCTION);
- if (rc == MMSYSERR_NOERROR)
- {
- setOwner ();
- if (!init (bSize))
- {
- stop ();
- return false;
- }
- }
-
- debug_printf ("freq=%d bits=%d channels=%d %s", rate, bits, channels,
- (rc != MMSYSERR_NOERROR) ? "FAIL" : "OK");
-
- return (rc == MMSYSERR_NOERROR);
-}
-
-void
-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 ())
- {
- 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);
-
- do
- {
- 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");
- }
- }
- while (gotblock);
- while (Qapp2app_->recv (&pHdr))
- /* flush queue */;
-
- rc = waveInClose (dev_);
- debug_printf ("waveInClose rc=%d", rc);
-
- clearOwner ();
-
- if (bigwavebuffer_)
- {
- delete[] bigwavebuffer_;
- bigwavebuffer_ = NULL;
- }
- }
-}
-
-bool
-fhandler_dev_dsp::Audio_in::queueblock (WAVEHDR *pHdr)
-{
- MMRESULT rc;
- pHdr->dwFlags = 0;
- rc = waveInPrepareHeader (dev_, pHdr, sizeof (WAVEHDR));
- 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);
-}
-
-bool
-fhandler_dev_dsp::Audio_in::init (unsigned blockSize)
-{
- MMRESULT rc;
- int i;
-
- // try to queue all of our buffer for reception
- for (i = 0; i < MAX_BLOCKS; i++)
- {
- wavehdr_[i].lpData = &bigwavebuffer_[i * blockSize];
- wavehdr_[i].dwBufferLength = blockSize;
- if (!queueblock (&wavehdr_[i]))
- break;
- }
- pHdr_ = NULL;
- rc = waveInStart (dev_);
- debug_printf ("waveInStart=%d %s queued=%d",
- rc, (rc != MMSYSERR_NOERROR) ? "FAIL" : "OK", i);
- return (rc == MMSYSERR_NOERROR);
-}
-
-bool
-fhandler_dev_dsp::Audio_in::read (char *pSampleData, int &nBytes)
-{
- int bytes_to_read = nBytes;
- nBytes = 0;
- debug_printf ("pSampleData=%08x nBytes=%d", pSampleData, bytes_to_read);
- while (bytes_to_read != 0)
- { // Block till next sound has been read
- waitfordata ();
-
- // Handle gathering our blocks into smaller or larger buffer
- int sizeleft = pHdr_->dwBytesRecorded - bufferIndex_;
- if (bytes_to_read < sizeleft)
- { // The current buffer holds more data than requested
- memcpy (pSampleData, &pHdr_->lpData[bufferIndex_], bytes_to_read);
- (this->*convert_) ((unsigned char *)pSampleData, bytes_to_read);
- nBytes += bytes_to_read;
- bufferIndex_ += bytes_to_read;
- debug_printf ("got %d", bytes_to_read);
- break; // done; use remaining data in next call to read
- }
- else
- { // not enough or exact amount in the current buffer
- if (sizeleft)
- { // use up what we have
- memcpy (pSampleData, &pHdr_->lpData[bufferIndex_], sizeleft);
- (this->*convert_) ((unsigned char *)pSampleData, sizeleft);
- nBytes += sizeleft;
- bytes_to_read -= sizeleft;
- pSampleData += sizeleft;
- debug_printf ("got %d", sizeleft);
- }
- queueblock (pHdr_); // re-queue this block to ISR
- pHdr_ = NULL; // need to wait for a new block
- // if more samples are needed, we need a new block now
- }
- }
- debug_printf ("end nBytes=%d", nBytes);
- return true;
-}
-
-void
-fhandler_dev_dsp::Audio_in::waitfordata ()
-{
- WAVEHDR *pHdr;
- bool gotblock;
- MMRESULT rc;
-
- if (pHdr_ != NULL)
- return;
- while (Qapp2app_->recv (&pHdr) == false)
- {
- 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);
- }
- }
- pHdr_ = pHdr;
- bufferIndex_ = 0;
-}
-
-void
-fhandler_dev_dsp::Audio_in::buf_info (audio_buf_info *p,
- int rate, int bits, int channels)
-{
- p->fragstotal = MAX_BLOCKS;
- p->fragsize = blockSize (rate, bits, channels);
- if (getOwner ())
- {
- lock ();
- p->fragments = Qisr2app_->query ();
- unlock ();
- p->fragments += Qapp2app_->query ();
- if (pHdr_ != NULL)
- p->bytes = pHdr_->dwBytesRecorded - bufferIndex_
- + p->fragsize * p->fragments;
- else
- p->bytes = p->fragsize * p->fragments;
- }
- else
- {
- p->fragments = 0;
- p->bytes = 0;
- }
-}
-
-// This is called on an interrupt so use locking..
-void
-fhandler_dev_dsp::Audio_in::callback_blockfull (WAVEHDR *pHdr)
-{
- lock ();
- Qisr2app_->send (pHdr);
- unlock ();
-}
-
-static void CALLBACK
-waveIn_callback (HWAVEIN hWave, UINT msg, DWORD instance, DWORD param1,
- DWORD param2)
-{
- if (msg == WIM_DATA)
- {
- fhandler_dev_dsp::Audio_in *ptr =
- (fhandler_dev_dsp::Audio_in *) instance;
- ptr->callback_blockfull ((WAVEHDR *) param1);
- }
-}
-
-
-/* ------------------------------------------------------------------------
- /dev/dsp handler
- ------------------------------------------------------------------------
- instances of the handler statics */
-int fhandler_dev_dsp::open_count = 0;
-
-fhandler_dev_dsp::fhandler_dev_dsp ():
- fhandler_base ()
-{
- debug_printf ("0x%08x", (int)this);
- audio_in_ = NULL;
- 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)
- {
- set_errno (EBUSY);
- return 0;
- }
- set_flags ((flags & ~O_TEXT) | O_BINARY);
- // Work out initial sample format & frequency, /dev/dsp defaults
- audioformat_ = AFMT_U8;
- audiofreq_ = 8000;
- audiobits_ = 8;
- audiochannels_ = 1;
- switch (flags & O_ACCMODE)
- {
- case O_WRONLY:
- audio_out_ = new Audio_out;
- if (!audio_out_->query (audiofreq_, audiobits_, audiochannels_))
- {
- delete audio_out_;
- audio_out_ = NULL;
- }
- 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;
- }
- break;
- default:
- set_errno (EINVAL);
- return 0;
- } // switch (flags & O_ACCMODE)
- int rc;
- if (audio_in_ || audio_out_)
- { /* All tried query () succeeded */
- rc = 1;
- set_open_status ();
- need_fork_fixup (true);
- close_on_exec (true);
- }
- 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;
-}
-
-#define RETURN_ERROR_WHEN_BUSY(audio)\
- if ((audio)->denyAccess ()) \
- {\
- set_errno (EBUSY);\
- return -1;\
- }
-
-int
-fhandler_dev_dsp::write (const void *ptr, size_t 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_)
- {
- set_errno (EACCES); // device was opened for read?
- 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;
-}
-
-void __stdcall
-fhandler_dev_dsp::read (void *ptr, size_t& len)
-{
- debug_printf ("ptr=%08x len=%d", ptr, len);
- if (!audio_in_)
- {
- len = (size_t)-1;
- set_errno (EACCES); // device was opened for write?
- return;
- }
- if (audio_in_->denyAccess ())
- {
- len = (size_t)-1;
- set_errno (EBUSY);
- 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;
-}
-
-_off64_t
-fhandler_dev_dsp::lseek (_off64_t offset, int whence)
-{
- return 0;
-}
-
-int
-fhandler_dev_dsp::close (void)
-{
- debug_printf ("audio_in=%08x audio_out=%08x",
- (int)audio_in_, (int)audio_out_);
- if (audio_in_)
- {
- delete audio_in_;
- audio_in_ = NULL;
- }
- if (audio_out_)
- {
- delete audio_out_;
- audio_out_ = NULL;
- }
- if (open_count > 0)
- open_count--;
- return 0;
-}
-
-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_;
- 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_);
- 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;
- break;
-
- CASE (SNDCTL_DSP_GETBLKSIZE)
- if (audio_out_)
- {
- *intptr = audio_out_->blockSize (audiofreq_,
- audiobits_,
- audiochannels_);
- }
- else
- { // I am very sure that audio_in_ is valid
- *intptr = audio_in_->blockSize (audiofreq_,
- audiobits_,
- audiochannels_);
- }
- return 0;
- break;
-
- CASE (SNDCTL_DSP_SETFMT)
- {
- int nBits;
- switch (*intptr)
- {
- case AFMT_QUERY:
- *intptr = audioformat_;
- return 0;
- break;
- case AFMT_U16_BE:
- case AFMT_U16_LE:
- case AFMT_S16_BE:
- case AFMT_S16_LE:
- nBits = 16;
- break;
- case AFMT_U8:
- case AFMT_S8:
- nBits = 8;
- break;
- default:
- nBits = 0;
- }
- if (nBits && audio_out_)
- {
- RETURN_ERROR_WHEN_BUSY (audio_out_);
- audio_out_->stop ();
- audio_out_->setformat (*intptr);
- if (audio_out_->query (audiofreq_, nBits, audiochannels_))
- {
- audiobits_ = nBits;
- audioformat_ = *intptr;
- }
- else
- {
- *intptr = audiobits_;
- return -1;
- }
- }
- if (nBits && audio_in_)
- {
- RETURN_ERROR_WHEN_BUSY (audio_in_);
- audio_in_->stop ();
- audio_in_->setformat (*intptr);
- if (audio_in_->query (audiofreq_, nBits, audiochannels_))
- {
- audiobits_ = nBits;
- audioformat_ = *intptr;
- }
- else
- {
- *intptr = audiobits_;
- return -1;
- }
- }
- return 0;
- }
- break;
-
- CASE (SNDCTL_DSP_SPEED)
- {
- if (audio_out_)
- {
- RETURN_ERROR_WHEN_BUSY (audio_out_);
- audio_out_->stop ();
- if (audio_out_->query (*intptr, audiobits_, audiochannels_))
- audiofreq_ = *intptr;
- else
- {
- *intptr = audiofreq_;
- return -1;
- }
- }
- if (audio_in_)
- {
- RETURN_ERROR_WHEN_BUSY (audio_in_);
- audio_in_->stop ();
- if (audio_in_->query (*intptr, audiobits_, audiochannels_))
- audiofreq_ = *intptr;
- else
- {
- *intptr = audiofreq_;
- return -1;
- }
- }
- 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;
- }
- break;
-
- CASE (SNDCTL_DSP_CHANNELS)
- {
- int nChannels = *intptr;
-
- if (audio_out_)
- {
- RETURN_ERROR_WHEN_BUSY (audio_out_);
- audio_out_->stop ();
- if (audio_out_->query (audiofreq_, audiobits_, nChannels))
- audiochannels_ = nChannels;
- else
- {
- *intptr = audiochannels_;
- 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_;
- return -1;
- }
- }
- return 0;
- }
- break;
-
- CASE (SNDCTL_DSP_GETOSPACE)
- {
- audio_buf_info *p = (audio_buf_info *) ptr;
- if (audio_out_)
- {
- 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);
- }
- return 0;
- }
- break;
-
- CASE (SNDCTL_DSP_GETISPACE)
- {
- audio_buf_info *p = (audio_buf_info *) ptr;
- if (audio_in_)
- {
- 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);
- }
- 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 ();
- }
- return 0;
- }
- break;
-
- default:
- debug_printf ("/dev/dsp: ioctl 0x%08x not handled yet! FIXME:", cmd);
- break;
-
-#undef CASE
- };
- set_errno (EINVAL);
- return -1;
-}
-
-void
-fhandler_dev_dsp::dump ()
-{
- paranoid_printf ("here");
-}
-
-void
-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_ )
- audio_in_ ->fork_fixup (parent);
- if (audio_out_)
- audio_out_->fork_fixup (parent);
-}
-
-void
-fhandler_dev_dsp::fixup_after_exec ()
-{
- debug_printf ("audio_in=%08x audio_out=%08x",
- (int)audio_in_, (int)audio_out_);
-}
-
-