From 890bee64a4494b8575c53c68adfaf7c594d07c27 Mon Sep 17 00:00:00 2001 From: Ozkan Sezer Date: Tue, 25 Jul 2023 11:40:02 +0300 Subject: [PATCH] os2 audio refactoring and capture support - Fixed audio device detection and usage. - Implemented audio capture support - Refactored buffer handling to separate pointers to fill and drain buffers. Based on patches by josch1710 and Lars Erdmann: https://github.com/bitwiseworks/SDL2-os2/pull/7 --- src/audio/os2/SDL_os2audio.c | 289 ++++++++++++++++++++++++++--------- src/audio/os2/SDL_os2audio.h | 5 +- 2 files changed, 223 insertions(+), 71 deletions(-) diff --git a/src/audio/os2/SDL_os2audio.c b/src/audio/os2/SDL_os2audio.c index ec17255dc156b..e8d4cb51e764c 100644 --- a/src/audio/os2/SDL_os2audio.c +++ b/src/audio/os2/SDL_os2audio.c @@ -30,17 +30,12 @@ #include "../SDL_audio_c.h" #include "SDL_os2audio.h" -/* -void lockIncr(volatile int *piVal); -#pragma aux lockIncr = \ - "lock add [eax], 1 "\ - parm [eax]; - -void lockDecr(volatile int *piVal); -#pragma aux lockDecr = \ - "lock sub [eax], 1 "\ - parm [eax]; -*/ +static PMCI_MIX_BUFFER _getNextBuffer(SDL_PrivateAudioData *pAData, PMCI_MIX_BUFFER pBuffer) +{ + PMCI_MIX_BUFFER pFirstBuffer = &pAData->aMixBuffers[0]; + PMCI_MIX_BUFFER pLastBuffer = &pAData->aMixBuffers[pAData->cMixBuffers -1]; + return (pBuffer == pLastBuffer ? pFirstBuffer : pBuffer+1); +} static ULONG _getEnvULong(const char *name, ULONG ulMax, ULONG ulDefault) { @@ -64,7 +59,7 @@ static int _MCIError(const char *func, ULONG ulResult) static void _mixIOError(const char *function, ULONG ulRC) { - debug_os2("%s() - failed, rc = 0x%X (%s)", + debug_os2("%s() - failed, rc = 0x%lX (%s)", function, ulRC, (ulRC == MCIERR_INVALID_MODE) ? "Mixer mode does not match request" : (ulRC == MCIERR_INVALID_BUFFER) ? "Caller sent an invalid buffer" : "unknown"); @@ -73,18 +68,33 @@ static void _mixIOError(const char *function, ULONG ulRC) static LONG APIENTRY cbAudioWriteEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) { - SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)pBuffer->ulUserParm; + SDL_AudioDevice *_this = (SDL_AudioDevice *)pBuffer->ulUserParm; + SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden; ULONG ulRC; + debug_os2("cbAudioWriteEvent: ulStatus = %lu, pBuffer = %p, ulFlags = %#lX",ulStatus,pBuffer,ulFlags); + + if (pAData->ulState == 2) + { + return 0; + } + if (ulFlags != MIX_WRITE_COMPLETE) { - debug_os2("flags = 0x%X", ulFlags); + debug_os2("flags = 0x%lX", ulFlags); + return 0; + } + + pAData->pDrainBuffer = pBuffer; + ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle, + pAData->pDrainBuffer, 1); + if (ulRC != MCIERR_SUCCESS) { + _mixIOError("pmixWrite", ulRC); return 0; } - /*lockDecr((int *)&pAData->ulQueuedBuf);*/ ulRC = DosPostEventSem(pAData->hevBuf); if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) { - debug_os2("DosPostEventSem(), rc = %u", ulRC); + debug_os2("DosPostEventSem(), rc = %lu", ulRC); } return 1; /* return value doesn't seem to matter. */ @@ -93,19 +103,36 @@ static LONG APIENTRY cbAudioWriteEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, static LONG APIENTRY cbAudioReadEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) { - SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)pBuffer->ulUserParm; + SDL_AudioDevice *_this = (SDL_AudioDevice *)pBuffer->ulUserParm; + SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden; ULONG ulRC; + debug_os2("cbAudioReadEvent: ulStatus = %lu, pBuffer = %p, ulFlags = %#lX",ulStatus,pBuffer,ulFlags); + + if (pAData->ulState == 2) + { + return 0; + } + if (ulFlags != MIX_READ_COMPLETE) { - debug_os2("flags = 0x%X", ulFlags); + debug_os2("flags = 0x%lX", ulFlags); return 0; } - pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle, pBuffer, 1); + pAData->pFillBuffer = pBuffer; + if (pAData->pFillBuffer == pAData->aMixBuffers) + { + ulRC = pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle, + pAData->pFillBuffer, pAData->cMixBuffers); + if (ulRC != MCIERR_SUCCESS) { + _mixIOError("pmixRead", ulRC); + return 0; + } + } ulRC = DosPostEventSem(pAData->hevBuf); if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) { - debug_os2("DosPostEventSem(), rc = %u", ulRC); + debug_os2("DosPostEventSem(), rc = %lu", ulRC); } return 1; @@ -120,31 +147,36 @@ static void OS2_DetectDevices(void) MCI_SYSINFO_LOGDEVICE stLogDevice; MCI_SYSINFO_PARMS stSysInfoParams; ULONG ulRC; - ULONG ulHandle = 0; + ULONG ulNumber; + MCI_GETDEVCAPS_PARMS stDevCapsParams; + MCI_OPEN_PARMS stMCIOpen; + MCI_GENERIC_PARMS stMCIGenericParams; + SDL_memset(&stMCISysInfo, 0, sizeof(stMCISysInfo)); acBuf[0] = '\0'; stMCISysInfo.pszReturn = acBuf; stMCISysInfo.ulRetSize = sizeof(acBuf); stMCISysInfo.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX; ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_QUANTITY, &stMCISysInfo, 0); - if (ulRC != NO_ERROR) { - debug_os2("MCI_SYSINFO, MCI_SYSINFO_QUANTITY - failed, rc = 0x%X", ulRC); + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { + debug_os2("MCI_SYSINFO, MCI_SYSINFO_QUANTITY - failed, rc = 0x%hX", LOUSHORT(ulRC)); return; } ulDevicesNum = SDL_strtoul(stMCISysInfo.pszReturn, NULL, 10); - for (stSysInfoParams.ulNumber = 0; stSysInfoParams.ulNumber < ulDevicesNum; - stSysInfoParams.ulNumber++) { + for (ulNumber = 1; ulNumber <= ulDevicesNum; + ulNumber++) { /* Get device install name. */ + stSysInfoParams.ulNumber = ulNumber; stSysInfoParams.pszReturn = acBuf; stSysInfoParams.ulRetSize = sizeof(acBuf); stSysInfoParams.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX; ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_INSTALLNAME, &stSysInfoParams, 0); - if (ulRC != NO_ERROR) { - debug_os2("MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME - failed, rc = 0x%X", ulRC); + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { + debug_os2("MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME - failed, rc = 0x%hX", LOUSHORT(ulRC)); continue; } @@ -154,15 +186,45 @@ static void OS2_DetectDevices(void) SDL_strlcpy(stLogDevice.szInstallName, stSysInfoParams.pszReturn, MAX_DEVICE_NAME); ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_ITEM, &stSysInfoParams, 0); - if (ulRC != NO_ERROR) { - debug_os2("MCI_SYSINFO, MCI_SYSINFO_ITEM - failed, rc = 0x%X", ulRC); + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { + debug_os2("MCI_SYSINFO, MCI_SYSINFO_ITEM - failed, rc = 0x%hX", LOUSHORT(ulRC)); continue; } - ulHandle++; - SDL_AddAudioDevice(0, stLogDevice.szProductInfo, NULL, (void *)(ulHandle)); - ulHandle++; - SDL_AddAudioDevice(1, stLogDevice.szProductInfo, NULL, (void *)(ulHandle)); + SDL_AddAudioDevice(0, stLogDevice.szProductInfo, NULL, (void *)ulNumber); + + /* Open audio device for querying its capabilities */ + /* at this point we HAVE TO OPEN the waveaudio device and not the ampmix device */ + /* because only the waveaudio device (tied to the ampmix device) supports querying for playback/record capability */ + SDL_memset(&stMCIOpen, 0, sizeof(stMCIOpen)); + stMCIOpen.pszDeviceType = (PSZ)MAKEULONG(MCI_DEVTYPE_WAVEFORM_AUDIO,LOUSHORT(ulNumber)); + ulRC = mciSendCommand(0, MCI_OPEN,MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,&stMCIOpen, 0); + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { + debug_os2("MCI_OPEN (getDevCaps) - failed"); + continue; + } + + /* check for recording capability */ + SDL_memset(&stDevCapsParams, 0, sizeof(stDevCapsParams)); + stDevCapsParams.ulItem = MCI_GETDEVCAPS_CAN_RECORD; + ulRC = mciSendCommand(stMCIOpen.usDeviceID, MCI_GETDEVCAPS, MCI_WAIT | MCI_GETDEVCAPS_ITEM, + &stDevCapsParams, 0); + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { + debug_os2("MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM - failed, rc = 0x%hX", LOUSHORT(ulRC)); + } + else { + if (stDevCapsParams.ulReturn) { + SDL_AddAudioDevice(1, stLogDevice.szProductInfo, NULL, (void *)(ulNumber | 0x80000000)); + } + } + + /* close the audio device, we are done querying its capabilities */ + SDL_memset(&stMCIGenericParams, 0, sizeof(stMCIGenericParams)); + ulRC = mciSendCommand(stMCIOpen.usDeviceID, MCI_CLOSE, MCI_WAIT, + &stMCIGenericParams, 0); + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { + debug_os2("MCI_CLOSE (getDevCaps) - failed"); + } } } @@ -171,52 +233,145 @@ static void OS2_WaitDevice(_THIS) SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden; ULONG ulRC; + debug_os2("Enter"); + /* Wait for an audio chunk to finish */ ulRC = DosWaitEventSem(pAData->hevBuf, 5000); if (ulRC != NO_ERROR) { - debug_os2("DosWaitEventSem(), rc = %u", ulRC); + debug_os2("DosWaitEventSem(), rc = %lu", ulRC); } } static Uint8 *OS2_GetDeviceBuf(_THIS) { SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden; - return (Uint8 *) pAData->aMixBuffers[pAData->ulNextBuf].pBuffer; + + debug_os2("Enter"); + + return (Uint8 *) pAData->pFillBuffer->pBuffer; } static void OS2_PlayDevice(_THIS) { SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden; ULONG ulRC; - PMCI_MIX_BUFFER pMixBuffer = &pAData->aMixBuffers[pAData->ulNextBuf]; + PMCI_MIX_BUFFER pMixBuffer = NULL; + + debug_os2("Enter"); + + pMixBuffer = pAData->pDrainBuffer; + pAData->pFillBuffer = _getNextBuffer(pAData, pAData->pFillBuffer); + if (!pAData->ulState && pAData->pFillBuffer != pMixBuffer) + { + /* + * this buffer was filled but we have not yet filled all buffers + * so just signal event sem so that OS2_WaitDevice does not need + * to block + */ + ulRC = DosPostEventSem(pAData->hevBuf); + } - /* Queue it up */ - /*lockIncr((int *)&pAData->ulQueuedBuf);*/ - ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle, - pMixBuffer, 1); - if (ulRC != MCIERR_SUCCESS) { - _mixIOError("pmixWrite", ulRC); - } else { - pAData->ulNextBuf = (pAData->ulNextBuf + 1) % pAData->cMixBuffers; + if (!pAData->ulState && (pAData->pFillBuffer == pMixBuffer) ) + { + debug_os2("!hasStarted"); + pAData->ulState = 1; + + /* Write buffers to kick off the amp mixer */ + ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle, + pMixBuffer, pAData->cMixBuffers); + + if (ulRC != MCIERR_SUCCESS) { + _mixIOError("pmixWrite", ulRC); + } } } +static int OS2_CaptureFromDevice(_THIS,void *buffer,int buflen) +{ + SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden; + ULONG ulRC; + PMCI_MIX_BUFFER pMixBuffer = NULL; + int len = 0; + + if (!pAData->ulState) + { + pAData->ulState = 1; + ulRC = pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle, + pAData->aMixBuffers, pAData->cMixBuffers); + if (ulRC != MCIERR_SUCCESS) { + _mixIOError("pmixRead", ulRC); + return -1; + } + } + + /* Wait for an audio chunk to finish */ + ulRC = DosWaitEventSem(pAData->hevBuf, 5000); + if (ulRC != NO_ERROR) + { + debug_os2("DosWaitEventSem(), rc = %lu", ulRC); + return -1; + } + + pMixBuffer = pAData->pDrainBuffer; + len = SDL_min((int)pMixBuffer->ulBufferLength, buflen); + SDL_memcpy(buffer,pMixBuffer->pBuffer, len); + pAData->pDrainBuffer = _getNextBuffer(pAData, pMixBuffer); + + debug_os2("buflen = %u, ulBufferLength = %lu",buflen,pMixBuffer->ulBufferLength); + + return len; +} + +static void OS2_FlushCapture(_THIS) +{ + SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden; + ULONG ulIdx; + + debug_os2("Enter"); + + /* Fill all device buffers with data */ + for (ulIdx = 0; ulIdx < pAData->cMixBuffers; ulIdx++) { + pAData->aMixBuffers[ulIdx].ulFlags = 0; + pAData->aMixBuffers[ulIdx].ulBufferLength = _this->spec.size; + pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)_this; + + SDL_memset(((PMCI_MIX_BUFFER)pAData->aMixBuffers)[ulIdx].pBuffer, + _this->spec.silence, _this->spec.size); + } + pAData->pFillBuffer = pAData->aMixBuffers; + pAData->pDrainBuffer = pAData->aMixBuffers; +} + + static void OS2_CloseDevice(_THIS) { SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden; MCI_GENERIC_PARMS sMCIGenericParms; ULONG ulRC; + debug_os2("Enter"); + if (pAData == NULL) return; + pAData->ulState = 2; + /* Close up audio */ if (pAData->usDeviceId != (USHORT)~0) { /* Device is open. */ + SDL_zero(sMCIGenericParms); + + ulRC = mciSendCommand(pAData->usDeviceId, MCI_STOP, + MCI_WAIT, + &sMCIGenericParms, 0); + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { + debug_os2("MCI_STOP - failed" ); + } + if (pAData->stMCIMixSetup.ulBitsPerSample != 0) { /* Mixer was initialized. */ ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP, MCI_WAIT | MCI_MIXSETUP_DEINIT, &pAData->stMCIMixSetup, 0); - if (ulRC != MCIERR_SUCCESS) { + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { debug_os2("MCI_MIXSETUP, MCI_MIXSETUP_DEINIT - failed"); } } @@ -230,14 +385,14 @@ static void OS2_CloseDevice(_THIS) ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &stMCIBuffer, 0); - if (ulRC != MCIERR_SUCCESS) { + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { debug_os2("MCI_BUFFER, MCI_DEALLOCATE_MEMORY - failed"); } } ulRC = mciSendCommand(pAData->usDeviceId, MCI_CLOSE, MCI_WAIT, &sMCIGenericParms, 0); - if (ulRC != MCIERR_SUCCESS) { + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { debug_os2("MCI_CLOSE - failed"); } } @@ -258,6 +413,7 @@ static int OS2_OpenDevice(_THIS, const char *devname) ULONG ulIdx; BOOL new_freq; SDL_bool iscapture = _this->iscapture; + ULONG ulHandle = (ULONG)_this->handle; new_freq = FALSE; SDL_zero(stMCIAmpOpen); @@ -279,20 +435,21 @@ static int OS2_OpenDevice(_THIS, const char *devname) ulRC = DosCreateEventSem(NULL, &pAData->hevBuf, DCE_AUTORESET, TRUE); if (ulRC != NO_ERROR) { - debug_os2("DosCreateEventSem() failed, rc = %u", ulRC); + debug_os2("DosCreateEventSem() failed, rc = %lu", ulRC); return -1; } /* Open audio device */ - stMCIAmpOpen.usDeviceID = (_this->handle != NULL) ? ((ULONG)_this->handle - 1) : 0; - stMCIAmpOpen.pszDeviceType = (PSZ)MCI_DEVTYPE_AUDIO_AMPMIX; + stMCIAmpOpen.usDeviceID = 0; + stMCIAmpOpen.pszDeviceType = (PSZ)MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX,LOUSHORT(ulHandle)); ulRC = mciSendCommand(0, MCI_OPEN, (_getEnvULong("SDL_AUDIO_SHARE", 1, 0) != 0)? MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE : MCI_WAIT | MCI_OPEN_TYPE_ID, &stMCIAmpOpen, 0); - if (ulRC != MCIERR_SUCCESS) { - stMCIAmpOpen.usDeviceID = (USHORT)~0; + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { + DosCloseEventSem(pAData->hevBuf); + pAData->usDeviceId = (USHORT)~0; return _MCIError("MCI_OPEN", ulRC); } pAData->usDeviceId = stMCIAmpOpen.usDeviceID; @@ -355,7 +512,7 @@ static int OS2_OpenDevice(_THIS, const char *devname) ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP, MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0); - if (ulRC != MCIERR_SUCCESS && _this->spec.freq > 44100) { + if (LOUSHORT(ulRC) != MCIERR_SUCCESS && _this->spec.freq > 44100) { new_freq = TRUE; pAData->stMCIMixSetup.ulSamplesPerSec = 44100; _this->spec.freq = 44100; @@ -363,7 +520,7 @@ static int OS2_OpenDevice(_THIS, const char *devname) MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0); } - debug_os2("Setup mixer [BPS: %u, Freq.: %u, Channels: %u]: %s", + debug_os2("Setup mixer [BPS: %lu, Freq.: %lu, Channels: %lu]: %s", pAData->stMCIMixSetup.ulBitsPerSample, pAData->stMCIMixSetup.ulSamplesPerSec, pAData->stMCIMixSetup.ulChannels, @@ -394,29 +551,25 @@ static int OS2_OpenDevice(_THIS, const char *devname) ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER, MCI_WAIT | MCI_ALLOCATE_MEMORY, &stMCIBuffer, 0); - if (ulRC != MCIERR_SUCCESS) { + if (LOUSHORT(ulRC) != MCIERR_SUCCESS) { return _MCIError("MCI_BUFFER", ulRC); } pAData->cMixBuffers = stMCIBuffer.ulNumBuffers; _this->spec.size = stMCIBuffer.ulBufferSize; + debug_os2("%s, number of mix buffers: %lu",iscapture ? "capture": "play",pAData->cMixBuffers); + /* Fill all device buffers with data */ for (ulIdx = 0; ulIdx < stMCIBuffer.ulNumBuffers; ulIdx++) { pAData->aMixBuffers[ulIdx].ulFlags = 0; pAData->aMixBuffers[ulIdx].ulBufferLength = stMCIBuffer.ulBufferSize; - pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)pAData; + pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)_this; SDL_memset(((PMCI_MIX_BUFFER)stMCIBuffer.pBufList)[ulIdx].pBuffer, _this->spec.silence, stMCIBuffer.ulBufferSize); } - - /* Write buffers to kick off the amp mixer */ - ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle, - pAData->aMixBuffers, 1); - if (ulRC != MCIERR_SUCCESS) { - _mixIOError("pmixWrite", ulRC); - return -1; - } + pAData->pFillBuffer = pAData->aMixBuffers; + pAData->pDrainBuffer = pAData->aMixBuffers; return 0; } @@ -431,12 +584,10 @@ static SDL_bool OS2_Init(SDL_AudioDriverImpl * impl) impl->WaitDevice = OS2_WaitDevice; impl->GetDeviceBuf = OS2_GetDeviceBuf; impl->CloseDevice = OS2_CloseDevice; - - /* TODO: IMPLEMENT CAPTURE SUPPORT: - impl->CaptureFromDevice = ; - impl->FlushCapture = ; + impl->CaptureFromDevice = OS2_CaptureFromDevice ; + impl->FlushCapture = OS2_FlushCapture; impl->HasCaptureSupport = SDL_TRUE; - */ + return SDL_TRUE; /* this audio target is available. */ } diff --git a/src/audio/os2/SDL_os2audio.h b/src/audio/os2/SDL_os2audio.h index 0bee30787e130..fb6a832b67d52 100644 --- a/src/audio/os2/SDL_os2audio.h +++ b/src/audio/os2/SDL_os2audio.h @@ -43,10 +43,11 @@ typedef struct SDL_PrivateAudioData BYTE _pad[2]; MCI_MIXSETUP_PARMS stMCIMixSetup; HEV hevBuf; - ULONG ulNextBuf; + PMCI_MIX_BUFFER pFillBuffer; + PMCI_MIX_BUFFER pDrainBuffer; + ULONG ulState; ULONG cMixBuffers; MCI_MIX_BUFFER aMixBuffers[NUM_BUFFERS]; -/* ULONG ulQueuedBuf;*/ } SDL_PrivateAudioData; #endif /* SDL_os2mm_h_ */