SDL: os2 audio refactoring and capture support (b4d87)

From b4d87654260379f8fbc09bb84561cda125f76de9 Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
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
(cherry picked from commit 890bee64a4494b8575c53c68adfaf7c594d07c27)
---
 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 ec17255dc156..e8d4cb51e764 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 0bee30787e13..fb6a832b67d5 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_ */