| /* |
| * Sample Wine Driver for Linux |
| * |
| * Copyright 1994 Martin Ayotte |
| */ |
| |
| #ifndef WINELIB |
| #define BUILTIN_MMSYSTEM |
| #endif |
| |
| #ifdef BUILTIN_MMSYSTEM |
| |
| #define EMULATE_SB16 |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <sys/ioctl.h> |
| #include "windows.h" |
| #include "user.h" |
| #include "driver.h" |
| #include "mmsystem.h" |
| #include "ldt.h" |
| #include "stackframe.h" |
| |
| #ifdef linux |
| #include <linux/soundcard.h> |
| #endif |
| |
| #include "stddebug.h" |
| #include "debug.h" |
| |
| #ifdef linux |
| #define SOUND_DEV "/dev/dsp" |
| |
| #ifdef SOUND_VERSION |
| #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0)) |
| #else |
| #define IOCTL(a,b,c) (c = ioctl(a,b,c) ) |
| #endif |
| |
| #define MAX_WAVOUTDRV 2 |
| #define MAX_WAVINDRV 2 |
| #define MAX_MCIWAVDRV 2 |
| |
| typedef struct { |
| int unixdev; |
| int state; |
| DWORD bufsize; |
| WAVEOPENDESC waveDesc; |
| WORD wFlags; |
| PCMWAVEFORMAT Format; |
| LPWAVEHDR lpQueueHdr; |
| DWORD dwTotalPlayed; |
| } LINUX_WAVEOUT; |
| |
| typedef struct { |
| int unixdev; |
| int state; |
| DWORD bufsize; /* Linux '/dev/dsp' give us that size */ |
| WAVEOPENDESC waveDesc; |
| WORD wFlags; |
| PCMWAVEFORMAT Format; |
| LPWAVEHDR lpQueueHdr; |
| DWORD dwTotalRecorded; |
| } LINUX_WAVEIN; |
| |
| typedef struct { |
| int nUseCount; /* Incremented for each shared open */ |
| BOOL fShareable; /* TRUE if first open was shareable */ |
| WORD wNotifyDeviceID; /* MCI device ID with a pending notification */ |
| HANDLE hCallback; /* Callback handle for pending notification */ |
| HMMIO hFile; /* mmio file handle open as Element */ |
| MCI_WAVE_OPEN_PARMS openParms; |
| PCMWAVEFORMAT WaveFormat; |
| WAVEHDR WaveHdr; |
| } LINUX_MCIWAVE; |
| |
| static LINUX_WAVEOUT WOutDev[MAX_WAVOUTDRV]; |
| static LINUX_WAVEIN WInDev[MAX_WAVOUTDRV]; |
| static LINUX_MCIWAVE MCIWavDev[MAX_MCIWAVDRV]; |
| |
| |
| /************************************************************************** |
| * WAVE_NotifyClient [internal] |
| */ |
| static DWORD WAVE_NotifyClient(UINT wDevID, WORD wMsg, |
| DWORD dwParam1, DWORD dwParam2) |
| { |
| if (WInDev[wDevID].wFlags != DCB_NULL && !DriverCallback( |
| WInDev[wDevID].waveDesc.dwCallBack, WInDev[wDevID].wFlags, |
| WInDev[wDevID].waveDesc.hWave, wMsg, |
| WInDev[wDevID].waveDesc.dwInstance, dwParam1, dwParam2)) { |
| dprintf_mciwave(stddeb,"WAVE_NotifyClient // can't notify client !\n"); |
| return MMSYSERR_NOERROR; |
| } |
| return 0; |
| } |
| |
| |
| /************************************************************************** |
| * WAVE_mciOpen */ |
| static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMS lpParms) |
| { |
| HANDLE hFormat; |
| LPPCMWAVEFORMAT lpWaveFormat; |
| HANDLE hDesc; |
| LPWAVEOPENDESC lpDesc; |
| LPSTR lpstrElementName; |
| DWORD dwRet; |
| char str[128]; |
| |
| dprintf_mciwave(stddeb,"WAVE_mciOpen(%04X, %08lX, %p)\n", |
| wDevID, dwFlags, lpParms); |
| if (lpParms == NULL) return MCIERR_INTERNAL; |
| dprintf_mciwave(stddeb,"WAVE_mciOpen // wDevID=%04X\n", wDevID); |
| if (MCIWavDev[wDevID].nUseCount > 0) { |
| /* The driver already open on this channel */ |
| /* If the driver was opened shareable before and this open specifies */ |
| /* shareable then increment the use count */ |
| if (MCIWavDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE)) |
| ++MCIWavDev[wDevID].nUseCount; |
| else |
| return MCIERR_MUST_USE_SHAREABLE; |
| } |
| else { |
| MCIWavDev[wDevID].nUseCount = 1; |
| MCIWavDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE; |
| } |
| dprintf_mciwave(stddeb,"WAVE_mciOpen // before setting lParams->wDeviceID // winstack=%p ds=%04X ss=%04X sp=%04X\n", |
| (BYTE *)CURRENT_STACK16->args, |
| CURRENT_STACK16->ds, IF1632_Saved16_ss, IF1632_Saved16_sp); |
| lpParms->wDeviceID = wDevID; |
| dprintf_mciwave(stddeb,"WAVE_mciOpen // wDevID=%04X\n", wDevID); |
| dprintf_mciwave(stddeb,"WAVE_mciOpen // before OPEN_ELEMENT\n"); |
| if (dwFlags & MCI_OPEN_ELEMENT) { |
| lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(lpParms->lpstrElementName); |
| dprintf_mciwave(stddeb,"WAVE_mciOpen // MCI_OPEN_ELEMENT '%s' !\n", |
| lpstrElementName); |
| if (strlen(lpstrElementName) > 0) { |
| strcpy(str, lpstrElementName); |
| AnsiUpper(str); |
| MCIWavDev[wDevID].hFile = mmioOpen(str, NULL, |
| MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE); |
| if (MCIWavDev[wDevID].hFile == 0) { |
| dprintf_mciwave(stddeb,"WAVE_mciOpen // can't find file='%s' !\n", str); |
| return MCIERR_FILE_NOT_FOUND; |
| } |
| } |
| else |
| MCIWavDev[wDevID].hFile = 0; |
| } |
| dprintf_mciwave(stddeb,"WAVE_mciOpen // hFile=%u\n", MCIWavDev[wDevID].hFile); |
| memcpy(&MCIWavDev[wDevID].openParms, lpParms, sizeof(MCI_WAVE_OPEN_PARMS)); |
| MCIWavDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID; |
| lpWaveFormat = &MCIWavDev[wDevID].WaveFormat; |
| hDesc = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC)); |
| lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hDesc); |
| lpDesc->hWave = 0; |
| /* |
| lpWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM; |
| lpWaveFormat->wBitsPerSample = 8; |
| lpWaveFormat->wf.nChannels = 1; |
| lpWaveFormat->wf.nSamplesPerSec = 11025; |
| lpWaveFormat->wf.nAvgBytesPerSec = 11025; |
| lpWaveFormat->wf.nBlockAlign = 1; |
| */ |
| if (MCIWavDev[wDevID].hFile != 0) { |
| MMCKINFO mmckInfo; |
| MMCKINFO ckMainRIFF; |
| if (mmioDescend(MCIWavDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0) { |
| return MCIERR_INTERNAL; |
| } |
| dprintf_mciwave(stddeb, |
| "WAVE_mciOpen // ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n", |
| (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, |
| ckMainRIFF.cksize); |
| if ((ckMainRIFF.ckid != FOURCC_RIFF) || |
| (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) { |
| return MCIERR_INTERNAL; |
| } |
| mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' '); |
| if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) { |
| return MCIERR_INTERNAL; |
| } |
| dprintf_mciwave(stddeb, |
| "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n", |
| (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, |
| mmckInfo.cksize); |
| if (mmioRead(MCIWavDev[wDevID].hFile, (HPSTR) lpWaveFormat, |
| (long) sizeof(PCMWAVEFORMAT)) != (long) sizeof(PCMWAVEFORMAT)) { |
| return MCIERR_INTERNAL; |
| } |
| mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a'); |
| if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) { |
| return MCIERR_INTERNAL; |
| } |
| dprintf_mciwave(stddeb, |
| "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n", |
| (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, |
| mmckInfo.cksize); |
| dprintf_mciwave(stddeb, |
| "WAVE_mciOpen // nChannels=%d nSamplesPerSec=%ld\n", |
| lpWaveFormat->wf.nChannels, lpWaveFormat->wf.nSamplesPerSec); |
| lpWaveFormat->wBitsPerSample = 0; |
| } |
| lpWaveFormat->wf.nAvgBytesPerSec = |
| lpWaveFormat->wf.nSamplesPerSec * lpWaveFormat->wf.nBlockAlign; |
| hFormat = USER_HEAP_ALLOC(sizeof(PCMWAVEFORMAT)); |
| lpDesc->lpFormat = (LPWAVEFORMAT) USER_HEAP_LIN_ADDR(hFormat); |
| memcpy(lpDesc->lpFormat, lpWaveFormat, sizeof(PCMWAVEFORMAT)); |
| lpDesc = (LPWAVEOPENDESC) USER_HEAP_SEG_ADDR(hDesc); |
| dwRet = wodMessage(0, WODM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL); |
| dwRet = widMessage(0, WIDM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL); |
| USER_HEAP_FREE(hFormat); |
| USER_HEAP_FREE(hDesc); |
| return 0; |
| } |
| |
| /************************************************************************** |
| * WAVE_mciClose [internal] |
| */ |
| static DWORD WAVE_mciClose(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms) |
| { |
| DWORD dwRet; |
| dprintf_mciwave(stddeb, |
| "WAVE_mciClose(%u, %08lX, %p);\n", wDevID, dwParam, lpParms); |
| MCIWavDev[wDevID].nUseCount--; |
| if (MCIWavDev[wDevID].nUseCount == 0) { |
| if (MCIWavDev[wDevID].hFile != 0) { |
| mmioClose(MCIWavDev[wDevID].hFile, 0); |
| MCIWavDev[wDevID].hFile = 0; |
| } |
| dwRet = wodMessage(0, WODM_CLOSE, 0, 0L, 0L); |
| if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL; |
| dwRet = widMessage(0, WIDM_CLOSE, 0, 0L, 0L); |
| if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL; |
| } |
| return 0; |
| } |
| |
| |
| /************************************************************************** |
| * WAVE_mciPlay [internal] |
| */ |
| static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms) |
| { |
| int start, end; |
| LONG bufsize, count; |
| HANDLE hData; |
| HANDLE hWaveHdr; |
| LPWAVEHDR lpWaveHdr; |
| LPWAVEHDR lp16WaveHdr; |
| DWORD dwRet; |
| dprintf_mciwave(stddeb, |
| "WAVE_mciPlay(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); |
| if (MCIWavDev[wDevID].hFile == 0) { |
| dprintf_mciwave(stddeb,"WAVE_mciPlay // can't find file='%s' !\n", |
| MCIWavDev[wDevID].openParms.lpstrElementName); |
| return MCIERR_FILE_NOT_FOUND; |
| } |
| start = 1; end = 99999; |
| if (dwFlags & MCI_FROM) { |
| start = lpParms->dwFrom; |
| dprintf_mciwave(stddeb, |
| "WAVE_mciPlay // MCI_FROM=%d \n", start); |
| } |
| if (dwFlags & MCI_TO) { |
| end = lpParms->dwTo; |
| dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_TO=%d \n", end); |
| } |
| #if 0 |
| if (dwFlags & MCI_NOTIFY) { |
| dprintf_mciwave(stddeb, |
| "WAVE_mciPlay // MCI_NOTIFY %08lX !\n", lpParms->dwCallback); |
| switch(fork()) { |
| case -1: |
| dprintf_mciwave(stddeb, |
| "WAVE_mciPlay // Can't 'fork' process !\n"); |
| break; |
| case 0: |
| break; |
| default: |
| dprintf_mciwave(stddeb,"WAVE_mciPlay // process started ! return to caller...\n"); |
| return 0; |
| } |
| } |
| #endif |
| bufsize = 64000; |
| lpWaveHdr = &MCIWavDev[wDevID].WaveHdr; |
| hData = GlobalAlloc(GMEM_MOVEABLE, bufsize); |
| lpWaveHdr->lpData = (LPSTR) WIN16_GlobalLock(hData); |
| lpWaveHdr->dwUser = 0L; |
| lpWaveHdr->dwFlags = 0L; |
| lpWaveHdr->dwLoops = 0L; |
| hWaveHdr = USER_HEAP_ALLOC(sizeof(WAVEHDR)); |
| lp16WaveHdr = (LPWAVEHDR) USER_HEAP_SEG_ADDR(hWaveHdr); |
| memcpy(PTR_SEG_TO_LIN(lp16WaveHdr), lpWaveHdr, sizeof(WAVEHDR)); |
| lpWaveHdr = PTR_SEG_TO_LIN(lp16WaveHdr); |
| dwRet = wodMessage(0, WODM_PREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR)); |
| while(TRUE) { |
| count = mmioRead(MCIWavDev[wDevID].hFile, |
| PTR_SEG_TO_LIN(lpWaveHdr->lpData), bufsize); |
| dprintf_mciwave(stddeb,"WAVE_mciPlay // mmioRead bufsize=%ld count=%ld\n", bufsize, count); |
| if (count < 1) break; |
| lpWaveHdr->dwBufferLength = count; |
| /* lpWaveHdr->dwBytesRecorded = count; */ |
| dprintf_mciwave(stddeb,"WAVE_mciPlay // before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n", |
| lpWaveHdr, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBytesRecorded); |
| dwRet = wodMessage(0, WODM_WRITE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR)); |
| } |
| dwRet = wodMessage(0, WODM_UNPREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR)); |
| if (lpWaveHdr->lpData != NULL) { |
| GlobalUnlock(hData); |
| GlobalFree(hData); |
| lpWaveHdr->lpData = NULL; |
| } |
| USER_HEAP_FREE(hWaveHdr); |
| if (dwFlags & MCI_NOTIFY) { |
| dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback); |
| mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), |
| MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL); |
| } |
| return 0; |
| } |
| |
| |
| /************************************************************************** |
| * WAVE_mciRecord [internal] |
| */ |
| static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms) |
| { |
| int start, end; |
| LONG bufsize; |
| HANDLE hData; |
| HANDLE hWaveHdr; |
| LPWAVEHDR lpWaveHdr; |
| LPWAVEHDR lp16WaveHdr; |
| DWORD dwRet; |
| |
| dprintf_mciwave(stddeb, |
| "WAVE_mciRecord(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); |
| if (MCIWavDev[wDevID].hFile == 0) { |
| dprintf_mciwave(stddeb,"WAVE_mciRecord // can't find file='%s' !\n", |
| MCIWavDev[wDevID].openParms.lpstrElementName); |
| return MCIERR_FILE_NOT_FOUND; |
| } |
| start = 1; end = 99999; |
| if (dwFlags & MCI_FROM) { |
| start = lpParms->dwFrom; |
| dprintf_mciwave(stddeb, |
| "WAVE_mciRecord // MCI_FROM=%d \n", start); |
| } |
| if (dwFlags & MCI_TO) { |
| end = lpParms->dwTo; |
| dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_TO=%d \n", end); |
| } |
| bufsize = 64000; |
| lpWaveHdr = &MCIWavDev[wDevID].WaveHdr; |
| hData = GlobalAlloc(GMEM_MOVEABLE, bufsize); |
| lpWaveHdr->lpData = (LPSTR) WIN16_GlobalLock(hData); |
| lpWaveHdr->dwBufferLength = bufsize; |
| lpWaveHdr->dwUser = 0L; |
| lpWaveHdr->dwFlags = 0L; |
| lpWaveHdr->dwLoops = 0L; |
| hWaveHdr = USER_HEAP_ALLOC(sizeof(WAVEHDR)); |
| lp16WaveHdr = (LPWAVEHDR) USER_HEAP_SEG_ADDR(hWaveHdr); |
| memcpy(PTR_SEG_TO_LIN(lp16WaveHdr), lpWaveHdr, sizeof(WAVEHDR)); |
| lpWaveHdr = PTR_SEG_TO_LIN(lp16WaveHdr); |
| dwRet = widMessage(0, WIDM_PREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR)); |
| dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_PREPARE \n"); |
| while(TRUE) { |
| lpWaveHdr->dwBytesRecorded = 0; |
| dwRet = widMessage(0, WIDM_START, 0, 0L, 0L); |
| dprintf_mciwave(stddeb, |
| "WAVE_mciRecord // after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n", |
| lpWaveHdr, lpWaveHdr->dwBytesRecorded); |
| if (lpWaveHdr->dwBytesRecorded == 0) break; |
| } |
| dprintf_mciwave(stddeb,"WAVE_mciRecord // before WIDM_UNPREPARE \n"); |
| dwRet = widMessage(0, WIDM_UNPREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR)); |
| dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_UNPREPARE \n"); |
| if (lpWaveHdr->lpData != NULL) { |
| GlobalUnlock(hData); |
| GlobalFree(hData); |
| lpWaveHdr->lpData = NULL; |
| } |
| USER_HEAP_FREE(hWaveHdr); |
| if (dwFlags & MCI_NOTIFY) { |
| dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback); |
| mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), |
| MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL); |
| } |
| return 0; |
| } |
| |
| |
| /************************************************************************** |
| * WAVE_mciStop [internal] |
| */ |
| static DWORD WAVE_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) |
| { |
| dprintf_mciwave(stddeb, |
| "WAVE_mciStop(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); |
| if (lpParms == NULL) return MCIERR_INTERNAL; |
| return 0; |
| } |
| |
| |
| /************************************************************************** |
| * WAVE_mciPause [internal] |
| */ |
| static DWORD WAVE_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) |
| { |
| dprintf_mciwave(stddeb, |
| "WAVE_mciPause(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); |
| if (lpParms == NULL) return MCIERR_INTERNAL; |
| return 0; |
| } |
| |
| |
| /************************************************************************** |
| * WAVE_mciResume [internal] |
| */ |
| static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms) |
| { |
| dprintf_mciwave(stddeb, |
| "WAVE_mciResume(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); |
| if (lpParms == NULL) return MCIERR_INTERNAL; |
| return 0; |
| } |
| |
| |
| /************************************************************************** |
| * WAVE_mciSet [internal] |
| */ |
| static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms) |
| { |
| dprintf_mciwave(stddeb, |
| "WAVE_mciSet(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); |
| if (lpParms == NULL) return MCIERR_INTERNAL; |
| dprintf_mciwave(stddeb, |
| "WAVE_mciSet // dwTimeFormat=%08lX\n", lpParms->dwTimeFormat); |
| dprintf_mciwave(stddeb, |
| "WAVE_mciSet // dwAudio=%08lX\n", lpParms->dwAudio); |
| if (dwFlags & MCI_SET_TIME_FORMAT) { |
| switch (lpParms->dwTimeFormat) { |
| case MCI_FORMAT_MILLISECONDS: |
| dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_MILLISECONDS !\n"); |
| break; |
| case MCI_FORMAT_BYTES: |
| dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_BYTES !\n"); |
| break; |
| case MCI_FORMAT_SAMPLES: |
| dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_SAMPLES !\n"); |
| break; |
| default: |
| dprintf_mciwave(stddeb, "WAVE_mciSet // bad time format !\n"); |
| return MCIERR_BAD_TIME_FORMAT; |
| } |
| } |
| if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION; |
| if (dwFlags & MCI_SET_DOOR_OPEN) return MCIERR_UNSUPPORTED_FUNCTION; |
| if (dwFlags & MCI_SET_DOOR_CLOSED) return MCIERR_UNSUPPORTED_FUNCTION; |
| if (dwFlags & MCI_SET_AUDIO) |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO !\n"); |
| if (dwFlags && MCI_SET_ON) { |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_ON !\n"); |
| if (dwFlags && MCI_SET_AUDIO_LEFT) |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_LEFT !\n"); |
| if (dwFlags && MCI_SET_AUDIO_RIGHT) |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_RIGHT !\n"); |
| } |
| if (dwFlags & MCI_SET_OFF) |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_OFF !\n"); |
| if (dwFlags & MCI_WAVE_INPUT) |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_INPUT !\n"); |
| if (dwFlags & MCI_WAVE_OUTPUT) |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_OUTPUT !\n"); |
| if (dwFlags & MCI_WAVE_SET_ANYINPUT) |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYINPUT !\n"); |
| if (dwFlags & MCI_WAVE_SET_ANYOUTPUT) |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYOUTPUT !\n"); |
| if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) |
| dprintf_mciwave(stddeb, |
| "WAVE_mciSet // MCI_WAVE_SET_AVGBYTESPERSEC !\n"); |
| if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) |
| dprintf_mciwave(stddeb, |
| "WAVE_mciSet // MCI_WAVE_SET_BITSPERSAMPLE !\n"); |
| if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_BLOCKALIGN !\n"); |
| if (dwFlags & MCI_WAVE_SET_CHANNELS) |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_CHANNELS !\n"); |
| if (dwFlags & MCI_WAVE_SET_FORMATTAG) |
| dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_FORMATTAG !\n"); |
| if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) |
| dprintf_mciwave(stddeb, |
| "WAVE_mciSet // MCI_WAVE_SET_SAMPLESPERSEC !\n"); |
| return 0; |
| } |
| |
| |
| /************************************************************************** |
| * WAVE_mciStatus [internal] |
| */ |
| static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms) |
| { |
| dprintf_mciwave(stddeb, |
| "WAVE_mciStatus(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); |
| if (lpParms == NULL) return MCIERR_INTERNAL; |
| if (dwFlags & MCI_STATUS_ITEM) { |
| switch(lpParms->dwItem) { |
| case MCI_STATUS_CURRENT_TRACK: |
| lpParms->dwReturn = 1; |
| break; |
| case MCI_STATUS_LENGTH: |
| lpParms->dwReturn = 5555; |
| if (dwFlags & MCI_TRACK) { |
| lpParms->dwTrack = 1; |
| lpParms->dwReturn = 2222; |
| } |
| break; |
| case MCI_STATUS_MODE: |
| lpParms->dwReturn = MCI_MODE_STOP; |
| break; |
| case MCI_STATUS_MEDIA_PRESENT: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_MEDIA_PRESENT !\n"); |
| lpParms->dwReturn = TRUE; |
| break; |
| case MCI_STATUS_NUMBER_OF_TRACKS: |
| lpParms->dwReturn = 1; |
| break; |
| case MCI_STATUS_POSITION: |
| lpParms->dwReturn = 3333; |
| if (dwFlags & MCI_STATUS_START) { |
| lpParms->dwItem = 1; |
| } |
| if (dwFlags & MCI_TRACK) { |
| lpParms->dwTrack = 1; |
| lpParms->dwReturn = 777; |
| } |
| break; |
| case MCI_STATUS_READY: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_READY !\n"); |
| lpParms->dwReturn = TRUE; |
| break; |
| case MCI_STATUS_TIME_FORMAT: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_TIME_FORMAT !\n"); |
| lpParms->dwReturn = MCI_FORMAT_MILLISECONDS; |
| break; |
| case MCI_WAVE_INPUT: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_INPUT !\n"); |
| lpParms->dwReturn = 0; |
| break; |
| case MCI_WAVE_OUTPUT: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_OUTPUT !\n"); |
| lpParms->dwReturn = 0; |
| break; |
| case MCI_WAVE_STATUS_AVGBYTESPERSEC: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_AVGBYTESPERSEC !\n"); |
| lpParms->dwReturn = 22050; |
| break; |
| case MCI_WAVE_STATUS_BITSPERSAMPLE: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BITSPERSAMPLE !\n"); |
| lpParms->dwReturn = 8; |
| break; |
| case MCI_WAVE_STATUS_BLOCKALIGN: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BLOCKALIGN !\n"); |
| lpParms->dwReturn = 1; |
| break; |
| case MCI_WAVE_STATUS_CHANNELS: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_CHANNELS !\n"); |
| lpParms->dwReturn = 1; |
| break; |
| case MCI_WAVE_STATUS_FORMATTAG: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_FORMATTAG !\n"); |
| lpParms->dwReturn = WAVE_FORMAT_PCM; |
| break; |
| case MCI_WAVE_STATUS_LEVEL: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_LEVEL !\n"); |
| lpParms->dwReturn = 0xAAAA5555; |
| break; |
| case MCI_WAVE_STATUS_SAMPLESPERSEC: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_SAMPLESPERSEC !\n"); |
| lpParms->dwReturn = 22050; |
| break; |
| default: |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // unknown command %08lX !\n", lpParms->dwItem); |
| return MCIERR_UNRECOGNIZED_COMMAND; |
| } |
| } |
| if (dwFlags & MCI_NOTIFY) { |
| dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback); |
| mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), |
| MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL); |
| } |
| return 0; |
| } |
| |
| /************************************************************************** |
| * WAVE_mciGetDevCaps [internal] |
| */ |
| static DWORD WAVE_mciGetDevCaps(UINT wDevID, DWORD dwFlags, |
| LPMCI_GETDEVCAPS_PARMS lpParms) |
| { |
| dprintf_mciwave(stddeb, |
| "WAVE_mciGetDevCaps(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); |
| if (lpParms == NULL) return MCIERR_INTERNAL; |
| if (dwFlags & MCI_GETDEVCAPS_ITEM) { |
| switch(lpParms->dwItem) { |
| case MCI_GETDEVCAPS_CAN_RECORD: |
| lpParms->dwReturn = TRUE; |
| break; |
| case MCI_GETDEVCAPS_HAS_AUDIO: |
| lpParms->dwReturn = TRUE; |
| break; |
| case MCI_GETDEVCAPS_HAS_VIDEO: |
| lpParms->dwReturn = FALSE; |
| break; |
| case MCI_GETDEVCAPS_DEVICE_TYPE: |
| lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO; |
| break; |
| case MCI_GETDEVCAPS_USES_FILES: |
| lpParms->dwReturn = TRUE; |
| break; |
| case MCI_GETDEVCAPS_COMPOUND_DEVICE: |
| lpParms->dwReturn = TRUE; |
| break; |
| case MCI_GETDEVCAPS_CAN_EJECT: |
| lpParms->dwReturn = FALSE; |
| break; |
| case MCI_GETDEVCAPS_CAN_PLAY: |
| lpParms->dwReturn = TRUE; |
| break; |
| case MCI_GETDEVCAPS_CAN_SAVE: |
| lpParms->dwReturn = TRUE; |
| break; |
| case MCI_WAVE_GETDEVCAPS_INPUTS: |
| lpParms->dwReturn = 1; |
| break; |
| case MCI_WAVE_GETDEVCAPS_OUTPUTS: |
| lpParms->dwReturn = 1; |
| break; |
| default: |
| return MCIERR_UNRECOGNIZED_COMMAND; |
| } |
| } |
| return 0; |
| } |
| |
| /************************************************************************** |
| * WAVE_mciInfo [internal] |
| */ |
| static DWORD WAVE_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMS lpParms) |
| { |
| dprintf_mciwave(stddeb, |
| "WAVE_mciInfo(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms); |
| if (lpParms == NULL) return MCIERR_INTERNAL; |
| lpParms->lpstrReturn = NULL; |
| switch(dwFlags) { |
| case MCI_INFO_PRODUCT: |
| lpParms->lpstrReturn = "Linux Sound System 0.5"; |
| break; |
| case MCI_INFO_FILE: |
| lpParms->lpstrReturn = |
| (LPSTR)MCIWavDev[wDevID].openParms.lpstrElementName; |
| break; |
| case MCI_WAVE_INPUT: |
| lpParms->lpstrReturn = "Linux Sound System 0.5"; |
| break; |
| case MCI_WAVE_OUTPUT: |
| lpParms->lpstrReturn = "Linux Sound System 0.5"; |
| break; |
| default: |
| return MCIERR_UNRECOGNIZED_COMMAND; |
| } |
| if (lpParms->lpstrReturn != NULL) |
| lpParms->dwRetSize = strlen(lpParms->lpstrReturn); |
| else |
| lpParms->dwRetSize = 0; |
| return 0; |
| } |
| |
| |
| /*-----------------------------------------------------------------------*/ |
| |
| |
| /************************************************************************** |
| * wodGetDevCaps [internal] |
| */ |
| static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS lpCaps, DWORD dwSize) |
| { |
| int audio; |
| int smplrate; |
| int samplesize = 16; |
| int dsp_stereo = 1; |
| int bytespersmpl; |
| dprintf_mciwave(stddeb, |
| "wodGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize); |
| if (lpCaps == NULL) return MMSYSERR_NOTENABLED; |
| audio = open (SOUND_DEV, O_WRONLY, 0); |
| if (audio == -1) return MMSYSERR_NOTENABLED; |
| #ifdef EMULATE_SB16 |
| lpCaps->wMid = 0x0002; |
| lpCaps->wPid = 0x0104; |
| strcpy(lpCaps->szPname, "SB16 Wave Out"); |
| #else |
| lpCaps->wMid = 0x00FF; /* Manufac ID */ |
| lpCaps->wPid = 0x0001; /* Product ID */ |
| strcpy(lpCaps->szPname, "Linux WAVOUT Driver"); |
| #endif |
| lpCaps->dwFormats = 0x00000000; |
| lpCaps->dwSupport = WAVECAPS_VOLUME; |
| lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2; |
| if (lpCaps->wChannels > 1) lpCaps->dwSupport |= WAVECAPS_LRVOLUME; |
| bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2; |
| smplrate = 44100; |
| if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { |
| lpCaps->dwFormats |= WAVE_FORMAT_4M08; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S08; |
| if (bytespersmpl > 1) { |
| lpCaps->dwFormats |= WAVE_FORMAT_4M16; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S16; |
| } |
| } |
| smplrate = 22050; |
| if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { |
| lpCaps->dwFormats |= WAVE_FORMAT_2M08; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S08; |
| if (bytespersmpl > 1) { |
| lpCaps->dwFormats |= WAVE_FORMAT_2M16; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S16; |
| } |
| } |
| smplrate = 11025; |
| if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { |
| lpCaps->dwFormats |= WAVE_FORMAT_1M08; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S08; |
| if (bytespersmpl > 1) { |
| lpCaps->dwFormats |= WAVE_FORMAT_1M16; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S16; |
| } |
| } |
| close(audio); |
| dprintf_mciwave(stddeb, |
| "wodGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats); |
| return MMSYSERR_NOERROR; |
| } |
| |
| |
| /************************************************************************** |
| * wodOpen [internal] |
| */ |
| static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) |
| { |
| int audio; |
| int abuf_size; |
| int smplrate; |
| int samplesize; |
| int dsp_stereo; |
| LPWAVEFORMAT lpFormat; |
| |
| dprintf_mciwave(stddeb, |
| "wodOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags); |
| if (lpDesc == NULL) { |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // Invalid Parameter !\n"); |
| return MMSYSERR_INVALPARAM; |
| } |
| if (wDevID >= MAX_WAVOUTDRV) { |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // MAX_WAVOUTDRV reached !\n"); |
| return MMSYSERR_ALLOCATED; |
| } |
| WOutDev[wDevID].unixdev = 0; |
| audio = open (SOUND_DEV, O_WRONLY, 0); |
| if (audio == -1) { |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't open !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size); |
| if (abuf_size < 4096 || abuf_size > 65536) { |
| if (abuf_size == -1) |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n"); |
| else |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); |
| switch(WOutDev[wDevID].wFlags) { |
| case DCB_NULL: |
| dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_NULL !\n"); |
| break; |
| case DCB_WINDOW: |
| dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_WINDOW !\n"); |
| break; |
| case DCB_TASK: |
| dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_TASK !\n"); |
| break; |
| case DCB_FUNCTION: |
| dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_FUNCTION !\n"); |
| break; |
| } |
| WOutDev[wDevID].lpQueueHdr = NULL; |
| WOutDev[wDevID].unixdev = audio; |
| WOutDev[wDevID].dwTotalPlayed = 0; |
| WOutDev[wDevID].bufsize = abuf_size; |
| memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC)); |
| /* lpFormat = (LPWAVEFORMAT) PTR_SEG_TO_LIN(lpDesc->lpFormat); */ |
| lpFormat = lpDesc->lpFormat; |
| if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) { |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad format %04X !\n", |
| lpFormat->wFormatTag); |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nChannels %d !\n", |
| lpFormat->nChannels); |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nSamplesPerSec %ld !\n", |
| lpFormat->nSamplesPerSec); |
| return WAVERR_BADFORMAT; |
| } |
| memcpy(&WOutDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT)); |
| if (WOutDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT; |
| if (WOutDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT; |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n", |
| WOutDev[wDevID].Format.wBitsPerSample); |
| if (WOutDev[wDevID].Format.wBitsPerSample == 0) { |
| WOutDev[wDevID].Format.wBitsPerSample = 8 * |
| (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / |
| WOutDev[wDevID].Format.wf.nSamplesPerSec) / |
| WOutDev[wDevID].Format.wf.nChannels; |
| } |
| samplesize = WOutDev[wDevID].Format.wBitsPerSample; |
| smplrate = WOutDev[wDevID].Format.wf.nSamplesPerSec; |
| dsp_stereo = (WOutDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE; |
| IOCTL(audio, SNDCTL_DSP_SPEED, smplrate); |
| IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize); |
| IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo); |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n", |
| WOutDev[wDevID].Format.wBitsPerSample); |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // nAvgBytesPerSec=%lu !\n", |
| WOutDev[wDevID].Format.wf.nAvgBytesPerSec); |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // nSamplesPerSec=%lu !\n", |
| WOutDev[wDevID].Format.wf.nSamplesPerSec); |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // nChannels=%u !\n", |
| WOutDev[wDevID].Format.wf.nChannels); |
| if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) { |
| dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't notify client !\n"); |
| return MMSYSERR_INVALPARAM; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * wodClose [internal] |
| */ |
| static DWORD wodClose(WORD wDevID) |
| { |
| dprintf_mciwave(stddeb,"wodClose(%u);\n", wDevID); |
| if (WOutDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'wodClose' // can't close !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| close(WOutDev[wDevID].unixdev); |
| WOutDev[wDevID].unixdev = 0; |
| WOutDev[wDevID].bufsize = 0; |
| WOutDev[wDevID].lpQueueHdr = NULL; |
| if (WAVE_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) { |
| dprintf_mciwave(stddeb,"Linux 'wodClose' // can't notify client !\n"); |
| return MMSYSERR_INVALPARAM; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * wodWrite [internal] |
| */ |
| static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) |
| { |
| int count; |
| LPSTR lpData; |
| dprintf_mciwave(stddeb,"wodWrite(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); |
| if (WOutDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't play !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| if (lpWaveHdr->lpData == NULL) return WAVERR_UNPREPARED; |
| if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) return WAVERR_UNPREPARED; |
| if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING; |
| lpWaveHdr->dwFlags &= ~WHDR_DONE; |
| lpWaveHdr->dwFlags |= WHDR_INQUEUE; |
| dprintf_mciwave(stddeb, |
| "wodWrite() // dwBufferLength %lu !\n", lpWaveHdr->dwBufferLength); |
| dprintf_mciwave(stddeb, |
| "wodWrite() // WOutDev[%u].unixdev %u !\n", wDevID, WOutDev[wDevID].unixdev); |
| lpData = PTR_SEG_TO_LIN(lpWaveHdr->lpData); |
| count = write (WOutDev[wDevID].unixdev, lpData, lpWaveHdr->dwBufferLength); |
| dprintf_mciwave(stddeb, |
| "wodWrite() // write returned count %u !\n", count); |
| if (count != lpWaveHdr->dwBufferLength) { |
| dprintf_mciwave(stddeb,"Linux 'wodWrite' // error writting !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| WOutDev[wDevID].dwTotalPlayed += count; |
| lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; |
| lpWaveHdr->dwFlags |= WHDR_DONE; |
| if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) { |
| dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't notify client !\n"); |
| return MMSYSERR_INVALPARAM; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * wodPrepare [internal] |
| */ |
| static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) |
| { |
| dprintf_mciwave(stddeb, |
| "wodPrepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); |
| if (WOutDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'wodPrepare' // can't prepare !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| /* the COOL waveeditor feels much better without this check... |
| * someone please have a look at available documentation |
| if (WOutDev[wDevID].lpQueueHdr != NULL) { |
| dprintf_mciwave(stddeb,"Linux 'wodPrepare' // already prepare !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| */ |
| WOutDev[wDevID].dwTotalPlayed = 0; |
| WOutDev[wDevID].lpQueueHdr = lpWaveHdr; |
| if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING; |
| lpWaveHdr->dwFlags |= WHDR_PREPARED; |
| lpWaveHdr->dwFlags &= ~WHDR_DONE; |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * wodUnprepare [internal] |
| */ |
| static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) |
| { |
| dprintf_mciwave(stddeb, |
| "wodUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); |
| if (WOutDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'wodUnprepare' // can't unprepare !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * wodRestart [internal] |
| */ |
| static DWORD wodRestart(WORD wDevID) |
| { |
| dprintf_mciwave(stddeb,"wodRestart(%u);\n", wDevID); |
| if (WOutDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'wodRestart' // can't restart !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * wodReset [internal] |
| */ |
| static DWORD wodReset(WORD wDevID) |
| { |
| dprintf_mciwave(stddeb,"wodReset(%u);\n", wDevID); |
| if (WOutDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'wodReset' // can't reset !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| |
| /************************************************************************** |
| * wodGetPosition [internal] |
| */ |
| static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize) |
| { |
| int time; |
| dprintf_mciwave(stddeb,"wodGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize); |
| if (WOutDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'wodGetPosition' // can't get pos !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| if (lpTime == NULL) return MMSYSERR_INVALPARAM; |
| switch(lpTime->wType) { |
| case TIME_BYTES: |
| lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed; |
| dprintf_mciwave(stddeb,"wodGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb); |
| break; |
| case TIME_SAMPLES: |
| dprintf_mciwave(stddeb,"wodGetPosition // dwTotalPlayed=%lu\n", |
| WOutDev[wDevID].dwTotalPlayed); |
| dprintf_mciwave(stddeb,"wodGetPosition // wBitsPerSample=%u\n", |
| WOutDev[wDevID].Format.wBitsPerSample); |
| lpTime->u.sample = WOutDev[wDevID].dwTotalPlayed * 8 / |
| WOutDev[wDevID].Format.wBitsPerSample; |
| dprintf_mciwave(stddeb,"wodGetPosition // TIME_SAMPLES=%lu\n", lpTime->u.sample); |
| break; |
| case TIME_SMPTE: |
| time = WOutDev[wDevID].dwTotalPlayed / |
| (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000); |
| lpTime->u.smpte.hour = time / 108000; |
| time -= lpTime->u.smpte.hour * 108000; |
| lpTime->u.smpte.min = time / 1800; |
| time -= lpTime->u.smpte.min * 1800; |
| lpTime->u.smpte.sec = time / 30; |
| time -= lpTime->u.smpte.sec * 30; |
| lpTime->u.smpte.frame = time; |
| lpTime->u.smpte.fps = 30; |
| dprintf_mciwave(stddeb, |
| "wodGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n", |
| lpTime->u.smpte.hour, lpTime->u.smpte.min, |
| lpTime->u.smpte.sec, lpTime->u.smpte.frame); |
| break; |
| default: |
| dprintf_mciwave(stddeb,"wodGetPosition() format not supported ! use TIME_MS !\n"); |
| lpTime->wType = TIME_MS; |
| case TIME_MS: |
| lpTime->u.ms = WOutDev[wDevID].dwTotalPlayed / |
| (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000); |
| dprintf_mciwave(stddeb,"wodGetPosition // TIME_MS=%lu\n", lpTime->u.ms); |
| break; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * wodGetVolume [internal] |
| */ |
| static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol) |
| { |
| int mixer; |
| int volume, left, right; |
| dprintf_mciwave(stddeb,"wodGetVolume(%u, %p);\n", wDevID, lpdwVol); |
| if (lpdwVol == NULL) return MMSYSERR_NOTENABLED; |
| if ((mixer = open("/dev/mixer", O_RDONLY)) < 0) { |
| dprintf_mciwave(stddeb, "Linux 'wodGetVolume' // mixer device not available !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) { |
| dprintf_mciwave(stddeb,"Linux 'wodGetVolume' // unable read mixer !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| close(mixer); |
| left = volume & 0x7F; |
| right = (volume >> 8) & 0x7F; |
| printf("Linux 'AUX_GetVolume' // left=%d right=%d !\n", left, right); |
| *lpdwVol = MAKELONG(left << 9, right << 9); |
| return MMSYSERR_NOERROR; |
| } |
| |
| |
| /************************************************************************** |
| * wodSetVolume [internal] |
| */ |
| static DWORD wodSetVolume(WORD wDevID, DWORD dwParam) |
| { |
| int mixer; |
| int volume; |
| dprintf_mciwave(stddeb,"wodSetVolume(%u, %08lX);\n", wDevID, dwParam); |
| volume = (LOWORD(dwParam) >> 9 & 0x7F) + |
| ((HIWORD(dwParam) >> 9 & 0x7F) << 8); |
| if ((mixer = open("/dev/mixer", O_WRONLY)) < 0) { |
| dprintf_mciwave(stddeb, "Linux 'wodSetVolume' // mixer device not available !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) { |
| dprintf_mciwave(stddeb,"Linux 'wodSetVolume' // unable set mixer !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| close(mixer); |
| return MMSYSERR_NOERROR; |
| } |
| |
| #endif /* linux */ |
| |
| /************************************************************************** |
| * wodMessage [sample driver] |
| */ |
| DWORD wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, |
| DWORD dwParam1, DWORD dwParam2) |
| { |
| dprintf_mciwave(stddeb,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n", |
| wDevID, wMsg, dwUser, dwParam1, dwParam2); |
| #ifdef linux |
| switch(wMsg) { |
| case WODM_OPEN: |
| return wodOpen(wDevID, (LPWAVEOPENDESC)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WODM_CLOSE: |
| return wodClose(wDevID); |
| case WODM_WRITE: |
| return wodWrite(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WODM_PAUSE: |
| return 0L; |
| case WODM_GETPOS: |
| return wodGetPosition(wDevID, (LPMMTIME)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WODM_BREAKLOOP: |
| return 0L; |
| case WODM_PREPARE: |
| return wodPrepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WODM_UNPREPARE: |
| return wodUnprepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WODM_GETDEVCAPS: |
| return wodGetDevCaps(wDevID, (LPWAVEOUTCAPS)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WODM_GETNUMDEVS: |
| return 1L; |
| case WODM_GETPITCH: |
| return 0L; |
| case WODM_SETPITCH: |
| return 0L; |
| case WODM_GETPLAYBACKRATE: |
| return 0L; |
| case WODM_SETPLAYBACKRATE: |
| return 0L; |
| case WODM_GETVOLUME: |
| return wodGetVolume(wDevID, (LPDWORD)PTR_SEG_TO_LIN(dwParam1)); |
| case WODM_SETVOLUME: |
| return wodSetVolume(wDevID, dwParam1); |
| case WODM_RESTART: |
| return wodRestart(wDevID); |
| case WODM_RESET: |
| return wodReset(wDevID); |
| default: |
| dprintf_mciwave(stddeb,"wodMessage // unknown message !\n"); |
| } |
| return MMSYSERR_NOTSUPPORTED; |
| #else |
| return MMSYSERR_NOTENABLED; |
| #endif |
| } |
| |
| |
| /*-----------------------------------------------------------------------*/ |
| |
| #ifdef linux |
| |
| /************************************************************************** |
| * widGetDevCaps [internal] |
| */ |
| static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPS lpCaps, DWORD dwSize) |
| { |
| int audio; |
| int smplrate; |
| int samplesize = 16; |
| int dsp_stereo = 1; |
| int bytespersmpl; |
| dprintf_mciwave(stddeb, |
| "widGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize); |
| if (lpCaps == NULL) return MMSYSERR_NOTENABLED; |
| audio = open (SOUND_DEV, O_RDONLY, 0); |
| if (audio == -1) return MMSYSERR_NOTENABLED; |
| #ifdef EMULATE_SB16 |
| lpCaps->wMid = 0x0002; |
| lpCaps->wPid = 0x0004; |
| strcpy(lpCaps->szPname, "SB16 Wave Out"); |
| #else |
| lpCaps->wMid = 0x00FF; /* Manufac ID */ |
| lpCaps->wPid = 0x0001; /* Product ID */ |
| strcpy(lpCaps->szPname, "Linux WAVIN Driver"); |
| #endif |
| lpCaps->dwFormats = 0x00000000; |
| lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2; |
| bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2; |
| smplrate = 44100; |
| if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { |
| lpCaps->dwFormats |= WAVE_FORMAT_4M08; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S08; |
| if (bytespersmpl > 1) { |
| lpCaps->dwFormats |= WAVE_FORMAT_4M16; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S16; |
| } |
| } |
| smplrate = 22050; |
| if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { |
| lpCaps->dwFormats |= WAVE_FORMAT_2M08; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S08; |
| if (bytespersmpl > 1) { |
| lpCaps->dwFormats |= WAVE_FORMAT_2M16; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S16; |
| } |
| } |
| smplrate = 11025; |
| if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) { |
| lpCaps->dwFormats |= WAVE_FORMAT_1M08; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S08; |
| if (bytespersmpl > 1) { |
| lpCaps->dwFormats |= WAVE_FORMAT_1M16; |
| if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S16; |
| } |
| } |
| close(audio); |
| dprintf_mciwave(stddeb, |
| "widGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats); |
| return MMSYSERR_NOERROR; |
| } |
| |
| |
| /************************************************************************** |
| * widOpen [internal] |
| */ |
| static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) |
| { |
| int audio; |
| int abuf_size; |
| int smplrate; |
| int samplesize; |
| int dsp_stereo; |
| LPWAVEFORMAT lpFormat; |
| dprintf_mciwave(stddeb, "widOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags); |
| if (lpDesc == NULL) { |
| dprintf_mciwave(stddeb,"Linux 'widOpen' // Invalid Parameter !\n"); |
| return MMSYSERR_INVALPARAM; |
| } |
| if (wDevID >= MAX_WAVINDRV) { |
| dprintf_mciwave(stddeb,"Linux 'widOpen' // MAX_WAVINDRV reached !\n"); |
| return MMSYSERR_ALLOCATED; |
| } |
| WInDev[wDevID].unixdev = 0; |
| audio = open (SOUND_DEV, O_RDONLY, 0); |
| if (audio == -1) { |
| dprintf_mciwave(stddeb,"Linux 'widOpen' // can't open !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size); |
| if (abuf_size < 4096 || abuf_size > 65536) { |
| if (abuf_size == -1) |
| dprintf_mciwave(stddeb,"Linux 'widOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n"); |
| else |
| dprintf_mciwave(stddeb,"Linux 'widOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| WInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); |
| switch(WInDev[wDevID].wFlags) { |
| case DCB_NULL: |
| dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_NULL !\n"); |
| break; |
| case DCB_WINDOW: |
| dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_WINDOW !\n"); |
| break; |
| case DCB_TASK: |
| dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_TASK !\n"); |
| break; |
| case DCB_FUNCTION: |
| dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_FUNCTION !\n"); |
| break; |
| } |
| WInDev[wDevID].lpQueueHdr = NULL; |
| WInDev[wDevID].unixdev = audio; |
| WInDev[wDevID].bufsize = abuf_size; |
| WInDev[wDevID].dwTotalRecorded = 0; |
| memcpy(&WInDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC)); |
| lpFormat = lpDesc->lpFormat; |
| if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) { |
| dprintf_mciwave(stddeb,"Linux 'widOpen' // Bad format %04X !\n", |
| lpFormat->wFormatTag); |
| return WAVERR_BADFORMAT; |
| } |
| memcpy(&WInDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT)); |
| WInDev[wDevID].Format.wBitsPerSample = 8; /* <-------------- */ |
| if (WInDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT; |
| if (WInDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT; |
| if (WInDev[wDevID].Format.wBitsPerSample == 0) { |
| WInDev[wDevID].Format.wBitsPerSample = 8 * |
| (WInDev[wDevID].Format.wf.nAvgBytesPerSec / |
| WInDev[wDevID].Format.wf.nSamplesPerSec) / |
| WInDev[wDevID].Format.wf.nChannels; |
| } |
| samplesize = WInDev[wDevID].Format.wBitsPerSample; |
| smplrate = WInDev[wDevID].Format.wf.nSamplesPerSec; |
| dsp_stereo = (WInDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE; |
| IOCTL(audio, SNDCTL_DSP_SPEED, smplrate); |
| IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize); |
| IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo); |
| dprintf_mciwave(stddeb,"Linux 'widOpen' // wBitsPerSample=%u !\n", |
| WInDev[wDevID].Format.wBitsPerSample); |
| dprintf_mciwave(stddeb,"Linux 'widOpen' // nSamplesPerSec=%lu !\n", |
| WInDev[wDevID].Format.wf.nSamplesPerSec); |
| dprintf_mciwave(stddeb,"Linux 'widOpen' // nChannels=%u !\n", |
| WInDev[wDevID].Format.wf.nChannels); |
| dprintf_mciwave(stddeb,"Linux 'widOpen' // nAvgBytesPerSec=%lu\n", |
| WInDev[wDevID].Format.wf.nAvgBytesPerSec); |
| if (WAVE_NotifyClient(wDevID, WIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) { |
| dprintf_mciwave(stddeb,"Linux 'widOpen' // can't notify client !\n"); |
| return MMSYSERR_INVALPARAM; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * widClose [internal] |
| */ |
| static DWORD widClose(WORD wDevID) |
| { |
| dprintf_mciwave(stddeb,"widClose(%u);\n", wDevID); |
| if (WInDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'widClose' // can't close !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| close(WInDev[wDevID].unixdev); |
| WInDev[wDevID].unixdev = 0; |
| WInDev[wDevID].bufsize = 0; |
| if (WAVE_NotifyClient(wDevID, WIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) { |
| dprintf_mciwave(stddeb,"Linux 'widClose' // can't notify client !\n"); |
| return MMSYSERR_INVALPARAM; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * widAddBuffer [internal] |
| */ |
| static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) |
| { |
| int count = 1; |
| LPWAVEHDR lpWIHdr; |
| dprintf_mciwave(stddeb, |
| "widAddBuffer(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); |
| if (WInDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'widAddBuffer' // can't do it !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) { |
| dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // never been prepared !\n"); |
| return WAVERR_UNPREPARED; |
| } |
| if (lpWaveHdr->dwFlags & WHDR_INQUEUE) { |
| dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // header already in use !\n"); |
| return WAVERR_STILLPLAYING; |
| } |
| lpWaveHdr->dwFlags |= WHDR_PREPARED; |
| lpWaveHdr->dwFlags |= WHDR_INQUEUE; |
| lpWaveHdr->dwFlags &= ~WHDR_DONE; |
| lpWaveHdr->dwBytesRecorded = 0; |
| if (WInDev[wDevID].lpQueueHdr == NULL) { |
| /* begin the queue with a first header ... */ |
| WInDev[wDevID].lpQueueHdr = lpWaveHdr; |
| WInDev[wDevID].dwTotalRecorded = 0; |
| } |
| else { |
| /* added to the queue, except if it's the one just prepared ... */ |
| lpWIHdr = WInDev[wDevID].lpQueueHdr; |
| while (lpWIHdr->lpNext != NULL) { |
| lpWIHdr = lpWIHdr->lpNext; |
| count++; |
| } |
| lpWIHdr->lpNext = lpWaveHdr; |
| count++; |
| } |
| dprintf_mciwave(stddeb, |
| "widAddBuffer // buffer added ! (now %u in queue)\n", count); |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * widPrepare [internal] |
| */ |
| static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) |
| { |
| dprintf_mciwave(stddeb, |
| "widPrepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); |
| if (WInDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'widPrepare' // can't prepare !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| if (WInDev[wDevID].lpQueueHdr != NULL) { |
| dprintf_mciwave(stddeb,"Linux 'widPrepare' // already prepare !\n"); |
| return WAVERR_BADFORMAT; |
| } |
| if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING; |
| lpWaveHdr->dwFlags |= WHDR_PREPARED; |
| lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; |
| lpWaveHdr->dwFlags &= ~WHDR_DONE; |
| lpWaveHdr->dwBytesRecorded = 0; |
| dprintf_mciwave(stddeb,"Linux 'widPrepare' // header prepared !\n"); |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * widUnprepare [internal] |
| */ |
| static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) |
| { |
| dprintf_mciwave(stddeb, |
| "widUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); |
| if (WInDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'widUnprepare' // can't unprepare !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| lpWaveHdr->dwFlags &= ~WHDR_PREPARED; |
| lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; |
| lpWaveHdr->dwFlags |= WHDR_DONE; |
| WInDev[wDevID].lpQueueHdr = NULL; |
| dprintf_mciwave(stddeb, |
| "Linux 'widUnprepare' // all headers unprepared !\n"); |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * widStart [internal] |
| */ |
| static DWORD widStart(WORD wDevID) |
| { |
| int count = 1; |
| LPWAVEHDR lpWIHdr; |
| dprintf_mciwave(stddeb,"widStart(%u);\n", wDevID); |
| if (WInDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb, "Linux 'widStart' // can't start recording !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| if (WInDev[wDevID].lpQueueHdr == NULL || |
| WInDev[wDevID].lpQueueHdr->lpData == NULL) { |
| dprintf_mciwave(stddeb,"Linux 'widStart' // never been prepared !\n"); |
| return WAVERR_UNPREPARED; |
| } |
| lpWIHdr = WInDev[wDevID].lpQueueHdr; |
| while(lpWIHdr != NULL) { |
| lpWIHdr->dwBufferLength &= 0xFFFF; |
| dprintf_mciwave(stddeb, |
| "widStart // recording buf#%u=%p size=%lu \n", |
| count, lpWIHdr->lpData, lpWIHdr->dwBufferLength); |
| fflush(stddeb); |
| read (WInDev[wDevID].unixdev, |
| PTR_SEG_TO_LIN(lpWIHdr->lpData), |
| lpWIHdr->dwBufferLength); |
| lpWIHdr->dwBytesRecorded = lpWIHdr->dwBufferLength; |
| WInDev[wDevID].dwTotalRecorded += lpWIHdr->dwBytesRecorded; |
| lpWIHdr->dwFlags &= ~WHDR_INQUEUE; |
| lpWIHdr->dwFlags |= WHDR_DONE; |
| if (WAVE_NotifyClient(wDevID, WIM_DATA, (DWORD)lpWIHdr, 0L) != |
| MMSYSERR_NOERROR) { |
| dprintf_mciwave(stddeb, "Linux 'widStart' // can't notify client !\n"); |
| return MMSYSERR_INVALPARAM; |
| } |
| lpWIHdr = lpWIHdr->lpNext; |
| count++; |
| } |
| dprintf_mciwave(stddeb,"widStart // end of recording !\n"); |
| fflush(stdout); |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * widStop [internal] |
| */ |
| static DWORD widStop(WORD wDevID) |
| { |
| dprintf_mciwave(stddeb,"widStop(%u);\n", wDevID); |
| if (WInDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'widStop' // can't stop !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * widReset [internal] |
| */ |
| static DWORD widReset(WORD wDevID) |
| { |
| dprintf_mciwave(stddeb,"widReset(%u);\n", wDevID); |
| if (WInDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'widReset' // can't reset !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * widGetPosition [internal] |
| */ |
| static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize) |
| { |
| int time; |
| |
| dprintf_mciwave(stddeb, |
| "widGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize); |
| if (WInDev[wDevID].unixdev == 0) { |
| dprintf_mciwave(stddeb,"Linux 'widGetPosition' // can't get pos !\n"); |
| return MMSYSERR_NOTENABLED; |
| } |
| if (lpTime == NULL) return MMSYSERR_INVALPARAM; |
| dprintf_mciwave(stddeb,"widGetPosition // wType=%04X !\n", |
| lpTime->wType); |
| dprintf_mciwave(stddeb,"widGetPosition // wBitsPerSample=%u\n", |
| WInDev[wDevID].Format.wBitsPerSample); |
| dprintf_mciwave(stddeb,"widGetPosition // nSamplesPerSec=%lu\n", |
| WInDev[wDevID].Format.wf.nSamplesPerSec); |
| dprintf_mciwave(stddeb,"widGetPosition // nChannels=%u\n", |
| WInDev[wDevID].Format.wf.nChannels); |
| dprintf_mciwave(stddeb,"widGetPosition // nAvgBytesPerSec=%lu\n", |
| WInDev[wDevID].Format.wf.nAvgBytesPerSec); |
| fflush(stddeb); |
| switch(lpTime->wType) { |
| case TIME_BYTES: |
| lpTime->u.cb = WInDev[wDevID].dwTotalRecorded; |
| dprintf_mciwave(stddeb, |
| "widGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb); |
| break; |
| case TIME_SAMPLES: |
| lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 / |
| WInDev[wDevID].Format.wBitsPerSample; |
| dprintf_mciwave(stddeb, |
| "widGetPosition // TIME_SAMPLES=%lu\n", |
| lpTime->u.sample); |
| break; |
| case TIME_SMPTE: |
| time = WInDev[wDevID].dwTotalRecorded / |
| (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000); |
| lpTime->u.smpte.hour = time / 108000; |
| time -= lpTime->u.smpte.hour * 108000; |
| lpTime->u.smpte.min = time / 1800; |
| time -= lpTime->u.smpte.min * 1800; |
| lpTime->u.smpte.sec = time / 30; |
| time -= lpTime->u.smpte.sec * 30; |
| lpTime->u.smpte.frame = time; |
| lpTime->u.smpte.fps = 30; |
| dprintf_mciwave(stddeb,"widGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n", |
| lpTime->u.smpte.hour, lpTime->u.smpte.min, |
| lpTime->u.smpte.sec, lpTime->u.smpte.frame); |
| break; |
| default: |
| dprintf_mciwave(stddeb,"widGetPosition() format not supported ! use TIME_MS !\n"); |
| lpTime->wType = TIME_MS; |
| case TIME_MS: |
| lpTime->u.ms = WInDev[wDevID].dwTotalRecorded / |
| (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000); |
| dprintf_mciwave(stddeb, |
| "widGetPosition // TIME_MS=%lu\n", lpTime->u.ms); |
| break; |
| } |
| return MMSYSERR_NOERROR; |
| } |
| |
| #endif /* linux */ |
| |
| /************************************************************************** |
| * widMessage [sample driver] |
| */ |
| DWORD widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, |
| DWORD dwParam1, DWORD dwParam2) |
| { |
| dprintf_mciwave(stddeb,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n", |
| wDevID, wMsg, dwUser, dwParam1, dwParam2); |
| #ifdef linux |
| switch(wMsg) { |
| case WIDM_OPEN: |
| return widOpen(wDevID, (LPWAVEOPENDESC)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WIDM_CLOSE: |
| return widClose(wDevID); |
| case WIDM_ADDBUFFER: |
| return widAddBuffer(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WIDM_PREPARE: |
| return widPrepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WIDM_UNPREPARE: |
| return widUnprepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WIDM_GETDEVCAPS: |
| return widGetDevCaps(wDevID, (LPWAVEINCAPS)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WIDM_GETNUMDEVS: |
| return 1; |
| case WIDM_GETPOS: |
| return widGetPosition(wDevID, (LPMMTIME)PTR_SEG_TO_LIN(dwParam1), dwParam2); |
| case WIDM_RESET: |
| return widReset(wDevID); |
| case WIDM_START: |
| return widStart(wDevID); |
| case WIDM_STOP: |
| return widStop(wDevID); |
| default: |
| dprintf_mciwave(stddeb,"widMessage // unknown message !\n"); |
| } |
| return MMSYSERR_NOTSUPPORTED; |
| #else |
| return MMSYSERR_NOTENABLED; |
| #endif |
| } |
| |
| |
| /************************************************************************** |
| * AUDIO_DriverProc [sample driver] |
| */ |
| LONG WAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg, |
| DWORD dwParam1, DWORD dwParam2) |
| { |
| #ifdef linux |
| dprintf_mciwave(stddeb,"WAVE_DriverProc(%08lX, %04X, %04X, %08lX, %08lX)\n", |
| dwDevID, hDriv, wMsg, dwParam1, dwParam2); |
| switch(wMsg) { |
| case DRV_LOAD: |
| return 1; |
| case DRV_FREE: |
| return 1; |
| case DRV_OPEN: |
| return 1; |
| case DRV_CLOSE: |
| return 1; |
| case DRV_ENABLE: |
| return 1; |
| case DRV_DISABLE: |
| return 1; |
| case DRV_QUERYCONFIGURE: |
| return 1; |
| case DRV_CONFIGURE: |
| MessageBox((HWND)NULL, "Sample MultiMedia Linux Driver !", |
| "MMLinux Driver", MB_OK); |
| return 1; |
| case DRV_INSTALL: |
| return DRVCNF_RESTART; |
| case DRV_REMOVE: |
| return DRVCNF_RESTART; |
| case MCI_OPEN_DRIVER: |
| case MCI_OPEN: |
| return WAVE_mciOpen(dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS)PTR_SEG_TO_LIN(dwParam2)); |
| case MCI_CLOSE_DRIVER: |
| case MCI_CLOSE: |
| return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2)); |
| case MCI_PLAY: |
| return WAVE_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2)); |
| case MCI_RECORD: |
| return WAVE_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2)); |
| case MCI_STOP: |
| return WAVE_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2)); |
| case MCI_SET: |
| return WAVE_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2)); |
| case MCI_PAUSE: |
| return WAVE_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2)); |
| case MCI_RESUME: |
| return WAVE_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2)); |
| case MCI_STATUS: |
| return WAVE_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2)); |
| case MCI_GETDEVCAPS: |
| return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2)); |
| case MCI_INFO: |
| return WAVE_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS)PTR_SEG_TO_LIN(dwParam2)); |
| default: |
| return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); |
| } |
| #else |
| return MMSYSERR_NOTENABLED; |
| #endif |
| } |
| |
| |
| #endif /* #ifdef BUILTIN_MMSYSTEM */ |