* autoload.cc: Add winmm functions needed by fhandler_dsp.cc.

* fhandler_dsp.cc: New file.  Implements OSS like /dev/dsp.
* include/sys/soundcard.h: New file.  User land includes for OSS /dev/dsp.
* fhandler.h: Add new class fhandler_dev_dsp and a FH_OSS_DSP definition.
* dtable.cc (dtable::build_fhandler): Allow creation of the /dev/dsp device.
* path.cc (windows_device_names): Add /dev/dsp into list of device names.
* Makefile.in (DLL_OFILES): Add fhandler_dsp.o.
This commit is contained in:
Christopher Faylor 2001-04-16 03:27:16 +00:00
parent 9f42525632
commit b0a50cf34c
8 changed files with 1979 additions and 11 deletions

View File

@ -1,3 +1,20 @@
Sun Apr 15 23:23:29 2001 Christopher Faylor <cgf@cygnus.com>
* autoload.cc: Add winmm functions needed by fhandler_dsp.cc.
Sun Apr 15 22:53:52 2001 Andy Younger <andylyounger@hotmail.com>
* fhandler_dsp.cc: New file. Implements OSS like /dev/dsp.
* include/sys/soundcard.h: New file. User land includes for OSS
/dev/dsp.
* fhandler.h: Add new class fhandler_dev_dsp and a FH_OSS_DSP
definition.
* dtable.cc (dtable::build_fhandler): Allow creation of the /dev/dsp
device.
* path.cc (windows_device_names): Add /dev/dsp into list of device
names.
* Makefile.in (DLL_OFILES): Add fhandler_dsp.o.
Sun Apr 15 16:36:27 2001 Christopher Faylor <cgf@cygnus.com>
* uname.c (uname): Default n in in86 to 6 if Windows returns > 6.

View File

@ -114,11 +114,10 @@ EXTRA_OFILES=$(bupdir1)/libiberty/random.o $(bupdir1)/libiberty/strsignal.o
DLL_IMPORTS:=$(w32api_lib)/libkernel32.a
DLL_OFILES:=assert.o autoload.o cygheap.o dcrt0.o debug.o delqueue.o dir.o \
dlfcn.o \
dll_init.o dtable.o environ.o errno.o exceptions.o exec.o external.o \
fcntl.o fhandler.o fhandler_clipboard.o fhandler_console.o \
fhandler_floppy.o fhandler_mem.o fhandler_random.o fhandler_raw.o \
fhandler_serial.o fhandler_socket.o fhandler_tape.o \
dlfcn.o dll_init.o dtable.o environ.o errno.o exceptions.o exec.o \
external.o fcntl.o fhandler.o fhandler_clipboard.o fhandler_console.o \
fhandler_dsp.o fhandler_floppy.o fhandler_mem.o fhandler_random.o \
fhandler_raw.o fhandler_serial.o fhandler_socket.o fhandler_tape.o \
fhandler_termios.o fhandler_tty.o fhandler_windows.o fhandler_zero.o \
fork.o glob.o grp.o heap.o init.o ioctl.o localtime.o malloc.o \
miscfuncs.o mmap.o net.o ntea.o passwd.o path.o pinfo.o pipe.o poll.o \
@ -190,7 +189,7 @@ new-$(LIB_NAME): $(LIB_NAME)
new-$(DLL_NAME): $(DLL_OFILES) $(DEF_FILE) $(DLL_IMPORTS) $(LIBC) $(LIBM) Makefile winver_stamp
$(CXX) $(CXXFLAGS) -nostdlib -Wl,-shared -o $@ -e $(DLL_ENTRY) $(DEF_FILE) $(DLL_OFILES) version.o \
winver.o $(DLL_IMPORTS) $(MALLOC_OBJ) $(LIBM) $(LIBC) -lstdc++ -lshell32 -luuid -lgcc
winver.o $(DLL_IMPORTS) $(MALLOC_OBJ) $(LIBM) $(LIBC) -lstdc++ -lgcc -lshell32 -luuid
dll_ofiles: $(DLL_OFILES)

View File

