Commit 672cdf46 authored by David Reid's avatar David Reid

Migrate the WinMM backend over to the new callback system.

parent eb694c44
......@@ -16705,6 +16705,8 @@ static ma_result ma_get_best_info_from_formats_flags__winmm(DWORD dwFormats, WOR
static ma_result ma_formats_flags_to_WAVEFORMATEX__winmm(DWORD dwFormats, WORD channels, WAVEFORMATEX* pWF)
{
ma_result result;
MA_ASSERT(pWF != NULL);
MA_ZERO_OBJECT(pWF);
......@@ -16715,62 +16717,9 @@ static ma_result ma_formats_flags_to_WAVEFORMATEX__winmm(DWORD dwFormats, WORD c
pWF->nChannels = 2;
}
if (channels == 1) {
pWF->wBitsPerSample = 16;
if ((dwFormats & WAVE_FORMAT_48M16) != 0) {
pWF->nSamplesPerSec = 48000;
} else if ((dwFormats & WAVE_FORMAT_44M16) != 0) {
pWF->nSamplesPerSec = 44100;
} else if ((dwFormats & WAVE_FORMAT_2M16) != 0) {
pWF->nSamplesPerSec = 22050;
} else if ((dwFormats & WAVE_FORMAT_1M16) != 0) {
pWF->nSamplesPerSec = 11025;
} else if ((dwFormats & WAVE_FORMAT_96M16) != 0) {
pWF->nSamplesPerSec = 96000;
} else {
pWF->wBitsPerSample = 8;
if ((dwFormats & WAVE_FORMAT_48M08) != 0) {
pWF->nSamplesPerSec = 48000;
} else if ((dwFormats & WAVE_FORMAT_44M08) != 0) {
pWF->nSamplesPerSec = 44100;
} else if ((dwFormats & WAVE_FORMAT_2M08) != 0) {
pWF->nSamplesPerSec = 22050;
} else if ((dwFormats & WAVE_FORMAT_1M08) != 0) {
pWF->nSamplesPerSec = 11025;
} else if ((dwFormats & WAVE_FORMAT_96M08) != 0) {
pWF->nSamplesPerSec = 96000;
} else {
return MA_FORMAT_NOT_SUPPORTED;
}
}
} else {
pWF->wBitsPerSample = 16;
if ((dwFormats & WAVE_FORMAT_48S16) != 0) {
pWF->nSamplesPerSec = 48000;
} else if ((dwFormats & WAVE_FORMAT_44S16) != 0) {
pWF->nSamplesPerSec = 44100;
} else if ((dwFormats & WAVE_FORMAT_2S16) != 0) {
pWF->nSamplesPerSec = 22050;
} else if ((dwFormats & WAVE_FORMAT_1S16) != 0) {
pWF->nSamplesPerSec = 11025;
} else if ((dwFormats & WAVE_FORMAT_96S16) != 0) {
pWF->nSamplesPerSec = 96000;
} else {
pWF->wBitsPerSample = 8;
if ((dwFormats & WAVE_FORMAT_48S08) != 0) {
pWF->nSamplesPerSec = 48000;
} else if ((dwFormats & WAVE_FORMAT_44S08) != 0) {
pWF->nSamplesPerSec = 44100;
} else if ((dwFormats & WAVE_FORMAT_2S08) != 0) {
pWF->nSamplesPerSec = 22050;
} else if ((dwFormats & WAVE_FORMAT_1S08) != 0) {
pWF->nSamplesPerSec = 11025;
} else if ((dwFormats & WAVE_FORMAT_96S08) != 0) {
pWF->nSamplesPerSec = 96000;
} else {
return MA_FORMAT_NOT_SUPPORTED;
}
}
result = ma_get_best_info_from_formats_flags__winmm(dwFormats, channels, &pWF->wBitsPerSample, &pWF->nSamplesPerSec);
if (result != MA_SUCCESS) {
return result;
}
pWF->nBlockAlign = (WORD)(pWF->nChannels * pWF->wBitsPerSample / 8);
......@@ -16856,22 +16805,21 @@ static ma_result ma_context_get_device_info_from_WAVECAPS(ma_context* pContext,
return result;
}
pDeviceInfo->minChannels = pCaps->wChannels;
pDeviceInfo->maxChannels = pCaps->wChannels;
pDeviceInfo->minSampleRate = sampleRate;
pDeviceInfo->maxSampleRate = sampleRate;
pDeviceInfo->formatCount = 1;
if (bitsPerSample == 8) {
pDeviceInfo->formats[0] = ma_format_u8;
pDeviceInfo->nativeDataFormats[0].format = ma_format_u8;
} else if (bitsPerSample == 16) {
pDeviceInfo->formats[0] = ma_format_s16;
pDeviceInfo->nativeDataFormats[0].format = ma_format_s16;
} else if (bitsPerSample == 24) {
pDeviceInfo->formats[0] = ma_format_s24;
pDeviceInfo->nativeDataFormats[0].format = ma_format_s24;
} else if (bitsPerSample == 32) {
pDeviceInfo->formats[0] = ma_format_s32;
pDeviceInfo->nativeDataFormats[0].format = ma_format_s32;
} else {
return MA_FORMAT_NOT_SUPPORTED;
}
pDeviceInfo->nativeDataFormats[0].channels = pCaps->wChannels;
pDeviceInfo->nativeDataFormats[0].sampleRate = sampleRate;
pDeviceInfo->nativeDataFormats[0].flags = 0;
pDeviceInfo->nativeDataFormatCount = 1;
return MA_SUCCESS;
}
......@@ -16887,7 +16835,7 @@ static ma_result ma_context_get_device_info_from_WAVEOUTCAPS2(ma_context* pConte
MA_COPY_MEMORY(caps.szPname, pCaps->szPname, sizeof(caps.szPname));
caps.dwFormats = pCaps->dwFormats;
caps.wChannels = pCaps->wChannels;
caps.NameGuid = pCaps->NameGuid;
caps.NameGuid = pCaps->NameGuid;
return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo);
}
......@@ -16902,7 +16850,7 @@ static ma_result ma_context_get_device_info_from_WAVEINCAPS2(ma_context* pContex
MA_COPY_MEMORY(caps.szPname, pCaps->szPname, sizeof(caps.szPname));
caps.dwFormats = pCaps->dwFormats;
caps.wChannels = pCaps->wChannels;
caps.NameGuid = pCaps->NameGuid;
caps.NameGuid = pCaps->NameGuid;
return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo);
}
......@@ -16978,16 +16926,12 @@ static ma_result ma_context_enumerate_devices__winmm(ma_context* pContext, ma_en
return MA_SUCCESS;
}
static ma_result ma_context_get_device_info__winmm(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
static ma_result ma_context_get_device_info__winmm(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
{
UINT winMMDeviceID;
MA_ASSERT(pContext != NULL);
if (shareMode == ma_share_mode_exclusive) {
return MA_SHARE_MODE_NOT_SUPPORTED;
}
winMMDeviceID = 0;
if (pDeviceID != NULL) {
winMMDeviceID = (UINT)pDeviceID->winmm;
......@@ -17026,7 +16970,7 @@ static ma_result ma_context_get_device_info__winmm(ma_context* pContext, ma_devi
}
static void ma_device_uninit__winmm(ma_device* pDevice)
static ma_result ma_device_uninit__winmm(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
......@@ -17044,9 +16988,27 @@ static void ma_device_uninit__winmm(ma_device* pDevice)
ma__free_from_callbacks(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks);
MA_ZERO_OBJECT(&pDevice->winmm); /* Safety. */
return MA_SUCCESS;
}
static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
static ma_uint32 ma_calculate_period_size_in_frames__winmm(ma_uint32 periodSizeInFrames, ma_uint32 periodSizeInMilliseconds, ma_uint32 sampleRate)
{
/* DirectSound has a minimum period size of 40ms. */
ma_uint32 minPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(40, sampleRate);
if (periodSizeInFrames == 0) {
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(periodSizeInMilliseconds, sampleRate);
}
if (periodSizeInFrames < minPeriodSizeInFrames) {
periodSizeInFrames = minPeriodSizeInFrames;
}
return periodSizeInFrames;
}
static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
{
const char* errorMsg = "";
ma_result errorCode = MA_ERROR;
......@@ -17054,9 +17016,9 @@ static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_con
ma_uint32 heapSize;
UINT winMMDeviceIDPlayback = 0;
UINT winMMDeviceIDCapture = 0;
ma_uint32 periodSizeInMilliseconds;
MA_ASSERT(pDevice != NULL);
MA_ZERO_OBJECT(&pDevice->winmm);
if (pConfig->deviceType == ma_device_type_loopback) {
......@@ -17069,26 +17031,11 @@ static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_con
return MA_SHARE_MODE_NOT_SUPPORTED;
}
periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
if (periodSizeInMilliseconds == 0) {
periodSizeInMilliseconds = ma_calculate_buffer_size_in_milliseconds_from_frames(pConfig->periodSizeInFrames, pConfig->sampleRate);
if (pDescriptorPlayback->pDeviceID != NULL) {
winMMDeviceIDPlayback = (UINT)pDescriptorPlayback->pDeviceID->winmm;
}
/* WinMM has horrible latency. */
if (pDevice->usingDefaultBufferSize) {
if (pConfig->performanceProfile == ma_performance_profile_low_latency) {
periodSizeInMilliseconds = 40;
} else {
periodSizeInMilliseconds = 400;
}
}
if (pConfig->playback.pDeviceID != NULL) {
winMMDeviceIDPlayback = (UINT)pConfig->playback.pDeviceID->winmm;
}
if (pConfig->capture.pDeviceID != NULL) {
winMMDeviceIDCapture = (UINT)pConfig->capture.pDeviceID->winmm;
if (pDescriptorCapture->pDeviceID != NULL) {
winMMDeviceIDCapture = (UINT)pDescriptorCapture->pDeviceID->winmm;
}
/* The capture device needs to be initialized first. */
......@@ -17105,7 +17052,7 @@ static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_con
}
/* The format should be based on the device's actual format. */
if (((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceIDCapture, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
if (((MA_PFN_waveInGetDevCapsA)pDevice->pContext->winmm.waveInGetDevCapsA)(winMMDeviceIDCapture, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
goto on_error;
}
......@@ -17122,12 +17069,12 @@ static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_con
goto on_error;
}
pDevice->capture.internalFormat = ma_format_from_WAVEFORMATEX(&wf);
pDevice->capture.internalChannels = wf.nChannels;
pDevice->capture.internalSampleRate = wf.nSamplesPerSec;
ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap);
pDevice->capture.internalPeriods = pConfig->periods;
pDevice->capture.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(periodSizeInMilliseconds, pDevice->capture.internalSampleRate);
pDescriptorCapture->format = ma_format_from_WAVEFORMATEX(&wf);
pDescriptorCapture->channels = wf.nChannels;
pDescriptorCapture->sampleRate = wf.nSamplesPerSec;
ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDescriptorCapture->channels, pDescriptorCapture->channelMap);
pDescriptorCapture->periodCount = pDescriptorCapture->periodCount;
pDescriptorCapture->periodSizeInFrames = ma_calculate_period_size_in_frames__winmm(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->periodSizeInMilliseconds, pDescriptorCapture->sampleRate);
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
......@@ -17143,7 +17090,7 @@ static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_con
}
/* The format should be based on the device's actual format. */
if (((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
if (((MA_PFN_waveOutGetDevCapsA)pDevice->pContext->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
goto on_error;
}
......@@ -17154,18 +17101,18 @@ static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_con
goto on_error;
}
resultMM = ((MA_PFN_waveOutOpen)pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevicePlayback, winMMDeviceIDPlayback, &wf, (DWORD_PTR)pDevice->winmm.hEventPlayback, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
resultMM = ((MA_PFN_waveOutOpen)pDevice->pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevicePlayback, winMMDeviceIDPlayback, &wf, (DWORD_PTR)pDevice->winmm.hEventPlayback, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
if (resultMM != MMSYSERR_NOERROR) {
errorMsg = "[WinMM] Failed to open playback device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
goto on_error;
}
pDevice->playback.internalFormat = ma_format_from_WAVEFORMATEX(&wf);
pDevice->playback.internalChannels = wf.nChannels;
pDevice->playback.internalSampleRate = wf.nSamplesPerSec;
ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap);
pDevice->playback.internalPeriods = pConfig->periods;
pDevice->playback.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(periodSizeInMilliseconds, pDevice->playback.internalSampleRate);
pDescriptorPlayback->format = ma_format_from_WAVEFORMATEX(&wf);
pDescriptorPlayback->channels = wf.nChannels;
pDescriptorPlayback->sampleRate = wf.nSamplesPerSec;
ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap);
pDescriptorPlayback->periodCount = pDescriptorPlayback->periodCount;
pDescriptorPlayback->periodSizeInFrames = ma_calculate_period_size_in_frames__winmm(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->periodSizeInMilliseconds, pDescriptorPlayback->sampleRate);
}
/*
......@@ -17175,13 +17122,13 @@ static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_con
*/
heapSize = 0;
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
heapSize += sizeof(WAVEHDR)*pDevice->capture.internalPeriods + (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
heapSize += sizeof(WAVEHDR)*pDescriptorCapture->periodCount + (pDescriptorCapture->periodSizeInFrames * pDescriptorCapture->periodCount * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels));
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
heapSize += sizeof(WAVEHDR)*pDevice->playback.internalPeriods + (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
heapSize += sizeof(WAVEHDR)*pDescriptorPlayback->periodCount + (pDescriptorPlayback->periodSizeInFrames * pDescriptorPlayback->periodCount * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels));
}
pDevice->winmm._pHeapData = (ma_uint8*)ma__calloc_from_callbacks(heapSize, &pContext->allocationCallbacks);
pDevice->winmm._pHeapData = (ma_uint8*)ma__calloc_from_callbacks(heapSize, &pDevice->pContext->allocationCallbacks);
if (pDevice->winmm._pHeapData == NULL) {
errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MA_OUT_OF_MEMORY;
goto on_error;
......@@ -17194,21 +17141,21 @@ static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_con
if (pConfig->deviceType == ma_device_type_capture) {
pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData;
pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods));
pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount));
} else {
pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData;
pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods + pDevice->playback.internalPeriods));
pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount + pDescriptorPlayback->periodCount));
}
/* Prepare headers. */
for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalFormat, pDevice->capture.internalChannels);
for (iPeriod = 0; iPeriod < pDescriptorCapture->periodCount; ++iPeriod) {
ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->format, pDescriptorCapture->channels);
((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBufferCapture + (periodSizeInBytes*iPeriod));
((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwBufferLength = periodSizeInBytes;
((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwFlags = 0L;
((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwLoops = 0L;
((MA_PFN_waveInPrepareHeader)pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
((MA_PFN_waveInPrepareHeader)pDevice->pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
/*
The user data of the WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means
......@@ -17217,26 +17164,27 @@ static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_con
((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwUser = 0;
}
}
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_uint32 iPeriod;
if (pConfig->deviceType == ma_device_type_playback) {
pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData;
pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*pDevice->playback.internalPeriods);
pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*pDescriptorPlayback->periodCount);
} else {
pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods));
pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods + pDevice->playback.internalPeriods)) + (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount));
pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount + pDescriptorPlayback->periodCount)) + (pDescriptorCapture->periodSizeInFrames*pDescriptorCapture->periodCount*ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels));
}
/* Prepare headers. */
for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) {
ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalFormat, pDevice->playback.internalChannels);
for (iPeriod = 0; iPeriod < pDescriptorPlayback->periodCount; ++iPeriod) {
ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->format, pDescriptorPlayback->channels);
((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBufferPlayback + (periodSizeInBytes*iPeriod));
((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwBufferLength = periodSizeInBytes;
((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwFlags = 0L;
((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwLoops = 0L;
((MA_PFN_waveOutPrepareHeader)pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
((MA_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
/*
The user data of the WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means
......@@ -17252,29 +17200,68 @@ on_error:
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
if (pDevice->winmm.pWAVEHDRCapture != NULL) {
ma_uint32 iPeriod;
for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
((MA_PFN_waveInUnprepareHeader)pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
for (iPeriod = 0; iPeriod < pDescriptorCapture->periodCount; ++iPeriod) {
((MA_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
}
}
((MA_PFN_waveInClose)pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture);
((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture);
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
if (pDevice->winmm.pWAVEHDRCapture != NULL) {
ma_uint32 iPeriod;
for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) {
((MA_PFN_waveOutUnprepareHeader)pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
for (iPeriod = 0; iPeriod < pDescriptorPlayback->periodCount; ++iPeriod) {
((MA_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
}
}
((MA_PFN_waveOutClose)pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
}
ma__free_from_callbacks(pDevice->winmm._pHeapData, &pContext->allocationCallbacks);
ma__free_from_callbacks(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks);
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, errorMsg, errorCode);
}
static ma_result ma_device_start__winmm(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
MMRESULT resultMM;
WAVEHDR* pWAVEHDR;
ma_uint32 iPeriod;
pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRCapture;
/* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */
ResetEvent((HANDLE)pDevice->winmm.hEventCapture);
/* To start the device we attach all of the buffers and then start it. As the buffers are filled with data we will get notifications. */
for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
if (resultMM != MMSYSERR_NOERROR) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to attach input buffers to capture device in preparation for capture.", ma_result_from_MMRESULT(resultMM));
}
/* Make sure all of the buffers start out locked. We don't want to access them until the backend tells us we can. */
pWAVEHDR[iPeriod].dwUser = 1; /* 1 = locked. */
}
/* Capture devices need to be explicitly started, unlike playback devices. */
resultMM = ((MA_PFN_waveInStart)pDevice->pContext->winmm.waveInStart)((HWAVEIN)pDevice->winmm.hDeviceCapture);
if (resultMM != MMSYSERR_NOERROR) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device.", ma_result_from_MMRESULT(resultMM));
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
/* Don't need to do anything for playback. It'll be started automatically in ma_device_start__winmm(). */
}
return MA_SUCCESS;
}
static ma_result ma_device_stop__winmm(ma_device* pDevice)
{
MMRESULT resultMM;
......@@ -17502,197 +17489,6 @@ static ma_result ma_device_read__winmm(ma_device* pDevice, void* pPCMFrames, ma_
return result;
}
static ma_result ma_device_main_loop__winmm(ma_device* pDevice)
{
ma_result result = MA_SUCCESS;
ma_bool32 exitLoop = MA_FALSE;
ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
MA_ASSERT(pDevice != NULL);
/* The capture device needs to be started immediately. */
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
MMRESULT resultMM;
WAVEHDR* pWAVEHDR;
ma_uint32 iPeriod;
pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRCapture;
/* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */
ResetEvent((HANDLE)pDevice->winmm.hEventCapture);
/* To start the device we attach all of the buffers and then start it. As the buffers are filled with data we will get notifications. */
for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
if (resultMM != MMSYSERR_NOERROR) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to attach input buffers to capture device in preparation for capture.", ma_result_from_MMRESULT(resultMM));
}
/* Make sure all of the buffers start out locked. We don't want to access them until the backend tells us we can. */
pWAVEHDR[iPeriod].dwUser = 1; /* 1 = locked. */
}
/* Capture devices need to be explicitly started, unlike playback devices. */
resultMM = ((MA_PFN_waveInStart)pDevice->pContext->winmm.waveInStart)((HWAVEIN)pDevice->winmm.hDeviceCapture);
if (resultMM != MMSYSERR_NOERROR) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device.", ma_result_from_MMRESULT(resultMM));
}
}
while (ma_device_get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
switch (pDevice->type)
{
case ma_device_type_duplex:
{
/* The process is: device_read -> convert -> callback -> convert -> device_write */
ma_uint32 totalCapturedDeviceFramesProcessed = 0;
ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
ma_uint32 capturedDeviceFramesRemaining;
ma_uint32 capturedDeviceFramesProcessed;
ma_uint32 capturedDeviceFramesToProcess;
ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed;
if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) {
capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames;
}
result = ma_device_read__winmm(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
capturedDeviceFramesRemaining = capturedDeviceFramesToProcess;
capturedDeviceFramesProcessed = 0;
for (;;) {
ma_uint8 capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint8 playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames);
ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining;
ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
/* Convert capture data from device format to client format. */
result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration);
if (result != MA_SUCCESS) {
break;
}
/*
If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small
which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
*/
if (capturedClientFramesToProcessThisIteration == 0) {
break;
}
ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/
capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
/* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */
for (;;) {
ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration;
ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames;
result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount);
if (result != MA_SUCCESS) {
break;
}
result = ma_device_write__winmm(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL); /* Safe cast. */
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount; /* Safe cast. */
if (capturedClientFramesToProcessThisIteration == 0) {
break;
}
}
/* In case an error happened from ma_device_write__winmm()... */
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
}
totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed;
}
} break;
case ma_device_type_capture:
{
/* We read in chunks of the period size, but use a stack allocated buffer for the intermediary. */
ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
ma_uint32 framesReadThisPeriod = 0;
while (framesReadThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
if (framesToReadThisIteration > capturedDeviceDataCapInFrames) {
framesToReadThisIteration = capturedDeviceDataCapInFrames;
}
result = ma_device_read__winmm(pDevice, capturedDeviceData, framesToReadThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
ma_device__send_frames_to_client(pDevice, framesProcessed, capturedDeviceData);
framesReadThisPeriod += framesProcessed;
}
} break;
case ma_device_type_playback:
{
/* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
ma_uint32 framesWrittenThisPeriod = 0;
while (framesWrittenThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
if (framesToWriteThisIteration > playbackDeviceDataCapInFrames) {
framesToWriteThisIteration = playbackDeviceDataCapInFrames;
}
ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, playbackDeviceData);
result = ma_device_write__winmm(pDevice, playbackDeviceData, framesToWriteThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
framesWrittenThisPeriod += framesProcessed;
}
} break;
/* To silence a warning. Will never hit this. */
case ma_device_type_loopback:
default: break;
}
}
/* Here is where the device is started. */
ma_device_stop__winmm(pDevice);
return result;
}
static ma_result ma_context_uninit__winmm(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
......@@ -17702,7 +17498,7 @@ static ma_result ma_context_uninit__winmm(ma_context* pContext)
return MA_SUCCESS;
}
static ma_result ma_context_init__winmm(const ma_context_config* pConfig, ma_context* pContext)
static ma_result ma_context_init__winmm(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
{
MA_ASSERT(pContext != NULL);
......@@ -17731,14 +17527,17 @@ static ma_result ma_context_init__winmm(const ma_context_config* pConfig, ma_con
pContext->winmm.waveInStart = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInStart");
pContext->winmm.waveInReset = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInReset");
pContext->onUninit = ma_context_uninit__winmm;
pContext->onEnumDevices = ma_context_enumerate_devices__winmm;
pContext->onGetDeviceInfo = ma_context_get_device_info__winmm;
pContext->onDeviceInit = ma_device_init__winmm;
pContext->onDeviceUninit = ma_device_uninit__winmm;
pContext->onDeviceStart = NULL; /* Not used with synchronous backends. */
pContext->onDeviceStop = NULL; /* Not used with synchronous backends. */
pContext->onDeviceMainLoop = ma_device_main_loop__winmm;
pCallbacks->onContextInit = ma_context_init__winmm;
pCallbacks->onContextUninit = ma_context_uninit__winmm;
pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__winmm;
pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__winmm;
pCallbacks->onDeviceInit = ma_device_init__winmm;
pCallbacks->onDeviceUninit = ma_device_uninit__winmm;
pCallbacks->onDeviceStart = ma_device_start__winmm;
pCallbacks->onDeviceStop = ma_device_stop__winmm;
pCallbacks->onDeviceRead = ma_device_read__winmm;
pCallbacks->onDeviceWrite = ma_device_write__winmm;
pCallbacks->onDeviceAudioThread = NULL; /* This is a blocking read-write API, so this can be NULL since miniaudio will manage the audio thread for us. */
return MA_SUCCESS;
}
......@@ -31920,6 +31719,12 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
pContext->callbacks.onContextInit = ma_context_init__dsound;
} break;
#endif
#ifdef MA_HAS_WINMM
case ma_backend_winmm:
{
pContext->callbacks.onContextInit = ma_context_init__winmm;
} break;
#endif
#ifdef MA_HAS_CUSTOM
case ma_backend_custom:
{
......@@ -31953,7 +31758,7 @@ MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendC
#ifdef MA_HAS_WINMM
case ma_backend_winmm:
{
result = ma_context_init__winmm(pConfig, pContext);
/*result = ma_context_init__winmm(pConfig, pContext);*/
} break;
#endif
#ifdef MA_HAS_ALSA
......@@ -32598,6 +32403,10 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
descriptorPlayback.periodSizeInMilliseconds = (pConfig->performanceProfile == ma_performance_profile_low_latency) ? MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY : MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE;
}
if (descriptorPlayback.periodCount == 0) {
descriptorPlayback.periodCount = MA_DEFAULT_PERIODS;
}
MA_ZERO_OBJECT(&descriptorCapture);
descriptorCapture.pDeviceID = pConfig->capture.pDeviceID;
......@@ -32614,6 +32423,10 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
descriptorCapture.periodSizeInMilliseconds = (pConfig->performanceProfile == ma_performance_profile_low_latency) ? MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY : MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE;
}
if (descriptorCapture.periodCount == 0) {
descriptorCapture.periodCount = MA_DEFAULT_PERIODS;
}
result = pContext->callbacks.onDeviceInit(pDevice, pConfig, &descriptorPlayback, &descriptorCapture);
if (result != MA_SUCCESS) {
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment