App-MHFS

 view release on metacpan or  search on metacpan

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

                    continue; /* Nothing is available in the capture buffer. */
                }

                hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0);
                if (FAILED(hr)) {
                    return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
                }


                /* At this point we have some input data that we need to output. We do not return until every mapped frame of the input data is written to the playback device. */
                mappedDeviceFramesProcessedCapture = 0;

                for (;;) {  /* Keep writing to the playback device. */
                    ma_uint8  inputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
                    ma_uint32 inputFramesInClientFormatCap = sizeof(inputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
                    ma_uint8  outputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
                    ma_uint32 outputFramesInClientFormatCap = sizeof(outputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
                    ma_uint32 outputFramesInClientFormatCount;
                    ma_uint32 outputFramesInClientFormatConsumed = 0;
                    ma_uint64 clientCapturedFramesToProcess = ma_min(inputFramesInClientFormatCap, outputFramesInClientFormatCap);
                    ma_uint64 deviceCapturedFramesToProcess = (mappedSizeInBytesCapture / bpfDeviceCapture) - mappedDeviceFramesProcessedCapture;
                    void* pRunningMappedDeviceBufferCapture = ma_offset_ptr(pMappedDeviceBufferCapture, mappedDeviceFramesProcessedCapture * bpfDeviceCapture);

                    result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningMappedDeviceBufferCapture, &deviceCapturedFramesToProcess, inputFramesInClientFormat, &clientCapturedFramesToProcess);
                    if (result != MA_SUCCESS) {
                        break;
                    }

                    outputFramesInClientFormatCount     = (ma_uint32)clientCapturedFramesToProcess;
                    mappedDeviceFramesProcessedCapture += (ma_uint32)deviceCapturedFramesToProcess;

                    ma_device__on_data(pDevice, outputFramesInClientFormat, inputFramesInClientFormat, (ma_uint32)clientCapturedFramesToProcess);

                    /* At this point we have input and output data in client format. All we need to do now is convert it to the output device format. This may take a few passes. */
                    for (;;) {
                        ma_uint32 framesWrittenThisIteration;
                        DWORD physicalPlayCursorInBytes;
                        DWORD physicalWriteCursorInBytes;
                        DWORD availableBytesPlayback;
                        DWORD silentPaddingInBytes = 0; /* <-- Must be initialized to 0. */

                        /* We need the physical play and write cursors. */
                        if (FAILED(ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes))) {
                            break;
                        }

                        if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
                            physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
                        }
                        prevPlayCursorInBytesPlayback  = physicalPlayCursorInBytes;

                        /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */
                        if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
                            /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
                            if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
                                availableBytesPlayback  = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
                                availableBytesPlayback += physicalPlayCursorInBytes;    /* Wrap around. */
                            } else {
                                /* This is an error. */
                            #ifdef MA_DEBUG_OUTPUT
                                printf("[DirectSound] (Duplex/Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, v...
                            #endif
                                availableBytesPlayback = 0;
                            }
                        } else {
                            /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
                            if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
                                availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
                            } else {
                                /* This is an error. */
                            #ifdef MA_DEBUG_OUTPUT
                                printf("[DirectSound] (Duplex/Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, v...
                            #endif
                                availableBytesPlayback = 0;
                            }
                        }

                    #ifdef MA_DEBUG_OUTPUT
                        /*printf("[DirectSound] (Duplex/Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/
                    #endif

                        /* If there's no room available for writing we need to wait for more. */
                        if (availableBytesPlayback == 0) {
                            /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */
                            if (!isPlaybackDeviceStarted) {
                                hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
                                if (FAILED(hr)) {
                                    ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
                                    return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
                                }
                                isPlaybackDeviceStarted = MA_TRUE;
                            } else {
                                ma_sleep(waitTimeInMilliseconds);
                                continue;
                            }
                        }


                        /* Getting here means there room available somewhere. We limit this to either the end of the buffer or the physical play cursor, whichever is closest. */
                        lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback;
                        if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
                            /* Same loop iteration. Go up to the end of the buffer. */
                            lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
                        } else {
                            /* Different loop iterations. Go up to the physical play cursor. */
                            lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
                        }

                        hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0);
                        if (FAILED(hr)) {
                            result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
                            break;
                        }

                        /*
                        Experiment: If the playback buffer is being starved, pad it with some silence to get it back in sync. This will cause a glitch, but it may prevent
                        endless glitching due to it constantly running out of data.
                        */
                        if (isPlaybackDeviceStarted) {
                            DWORD bytesQueuedForPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - availableBytesPlayback;
                            if (bytesQueuedForPlayback < (pDevice->playback.internalPeriodSizeInFrames*bpfDevicePlayback)) {
                                silentPaddingInBytes   = (pDevice->playback.internalPeriodSizeInFrames*2*bpfDevicePlayback) - bytesQueuedForPlayback;
                                if (silentPaddingInBytes > lockSizeInBytesPlayback) {
                                    silentPaddingInBytes = lockSizeInBytesPlayback;
                                }

                        #ifdef MA_DEBUG_OUTPUT
                                printf("[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%ld, silentPaddingInBytes=%ld\n", availableBytesPlayback, silentPaddingInBytes);
                        #endif
                            }
                        }

                        /* At this point we have a buffer for output. */
                        if (silentPaddingInBytes > 0) {
                            MA_ZERO_MEMORY(pMappedDeviceBufferPlayback, silentPaddingInBytes);
                            framesWrittenThisIteration = silentPaddingInBytes/bpfDevicePlayback;
                        } else {
                            ma_uint64 convertedFrameCountIn  = (outputFramesInClientFormatCount - outputFramesInClientFormatConsumed);
                            ma_uint64 convertedFrameCountOut = mappedSizeInBytesPlayback/bpfDevicePlayback;
                            void* pConvertedFramesIn  = ma_offset_ptr(outputFramesInClientFormat, outputFramesInClientFormatConsumed * bpfDevicePlayback);
                            void* pConvertedFramesOut = pMappedDeviceBufferPlayback;

                            result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pConvertedFramesIn, &convertedFrameCountIn, pConvertedFramesOut, &convertedFrameCountOut);
                            if (result != MA_SUCCESS) {
                                break;
                            }

                            outputFramesInClientFormatConsumed += (ma_uint32)convertedFrameCountOut;
                            framesWrittenThisIteration          = (ma_uint32)convertedFrameCountOut;
                        }
                        

                        hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, framesWrittenThisIteration*bpfDevicePlayback, NULL, 0);
                        if (FAILED(hr)) {
                            result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
                            break;
                        }

                        virtualWriteCursorInBytesPlayback += framesWrittenThisIteration*bpfDevicePlayback;
                        if ((virtualWriteCursorInBytesPlayback/bpfDevicePlayback) == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods) {
                            virtualWriteCursorInBytesPlayback  = 0;
                            virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback;
                        }
                        
                        /*

share/public_html/static/music_inc/src/miniaudio.h  view on Meta::CPAN

            #ifdef MA_DEBUG_OUTPUT
                /*printf("[DirectSound] (Capture) physicalCaptureCursorInBytes=%d, physicalReadCursorInBytes=%d\n", physicalCaptureCursorInBytes, physicalReadCursorInBytes);*/
                /*printf("[DirectSound] (Capture) lockOffsetInBytesCapture=%d, lockSizeInBytesCapture=%d\n", lockOffsetInBytesCapture, lockSizeInBytesCapture);*/
            #endif

                if (lockSizeInBytesCapture < pDevice->capture.internalPeriodSizeInFrames) {
                    ma_sleep(waitTimeInMilliseconds);
                    continue; /* Nothing is available in the capture buffer. */
                }

                hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0);
                if (FAILED(hr)) {
                    return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
                }

            #ifdef MA_DEBUG_OUTPUT
                if (lockSizeInBytesCapture != mappedSizeInBytesCapture) {
                    printf("[DirectSound] (Capture) lockSizeInBytesCapture=%ld != mappedSizeInBytesCapture=%ld\n", lockSizeInBytesCapture, mappedSizeInBytesCapture);
                }
            #endif

                ma_device__send_frames_to_client(pDevice, mappedSizeInBytesCapture/bpfDeviceCapture, pMappedDeviceBufferCapture);

                hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0);
                if (FAILED(hr)) {
                    return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr));
                }
                prevReadCursorInBytesCapture = lockOffsetInBytesCapture + mappedSizeInBytesCapture;

                if (prevReadCursorInBytesCapture == (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture)) {
                    prevReadCursorInBytesCapture = 0;
                }
            } break;



            case ma_device_type_playback:
            {
                DWORD availableBytesPlayback;
                DWORD physicalPlayCursorInBytes;
                DWORD physicalWriteCursorInBytes;
                hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes);
                if (FAILED(hr)) {
                    break;
                }

                if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
                    physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
                }
                prevPlayCursorInBytesPlayback  = physicalPlayCursorInBytes;

                /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */
                if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
                    /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
                    if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
                        availableBytesPlayback  = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
                        availableBytesPlayback += physicalPlayCursorInBytes;    /* Wrap around. */
                    } else {
                        /* This is an error. */
                    #ifdef MA_DEBUG_OUTPUT
                        printf("[DirectSound] (Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCurs...
                    #endif
                        availableBytesPlayback = 0;
                    }
                } else {
                    /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
                    if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
                        availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
                    } else {
                        /* This is an error. */
                    #ifdef MA_DEBUG_OUTPUT
                        printf("[DirectSound] (Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCurs...
                    #endif
                        availableBytesPlayback = 0;
                    }
                }

            #ifdef MA_DEBUG_OUTPUT
                /*printf("[DirectSound] (Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/
            #endif

                /* If there's no room available for writing we need to wait for more. */
                if (availableBytesPlayback < pDevice->playback.internalPeriodSizeInFrames) {
                    /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */
                    if (availableBytesPlayback == 0 && !isPlaybackDeviceStarted) {
                        hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
                        if (FAILED(hr)) {
                            return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
                        }
                        isPlaybackDeviceStarted = MA_TRUE;
                    } else {
                        ma_sleep(waitTimeInMilliseconds);
                        continue;
                    }
                }

                /* Getting here means there room available somewhere. We limit this to either the end of the buffer or the physical play cursor, whichever is closest. */
                lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback;
                if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
                    /* Same loop iteration. Go up to the end of the buffer. */
                    lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
                } else {
                    /* Different loop iterations. Go up to the physical play cursor. */
                    lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
                }

                hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0);
                if (FAILED(hr)) {
                    result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
                    break;
                }

                /* At this point we have a buffer for output. */
                ma_device__read_frames_from_client(pDevice, (mappedSizeInBytesPlayback/bpfDevicePlayback), pMappedDeviceBufferPlayback);

                hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, mappedSizeInBytesPlayback, NULL, 0);
                if (FAILED(hr)) {
                    result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
                    break;
                }

                virtualWriteCursorInBytesPlayback += mappedSizeInBytesPlayback;
                if (virtualWriteCursorInBytesPlayback == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) {
                    virtualWriteCursorInBytesPlayback  = 0;
                    virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback;
                }
                        
                /*
                We may need to start the device. We want two full periods to be written before starting the playback device. Having an extra period adds
                a bit of a buffer to prevent the playback buffer from getting starved.
                */
                framesWrittenToPlaybackDevice += mappedSizeInBytesPlayback/bpfDevicePlayback;
                if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= pDevice->playback.internalPeriodSizeInFrames) {
                    hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
                    if (FAILED(hr)) {
                        return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
                    }
                    isPlaybackDeviceStarted = MA_TRUE;
                }
            } break;


            default: return MA_INVALID_ARGS;   /* Invalid device type. */
        }

        if (result != MA_SUCCESS) {
            return result;
        }
    }

    /* Getting here means the device is being stopped. */
    if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
        hr = ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
        if (FAILED(hr)) {
            return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed.", ma_result_from_HRESULT(hr));
        }
    }

    if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
        /* The playback device should be drained before stopping. All we do is wait until the available bytes is equal to the size of the buffer. */
        if (isPlaybackDeviceStarted) {
            for (;;) {
                DWORD availableBytesPlayback = 0;
                DWORD physicalPlayCursorInBytes;
                DWORD physicalWriteCursorInBytes;
                hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes);
                if (FAILED(hr)) {
                    break;
                }

                if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
                    physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
                }
                prevPlayCursorInBytesPlayback  = physicalPlayCursorInBytes;

                if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
                    /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
                    if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
                        availableBytesPlayback  = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
                        availableBytesPlayback += physicalPlayCursorInBytes;    /* Wrap around. */
                    } else {
                        break;
                    }
                } else {
                    /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
                    if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
                        availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
                    } else {
                        break;
                    }
                }

                if (availableBytesPlayback >= (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback)) {
                    break;
                }

                ma_sleep(waitTimeInMilliseconds);
            }
        }

        hr = ma_IDirectSoundBuffer_Stop((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer);
        if (FAILED(hr)) {
            return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Stop() failed.", ma_result_from_HRESULT(hr));
        }

        ma_IDirectSoundBuffer_SetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0);
    }

    return MA_SUCCESS;
}