@ -102,6 +102,8 @@ LoadDLLinitfunc (netapi32)
netapi32_handle = h;
else if (! netapi32_handle)
api_fatal ("could not load netapi32.dll. %d", GetLastError ());
InterlockedDecrement (&here);
return 0;
}
@ -228,19 +230,38 @@ LoadDLLinitfunc (ole32)
LoadDLLinitfunc (kernel32)
{
extern void wsock_init ();
HANDLE h;
if ((h = LoadLibrary ("kernel32.dll")) != NULL)
kernel32_handle = h;
else if (!kernel32_handle)
api_fatal ("could not load wsock32.dll. Is TCP/IP installed?");
api_fatal ("could not load kernel32.dll, %E");
else
return 0; /* Already done by another thread? */
return 0;
}
LoadDLLinitfunc (winmm)
{
HANDLE h;
static NO_COPY LONG here = -1L;
while (InterlockedIncrement (&here))
{
InterlockedDecrement (&here);
Sleep (0);
}
if ((h = LoadLibrary ("winmm.dll")) != NULL)
winmm_handle = h;
else if (! winmm_handle)
api_fatal ("could not load winmm.dll. %d", GetLastError ());
InterlockedDecrement (&here);
return 0;
}
static void __stdcall dummy_autoload (void) __attribute__ ((unused));
static void __stdcall
dummy_autoload (void)
@ -396,5 +417,16 @@ LoadDLLfunc (CoCreateInstance, 20, ole32)
LoadDLLinit (kernel32)
LoadDLLfuncEx (SignalObjectAndWait, 16, kernel32, 1)
LoadDLLinit (winmm)
LoadDLLfuncEx (waveOutGetNumDevs, 0, winmm, 1)
LoadDLLfuncEx (waveOutOpen, 24, winmm, 1)
LoadDLLfuncEx (waveOutReset, 4, winmm, 1)
LoadDLLfuncEx (waveOutClose, 4, winmm, 1)
LoadDLLfuncEx (waveOutGetVolume, 8, winmm, 1)
LoadDLLfuncEx (waveOutSetVolume, 8, winmm, 1)
LoadDLLfuncEx (waveOutUnprepareHeader, 12, winmm, 1)
LoadDLLfuncEx (waveOutPrepareHeader, 12, winmm, 1)
LoadDLLfuncEx (waveOutWrite, 12, winmm, 1)
}
}

View File

@ -316,6 +316,9 @@ dtable::build_fhandler (int fd, DWORD dev, const char *name, int unit)
case FH_CLIPBOARD:
fh = new (buf) fhandler_dev_clipboard (name);
break;
case FH_OSS_DSP:
fh = new (buf) fhandler_dev_dsp (name);
break;
default:
/* FIXME - this could recurse forever */
return build_fhandler (fd, name, NULL);

View File

