/*==========================================================================; * * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved. * * File: priority.cpp * Content: Implements a process that uses DirectSound in prioirty * mode to simulate an aggressive external playback only * application (such as a game) that may be running while * the full duplex application is in use. Note that WinMain * is in fdtest.cpp, but the guts are here. * History: * Date By Reason * ============ * 08/19/99 pnewson created * 10/28/99 pnewson Bug #113937 audible clicking during full duplex test * 11/02/99 pnewson Fix: Bug #116365 - using wrong DSBUFFERDESC * 01/21/2000 pnewson Workaround for broken SetNotificationPositions call. * undef DSOUND_BROKEN once the SetNotificationPositions * no longer broken. * 02/15/2000 pnewson Removed the workaround for bug 116365 * 04/04/2000 pnewson Changed a SendMessage to PostMessage to fix deadlock * 04/19/2000 pnewson Error handling cleanup * 07/12/2000 rodtoll Bug #31468 - Add diagnostic spew to logfile to show what is failing the HW Wizard * 08/25/2000 rodtoll Bug #43363 - CommandPriorityStart does not init return param and uses stack trash. * ***************************************************************************/ #include "dxvtlibpch.h" #undef DPF_SUBCOMP #define DPF_SUBCOMP DN_SUBCOMP_VOICE static HRESULT CommandLoop(CPriorityIPC* lpipcPriority); static HRESULT DispatchCommand(CPriorityIPC* lpipcPriority, SFDTestCommand* pfdtc); static HRESULT CommandPriorityStart(SFDTestCommandPriorityStart* pfdtcPriorityStart, HRESULT* phrIPC); static HRESULT CommandPriorityStop(SFDTestCommandPriorityStop* pfdtcPriorityStop, HRESULT* phrIPC); #undef DPF_MODNAME #define DPF_MODNAME "PriorityProcess" HRESULT PriorityProcess(HINSTANCE hResDLLInstance, HINSTANCE hPrevInstance, TCHAR *szCmdLine, int iCmdShow) { //DEBUG_ONLY(_asm int 3;) DPF_ENTER(); HRESULT hr; CPriorityIPC ipcPriority; BOOL fIPCInit = FALSE; BOOL fGuardInit = FALSE; if (!InitGlobGuard()) { return DVERR_OUTOFMEMORY; } fGuardInit = TRUE; // Init the common control library. Use the old style // call, so we're compatibile right back to 95. InitCommonControls(); // get the mutex, events and shared memory stuff hr = ipcPriority.Init(); if (FAILED(hr)) { goto error_cleanup; } fIPCInit = TRUE; // start up the testing loop hr = CommandLoop(&ipcPriority); if (FAILED(hr)) { goto error_cleanup; } // close the mutex, events and shared memory stuff hr = ipcPriority.Deinit(); fIPCInit = FALSE; if (FAILED(hr)) { goto error_cleanup; } DeinitGlobGuard(); DPF_EXIT(); return S_OK; error_cleanup: if (fIPCInit == TRUE) { ipcPriority.Deinit(); fIPCInit = FALSE; } if (fGuardInit == TRUE) { DeinitGlobGuard(); fGuardInit = FALSE; } DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CommandLoop" static HRESULT CommandLoop(CPriorityIPC* lpipcPriority) { DPF_ENTER(); BOOL fRet; LONG lRet; HRESULT hr; DWORD dwRet; SFDTestCommand fdtc; // Kick the supervisor process to let it know // we're ready to go. hr = lpipcPriority->SignalParentReady(); if (FAILED(hr)) { DPF_EXIT(); return hr; } // enter the main command loop while (1) { // wait for a command from the supervisor process fdtc.dwSize = sizeof(fdtc); hr = lpipcPriority->Receive(&fdtc); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "CPriorityIPC::Receive() failed, hr: 0x%x", hr); break; } // dispatch the command hr = DispatchCommand(lpipcPriority, &fdtc); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "DispatchCommand() failed, hr: 0x%x", hr); break; } if (hr == DV_EXIT) { DPFX(DPFPREP, DVF_INFOLEVEL, "Exiting Priority process command loop"); break; } } DPF_EXIT(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "DispatchCommand" static HRESULT DispatchCommand(CPriorityIPC* lpipcPriority, SFDTestCommand* pfdtc) { DPF_ENTER(); HRESULT hr; HRESULT hrIPC; switch (pfdtc->fdtcc) { case fdtccExit: // ok - reply to the calling process to let them // know we are getting out. DPFX(DPFPREP, DVF_INFOLEVEL, "Priority received Exit command"); lpipcPriority->Reply(DV_EXIT); // returning this code will break us out of // the command processing loop DPF_EXIT(); return DV_EXIT; case fdtccPriorityStart: hr = CommandPriorityStart(&(pfdtc->fdtu.fdtcPriorityStart), &hrIPC); if (FAILED(hr)) { lpipcPriority->Reply(hrIPC); DPF_EXIT(); return hr; } hr = lpipcPriority->Reply(hrIPC); DPF_EXIT(); return hr; case fdtccPriorityStop: hr = CommandPriorityStop(&(pfdtc->fdtu.fdtcPriorityStop), &hrIPC); if (FAILED(hr)) { lpipcPriority->Reply(hrIPC); DPF_EXIT(); return hr; } hr = lpipcPriority->Reply(hrIPC); DPF_EXIT(); return hr; default: // Don't know this command. Reply with the appropriate // code. DPFX(DPFPREP, DVF_INFOLEVEL, "Priority received Unknown command"); hr = lpipcPriority->Reply(DVERR_UNKNOWN); if (FAILED(hr)) { DPF_EXIT(); return hr; } // While this is an error, it is one that the calling // process needs to figure out. In the meantime, this // process will happily continue on. DPF_EXIT(); return S_OK; } } #undef DPF_MODNAME #define DPF_MODNAME "CommandPriorityStart" HRESULT CommandPriorityStart(SFDTestCommandPriorityStart* pfdtcPriorityStart, HRESULT* phrIPC) { DPF_ENTER(); *phrIPC = DV_OK; HRESULT hr = S_OK; DSBUFFERDESC dsbd; WAVEFORMATEX wfx; DWORD dwSizeWritten; DSBCAPS dsbc; LPVOID lpvAudio1 = NULL; DWORD dwAudio1Size = NULL; LPVOID lpvAudio2 = NULL; DWORD dwAudio2Size = NULL; DSBPOSITIONNOTIFY dsbPositionNotify; DWORD dwRet; LONG lRet; BOOL fRet; HWND hwnd; BYTE bSilence; BOOL bBufferPlaying = FALSE; GUID guidTmp; memset( &guidTmp, 0x00, sizeof( GUID ) ); // initalize the global vars GlobGuardIn(); g_lpdsPriorityRender = NULL; g_lpdsbPriorityPrimary = NULL; g_lpdsbPrioritySecondary = NULL; GlobGuardOut(); Diagnostics_Write( DVF_INFOLEVEL, "-----------------------------------------------------------" ); hr = Diagnostics_DeviceInfo( &pfdtcPriorityStart->guidRenderDevice, &guidTmp ); if( FAILED( hr ) ) { Diagnostics_Write( 0, "Error getting device information hr=0x%x", hr ); } Diagnostics_Write( DVF_INFOLEVEL, "-----------------------------------------------------------" ); Diagnostics_Write( DVF_INFOLEVEL, "Primary Format: " ); Diagnositcs_WriteWAVEFORMATEX( DVF_INFOLEVEL, &pfdtcPriorityStart->wfxRenderFormat ); // make sure the priority dialog is in the foreground DPFX(DPFPREP, DVF_INFOLEVEL, "Bringing Wizard to the foreground"); fRet = SetForegroundWindow(pfdtcPriorityStart->hwndWizard); if (!fRet) { DPFX(DPFPREP, DVF_WARNINGLEVEL, "Unable to bring wizard to foreground, continuing anyway..."); } // kick the progress bar forward one tick DPFX(DPFPREP, DVF_INFOLEVEL, "Incrementing progress bar in dialog"); PostMessage(pfdtcPriorityStart->hwndProgress, PBM_STEPIT, 0, 0); // create the DirectSound interface DPFX(DPFPREP, DVF_INFOLEVEL, "Creating DirectSound"); GlobGuardIn(); hr = DirectSoundCreate(&pfdtcPriorityStart->guidRenderDevice, &g_lpdsPriorityRender, NULL); if (FAILED(hr)) { g_lpdsPriorityRender = NULL; GlobGuardOut(); Diagnostics_Write(DVF_ERRORLEVEL, "DirectSoundCreate failed, code: 0x%x", hr); *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; goto error_cleanup; } GlobGuardOut(); // set to priority mode DPFX(DPFPREP, DVF_INFOLEVEL, "Setting Cooperative Level"); GlobGuardIn(); hr = g_lpdsPriorityRender->SetCooperativeLevel(pfdtcPriorityStart->hwndWizard, DSSCL_PRIORITY); GlobGuardOut(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetCooperativeLevel failed, code: 0x%x", hr); *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; goto error_cleanup; } // Create a primary buffer object with 3d controls. // We're not actually going to use the controls, but a game probably would, // and we are really trying to emulate a game in this process. DPFX(DPFPREP, DVF_INFOLEVEL, "Creating Primary Sound Buffer"); ZeroMemory(&dsbd, sizeof(dsbd)); dsbd.dwSize = sizeof(dsbd); dsbd.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER; dsbd.dwBufferBytes = 0; dsbd.dwReserved = 0; dsbd.lpwfxFormat = NULL; dsbd.guid3DAlgorithm = DS3DALG_DEFAULT; GlobGuardIn(); hr = g_lpdsPriorityRender->CreateSoundBuffer((LPDSBUFFERDESC)&dsbd, &g_lpdsbPriorityPrimary, NULL); if (FAILED(hr)) { g_lpdsbPriorityPrimary = NULL; GlobGuardOut(); Diagnostics_Write(DVF_ERRORLEVEL, "CreateSoundBuffer failed, code: 0x%x", hr); *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; goto error_cleanup; } GlobGuardOut(); // Set the format of the primary buffer to the requested format. DPFX(DPFPREP, DVF_INFOLEVEL, "Setting Primary Buffer Format"); GlobGuardIn(); hr = g_lpdsbPriorityPrimary->SetFormat(&pfdtcPriorityStart->wfxRenderFormat); GlobGuardOut(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "SetFormat failed, code: 0x%x ", hr); *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; goto error_cleanup; } // check to make sure the SetFormat actually worked DPFX(DPFPREP, DVF_INFOLEVEL, "Verifying Primary Buffer Format"); GlobGuardIn(); hr = g_lpdsbPriorityPrimary->GetFormat(&wfx, sizeof(wfx), &dwSizeWritten); GlobGuardOut(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "GetFormat failed, code: 0x%x ", hr); *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; goto error_cleanup; } if (dwSizeWritten != sizeof(wfx)) { *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; goto error_cleanup; } if (memcmp(&wfx, &pfdtcPriorityStart->wfxRenderFormat, sizeof(wfx)) != 0) { // This is an interesting case. Is it really a full duplex error that // we are unable to initialize a primary buffer in this format? // Perhaps not. Perhaps it is sufficient that we can get full duplex // sound even if the forground priority mode app attempts to play // using this format. So just dump a debug note, and move along... DPFX(DPFPREP, DVF_WARNINGLEVEL, "Warning: SetFormat on primary buffer did not actually set the format"); } // Create a secondary buffer object with 3d controls. // We're not actually going to use the controls, but a game probably would, // and we are really trying to emulate a game in this process. DPFX(DPFPREP, DVF_INFOLEVEL, "Creating Secondary Buffer"); dsbd.dwSize = sizeof(dsbd); dsbd.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY; dsbd.dwBufferBytes = (pfdtcPriorityStart->wfxSecondaryFormat.nSamplesPerSec * pfdtcPriorityStart->wfxSecondaryFormat.nBlockAlign) / (1000 / gc_dwFrameSize); dsbd.dwReserved = 0; dsbd.guid3DAlgorithm = DS3DALG_DEFAULT; dsbd.lpwfxFormat = &(pfdtcPriorityStart->wfxSecondaryFormat); GlobGuardIn(); hr = g_lpdsPriorityRender->CreateSoundBuffer((LPDSBUFFERDESC)&dsbd, &g_lpdsbPrioritySecondary, NULL); if (FAILED(hr)) { g_lpdsbPrioritySecondary = NULL; GlobGuardOut(); Diagnostics_Write(DVF_ERRORLEVEL, "CreateSoundBuffer failed, code: 0x%x Primary ", hr); *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; goto error_cleanup; } GlobGuardOut(); // clear out the secondary buffer DPFX(DPFPREP, DVF_INFOLEVEL, "Clearing Secondary Buffer"); GlobGuardIn(); hr = g_lpdsbPrioritySecondary->Lock( 0, 0, &lpvAudio1, &dwAudio1Size, &lpvAudio2, &dwAudio2Size, DSBLOCK_ENTIREBUFFER); GlobGuardOut(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "Lock failed, code: 0x%x ", hr); *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; goto error_cleanup; } if (lpvAudio1 == NULL) { *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; goto error_cleanup; } if (pfdtcPriorityStart->wfxSecondaryFormat.wBitsPerSample == 8) { bSilence = 0x80; } else { bSilence = 0x00; } memset(lpvAudio1, bSilence, dwAudio1Size); if (lpvAudio2 != NULL) { memset(lpvAudio2, bSilence, dwAudio2Size); } GlobGuardIn(); hr = g_lpdsbPrioritySecondary->Unlock( lpvAudio1, dwAudio1Size, lpvAudio2, dwAudio2Size); GlobGuardOut(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "Unlock failed, code: 0x%x ", hr); *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; goto error_cleanup; } // start playing the secondary buffer DPFX(DPFPREP, DVF_INFOLEVEL, "Playing Secondary Buffer"); GlobGuardIn(); hr = g_lpdsbPrioritySecondary->Play(0, 0, DSBPLAY_LOOPING); GlobGuardOut(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "Play failed, code: 0x%x ", hr); *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; goto error_cleanup; } bBufferPlaying = TRUE; DPF_EXIT(); Diagnostics_Write(DVF_INFOLEVEL, "Priority Result = DV_OK" ); return DV_OK; error_cleanup: GlobGuardIn(); if (bBufferPlaying == TRUE) { if (g_lpdsbPrioritySecondary != NULL) { g_lpdsbPrioritySecondary->Stop(); } bBufferPlaying = FALSE; } if (g_lpdsbPrioritySecondary != NULL) { g_lpdsbPrioritySecondary->Release(); g_lpdsbPrioritySecondary = NULL; } if (g_lpdsbPriorityPrimary != NULL) { g_lpdsbPriorityPrimary->Release(); g_lpdsbPriorityPrimary = NULL; } if (g_lpdsPriorityRender != NULL) { g_lpdsPriorityRender->Release(); g_lpdsPriorityRender = NULL; } GlobGuardOut(); DPF_EXIT(); Diagnostics_Write(DVF_INFOLEVEL, "Priority Result = 0x%x", hr ); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "CommandPriorityStop" HRESULT CommandPriorityStop(SFDTestCommandPriorityStop* pfdtcPriorityStop, HRESULT* phrIPC) { DPF_ENTER(); HRESULT hr; LONG lRet; DWORD dwRet; *phrIPC = S_OK; hr = S_OK; GlobGuardIn(); if (g_lpdsbPrioritySecondary != NULL) { DPFX(DPFPREP, DVF_INFOLEVEL, "Stopping Secondary Buffer"); hr = g_lpdsbPrioritySecondary->Stop(); } GlobGuardOut(); if (FAILED(hr)) { Diagnostics_Write(DVF_ERRORLEVEL, "Stop failed, code: 0x%x", hr); *phrIPC = DVERR_SOUNDINITFAILURE; hr = DV_OK; } GlobGuardIn(); if (g_lpdsbPrioritySecondary != NULL) { DPFX(DPFPREP, DVF_INFOLEVEL, "Releasing Secondary Buffer"); g_lpdsbPrioritySecondary->Release(); g_lpdsbPrioritySecondary = NULL; } if (g_lpdsbPriorityPrimary != NULL) { DPFX(DPFPREP, DVF_INFOLEVEL, "Releasing Primary Buffer"); g_lpdsbPriorityPrimary->Release(); g_lpdsbPriorityPrimary = NULL; } if (g_lpdsPriorityRender != NULL) { DPFX(DPFPREP, DVF_INFOLEVEL, "Releasing DirectSound"); g_lpdsPriorityRender->Release(); g_lpdsPriorityRender = NULL; } GlobGuardOut(); DPF_EXIT(); return hr; }