/*========================================================================== * * Copyright (C) 1995-1999 Microsoft Corporation. All Rights Reserved. * * File: voice.cpp * Content: Voice Support Routines * History: * * Date By Reason * ==== == ====== * 10/15/99 rodtoll created it * rodtoll Plugged resource leak * 10/20/99 rodtoll Fix: Bug #113686 Not shutting down when receiving lobby message * 10/25/99 rodtoll Removed lpszVoicePassword member from sessiondesc * 10/28/99 pnewson Bug #114176 updated DVSOUNDDEVICECONFIG struct * 11/02/99 rodtoll Bug #116677 - Can't use lobby clients that don't hang around * 11/12/99 rodtoll Added support for the new waveIN/waveOut flags and the * echo suppression flag. * 11/29/99 rodtoll Bug #120249 - Modem host does not wait for connections. Added * message loop in voice thread. * 12/01/99 rodtoll Updated to use user selections for playback/record device * 12/07/99 rodtoll Bug #122628 Make error messages silent when running in silent mode * 12/08/99 rodtoll Bug #121054 Added support for flags to control new capture focus * 01/10/2000 pnewson Added support for dynamic Tx and Rx display for AGC & VA tuning * 01/14/2000 rodtoll Updated with API changes * 01/27/2000 rodtoll Updated with API changes * 01/28/2000 rodtoll Updated so Volume Set failures don't exit app (for records w/o volume) * 02/08/2000 rodtoll Bug #131496 - Selecting DVTHRESHOLD_DEFAULT results in voice * never being detected * 03/03/2000 rodtoll Updated to handle alternative gamevoice build. * 06/21/2000 rodtoll Bug #35767 - Implement ability for Dsound effects processing if dpvoice buffers * Updated DPVHELP to use new parameters * 06/27/2000 rodtoll Added support for new host migration message * 06/28/2000 rodtoll Prefix Bug #38033 * 08/31/2000 rodtoll Bug #43804 - DVOICE: dwSensitivity structure member is confusing - should be dwThreshold * 04/02/2001 simonpow Bug #354859 - Fixes for PREfast * (removal unecessary local vars in DVMessageHandlerClient) * ***************************************************************************/ #include "dxvhelppch.h" #define DVHELPER_CONNECT_TIMEOUT 15000 #define DPLSYS_LOBBYCLIENTRELEASE 0x0000000B void VoiceManager_DisplayStatus( PDXVHELP_RTINFO prtInfo, LPTSTR lpstrStatus ) { if( prtInfo->hMainDialog ) { MainDialog_DisplayStatus( prtInfo->hMainDialog, lpstrStatus ); } } BOOL VoiceManager_LobbyConnect( PDXVHELP_RTINFO prtInfo ) { HRESULT hr; LPBYTE lpBuffer = NULL; DWORD dwSize = 0; BYTE *lpAddressBuffer = NULL; DWORD dwAddressSize = 0; LPDPLCONNECTION lpdplConnection = NULL; LPDPLMSG_GENERIC lpdlmGeneric = NULL; DWORD dwFlags; hr = CoCreateInstance( DPLAY_CLSID_DPLOBBY, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlayLobby3A, (void **) &prtInfo->lpdpLobby ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Unable to to get ct info"), prtInfo->dxvParameters.fSilent); return FALSE; } dwSize = 0; if( prtInfo->dxvParameters.fWaitForSettings ) { VoiceManager_DisplayStatus( prtInfo, _T("Waiting for settings") ); hr = prtInfo->lpdpLobby->WaitForConnectionSettings( 0 ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("WaitForConnection FAILED"), prtInfo->dxvParameters.fSilent ); goto LOBBY_CONNECT_CLEANUP; } lpBuffer = new BYTE[2000]; lpdlmGeneric = (LPDPLMSG_GENERIC) lpBuffer; while( 1 ) { if( WaitForSingleObject( prtInfo->hShutdown, 0 ) != WAIT_TIMEOUT ) { goto LOBBY_CONNECT_CLEANUP; } dwSize = 2000; hr = prtInfo->lpdpLobby->ReceiveLobbyMessage( 0, 0, &dwFlags, lpBuffer, &dwSize ); if( hr == DP_OK ) { if( lpdlmGeneric->dwType == DPLSYS_NEWCONNECTIONSETTINGS ) { break; } } Sleep( 50 ); } delete [] lpBuffer; lpBuffer = NULL; } VoiceManager_DisplayStatus( prtInfo, _T("Getting Settings") ); hr = prtInfo->lpdpLobby->GetConnectionSettings( 0, NULL, &dwSize ); if( hr != DPERR_BUFFERTOOSMALL ) { DPVDX_DPERRDisplay( hr, _T("Error retrieving connection settings size"), prtInfo->dxvParameters.fSilent ); goto LOBBY_CONNECT_CLEANUP; } lpBuffer = new BYTE[dwSize]; if( lpBuffer == NULL ) { DPVDX_DPERRDisplay( DVERR_OUTOFMEMORY, _T("Failure allocating memory"), prtInfo->dxvParameters.fSilent ); goto LOBBY_CONNECT_CLEANUP; } lpdplConnection = (LPDPLCONNECTION) lpBuffer; hr = prtInfo->lpdpLobby->GetConnectionSettings( 0, lpBuffer, &dwSize ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Failed to retrieve settings"), prtInfo->dxvParameters.fSilent ); goto LOBBY_CONNECT_CLEANUP; } // If we're connecting to a session we need to find the session if( !(lpdplConnection->dwFlags & DPLCONNECTION_CREATESESSION) ) { prtInfo->dxvParameters.fHost = FALSE; VoiceManager_DisplayStatus( prtInfo, _T("Finding Session") ); } else { // Over-ride protocol settings from lobby launch lpdplConnection->lpSessionDesc->dwFlags |= DPSESSION_DIRECTPLAYPROTOCOL | DPSESSION_KEEPALIVE | DPSESSION_MIGRATEHOST; prtInfo->dxvParameters.fHost = TRUE; // Launching from a session where the GetPlayerAddress on the server doesn't // allow getting a player's address if( lpdplConnection->lpAddress == NULL ) { DPCOMPOUNDADDRESSELEMENT element; element.guidDataType = DPAID_ServiceProvider; element.dwDataSize = sizeof( GUID ); element.lpData = &lpdplConnection->guidSP; hr = prtInfo->lpdpLobby->CreateCompoundAddress( &element, 1, NULL, &dwAddressSize ); if( hr != DPERR_BUFFERTOOSMALL ) { DPVDX_DPERRDisplay( hr, _T("Unable to create compound address for session host"), prtInfo->dxvParameters.fSilent ); goto LOBBY_CONNECT_CLEANUP; } lpAddressBuffer = new BYTE[dwAddressSize]; hr = prtInfo->lpdpLobby->CreateCompoundAddress( &element, 1, lpAddressBuffer, &dwAddressSize ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Unable to create compound address for session host"), prtInfo->dxvParameters.fSilent ); goto LOBBY_CONNECT_CLEANUP; } lpdplConnection->lpAddress = lpAddressBuffer; lpdplConnection->dwAddressSize = dwAddressSize; } } hr = prtInfo->lpdpLobby->SetConnectionSettings( 0, 0, lpdplConnection ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Unable to set connection settings"), prtInfo->dxvParameters.fSilent ); goto LOBBY_CONNECT_CLEANUP; } prtInfo->hLobbyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); hr = prtInfo->lpdpLobby->SetLobbyMessageEvent( 0, 0, prtInfo->hLobbyEvent ); VoiceManager_DisplayStatus( prtInfo, _T("Connect/Start") ); hr = prtInfo->lpdpLobby->ConnectEx( 0, IID_IDirectPlay4A, (void **) &prtInfo->lpdpDirectPlay, NULL ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Failed to ConnectEx"), prtInfo->dxvParameters.fSilent ); goto LOBBY_CONNECT_CLEANUP; } prtInfo->hReceiveEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); hr = prtInfo->lpdpDirectPlay->CreatePlayer( &prtInfo->dpidLocalPlayer, NULL, prtInfo->hReceiveEvent, NULL, 0, 0 ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("CreatePlayer Failed"), prtInfo->dxvParameters.fSilent ); goto LOBBY_CONNECT_CLEANUP; } if( lpBuffer ) delete [] lpBuffer; return TRUE; LOBBY_CONNECT_CLEANUP: if( prtInfo->lpdpLobby != NULL ) { prtInfo->lpdpLobby->Release(); } if( lpAddressBuffer != NULL ) { delete [] lpAddressBuffer; } if( lpBuffer != NULL ) { delete [] lpBuffer; } if( prtInfo->lpdpDirectPlay != NULL ) { prtInfo->lpdpDirectPlay->Release(); } return FALSE; } BOOL VoiceManager_StandardConnect( PDXVHELP_RTINFO prtInfo ) { HRESULT hr; DWORD dwFlags = 0; GUID guidInstance; VoiceManager_DisplayStatus( prtInfo, _T("Creating dplay") ); hr = CoCreateInstance( DPLAY_CLSID_DPLAY, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay4A, (void **) &prtInfo->lpdpDirectPlay ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Unable to Create Lobby Object"), prtInfo->dxvParameters.fSilent ); return FALSE; } hr = DPVDX_DP_Init( prtInfo->lpdpDirectPlay, DPSPGUID_TCPIP, (prtInfo->dxvParameters.fHost) ? NULL : prtInfo->dxvParameters.lpszConnectAddress ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Initialize DirectPlay"), prtInfo->dxvParameters.fSilent ); return FALSE; } if( prtInfo->dxvParameters.fHost ) { dwFlags = DPSESSION_KEEPALIVE | DPSESSION_DIRECTPLAYPROTOCOL; if( prtInfo->dxvParameters.dwSessionType == DVSESSIONTYPE_PEER ) { dwFlags |= DPSESSION_MIGRATEHOST; } VoiceManager_DisplayStatus( prtInfo, _T("Starting Session") ); hr = DPVDX_DP_StartSession( prtInfo->lpdpDirectPlay, DPVHELP_PUBLIC_APPID, dwFlags, NULL, NULL, 0, &prtInfo->dpidLocalPlayer, &prtInfo->hReceiveEvent, &guidInstance ) ; if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Starting Session"), prtInfo->dxvParameters.fSilent ); return FALSE; } } else { VoiceManager_DisplayStatus( prtInfo, _T("Finding Session") ); hr = DPVDX_DP_FindSessionGUID( prtInfo->lpdpDirectPlay, DPVHELP_PUBLIC_APPID, DVHELPER_CONNECT_TIMEOUT, &guidInstance ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Finding Session"), prtInfo->dxvParameters.fSilent ); return FALSE; } VoiceManager_DisplayStatus( prtInfo, _T("Connecting") ); hr = DPVDX_DP_ConnectToSession( prtInfo->lpdpDirectPlay, DPVHELP_PUBLIC_APPID, guidInstance, NULL, &prtInfo->dpidLocalPlayer, &prtInfo->hReceiveEvent ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Connect To Session"), prtInfo->dxvParameters.fSilent ); return FALSE; } } VoiceManager_DisplayStatus( prtInfo, _T("Dplay started") ); return TRUE; } HRESULT PASCAL DVMessageHandlerServer( LPVOID lpvUserContext, DWORD dwMessageType, LPVOID lpMessage ) { TCHAR szTmpString[180]; PDXVHELP_RTINFO prtInfo = (PDXVHELP_RTINFO) lpvUserContext; PDVMSG_SESSIONLOST pdvSessionLost = NULL; PDVMSG_DELETEVOICEPLAYER pdvDeletePlayer = NULL; PDVMSG_CREATEVOICEPLAYER pdvCreatePlayer = NULL; switch( dwMessageType ) { case DVMSGID_CREATEVOICEPLAYER: pdvCreatePlayer = (PDVMSG_CREATEVOICEPLAYER) lpMessage; pdvCreatePlayer->pvPlayerContext = (PVOID) (DWORD_PTR) pdvCreatePlayer->dvidPlayer; _stprintf( szTmpString, _T("[DVMSGID_CREATEVOICEPLAYER] **SERVER** ID=0x%x"), pdvCreatePlayer->dvidPlayer ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); break; case DVMSGID_DELETEVOICEPLAYER: pdvDeletePlayer = (PDVMSG_DELETEVOICEPLAYER) lpMessage; _stprintf( szTmpString, _T("[DVMSGID_DELETEVOICEPLAYER] **SERVER** ID=0x%x"), pdvDeletePlayer->dvidPlayer ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); break; case DVMSGID_SESSIONLOST: pdvSessionLost = (PDVMSG_SESSIONLOST) lpMessage; _stprintf( szTmpString, _T("[DVMSGID_SESSIONLOST] **SERVER** Reason=0x%x"), pdvSessionLost->hrResult ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); if( !prtInfo->dxvParameters.fSilent ) { MessageBox( NULL, _T("Server Session lost!"),_T("Voice Conference"), MB_OK ); } SetEvent( prtInfo->hShutdown ); break; } return DV_OK; } HRESULT PASCAL DVMessageHandlerClient( LPVOID lpvUserContext, DWORD dwMessageType, LPVOID lpMessage ) { TCHAR szTmpString[180]; PDXVHELP_RTINFO prtInfo = (PDXVHELP_RTINFO) lpvUserContext; HWND hwndItem = NULL; PDVMSG_INPUTLEVEL pdvInputLevel = NULL; PDVMSG_OUTPUTLEVEL pdvOutputLevel = NULL; PDVMSG_HOSTMIGRATED pdvHostMigrated = NULL; PDVMSG_SESSIONLOST pdvSessionLost = NULL; PDVMSG_DELETEVOICEPLAYER pdvDeletePlayer = NULL; PDVMSG_CREATEVOICEPLAYER pdvCreatePlayer = NULL; PDVMSG_LOCALHOSTSETUP pdvLocalHostSetup = NULL; PDVMSG_PLAYERVOICESTART pdvPlayerVoiceStart = NULL; PDVMSG_PLAYERVOICESTOP pdvPlayerVoiceStop = NULL; PDVMSG_RECORDSTART pdvRecordStart = NULL; PDVMSG_RECORDSTOP pdvRecordStop = NULL; static int s_iRxCount = 0; char numBuffer[80]; switch( dwMessageType ) { case DVMSGID_LOCALHOSTSETUP: pdvLocalHostSetup = (PDVMSG_LOCALHOSTSETUP) lpMessage; _stprintf( szTmpString, _T("[DVMSGID_LOCALHOSTSETUP] Local client is to become host") ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); pdvLocalHostSetup->pMessageHandler = DVMessageHandlerServer; pdvLocalHostSetup->pvContext = lpvUserContext; break; case DVMSGID_CREATEVOICEPLAYER: pdvCreatePlayer = (PDVMSG_CREATEVOICEPLAYER) lpMessage; _stprintf( szTmpString, _T("[DVMSGID_CREATEVOICEPLAYER] ID=0x%x"), pdvCreatePlayer->dvidPlayer ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); MainDialog_AddVoicePlayer( prtInfo->hMainDialog, pdvCreatePlayer->dvidPlayer ); prtInfo->dwNumClients++; wsprintf( numBuffer, "%d", prtInfo->dwNumClients ); if( prtInfo->hMainDialog != NULL ) { hwndItem = GetDlgItem( prtInfo->hMainDialog, IDC_STATIC_PLAYERS ); if( hwndItem != NULL ) { SetWindowText( hwndItem, numBuffer ); } } pdvCreatePlayer->pvPlayerContext = (PVOID) (DWORD_PTR) pdvCreatePlayer->dvidPlayer; break; case DVMSGID_DELETEVOICEPLAYER: pdvDeletePlayer = (PDVMSG_DELETEVOICEPLAYER) lpMessage; _stprintf( szTmpString, _T("[DVMSGID_DELETEVOICEPLAYER] ID=0x%x"), pdvDeletePlayer->dvidPlayer ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); MainDialog_RemoveVoicePlayer( prtInfo->hMainDialog, pdvDeletePlayer->dvidPlayer ); prtInfo->dwNumClients--; wsprintf( numBuffer, "%d", prtInfo->dwNumClients ); if( prtInfo->hMainDialog != NULL ) { hwndItem = GetDlgItem( prtInfo->hMainDialog, IDC_STATIC_PLAYERS ); if( hwndItem != NULL ) { SetWindowText( hwndItem, numBuffer ); } } break; case DVMSGID_SESSIONLOST: pdvSessionLost = (PDVMSG_SESSIONLOST) lpMessage; _stprintf( szTmpString, _T("[DVMSGID_SESSIONLOST] Reason=0x%x"), pdvSessionLost->hrResult ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); if( !prtInfo->dxvParameters.fSilent ) { MessageBox( NULL, _T("Session lost!"),_T("Voice Conference"), MB_OK ); } SetEvent( prtInfo->hShutdown ); break; case DVMSGID_INPUTLEVEL: pdvInputLevel = (PDVMSG_INPUTLEVEL) lpMessage; if( prtInfo->hMainDialog != NULL ) { hwndItem = GetDlgItem( prtInfo->hMainDialog, IDC_PROGRESS_TX ); if( hwndItem != NULL ) { SendMessage( hwndItem, PBM_SETPOS, (WPARAM) pdvInputLevel->dwPeakLevel, 0 ); } } break; case DVMSGID_OUTPUTLEVEL: pdvOutputLevel = (PDVMSG_OUTPUTLEVEL) lpMessage; if( prtInfo->hMainDialog != NULL ) { hwndItem = GetDlgItem( prtInfo->hMainDialog, IDC_PROGRESS_RX ); if( hwndItem != NULL ) { SendMessage( hwndItem, PBM_SETPOS, (WPARAM) pdvOutputLevel->dwPeakLevel, 0 ); } } break; case DVMSGID_RECORDSTART: if( prtInfo->hMainDialog != NULL ) { pdvRecordStart = (PDVMSG_RECORDSTART) lpMessage; hwndItem = GetDlgItem( prtInfo->hMainDialog, IDC_STATIC_TX ); if( hwndItem != NULL ) { SendMessage( hwndItem, WM_SETTEXT, NULL, (LPARAM)"Tx" ); } _stprintf( szTmpString, _T("[DVMSGID_RECORDSTART]") ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); } break; case DVMSGID_RECORDSTOP: if( prtInfo->hMainDialog != NULL ) { pdvRecordStop = (PDVMSG_RECORDSTOP) lpMessage; hwndItem = GetDlgItem( prtInfo->hMainDialog, IDC_STATIC_TX ); if( hwndItem != NULL ) { SendMessage( hwndItem, WM_SETTEXT, NULL, (LPARAM)"" ); } _stprintf( szTmpString, _T("[DVMSGID_RECORDSTOP]") ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); } break; case DVMSGID_PLAYERVOICESTART: pdvPlayerVoiceStart = (PDVMSG_PLAYERVOICESTART) lpMessage; if( prtInfo->hMainDialog != NULL ) { hwndItem = GetDlgItem( prtInfo->hMainDialog, IDC_STATIC_RX ); if( hwndItem != NULL ) { ++s_iRxCount; SendMessage( hwndItem, WM_SETTEXT, NULL, (LPARAM)"Rx" ); } _stprintf( szTmpString, _T("[DVMSGID_PLAYERVOICESTART] ID=0x%x"), pdvPlayerVoiceStart->dvidSourcePlayerID ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); } break; case DVMSGID_PLAYERVOICESTOP: pdvPlayerVoiceStop = (PDVMSG_PLAYERVOICESTOP) lpMessage; if( prtInfo->hMainDialog != NULL ) { hwndItem = GetDlgItem( prtInfo->hMainDialog, IDC_STATIC_RX ); if( hwndItem != NULL ) { --s_iRxCount; if (s_iRxCount <= 0) { SendMessage( hwndItem, WM_SETTEXT, NULL, (LPARAM)"" ); } } _stprintf( szTmpString, _T("[DVMSGID_PLAYERVOICESTOP] ID=0x%x"), pdvPlayerVoiceStop->dvidSourcePlayerID ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); } break; case DVMSGID_HOSTMIGRATED: pdvHostMigrated = (PDVMSG_HOSTMIGRATED) lpMessage; _stprintf( szTmpString, _T("0x%x"), pdvHostMigrated->dvidNewHostID ); SetWindowText( GetDlgItem( prtInfo->hMainDialog, IDC_STATIC_HOST ), szTmpString ); _stprintf( szTmpString, _T("[DVMSGID_HOSTMIGRATED] New Voice Host=0x%x Local=%s"), pdvHostMigrated->dvidNewHostID, pdvHostMigrated->pdvServerInterface ? _T("Yes") : _T("No") ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); break; case DVMSGID_LOSTFOCUS: if( prtInfo->hMainDialog != NULL ) { VoiceManager_DisplayStatus( prtInfo, _T( "Connected (Focus Lost)" ) ); } _stprintf( szTmpString, _T("[DVMSGID_LOSTFOCUS]" ) ); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); break; case DVMSGID_GAINFOCUS: if( prtInfo->hMainDialog != NULL ) { VoiceManager_DisplayStatus( prtInfo, _T( "Connected" ) ); } _stprintf( szTmpString, _T("[DVMSGID_GAINFOCUS]" )); MainDialog_AddToLog( prtInfo->hMainDialog, szTmpString ); break; default: break; } return DV_OK; } void VoiceManager_MessageLoop( PDXVHELP_RTINFO prtInfo ) { LPBYTE lpbDataBuffer = (LPBYTE) new BYTE[30000]; if( lpbDataBuffer == NULL ) { goto BREAK_OUT; } DWORD dwSize; HRESULT hr; LONG lWakeResult; DWORD dwFlags; MSG msg; HANDLE hEvents[3]; LPDPLMSG_SYSTEMMESSAGE lpSysMessage; LPDPMSG_GENERIC lpGenericMessage; LPDPMSG_CREATEPLAYERORGROUP lpCreatePlayerMessage; LPDPMSG_DESTROYPLAYERORGROUP lpDeletePlayerMessage; BOOL bGotMsg; DPID dpidFrom, dpidTo; hEvents[0] = prtInfo->hShutdown; hEvents[1] = prtInfo->hReceiveEvent; hEvents[2] = prtInfo->hLobbyEvent; // hr = prtInfo->lpdpDirectPlay->CreatePlayer( &prtInfo->dpidLocalPlayer, NULL, prtInfo->hReceiveEvent, NULL, 0, 0 ); while( 1 ) { if( !prtInfo->dxvParameters.fLobbyLaunched ) { lWakeResult = MsgWaitForMultipleObjects( 2, hEvents, FALSE, INFINITE, QS_ALLINPUT); } else { lWakeResult = MsgWaitForMultipleObjects( 3, hEvents, FALSE, INFINITE, QS_ALLINPUT); } if( lWakeResult == WAIT_OBJECT_0 ) { break; } else if( lWakeResult == (WAIT_OBJECT_0+1) ) { while( 1 ) { dwSize = 30000; hr = prtInfo->lpdpDirectPlay->Receive( &dpidFrom, &dpidTo, DPRECEIVE_ALL, lpbDataBuffer, &dwSize ); if( hr == DPERR_NOMESSAGES ) { break; } lpGenericMessage = (LPDPMSG_GENERIC) lpbDataBuffer; switch( lpGenericMessage->dwType ) { case DPSYS_HOST: { MainDialog_AddToLog( prtInfo->hMainDialog, _T("[DPMSG_HOST] This client has just become the DPLAY host") ); } break; case DPSYS_CREATEPLAYERORGROUP: { TCHAR tszMessage[100]; lpCreatePlayerMessage = (LPDPMSG_CREATEPLAYERORGROUP) lpbDataBuffer; if( lpCreatePlayerMessage->dwPlayerType == DPPLAYERTYPE_PLAYER ) { _stprintf( tszMessage, _T("[DPMSG_CREATEPLAYER] Client 0x%x has just entered the session."), lpCreatePlayerMessage->dpId ); MainDialog_AddToLog( prtInfo->hMainDialog, tszMessage ); } MainDialog_AddTransportPlayer( prtInfo->hMainDialog, lpCreatePlayerMessage->dpId ); } break; case DPSYS_DESTROYPLAYERORGROUP: { TCHAR tszMessage[100]; lpDeletePlayerMessage = (LPDPMSG_DESTROYPLAYERORGROUP) lpbDataBuffer; if( lpDeletePlayerMessage->dwPlayerType == DPPLAYERTYPE_PLAYER ) { _stprintf( tszMessage, _T("[DPMSG_DELETEPLAYER] Client 0x%x has just left the session."), lpDeletePlayerMessage->dpId ); MainDialog_AddToLog( prtInfo->hMainDialog, tszMessage ); } MainDialog_RemoveTransportPlayer( prtInfo->hMainDialog, lpDeletePlayerMessage->dpId ); } break; } } } else if( prtInfo->dxvParameters.fLobbyLaunched && lWakeResult == (WAIT_OBJECT_0+2) ) { hr = DP_OK; while( hr != DPERR_NOMESSAGES ) { dwSize = 30000; hr = prtInfo->lpdpLobby->ReceiveLobbyMessage( 0, 0, &dwFlags, lpbDataBuffer, &dwSize ); if( hr == DPERR_NOMESSAGES ) { break; } else if( hr == DP_OK ) { if( !prtInfo->dxvParameters.fIgnoreLobbyDestroy ) { if( dwFlags == 0 ) { goto BREAK_OUT; } else if( dwFlags && DPLMSG_SYSTEM ) { lpSysMessage = (LPDPLMSG_SYSTEMMESSAGE) lpbDataBuffer; if( lpSysMessage->dwType == DPLSYS_LOBBYCLIENTRELEASE ) { goto BREAK_OUT; } } } } else { DPVDX_DPERRDisplay( hr, _T("Receive Lobby Message Error"), prtInfo->dxvParameters.fSilent ); } } } else { bGotMsg = TRUE; while( bGotMsg ) { bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ); if( bGotMsg ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } } } BREAK_OUT: if( lpbDataBuffer ) delete [] lpbDataBuffer; return; } void VoiceManager_Shutdown( PDXVHELP_RTINFO prtInfo ) { HRESULT hr; VoiceManager_DisplayStatus( prtInfo, _T("Disconnecting") ); if( prtInfo->lpdpLobby != NULL ) { prtInfo->lpdpLobby->Release(); prtInfo->lpdpLobby = NULL; } if( prtInfo->lpdvClient != NULL ) { VoiceManager_DisplayStatus( prtInfo, _T("Disconnecting") ); hr = prtInfo->lpdvClient->Disconnect( DVFLAGS_SYNC ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("Disconnect FAILED "), prtInfo->dxvParameters.fSilent ); } prtInfo->lpdvClient->Release(); } if( prtInfo->lpdvServer != NULL ) { VoiceManager_DisplayStatus( prtInfo, _T("Stopping Session") ); hr = prtInfo->lpdvServer->StopSession( 0 ); if( FAILED( hr ) ) { DPVDX_DPERRDisplay( hr, _T("StopSession FAILED "), prtInfo->dxvParameters.fSilent ); } prtInfo->lpdvServer->Release(); } if( prtInfo->lpdpDirectPlay != NULL ) { VoiceManager_DisplayStatus( prtInfo, _T("Stopping Dplay") ); prtInfo->lpdpDirectPlay->Close(); prtInfo->lpdpDirectPlay->Release(); } CloseHandle( prtInfo->hReceiveEvent ); if( prtInfo->hLobbyEvent != NULL ) { CloseHandle( prtInfo->hLobbyEvent ); } MainDialog_SetIdleState( prtInfo->hMainDialog, prtInfo ); } BOOL VoiceManager_VoiceConnect( PDXVHELP_RTINFO prtInfo ) { DVSESSIONDESC dvSessionDesc; DVCLIENTCONFIG dvClientConfig; DVSOUNDDEVICECONFIG dvSoundDeviceConfig; HRESULT hr; DVID dvidAllPlayers = DVID_ALLPLAYERS; // We're the host if( prtInfo->dxvParameters.fHost ) { VoiceManager_DisplayStatus( prtInfo, _T("Start Voice Host") ); hr = CoCreateInstance( DPVOICE_CLSID_DPVOICE, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlayVoiceServer, (void **) &prtInfo->lpdvServer ); if( FAILED( hr ) ) { DPVDX_DVERRDisplay( hr, _T("Create of voice server failed"), prtInfo->dxvParameters.fSilent ); goto EXIT_CLEANUP; } hr = prtInfo->lpdvServer->Initialize( prtInfo->lpdpDirectPlay, DVMessageHandlerServer, prtInfo, NULL, 0 ); if( FAILED( hr ) ) { DPVDX_DVERRDisplay( hr, _T("Initialize FAILED"), prtInfo->dxvParameters.fSilent ); goto EXIT_CLEANUP; } dvSessionDesc.dwSize = sizeof( DVSESSIONDESC ); dvSessionDesc.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT; dvSessionDesc.dwBufferQuality = DVBUFFERQUALITY_DEFAULT; dvSessionDesc.dwFlags = 0; dvSessionDesc.dwSessionType = prtInfo->dxvParameters.dwSessionType; dvSessionDesc.guidCT = prtInfo->dxvParameters.guidCT; hr = prtInfo->lpdvServer->StartSession( &dvSessionDesc, 0 ); if( FAILED( hr ) ) { DPVDX_DVERRDisplay( hr, _T("StartSession FAILED"), prtInfo->dxvParameters.fSilent ); goto EXIT_CLEANUP; } } VoiceManager_DisplayStatus( prtInfo, _T("Start Client") ); hr = CoCreateInstance( DPVOICE_CLSID_DPVOICE, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlayVoiceClient, (void **) &prtInfo->lpdvClient ); if( FAILED( hr ) ) { DPVDX_DVERRDisplay( hr, _T("Create of client failed"), prtInfo->dxvParameters.fSilent ); goto EXIT_CLEANUP; } hr = prtInfo->lpdvClient->Initialize( prtInfo->lpdpDirectPlay, DVMessageHandlerClient, prtInfo, NULL, 0 ); if( FAILED( hr ) ) { DPVDX_DVERRDisplay( hr, _T("Initialize FAILED"), prtInfo->dxvParameters.fSilent ); goto EXIT_CLEANUP; } dvSoundDeviceConfig.dwSize = sizeof( DVSOUNDDEVICECONFIG ); dvSoundDeviceConfig.hwndAppWindow = prtInfo->hMainWnd; dvSoundDeviceConfig.dwFlags = 0; if( prtInfo->dxvParameters.fForceWaveOut ) { dvSoundDeviceConfig.dwFlags |= DVSOUNDCONFIG_FORCEWAVEOUT; } else if( prtInfo->dxvParameters.fAllowWaveOut ) { dvSoundDeviceConfig.dwFlags |= DVSOUNDCONFIG_ALLOWWAVEOUT; } if( prtInfo->dxvParameters.fForceWaveIn ) { dvSoundDeviceConfig.dwFlags |= DVSOUNDCONFIG_FORCEWAVEIN; } else if( prtInfo->dxvParameters.fAllowWaveIn ) { dvSoundDeviceConfig.dwFlags |= DVSOUNDCONFIG_ALLOWWAVEIN; } if( prtInfo->dxvParameters.fAutoSelectMic ) { dvSoundDeviceConfig.dwFlags |= DVSOUNDCONFIG_AUTOSELECT; } if( prtInfo->dxvParameters.fDisableFocus ) { dvSoundDeviceConfig.dwFlags |= DVSOUNDCONFIG_NOFOCUS; } else if( prtInfo->dxvParameters.fStrictFocus ) { dvSoundDeviceConfig.dwFlags |= DVSOUNDCONFIG_STRICTFOCUS; } dvSoundDeviceConfig.guidCaptureDevice = prtInfo->dxvParameters.guidRecordDevice; dvSoundDeviceConfig.guidPlaybackDevice = prtInfo->dxvParameters.guidPlaybackDevice; dvSoundDeviceConfig.lpdsPlaybackDevice = NULL; dvSoundDeviceConfig.lpdsCaptureDevice = NULL; dvSoundDeviceConfig.lpdsMainBuffer = NULL; dvSoundDeviceConfig.dwMainBufferFlags = 0; dvSoundDeviceConfig.dwMainBufferPriority = 0; dvClientConfig.lRecordVolume = DSBVOLUME_MAX; MicrophoneGetVolume( 0, dvClientConfig.lRecordVolume ); prtInfo->dxvParameters.lRecordVolume = dvClientConfig.lRecordVolume; dvClientConfig.dwFlags = DVCLIENTCONFIG_AUTOVOICEACTIVATED; if( prtInfo->dxvParameters.fAGC ) { dvClientConfig.dwFlags |= DVCLIENTCONFIG_AUTORECORDVOLUME; dvClientConfig.lRecordVolume = DVRECORDVOLUME_LAST; } if( prtInfo->dxvParameters.fEchoSuppression ) { dvClientConfig.dwFlags |= DVCLIENTCONFIG_ECHOSUPPRESSION; } dvClientConfig.dwThreshold = DVTHRESHOLD_UNUSED; dvClientConfig.lPlaybackVolume = DSBVOLUME_MAX; dvClientConfig.dwNotifyPeriod = 51; dvClientConfig.dwBufferQuality = DVBUFFERQUALITY_DEFAULT; dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT; dvClientConfig.dwSize = sizeof( DVCLIENTCONFIG ); VoiceManager_DisplayStatus( prtInfo, _T("Connecting Voice") ); hr = prtInfo->lpdvClient->Connect( &dvSoundDeviceConfig, &dvClientConfig, DVFLAGS_SYNC ); if( hr != DV_OK && hr != DVERR_PENDING ) { DPVDX_DVERRDisplay( hr, _T("Connect FAILED"), prtInfo->dxvParameters.fSilent ); goto EXIT_CLEANUP; } MainDialog_DisplayVolumeSettings( prtInfo->hMainDialog, prtInfo ); VoiceManager_DisplayStatus( prtInfo, _T("Connected") ); MainDialog_ShowSessionSettings( prtInfo->hMainDialog, prtInfo); prtInfo->lpdvClient->SetTransmitTargets( &dvidAllPlayers, 1, 0 ); return TRUE; EXIT_CLEANUP: if( prtInfo->lpdvClient != NULL ) { prtInfo->lpdvClient->Release(); } if( prtInfo->lpdvServer != NULL ) { prtInfo->lpdvServer->Release(); } MainDialog_SetIdleState( prtInfo->hMainDialog, prtInfo ); VoiceManager_DisplayStatus( prtInfo, _T("Aborted") ); return FALSE; } // ManagerThread // // This thread is responsible for running the session, allowing the main interface // to remain responsive. // DWORD WINAPI VoiceManager_ThreadProc( LPVOID lpParameter ) { PDXVHELP_RTINFO prtInfo = (PDXVHELP_RTINFO) lpParameter; BOOL fResult; HANDLE hEventArray[2]; HRESULT hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ); if( FAILED( hr ) ) { goto EXIT_ERROR; } hEventArray[0] = prtInfo->hShutdown; // Cancel hEventArray[1] = prtInfo->hGo; // Start Session // Wait to be cancelled or started if( WaitForMultipleObjects( 2, hEventArray, FALSE, INFINITE ) != WAIT_OBJECT_0 ) { if( prtInfo->dxvParameters.fLobbyLaunched ) { fResult = VoiceManager_LobbyConnect( prtInfo ); } else { fResult = VoiceManager_StandardConnect( prtInfo ); } if( fResult ) { fResult = VoiceManager_VoiceConnect( prtInfo ); if( fResult ) { VoiceManager_MessageLoop( prtInfo ); VoiceManager_Shutdown( prtInfo ); } } } CoUninitialize(); EXIT_ERROR: SetEvent( prtInfo->hThreadDone ); return 0; } BOOL VoiceManager_Start( PDXVHELP_RTINFO prtInfo ) { DWORD dwThreadID = 0; prtInfo->hManagerThread = CreateThread( NULL, 0, VoiceManager_ThreadProc, prtInfo, 0, &dwThreadID ); return TRUE; } BOOL VoiceManager_Stop( PDXVHELP_RTINFO prtInfo ) { WaitForSingleObject( prtInfo->hThreadDone, INFINITE ); CloseHandle( prtInfo->hManagerThread ); return TRUE; }