@ -88,7 +88,7 @@ enum
FH_PIPEW = 0x0000000a, /* write end of a pipe */
FH_SOCKET = 0x0000000b, /* is a socket */
FH_WINDOWS = 0x0000000c, /* is a window */
FH_OSS_DSP = 0x0000000d, /* is the dsp audio device */
FH_SLOW = 0x00000010, /* "slow" device if below this */
/* Fast devices */
@ -941,6 +941,29 @@ public:
int ready_for_read (int fd, DWORD howlong, int ignra);
};
class fhandler_dev_dsp : public fhandler_base
{
private:
int audioformat_;
int audiofreq_;
int audiobits_;
int audiochannels_;
bool setupwav(const char *pData, int nBytes);
public:
fhandler_dev_dsp (const char *name = 0);
~fhandler_dev_dsp();
int open (const char *path, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
int read (void *ptr, size_t len);
int ioctl (unsigned int cmd, void *);
off_t lseek (off_t, int);
int close (void);
int dup (fhandler_base * child);
void dump (void);
};
#if 0
/* You can't do this */
typedef union

View File

@ -0,0 +1,604 @@
/* fhandler_dev_dsp: code to emulate OSS sound model /dev/dsp
Copyright 2001 Red Hat, Inc
Written by Andy Younger (andy@snoogie.demon.co.uk)
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 <errno.h>
#include "cygerrno.h"
#include "fhandler.h"
#include <windows.h>
#include <sys/soundcard.h>
#include <sys/fcntl.h>
#include <mmsystem.h>
//------------------------------------------------------------------------
// Simple encapsulation of the win32 audio device.
//
static void CALLBACK wave_callback(HWAVE hWave, UINT msg, DWORD instance,
DWORD param1, DWORD param2);
class Audio
{
public:
enum { MAX_BLOCKS = 8, BLOCK_SIZE = 16384 };
Audio ();
~Audio ();
bool open (int rate, int bits, int channels, bool bCallback = false);
void close ();
int getvolume ();
void setvolume (int newVolume);
bool write (const void *pSampleData, int nBytes);
int blocks ();
void callback_sampledone (void *pData);
int numbytesoutput ();
private:
char *initialisebuffer ();
void waitforcallback ();
bool flush ();
HWAVEOUT dev_;
volatile int nBlocksInQue_;
int nBytesWritten_;
char *buffer_;
int bufferIndex_;
CRITICAL_SECTION lock_;
char *freeblocks_[MAX_BLOCKS];
char bigwavebuffer_[MAX_BLOCKS * BLOCK_SIZE];
};
Audio::Audio()
{
int size = BLOCK_SIZE + sizeof(WAVEHDR);
InitializeCriticalSection(&lock_);
memset(freeblocks_, 0, sizeof(freeblocks_));
for (int i = 0; i < MAX_BLOCKS; i++)
{
char *pBuffer = &bigwavebuffer_[ i * size ];
memset(pBuffer, 0, size);
freeblocks_[i] = pBuffer;
}
}
Audio::~Audio()
{
if (dev_)
close();
DeleteCriticalSection(&lock_);
}
bool
Audio::open(int rate, int bits, int channels, bool bCallback = false)
{
WAVEFORMATEX format;
int nDevices = waveOutGetNumDevs();
nBytesWritten_ = 0L;
bufferIndex_ = 0;
buffer_ = 0L;
debug_printf("number devices %d\n", nDevices);
if (nDevices <= 0)
return false;
debug_printf("trying to map device freq %d, bits %d, "
"channels %d, callback %d\n", rate, bits, channels,
bCallback);
int bytesperSample = bits / 8;
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 *
bytesperSample;
format.nBlockAlign = format.nChannels * bytesperSample;
nBlocksInQue_ = 0;
HRESULT res = waveOutOpen(&dev_, WAVE_MAPPER, &format, (DWORD)wave_callback,
(DWORD)this, bCallback ? CALLBACK_FUNCTION : 0);
if (res == S_OK)
{
debug_printf("Sucessfully opened!");
return true;
}
else
{
debug_printf("failed to open");
return false;
}
}
void
Audio::close()
{
if (dev_)
{
flush(); // force out last block whatever size..
while (blocks()) // block till finished..
waitforcallback();
waveOutReset(dev_);
waveOutClose(dev_);
dev_ = 0L;
}
nBytesWritten_ = 0L;
}
int
Audio::numbytesoutput()
{
return nBytesWritten_;
}
int
Audio::getvolume()
{
DWORD volume;
waveOutGetVolume(dev_, &volume);
return ((volume >> 16) + (volume & 0xffff)) >> 1;
}
void
Audio::setvolume(int newVolume)
{
waveOutSetVolume(dev_, (newVolume<<16)|newVolume);
}
char *
Audio::initialisebuffer()
{
EnterCriticalSection(&lock_);
WAVEHDR *pHeader = 0L;
for (int i = 0; i < MAX_BLOCKS; i++)
{
char *pData = freeblocks_[i];
if (pData)
{
pHeader = (WAVEHDR *)pData;
if (pHeader->dwFlags & WHDR_DONE)
{
waveOutUnprepareHeader(dev_, pHeader, sizeof(WAVEHDR));
}
freeblocks_[i] = 0L;
break;
}
}
LeaveCriticalSection(&lock_);
if (pHeader)
{
memset(pHeader, 0, sizeof(WAVEHDR));
pHeader->dwBufferLength = BLOCK_SIZE;
pHeader->lpData = (LPSTR)(&pHeader[1]);
return (char *)pHeader->lpData;
}
return 0L;
}
bool
Audio::write(const void *pSampleData, int nBytes)
{
// split up big blocks into smaller BLOCK_SIZE chunks
while (nBytes > BLOCK_SIZE)
{
write(pSampleData, BLOCK_SIZE);
nBytes -= BLOCK_SIZE;
pSampleData = (void *)((char *)pSampleData + BLOCK_SIZE);
}
// Block till next sound is flushed
if (blocks() == MAX_BLOCKS)
waitforcallback();
// Allocate new wave buffer if necessary
if (buffer_ == 0L)
{
buffer_ = initialisebuffer();
if (buffer_ == 0L)
return false;
}
// Handle gathering blocks into larger buffer
int sizeleft = BLOCK_SIZE - bufferIndex_;
if (nBytes < sizeleft)
{
memcpy(&buffer_[bufferIndex_], pSampleData, nBytes);
bufferIndex_ += nBytes;
nBytesWritten_ += nBytes;
return true;
}
// flushing when we reach our limit of BLOCK_SIZE
memcpy(&buffer_[bufferIndex_], pSampleData, sizeleft);
bufferIndex_ += sizeleft;
nBytesWritten_ += sizeleft;
flush();
// change pointer to rest of sample, and size accordingly
pSampleData = (void *)((char *)pSampleData + sizeleft);
nBytes -= sizeleft;
// if we still have some sample left over write it out
if (nBytes)
return write(pSampleData, nBytes);
return true;
}
// return number of blocks back.
int
Audio::blocks()
{
EnterCriticalSection(&lock_);
int ret = nBlocksInQue_;
LeaveCriticalSection(&lock_);
return ret;
}
// This is called on an interupt so use locking.. Note nBlocksInQue_ is
// modified by it so we should wrap all references to it in locks.
void
Audio::callback_sampledone(void *pData)
{
EnterCriticalSection(&lock_);
nBlocksInQue_--;
for (int i = 0; i < MAX_BLOCKS; i++)
if (!freeblocks_[i])
{
freeblocks_[i] = (char *)pData;
break;
}
LeaveCriticalSection(&lock_);
}
void
Audio::waitforcallback()
{
int n = blocks();
if (!n)
return;
do
{
Sleep(250);
}
while (n == blocks());
}
bool
Audio::flush()
{
if (!buffer_)
return false;
// Send internal buffer out to the soundcard
WAVEHDR *pHeader = ((WAVEHDR *)buffer_) - 1;
pHeader->dwBufferLength = bufferIndex_;
if (waveOutPrepareHeader(dev_, pHeader, sizeof(WAVEHDR)) == S_OK &&
waveOutWrite(dev_, pHeader, sizeof (WAVEHDR)) == S_OK)
{
EnterCriticalSection(&lock_);
nBlocksInQue_++;
LeaveCriticalSection(&lock_);
bufferIndex_ = 0;
buffer_ = 0L;
return true;
}
else
{
EnterCriticalSection(&lock_);
for (int i = 0; i < MAX_BLOCKS; i++)
if (!freeblocks_[i])
{
freeblocks_[i] = (char *)pHeader;
break;
}
LeaveCriticalSection(&lock_);
}
return false;
}
//------------------------------------------------------------------------
// Call back routine
static void CALLBACK
wave_callback(HWAVE hWave, UINT msg, DWORD instance, DWORD param1, DWORD param2)
{
if (msg == WOM_DONE)
{
Audio *ptr = (Audio *)instance;
ptr->callback_sampledone((void *)param1);
}
}
//------------------------------------------------------------------------
// /dev/dsp handler
static Audio s_audio; // static instance of the Audio handler
//------------------------------------------------------------------------
// 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::setupwav(const char *pData, int nBytes)
{
int len;
const char *end = pData + nBytes;
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];
pData += 12;
while (len && pData < end)
{
wavchunk *pChunk = (wavchunk *)pData;
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;
// Open up audio device with correct frequency for wav file
//
// FIXME: should through away all the header & not output
// it to the soundcard.
s_audio.close();
if (s_audio.open(format->dwSamplesPerSec, format->wBitsPerSample,
format->wChannels) == false)
{
s_audio.open(audiofreq_, audiobits_, audiochannels_);
}
else
{
audiofreq_ = format->dwSamplesPerSec;
audiobits_ = format->wBitsPerSample;
audiochannels_ = format->wChannels;
}
return true;
}
pData += blklen + sizeof(wavchunk);
}
return false;
}
//------------------------------------------------------------------------
fhandler_dev_dsp::fhandler_dev_dsp (const char *name)
: fhandler_base (FH_OSS_DSP, name)
{
set_cb (sizeof *this);
}
fhandler_dev_dsp::~fhandler_dev_dsp()
{
}
int
fhandler_dev_dsp::open (const char *path, int flags, mode_t mode = 0)
{
// currently we only support writing
if ((flags & (O_WRONLY|O_RDONLY|O_RDWR)) != O_WRONLY)
return 0;
set_flags(flags);
// Work out initial sample format & frequency
if (strcmp(path, "/dev/dsp") == 0L)
{
// dev/dsp defaults
audioformat_ = AFMT_S8;
audiofreq_ = 8000;
audiobits_ = 8;
audiochannels_ = 1;
}
if (s_audio.open(audiofreq_, audiobits_, audiochannels_))
debug_printf("/dev/dsp: successfully opened\n");
else
debug_printf("/dev/dsp: failed to open\n");
return 1;
}
int
fhandler_dev_dsp::write (const void *ptr, size_t len)
{
if (s_audio.numbytesoutput() == 0)
{
// check for wave file & setup frequencys properly if possible.
setupwav((const char *)ptr, len);
// Open audio device properly with callbacks.
s_audio.close();
if (!s_audio.open(audiofreq_, audiobits_, audiochannels_, true))
return 0;
}
s_audio.write(ptr, len);
return len;
}
int
fhandler_dev_dsp::read (void *ptr, size_t len)
{
return len;
}
off_t
fhandler_dev_dsp::lseek (off_t offset, int whence)
{
return 0;
}
int
fhandler_dev_dsp::close (void)
{
s_audio.close();
return 0;
}
int
fhandler_dev_dsp::dup (fhandler_base * child)
{
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;
switch (cmd)
{
#define CASE(a) case a : debug_printf("/dev/dsp: ioctl %s\n", #a);
CASE(SNDCTL_DSP_RESET)
audioformat_ = AFMT_S8;
audiofreq_ = 8000;
audiobits_ = 8;
audiochannels_ = 1;
return 1;
CASE(SNDCTL_DSP_GETBLKSIZE)
*intptr = Audio::BLOCK_SIZE;
break;
CASE(SNDCTL_DSP_SETFMT)
{
int nBits = 0;
if (*intptr == AFMT_S16_LE)
nBits = 16;
else if (*intptr == AFMT_S8)
nBits = 8;
if (nBits)
{
s_audio.close();
if (s_audio.open(audiofreq_, nBits, audiochannels_) == true)
{
audiobits_ = nBits;
return 1;
}
else
{
s_audio.open(audiofreq_, audiobits_, audiochannels_);
return -1;
}
}
} break;
CASE(SNDCTL_DSP_SPEED)
s_audio.close();
if (s_audio.open(*intptr, audiobits_, audiochannels_) == true)
{
audiofreq_ = *intptr;
return 1;
}
else
{
s_audio.open(audiofreq_, audiobits_, audiochannels_);
return -1;
}
break;
CASE(SNDCTL_DSP_STEREO)
{
int nChannels = *intptr + 1;
s_audio.close();
if (s_audio.open(audiofreq_, audiobits_, nChannels) == true)
{
audiochannels_ = nChannels;
return 1;
}
else
{
s_audio.open(audiofreq_, audiobits_, audiochannels_);
return -1;
}
} break;
CASE(SNDCTL_DSP_GETOSPACE)
{
audio_buf_info *p = (audio_buf_info *)ptr;
int nBlocks = s_audio.blocks();
int leftblocks = ((Audio::MAX_BLOCKS - nBlocks)-1);
if (leftblocks < 0) leftblocks = 0;
if (leftblocks > 1)
leftblocks = 1;
int left = leftblocks * Audio::BLOCK_SIZE;
p->fragments = leftblocks;
p->fragstotal = Audio::MAX_BLOCKS;
p->fragsize = Audio::BLOCK_SIZE;
p->bytes = left;
debug_printf("ptr: %p "
"nblocks: %d "
"leftblocks: %d "
"left bytes: %d ", ptr, nBlocks, leftblocks, left);
return 1;
} break;
default:
debug_printf("/dev/dsp: ioctl not handled yet! FIXME:\n");
break;
#undef CASE
};
return -1;
}
void
fhandler_dev_dsp::dump ()
{
paranoid_printf("here, fhandler_dev_dsp");
}

File diff suppressed because it is too large Load Diff

View File

@ -535,8 +535,9 @@ const char *windows_device_names[] =
"\\dev\\pipew",
"\\dev\\socket",
"\\dev\\windows",
NULL, NULL, NULL,
"\\dev\\dsp",
NULL, NULL,
"\\dev\\disk",
"\\dev\\fd%d",
@ -602,6 +603,8 @@ get_device_number (const char *name, int &unit, BOOL from_conv)
devn = FH_PTYM;
else if (deveq ("windows"))
devn = FH_WINDOWS;
else if (deveq ("dsp"))
devn = FH_OSS_DSP;
else if (deveq ("conin"))
devn = FH_CONIN;
else if (deveq ("conout"))