HRESULT __stdcall getcurrentpadding_patch(IAudioClient* this_, UINT32* pNumPaddingFrames) { IAudioClient* proxy = get_duplicate(this_)->proxy; DWORD_PTR* old_vftptr = swap_vtable(this_); HRESULT hr = proxy->GetCurrentPadding(pNumPaddingFrames); ((DWORD_PTR**)this_)[0] = old_vftptr; for(iaudioclient_duplicate* next = get_duplicate(this_)->next; next != NULL; next = next->next) { UINT32 pad; next->proxy->GetCurrentPadding(&pad); //assert(pad == *pNumPaddingFrames); } return hr; }
void PlayAudio() { REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC; // microseconds, so this is 1 seconds REFERENCE_TIME hnsActualDuration; HRESULT hr; IMMDeviceEnumerator *pEnumerator = NULL; IMMDevice *pDevice = NULL; IAudioClient *pAudioClient = NULL; IAudioRenderClient *pRenderClient = NULL; WAVEFORMATEX *pwfx = NULL; UINT32 bufferFrameCount; UINT32 numFramesAvailable; UINT32 numFramesPadding; BYTE *pData; DWORD flags = 0; hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator); EXIT_ON_ERROR(hr); hr = pEnumerator->GetDefaultAudioEndpoint( eRender, eConsole, &pDevice); EXIT_ON_ERROR(hr); hr = pDevice->Activate( IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient); EXIT_ON_ERROR(hr); hr = pAudioClient->GetMixFormat(&pwfx); EXIT_ON_ERROR(hr); hr = pAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED, 0, hnsRequestedDuration, 0, pwfx, NULL); EXIT_ON_ERROR(hr); // Get the actual size of the allocated buffer. hr = pAudioClient->GetBufferSize(&bufferFrameCount); EXIT_ON_ERROR(hr); hr = pAudioClient->GetService( IID_IAudioRenderClient, (void**)&pRenderClient); EXIT_ON_ERROR(hr); // Grab the entire buffer for the initial fill operation. hr = pRenderClient->GetBuffer(bufferFrameCount, &pData); EXIT_ON_ERROR(hr); // load initial data hr = LoadAudioBuffer(bufferFrameCount, pData, pwfx, &flags); EXIT_ON_ERROR(hr); hr = pRenderClient->ReleaseBuffer(bufferFrameCount, flags); EXIT_ON_ERROR(hr); // Calculate the actual duration of the allocated buffer. hnsActualDuration = (REFERENCE_TIME)((double)REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec); hr = pAudioClient->Start(); // Start playing. EXIT_ON_ERROR(hr); // Each loop fills about half of the shared buffer. while (flags != AUDCLNT_BUFFERFLAGS_SILENT) { // Sleep for half the buffer duration. Sleep((DWORD)(hnsActualDuration/REFTIMES_PER_MILLISEC/2)); // See how much buffer space is available. hr = pAudioClient->GetCurrentPadding(&numFramesPadding); EXIT_ON_ERROR(hr) numFramesAvailable = bufferFrameCount - numFramesPadding; // Grab all the available space in the shared buffer. hr = pRenderClient->GetBuffer(numFramesAvailable, &pData); EXIT_ON_ERROR(hr) // Get next 1/2-second of data from the audio source. hr = LoadAudioBuffer(numFramesAvailable, pData, pwfx, &flags); EXIT_ON_ERROR(hr) hr = pRenderClient->ReleaseBuffer(numFramesAvailable, flags); EXIT_ON_ERROR(hr) } // Wait for last data in buffer to play before stopping. Sleep((DWORD)(hnsActualDuration/REFTIMES_PER_MILLISEC/2)); hr = pAudioClient->Stop(); // Stop playing. EXIT_ON_ERROR(hr); Exit: CoTaskMemFree(pwfx); SAFE_RELEASE(pEnumerator); SAFE_RELEASE(pDevice); SAFE_RELEASE(pAudioClient); SAFE_RELEASE(pRenderClient); }