static ma_result ma_context_uninit__dsound(ma_context* pContext)
{
    MA_ASSERT(pContext != NULL);
    MA_ASSERT(pContext->backend == ma_backend_dsound);

    ma_dlclose(pContext, pContext->dsound.hDSoundDLL);

    return MA_SUCCESS;
}

static ma_result ma_context_init__dsound(const ma_context_config* pConfig, ma_context* pContext)
{
    MA_ASSERT(pContext != NULL);

    (void)pConfig;

    pContext->dsound.hDSoundDLL = ma_dlopen(pContext, "dsound.dll");
    if (pContext->dsound.hDSoundDLL == NULL) {
        return MA_API_NOT_FOUND;
    }

    pContext->dsound.DirectSoundCreate            = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCreate");
    pContext->dsound.DirectSoundEnumerateA        = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundEnumerateA");
    pContext->dsound.DirectSoundCaptureCreate     = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureCreate");
    pContext->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA");

    pContext->onUninit         = ma_context_uninit__dsound;
    pContext->onDeviceIDEqual  = ma_context_is_device_id_equal__dsound;
    pContext->onEnumDevices    = ma_context_enumerate_devices__dsound;
    pContext->onGetDeviceInfo  = ma_context_get_device_info__dsound;
    pContext->onDeviceInit     = ma_device_init__dsound;
    pContext->onDeviceUninit   = ma_device_uninit__dsound;
    pContext->onDeviceStart    = NULL;  /* Not used. Started in onDeviceMainLoop. */
    pContext->onDeviceStop     = NULL;  /* Not used. Stopped in onDeviceMainLoop. */



( run in 0.369 second using v1.01-cache-2.11-cpan-96521ef73a4 )