home *** CD-ROM | disk | FTP | other *** search
/ Beginning Direct3D Game Programming / Direct3D.iso / directx / dxf / samples / multimedia / directplay / voicegroup / voicegroup.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  66.1 KB  |  1,712 lines

  1. //-----------------------------------------------------------------------------
  2. // File: VoiceGroup.cpp
  3. //
  4. // Desc: The main file for VoiceGroup that shows how use DirectPlay along 
  5. //       with DirectPlayVoice to allow talking in to a specific group
  6. //       of players.
  7. //
  8. // Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
  9. //-----------------------------------------------------------------------------
  10. #define STRICT
  11. #include <windows.h>
  12. #include <basetsd.h>
  13. #include <stdio.h>
  14. #include <dxerr8.h>
  15. #include <dplay8.h>
  16. #include <dplobby8.h>
  17. #include <dvoice.h>
  18. #include <commctrl.h>
  19. #include <cguid.h>
  20. #include "NetConnect.h"
  21. #include "NetVoice.h"
  22. #include "DXUtil.h"
  23. #include "resource.h"
  24.  
  25.  
  26.  
  27.  
  28. //-----------------------------------------------------------------------------
  29. // Player context locking defines
  30. //-----------------------------------------------------------------------------
  31. CRITICAL_SECTION g_csPlayerContext;
  32. #define PLAYER_LOCK()                   EnterCriticalSection( &g_csPlayerContext ); 
  33. #define PLAYER_ADDREF( pPlayerInfo )    if( pPlayerInfo ) pPlayerInfo->lRefCount++;
  34. #define PLAYER_RELEASE( pPlayerInfo )   if( pPlayerInfo ) { pPlayerInfo->lRefCount--; if( pPlayerInfo->lRefCount <= 0 ) SAFE_DELETE( pPlayerInfo ); } pPlayerInfo = NULL;
  35. #define PLAYER_UNLOCK()                 LeaveCriticalSection( &g_csPlayerContext );
  36.  
  37.  
  38. //-----------------------------------------------------------------------------
  39. // Defines, and constants
  40. //-----------------------------------------------------------------------------
  41. #define DPLAY_SAMPLE_KEY        TEXT("Software\\Microsoft\\DirectX DirectPlay Samples")
  42. #define MAX_GROUPS              5
  43. #define MAX_PLAYER_NAME         14
  44. #define WM_APP_DISPLAY_PLAYERS  (WM_APP + 0)
  45.  
  46. // This GUID allows DirectPlay to find other instances of the same game on
  47. // the network.  So it must be unique for every game, and the same for 
  48. // every instance of that game.  // {9F2DA206-D197-4871-AD1D-D12F59058B5B}
  49. GUID g_guidApp = { 0x9f2da206, 0xd197, 0x4871, { 0xad, 0x1d, 0xd1, 0x2f, 0x59, 0x5, 0x8b, 0x5b } };
  50.  
  51. struct PLAYER_STATE
  52. {
  53.     DWORD        dwGroup;                          // Group # that player joined in
  54.     DWORD        dwTarget;                         // Group # that player is targeting 
  55. };
  56.  
  57. struct APP_PLAYER_INFO
  58. {
  59.     LONG         lRefCount;                        // Ref count so we can cleanup when all threads 
  60.                                                    // are done w/ this object
  61.     DPNID        dpnidPlayer;                      // dpnid of the player
  62.     BOOL         bTalking;                         // Is the player talking
  63.     BOOL         bHalfDuplex;                      // If true, then player cannot talk
  64.     PLAYER_STATE ps;                               // State of player
  65.     TCHAR        strPlayerName[MAX_PLAYER_NAME];   // Player name
  66. };
  67.  
  68.  
  69.  
  70.  
  71. //-----------------------------------------------------------------------------
  72. // App specific DirectPlay messages and structures 
  73. //-----------------------------------------------------------------------------
  74. #define GAME_MSGID_PLAYERSTATECHANGE   1
  75.  
  76. // Change compiler pack alignment to be BYTE aligned, and pop the current value
  77. #pragma pack( push, 1 )
  78.  
  79. struct GAMEMSG_GENERIC
  80. {
  81.     DWORD dwType;
  82. };
  83.  
  84. struct GAMEMSG_PLAYERSTATECHANGE : public GAMEMSG_GENERIC
  85. {
  86.     PLAYER_STATE ps;
  87. };
  88.  
  89. // Pop the old pack alignment
  90. #pragma pack( pop )
  91.  
  92.  
  93.  
  94. //-----------------------------------------------------------------------------
  95. // Global variables
  96. //-----------------------------------------------------------------------------
  97. IDirectPlay8Peer*  g_pDP                         = NULL;    // DirectPlay peer object
  98. CNetConnectWizard* g_pNetConnectWizard           = NULL;    // Connection wizard
  99. CNetVoice*         g_pNetVoice                   = NULL;    // DirectPlay voice helper class
  100. IDirectPlay8LobbiedApplication* g_pLobbiedApp    = NULL;    // DirectPlay lobbied app 
  101. BOOL               g_bWasLobbyLaunched           = FALSE;   // TRUE if lobby launched
  102. HINSTANCE          g_hInst                       = NULL;    // HINST of app
  103. HWND               g_hDlg                        = NULL;    // HWND of main dialog
  104. TCHAR              g_strAppName[256]             = TEXT("VoiceGroup");
  105. APP_PLAYER_INFO*   g_pPlayerLocal                = NULL;    // APP_PLAYER_INFO* of local player
  106. BOOL               g_bVoiceSessionInProgress     = FALSE;   // True if voice has been init'ed
  107. DPNID*             g_pPlayers                    = NULL;    // Array of DPNIDs
  108. DWORD              g_dwPlayersArraySize          = 0;       // Size of g_pPlayers
  109. HRESULT            g_hrDialog;                              // Exit code for app 
  110. TCHAR              g_strLocalPlayerName[MAX_PATH];          // Local player name
  111. TCHAR              g_strSessionName[MAX_PATH];              // Session name
  112. TCHAR              g_strPreferredProvider[MAX_PATH];        // Provider string
  113. BOOL               g_bHostPlayer                 = FALSE;   // TRUE if local player is host
  114. DPNID              g_LocalPlayerDPNID            = 0;       // DPNID of local player
  115. DPNID              g_LocalGroupDPNID             = 0;       // DPNID of the group of the local player
  116. GUID               g_guidDVSessionCT;                       // GUID for choosen voice compression
  117. DVCLIENTCONFIG     g_dvClientConfig;                        // Voice client config
  118.  
  119.  
  120.  
  121.  
  122. //-----------------------------------------------------------------------------
  123. // Function-prototypes
  124. //-----------------------------------------------------------------------------
  125. INT_PTR CALLBACK VoiceDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  126. HRESULT          OnInitDialog( HWND hDlg );
  127. HRESULT WINAPI   DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  128. HRESULT WINAPI   DirectPlayLobbyMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  129. HRESULT WINAPI   DirectPlayVoiceClientMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  130. HRESULT WINAPI   DirectPlayVoiceServerMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  131. void             SetPlayerTalking( APP_PLAYER_INFO *pPlayerInfo, BOOL bTalking );
  132. INT_PTR CALLBACK VoiceConfigDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  133. HRESULT          VoiceConfigEnumCompressionCodecs( HWND hDlg );
  134. VOID             VoiceConfigDlgOnOK( HWND hDlg );
  135. HRESULT          InitDirectPlay();
  136. HRESULT          DisplayPlayersInChat( HWND hDlg );
  137. HRESULT          SendLocalStateToAll( HWND hDlg );
  138. HRESULT          SetGroupAndTarget();
  139.  
  140.  
  141.  
  142.  
  143. //-----------------------------------------------------------------------------
  144. // Name: WinMain()
  145. // Desc: Entry point for the application.  Since we use a simple dialog for 
  146. //       user interaction we don't need to pump messages.
  147. //-----------------------------------------------------------------------------
  148. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, 
  149.                       INT nCmdShow )
  150. {
  151.     HRESULT hr;
  152.     HKEY    hDPlaySampleRegKey;
  153.     BOOL    bConnectSuccess = FALSE;
  154.  
  155.     g_hInst = hInst;
  156.     InitializeCriticalSection( &g_csPlayerContext );
  157.  
  158.     // Init player ID array 
  159.     g_dwPlayersArraySize = 10;
  160.     g_pPlayers = (DPNID*) malloc( sizeof(DPNID)*g_dwPlayersArraySize );
  161.  
  162.     // Read persistent state information from registry
  163.     RegCreateKeyEx( HKEY_CURRENT_USER, DPLAY_SAMPLE_KEY, 0, NULL,
  164.                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
  165.                     &hDPlaySampleRegKey, NULL );
  166.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), 
  167.                              g_strLocalPlayerName, MAX_PATH, TEXT("TestPlayer") );
  168.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), 
  169.                              g_strSessionName, MAX_PATH, TEXT("TestGame") );
  170.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), 
  171.                              g_strPreferredProvider, MAX_PATH, TEXT("DirectPlay8 TCP/IP Service Provider") );
  172.  
  173.     InitCommonControls();
  174.  
  175.     // Init COM so we can use CoCreateInstance
  176.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  177.  
  178.     // Create helper class
  179.     g_pNetConnectWizard = new CNetConnectWizard( hInst, g_strAppName, &g_guidApp );
  180.     g_pNetVoice         = new CNetVoice( DirectPlayVoiceClientMessageHandler, DirectPlayVoiceServerMessageHandler );
  181.  
  182.     if( FAILED( hr = InitDirectPlay() ) )
  183.     {
  184.         DXTRACE_ERR( TEXT("InitDirectPlay"), hr );
  185.         MessageBox( NULL, TEXT("Failed initializing IDirectPlay8Peer. ")
  186.                     TEXT("The sample will now quit."),
  187.                     TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  188.         return FALSE;
  189.     }
  190.  
  191.     // Check if we were launched from a lobby client
  192.     if( g_bWasLobbyLaunched && g_pNetConnectWizard->HaveConnectionSettingsFromLobby() )
  193.     {
  194.         // If were lobby launched then DPL_MSGID_CONNECT has already been
  195.         // handled, so we can just tell the wizard to connect to the lobby
  196.         // that has sent us a DPL_MSGID_CONNECT msg.
  197.         if( FAILED( hr = g_pNetConnectWizard->ConnectUsingLobbySettings() ) )
  198.         {
  199.             DXTRACE_ERR( TEXT("ConnectUsingLobbySettings"), hr );
  200.             MessageBox( NULL, TEXT("Failed to connect using lobby settings. ")
  201.                         TEXT("The sample will now quit."),
  202.                         TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  203.  
  204.             bConnectSuccess = FALSE;
  205.         }
  206.         else
  207.         {
  208.             // Read information from g_pNetConnectWizard
  209.             _tcscpy( g_strLocalPlayerName, g_pNetConnectWizard->GetPlayerName() );
  210.             g_bHostPlayer = g_pNetConnectWizard->IsHostPlayer();
  211.  
  212.             bConnectSuccess = TRUE; 
  213.         }
  214.     }
  215.     else
  216.     {
  217.         // If not lobby launched, prompt the user about the network 
  218.         // connection and which session they would like to join or 
  219.         // if they want to create a new one.
  220.  
  221.         // Setup connection wizard
  222.         g_pNetConnectWizard->SetPlayerName( g_strLocalPlayerName );
  223.         g_pNetConnectWizard->SetSessionName( g_strSessionName );
  224.         g_pNetConnectWizard->SetPreferredProvider( g_strPreferredProvider );
  225.  
  226.         // Do the connection wizard
  227.         hr = g_pNetConnectWizard->DoConnectWizard( FALSE );        
  228.         if( FAILED( hr ) ) 
  229.         {
  230.             DXTRACE_ERR( TEXT("DoConnectWizard"), hr );
  231.             MessageBox( NULL, TEXT("Mutliplayer connect failed. ")  
  232.                         TEXT("The sample will now quit."),
  233.                         TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  234.             bConnectSuccess = FALSE;
  235.         } 
  236.         else if( hr == NCW_S_QUIT ) 
  237.         {
  238.             // The user canceled the mutliplayer connect, so quit 
  239.             bConnectSuccess = FALSE;
  240.         }
  241.         else
  242.         {
  243.             bConnectSuccess = TRUE; 
  244.  
  245.             // Read information from g_pNetConnectWizard
  246.             _tcscpy( g_strLocalPlayerName, g_pNetConnectWizard->GetPlayerName() );
  247.             _tcscpy( g_strSessionName, g_pNetConnectWizard->GetSessionName() );
  248.             _tcscpy( g_strPreferredProvider, g_pNetConnectWizard->GetPreferredProvider() );
  249.             g_bHostPlayer = g_pNetConnectWizard->IsHostPlayer();
  250.  
  251.             // Write information to the registry
  252.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), g_strLocalPlayerName );
  253.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), g_strSessionName );
  254.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), g_strPreferredProvider );
  255.         }
  256.     }
  257.  
  258.     if( bConnectSuccess )
  259.     {
  260.         // Set default DirectPlayVoice setup options
  261.         ZeroMemory( &g_dvClientConfig, sizeof(g_dvClientConfig) );
  262.         g_dvClientConfig.dwSize                 = sizeof(g_dvClientConfig);
  263.         g_dvClientConfig.dwFlags                = DVCLIENTCONFIG_AUTOVOICEACTIVATED |
  264.                                                   DVCLIENTCONFIG_AUTORECORDVOLUME;
  265.         g_dvClientConfig.lPlaybackVolume        = DVPLAYBACKVOLUME_DEFAULT;
  266.         g_dvClientConfig.dwBufferQuality        = DVBUFFERQUALITY_DEFAULT;
  267.         g_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  268.         g_dvClientConfig.dwThreshold          = DVTHRESHOLD_UNUSED;
  269.         g_dvClientConfig.lRecordVolume          = DVRECORDVOLUME_LAST;
  270.         g_dvClientConfig.dwNotifyPeriod         = 0;
  271.  
  272.         g_guidDVSessionCT                       = DPVCTGUID_DEFAULT;
  273.  
  274.         // Ask the user for DirectPlayVoice setup params
  275.         DWORD dwResult = (DWORD)DialogBox( hInst, MAKEINTRESOURCE(IDD_VOICE_SETUP), 
  276.                                            NULL, (DLGPROC) VoiceConfigDlgProc );
  277.         if( dwResult != IDCANCEL )
  278.             g_pNetVoice->ChangeVoiceClientSettings( &g_dvClientConfig );
  279.     }
  280.  
  281.     if( bConnectSuccess )
  282.     {
  283.         // App is now connected via DirectPlay, so start the game.  
  284.  
  285.         // For this sample, we just start a simple dialog box game.
  286.         g_hrDialog = S_OK;
  287.         DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN_GAME), NULL, (DLGPROC) VoiceDlgProc );
  288.  
  289.         if( FAILED( g_hrDialog ) )
  290.         {
  291.             if( g_hrDialog == DPNERR_CONNECTIONLOST )
  292.             {
  293.                 MessageBox( NULL, TEXT("The DirectPlay session was lost. ")
  294.                             TEXT("The sample will now quit."),
  295.                             TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  296.             }
  297.             else
  298.             {
  299.                 DXTRACE_ERR( TEXT("DialogBox"), hr );
  300.                 MessageBox( NULL, TEXT("An error occured during the game. ")
  301.                             TEXT("The sample will now quit."),
  302.                             TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  303.             }
  304.         }
  305.     }
  306.     
  307.     // Cleanup player ID array 
  308.     free( g_pPlayers );
  309.  
  310.     // Disconnect from the DirectPlayVoice session, 
  311.     // and destory it if we are the host player.
  312.     SAFE_DELETE( g_pNetVoice ); 
  313.  
  314.     // Cleanup DirectPlay and helper classes
  315.     g_pNetConnectWizard->Shutdown();
  316.  
  317.     if( g_pDP )
  318.     {
  319.         g_pDP->Close(0);
  320.         SAFE_RELEASE( g_pDP );
  321.     }
  322.  
  323.     if( g_pLobbiedApp )
  324.     {
  325.         g_pLobbiedApp->Close( 0 );
  326.         SAFE_RELEASE( g_pLobbiedApp );
  327.     }    
  328.  
  329.     // Don't delete the wizard until we know that 
  330.     // DirectPlay is out of its message handlers.
  331.     // This will be true after Close() has been called. 
  332.     SAFE_DELETE( g_pNetConnectWizard );
  333.  
  334.     RegCloseKey( hDPlaySampleRegKey );
  335.     DeleteCriticalSection( &g_csPlayerContext );
  336.     CoUninitialize();
  337.  
  338.     return TRUE;
  339. }
  340.  
  341.  
  342.  
  343.  
  344. //-----------------------------------------------------------------------------
  345. // Name: InitDirectPlay()
  346. // Desc: 
  347. //-----------------------------------------------------------------------------
  348. HRESULT InitDirectPlay()
  349. {
  350.     DPNHANDLE hLobbyLaunchedConnection = NULL;
  351.     HRESULT hr;
  352.  
  353.     // Create IDirectPlay8Peer
  354.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL, 
  355.                                        CLSCTX_INPROC_SERVER,
  356.                                        IID_IDirectPlay8Peer, 
  357.                                        (LPVOID*) &g_pDP ) ) )
  358.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  359.  
  360.     // Create IDirectPlay8LobbiedApplication
  361.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8LobbiedApplication, NULL, 
  362.                                        CLSCTX_INPROC_SERVER,
  363.                                        IID_IDirectPlay8LobbiedApplication, 
  364.                                        (LPVOID*) &g_pLobbiedApp ) ) )
  365.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  366.  
  367.     // Init the helper class, now that g_pDP and g_pLobbiedApp are valid
  368.     g_pNetConnectWizard->Init( g_pDP, g_pLobbiedApp );
  369.  
  370.     // Init IDirectPlay8Peer
  371.     if( FAILED( hr = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) )
  372.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  373.  
  374.     // Init IDirectPlay8LobbiedApplication.  Before this Initialize() returns 
  375.     // a DPL_MSGID_CONNECT msg may come in to the DirectPlayLobbyMessageHandler 
  376.     // so be prepared ahead of time.
  377.     if( FAILED( hr = g_pLobbiedApp->Initialize( NULL, DirectPlayLobbyMessageHandler, 
  378.                                                 &hLobbyLaunchedConnection, 0 ) ) )
  379.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  380.  
  381.     // IDirectPlay8LobbiedApplication::Initialize returns a handle to a connnection
  382.     // if we have been lobby launced.  Initialize is guanteeded to return after 
  383.     // the DPL_MSGID_CONNECT msg has been processed.  So unless a we are expected 
  384.     // multiple lobby connections, we do not need to remember the lobby connection
  385.     // handle since it will be recorded upon the DPL_MSGID_CONNECT msg.
  386.     g_bWasLobbyLaunched = ( hLobbyLaunchedConnection != NULL );
  387.  
  388.     return S_OK;
  389. }
  390.  
  391.  
  392.  
  393.  
  394. //-----------------------------------------------------------------------------
  395. // Name: VoiceDlgProc()
  396. // Desc: Handles dialog messages
  397. //-----------------------------------------------------------------------------
  398. INT_PTR CALLBACK VoiceDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  399. {
  400.     switch( msg ) 
  401.     {
  402.         case WM_INITDIALOG:
  403.             {
  404.                 g_hDlg = hDlg;
  405.  
  406.                 if( FAILED( g_hrDialog = g_pNetVoice->Init( hDlg, g_bHostPlayer, TRUE,
  407.                                                             g_pDP, DVSESSIONTYPE_PEER, 
  408.                                                             &g_guidDVSessionCT, &g_dvClientConfig ) ) )
  409.                 {
  410.                     if( g_hrDialog == DVERR_USERBACK )
  411.                     {
  412.                         MessageBox( hDlg, TEXT("The user backed out of the wizard.  ")
  413.                                     TEXT("This simple sample does not handle this case, so ")
  414.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  415.                         g_hrDialog = S_OK;
  416.                     }
  417.  
  418.                     if( g_hrDialog == DVERR_USERCANCEL )
  419.                     {
  420.                         MessageBox( hDlg, TEXT("The user canceled the wizard. ")
  421.                                     TEXT("This simple sample does not handle this case, so ")
  422.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  423.                         g_hrDialog = S_OK;
  424.                     }
  425.  
  426.                     if( FAILED(g_hrDialog) )
  427.                         DXTRACE_ERR( TEXT("Init"), g_hrDialog );
  428.  
  429.                     EndDialog( hDlg, 0 );
  430.                     break;
  431.                 }
  432.  
  433.                 if( g_pNetVoice->IsHalfDuplex() ) 
  434.                 {
  435.                     MessageBox( hDlg, TEXT("You are running in half duplex mode. In half duplex mode no recording takes place."), 
  436.                                 TEXT("DirectPlay Sample"), MB_OK );
  437.                 }
  438.  
  439.                 g_bVoiceSessionInProgress = TRUE;
  440.  
  441.                 if( FAILED( g_hrDialog = OnInitDialog( hDlg ) ) )
  442.                 {
  443.                     DXTRACE_ERR( TEXT("OnInitDialog"), g_hrDialog );
  444.                     EndDialog( hDlg, 0 );
  445.                     break;
  446.                 }
  447.             }
  448.             break;
  449.  
  450.         case WM_COMMAND:
  451.             switch( LOWORD(wParam) )
  452.             {
  453.                 case IDC_SETUP:
  454.                     {
  455.                         // Ask the user for DirectPlayVoice setup params
  456.                         DWORD dwResult = (DWORD)DialogBox( g_hInst, 
  457.                                                            MAKEINTRESOURCE(IDD_VOICE_SETUP), 
  458.                                                            hDlg, (DLGPROC) VoiceConfigDlgProc );
  459.                         if( dwResult != IDCANCEL )
  460.                             g_pNetVoice->ChangeVoiceClientSettings( &g_dvClientConfig );
  461.                     }
  462.                     return TRUE;
  463.  
  464.                 case IDC_CYCLEGROUP:
  465.                     {
  466.                         if( g_pPlayerLocal )
  467.                         {
  468.                             g_pPlayerLocal->ps.dwGroup++;
  469.                             g_pPlayerLocal->ps.dwGroup %= MAX_GROUPS + 1;
  470.                         }
  471.  
  472.                         if( FAILED( g_hrDialog = SetGroupAndTarget() ) )
  473.                         {
  474.                             DXTRACE_ERR( TEXT("SetGroupAndTarget"), g_hrDialog );
  475.                             EndDialog( hDlg, 0 );
  476.                             break;
  477.                         }
  478.  
  479.                         if( FAILED( g_hrDialog = SendLocalStateToAll( hDlg ) ) )
  480.                         {
  481.                             DXTRACE_ERR( TEXT("SendLocalStateToAll"), g_hrDialog );
  482.                             EndDialog( hDlg, 0 );
  483.                             break;
  484.                         }
  485.  
  486.                         // Update the listbox 
  487.                         PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  488.                     }
  489.                     break;
  490.  
  491.                 case IDC_CYCLETARGET:
  492.                     {
  493.                         if( g_pPlayerLocal )
  494.                         {
  495.                             g_pPlayerLocal->ps.dwTarget++;
  496.                             g_pPlayerLocal->ps.dwTarget %= MAX_GROUPS + 1;
  497.                         }
  498.  
  499.                         if( FAILED( g_hrDialog = SetGroupAndTarget() ) )
  500.                         {
  501.                             DXTRACE_ERR( TEXT("SetGroupAndTarget"), g_hrDialog );
  502.                             EndDialog( hDlg, 0 );
  503.                             break;
  504.                         }
  505.  
  506.                         if( FAILED( g_hrDialog = SendLocalStateToAll( hDlg ) ) )
  507.                         {
  508.                             DXTRACE_ERR( TEXT("SendLocalStateToAll"), g_hrDialog );
  509.                             EndDialog( hDlg, 0 );
  510.                             break;
  511.                         }
  512.  
  513.                         // Update the listbox 
  514.                         PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  515.                     }
  516.                     break;
  517.  
  518.                 case IDCANCEL:
  519.                     g_hrDialog = S_OK;
  520.                     EndDialog( hDlg, 0 );
  521.                     return TRUE;
  522.             }
  523.             break;
  524.  
  525.         case WM_APP_DISPLAY_PLAYERS:
  526.         {
  527.             DisplayPlayersInChat( hDlg );
  528.             break;
  529.         }
  530.  
  531.         case WM_TIMER:
  532.         {
  533.             DWORD            dwNumPlayers;
  534.             DWORD            iIndex;
  535.             LVITEM           lvItem;
  536.             APP_PLAYER_INFO* pPlayerInfo = NULL;
  537.             HWND             hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  538.  
  539.             dwNumPlayers = ListView_GetItemCount( hListView );
  540.  
  541.             // Now that they are added and the listview sorted them by name,
  542.             // run through them all caching the listview index with its dpnid
  543.             for( iIndex = 0; iIndex < dwNumPlayers; iIndex++ )
  544.             {
  545.                 HRESULT hr;
  546.                 APP_PLAYER_INFO* pPlayerInfo = NULL;
  547.                 DPNID dpnidPlayer;
  548.  
  549.                 lvItem.mask  = LVIF_PARAM;
  550.                 lvItem.iItem = iIndex;
  551.                 ListView_GetItem( hListView, &lvItem );
  552.  
  553.                 dpnidPlayer = (DPNID) lvItem.lParam;
  554.  
  555.                 PLAYER_LOCK(); // enter player context CS
  556.  
  557.                 // Get the player context accosicated with this DPNID
  558.                 hr = g_pDP->GetPlayerContext( dpnidPlayer, 
  559.                                               (LPVOID* const) &pPlayerInfo,
  560.                                               0);
  561.  
  562.  
  563.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  564.                 PLAYER_UNLOCK(); // leave player context CS
  565.  
  566.                 if( FAILED(hr) || pPlayerInfo == NULL )
  567.                 {
  568.                     // The player who sent this may have gone away before this 
  569.                     // message was handled, so just ignore it
  570.                     continue;
  571.                 }
  572.  
  573.                 TCHAR strStatus[255];
  574.  
  575.                 if( pPlayerInfo->bHalfDuplex )
  576.                 {
  577.                     _tcscpy( strStatus, TEXT("Can't talk") );
  578.                 }
  579.                 else
  580.                 {
  581.                     if( pPlayerInfo->bTalking )
  582.                         _tcscpy( strStatus, TEXT("Talking") );
  583.                     else
  584.                         _tcscpy( strStatus, TEXT("Silent") );
  585.                 }
  586.  
  587.                 lvItem.iItem      = iIndex;
  588.                 lvItem.iSubItem   = 1;
  589.                 lvItem.mask       = LVIF_TEXT;
  590.                 lvItem.pszText    = strStatus;
  591.  
  592.                 PLAYER_LOCK();
  593.                 PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  594.                 PLAYER_UNLOCK();
  595.  
  596.                 SendMessage( hListView, LVM_SETITEM, 0, (LPARAM) &lvItem );
  597.             }
  598.             break;
  599.         }
  600.     }
  601.  
  602.     return FALSE; // Didn't handle message
  603. }
  604.  
  605.  
  606.  
  607.  
  608. //-----------------------------------------------------------------------------
  609. // Name: OnInitDialog()
  610. // Desc: Inits the dialog 
  611. //-----------------------------------------------------------------------------
  612. HRESULT OnInitDialog( HWND hDlg )
  613. {
  614.     HRESULT  hr;
  615.     LVCOLUMN column;
  616.     RECT     rctListView;
  617.     TCHAR    strHeader[255];
  618.     DWORD    dwVertScrollBar;
  619.     DWORD    dwListViewWidth;
  620.  
  621.     // Load and set the icon
  622.     HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  623.     SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  624.     SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  625.  
  626.     if( g_bHostPlayer )
  627.         SetWindowText( hDlg, TEXT("VoiceGroup (Session Host)") );
  628.     else
  629.         SetWindowText( hDlg, TEXT("VoiceGroup (Session Client)") );
  630.  
  631.     SetDlgItemText( hDlg, IDC_GROUP_TEXT, TEXT("Unassigned") );
  632.     SetDlgItemText( hDlg, IDC_TARGET_TEXT, TEXT("Everyone") );
  633.  
  634.     // Setup the listview
  635.     HWND hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  636.  
  637.     dwVertScrollBar = GetSystemMetrics( SM_CXVSCROLL );  
  638.     GetClientRect( hListView, &rctListView );
  639.     dwListViewWidth = rctListView.right - dwVertScrollBar;
  640.     column.mask     = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
  641.     column.fmt      = LVCFMT_LEFT;
  642.     column.iSubItem = -1;
  643.  
  644.     // Insert the Name column
  645.     _tcscpy( strHeader, TEXT("Name") );
  646.     column.cx         = dwListViewWidth * 8 / 21;
  647.     column.pszText    = strHeader;
  648.     column.cchTextMax = _tcslen( strHeader );
  649.     ListView_InsertColumn( hListView, 0, &column );
  650.  
  651.     // Insert the Status column
  652.     _tcscpy( strHeader, TEXT("Status") );
  653.     column.cx         = dwListViewWidth * 4 / 21;
  654.     column.pszText    = strHeader;
  655.     column.cchTextMax = _tcslen( strHeader );
  656.     ListView_InsertColumn( hListView, 1, &column );
  657.  
  658.     // Insert the Group column
  659.     _tcscpy( strHeader, TEXT("Group") );
  660.     column.cx         = dwListViewWidth * 5 / 21;
  661.     column.pszText    = strHeader;
  662.     column.cchTextMax = _tcslen( strHeader );
  663.     ListView_InsertColumn( hListView, 2, &column );
  664.  
  665.     // Insert the Target column
  666.     _tcscpy( strHeader, TEXT("Target") );
  667.     column.cx         = dwListViewWidth * 4 / 21;
  668.     column.pszText    = strHeader;
  669.     column.cchTextMax = _tcslen( strHeader );
  670.     ListView_InsertColumn( hListView, 3, &column );
  671.  
  672.     if( FAILED( hr = SetGroupAndTarget() ) )
  673.         return DXTRACE_ERR( TEXT("SetGroupAndTarget"), hr );
  674.     if( FAILED( hr = SendLocalStateToAll( hDlg ) ) )
  675.         return DXTRACE_ERR( TEXT("SendLocalStateToAll"), hr );
  676.  
  677.     // Update the listbox 
  678.     PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  679.  
  680.     // Make a timer to update the listbox 
  681.     // 'Status' column every so often 
  682.     SetTimer( hDlg, 0, 250, NULL );
  683.  
  684.     // Create the groups if we are the host player
  685.     if( g_bHostPlayer )
  686.     {
  687.         DWORD dwIndex;
  688.  
  689.         for( dwIndex = 1; dwIndex < MAX_GROUPS + 1; dwIndex++ )
  690.         {
  691.             DPN_GROUP_INFO dpGroupInfo;
  692.             DWORD* pdwData = new DWORD;
  693.             *pdwData = dwIndex;
  694.             ZeroMemory( &dpGroupInfo, sizeof(DPN_GROUP_INFO) );
  695.             dpGroupInfo.dwSize = sizeof( DPN_GROUP_INFO );
  696.             dpGroupInfo.dwInfoFlags = DPNINFO_DATA;
  697.             dpGroupInfo.pvData = pdwData;
  698.             dpGroupInfo.dwDataSize = sizeof(DWORD);
  699.  
  700.             DPNHANDLE hAsync;
  701.             hr = g_pDP->CreateGroup( &dpGroupInfo, NULL,
  702.                                      NULL, &hAsync, 0 );
  703.             if( FAILED( hr ) ) 
  704.                 return DXTRACE_ERR( TEXT("CreateGroup"), hr );
  705.         }
  706.     }
  707.  
  708.     return S_OK;
  709. }
  710.  
  711.  
  712.  
  713.  
  714. //-----------------------------------------------------------------------------
  715. // Name: DisplayPlayersInChat()
  716. // Desc: Displays the active players in the listview
  717. //-----------------------------------------------------------------------------
  718. HRESULT DisplayPlayersInChat( HWND hDlg )
  719. {
  720.     if( hDlg == NULL )
  721.         return S_OK;
  722.  
  723.     HRESULT hr;
  724.     LVITEM  lvItem;
  725.     HWND    hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  726.     TCHAR   strText[32];
  727.     TCHAR   strNumberPlayers[32];
  728.     DWORD   dwNumPlayers;
  729.     APP_PLAYER_INFO* pPlayerInfo = NULL;
  730.  
  731.     // Remove all the players and re-add them in the player enum callback
  732.     ListView_DeleteAllItems( hListView );
  733.  
  734.     do
  735.     {
  736.         // Enum all players in the player ID array
  737.         dwNumPlayers = g_dwPlayersArraySize;
  738.         hr = g_pDP->EnumPlayersAndGroups( g_pPlayers, &dwNumPlayers, DPNENUM_PLAYERS );
  739.         if( SUCCEEDED(hr) )
  740.             break;
  741.  
  742.         if( hr == DPNERR_BUFFERTOOSMALL )
  743.         {
  744.             // Resize player pointer array     
  745.             g_dwPlayersArraySize += 10;
  746.             g_pPlayers = (DPNID*) realloc( g_pPlayers, sizeof(DPNID)*g_dwPlayersArraySize );
  747.         }
  748.     } 
  749.     while( hr == DPNERR_BUFFERTOOSMALL );
  750.     if( FAILED(hr) )
  751.         return DXTRACE_ERR( TEXT("EnumPlayersAndGroups"), hr );
  752.  
  753.     for( DWORD i = 0; i<dwNumPlayers; i++ )
  754.     {
  755.         PLAYER_LOCK(); // enter player context CS
  756.  
  757.         // Get the player context accosicated with this DPNID
  758.         hr = g_pDP->GetPlayerContext( g_pPlayers[i], 
  759.                                       (LPVOID* const) &pPlayerInfo,
  760.                                       0);
  761.  
  762.         PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  763.         PLAYER_UNLOCK(); // leave player context CS
  764.  
  765.         if( FAILED(hr) || pPlayerInfo == NULL )
  766.         {
  767.             // The player who sent this may have gone away before this 
  768.             // message was handled, so just ignore it
  769.             continue;
  770.         }
  771.  
  772.         ZeroMemory( &lvItem, sizeof(lvItem) );
  773.  
  774.         // Add the item, saving the player's name and dpnid in the listview
  775.         lvItem.mask       = LVIF_TEXT | LVIF_PARAM;
  776.         lvItem.iItem      = 0;
  777.         lvItem.iSubItem   = 0;
  778.         lvItem.pszText    = pPlayerInfo->strPlayerName;
  779.         lvItem.lParam     = g_pPlayers[i];
  780.         lvItem.cchTextMax = _tcslen( pPlayerInfo->strPlayerName );
  781.         int nIndex = ListView_InsertItem( hListView, &lvItem );
  782.  
  783.         if( pPlayerInfo->bHalfDuplex )
  784.         {
  785.             _tcscpy( strText, TEXT("Can't talk") );
  786.         }
  787.         else
  788.         {
  789.             if( pPlayerInfo->bTalking )
  790.                 _tcscpy( strText, TEXT("Talking") );
  791.             else
  792.                 _tcscpy( strText, TEXT("Silent") );
  793.         }
  794.  
  795.         // Start the player's status off as silent.  
  796.         lvItem.mask       = LVIF_TEXT;
  797.         lvItem.iItem      = nIndex;
  798.         lvItem.iSubItem   = 1;
  799.         lvItem.pszText    = strText;
  800.         lvItem.cchTextMax = _tcslen( strText );
  801.         ListView_SetItem( hListView, &lvItem );
  802.  
  803.         if( pPlayerInfo->ps.dwGroup == 0 )
  804.             _tcscpy( strText, TEXT("Unassigned") );
  805.         else
  806.             wsprintf( strText, TEXT("%d"), pPlayerInfo->ps.dwGroup );
  807.  
  808.         lvItem.mask       = LVIF_TEXT;
  809.         lvItem.iItem      = nIndex;
  810.         lvItem.iSubItem   = 2;
  811.         lvItem.pszText    = strText;
  812.         lvItem.cchTextMax = _tcslen( strText );
  813.         ListView_SetItem( hListView, &lvItem );
  814.  
  815.         if( pPlayerInfo->ps.dwTarget == 0 )
  816.             _tcscpy( strText, TEXT("Everyone") );
  817.         else
  818.             wsprintf( strText, TEXT("%d"), pPlayerInfo->ps.dwTarget );
  819.  
  820.         PLAYER_LOCK();
  821.         PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  822.         PLAYER_UNLOCK();
  823.  
  824.         lvItem.mask       = LVIF_TEXT;
  825.         lvItem.iItem      = nIndex;
  826.         lvItem.iSubItem   = 3;
  827.         lvItem.pszText    = strText;
  828.         lvItem.cchTextMax = _tcslen( strText );
  829.         ListView_SetItem( hListView, &lvItem );
  830.     }
  831.  
  832.     wsprintf( strNumberPlayers, TEXT("%d"), dwNumPlayers );
  833.     SetDlgItemText( hDlg, IDC_NUM_PLAYERS, strNumberPlayers );
  834.  
  835.     if( g_pPlayerLocal )
  836.     {
  837.         if( g_pPlayerLocal->ps.dwGroup == 0 )
  838.             _tcscpy( strText, TEXT("Unassigned") );
  839.         else
  840.             wsprintf( strText, TEXT("Group #%d"), g_pPlayerLocal->ps.dwGroup );
  841.         SetDlgItemText( hDlg, IDC_GROUP_TEXT, strText );
  842.  
  843.         if( g_pPlayerLocal->ps.dwTarget == 0 )
  844.             _tcscpy( strText, TEXT("Everyone") );
  845.         else
  846.             wsprintf( strText, TEXT("Group #%d"), g_pPlayerLocal->ps.dwTarget );
  847.         SetDlgItemText( hDlg, IDC_TARGET_TEXT, strText );
  848.     }
  849.  
  850.  
  851.     return S_OK;
  852. }
  853.  
  854.  
  855.  
  856.  
  857. //-----------------------------------------------------------------------------
  858. // Name: SendLocalStateToAll()
  859. // Desc: Send the local player's state to all of the players
  860. //-----------------------------------------------------------------------------
  861. HRESULT SendLocalStateToAll( HWND hDlg )
  862. {
  863.     if( g_pPlayerLocal )
  864.     {
  865.         GAMEMSG_PLAYERSTATECHANGE msgPlayerStateChange;
  866.         msgPlayerStateChange.dwType = GAME_MSGID_PLAYERSTATECHANGE;
  867.         msgPlayerStateChange.ps     = g_pPlayerLocal->ps; 
  868.  
  869.         DPN_BUFFER_DESC bufferDesc;
  870.         bufferDesc.dwBufferSize = sizeof(GAMEMSG_PLAYERSTATECHANGE);
  871.         bufferDesc.pBufferData  = (BYTE*) &msgPlayerStateChange;
  872.  
  873.         // DirectPlay will tell via the message handler 
  874.         // if there are any severe errors, so ignore any errors 
  875.         DPNHANDLE hAsync;
  876.         g_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  877.                        0, NULL, &hAsync, DPNSEND_NOLOOPBACK );
  878.     }
  879.  
  880.     return S_OK;
  881. }
  882.  
  883.  
  884.  
  885.  
  886. //-----------------------------------------------------------------------------
  887. // Name: SetGroupAndTarget()
  888. // Desc: 
  889. //-----------------------------------------------------------------------------
  890. HRESULT SetGroupAndTarget()
  891. {
  892.     HRESULT hr;
  893.  
  894.     LPDIRECTPLAYVOICECLIENT pVoiceClient = g_pNetVoice->GetVoiceClient();
  895.     if( pVoiceClient && g_pPlayerLocal->ps.dwTarget == 0 )
  896.     {
  897.         // Talk to everyone in the session 
  898.         DVID dvid = DVID_ALLPLAYERS;
  899.         if( FAILED( hr = pVoiceClient->SetTransmitTargets( &dvid, 1, 0 ) ) )
  900.             return DXTRACE_ERR( TEXT("SetTransmitTargets"), hr );
  901.     }
  902.  
  903.     if( g_LocalGroupDPNID != 0 )
  904.     {
  905.         // Remove player from current group
  906.         DPNHANDLE hAsync;
  907.         hr = g_pDP->RemovePlayerFromGroup( g_LocalGroupDPNID, 
  908.                                            g_LocalPlayerDPNID,
  909.                                            NULL, &hAsync, 0 );
  910.         if( FAILED(hr) )
  911.             return DXTRACE_ERR( TEXT("RemovePlayerFromGroup"), hr );
  912.  
  913.         g_LocalGroupDPNID = 0;
  914.     }
  915.  
  916.     // Enumerate all groups to figure out which group we are target, and joining
  917.     DPNID* aGroupsDPNID = NULL;
  918.     DWORD dwCount = 0;
  919.  
  920.     do
  921.     {
  922.         SAFE_DELETE_ARRAY( aGroupsDPNID );
  923.         if( dwCount ) 
  924.             aGroupsDPNID = new DPNID[ dwCount ];
  925.         hr = g_pDP->EnumPlayersAndGroups( aGroupsDPNID, &dwCount, DPNENUM_GROUPS );
  926.     }
  927.     while( hr == DPNERR_BUFFERTOOSMALL && dwCount != 0 );
  928.     if( FAILED(hr) && dwCount != 0 )
  929.         return DXTRACE_ERR( TEXT("EnumPlayersAndGroups"), hr );
  930.  
  931.     for( DWORD i=0; i<dwCount; i++ )
  932.     {
  933.         DWORD dwGroupNumber;
  934.  
  935.         // Get group info 
  936.         DWORD dwSize = 0;
  937.         DPN_GROUP_INFO* pdpGroupInfo = NULL;
  938.         hr = g_pDP->GetGroupInfo( aGroupsDPNID[i], pdpGroupInfo, &dwSize, 0 );
  939.         if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  940.             return DXTRACE_ERR( TEXT("GetGroupInfo"), hr );
  941.         pdpGroupInfo = (DPN_GROUP_INFO*) new BYTE[ dwSize ];
  942.         ZeroMemory( pdpGroupInfo, dwSize );
  943.         pdpGroupInfo->dwSize = sizeof(DPN_GROUP_INFO); 
  944.         hr = g_pDP->GetGroupInfo( aGroupsDPNID[i], pdpGroupInfo, &dwSize, 0 );
  945.         if( FAILED(hr) )
  946.             return DXTRACE_ERR( TEXT("GetGroupInfo"), hr );
  947.  
  948.         if( pdpGroupInfo->pvData )
  949.             dwGroupNumber = *( (DWORD*) pdpGroupInfo->pvData );
  950.         else
  951.             dwGroupNumber = 0;
  952.  
  953.         SAFE_DELETE_ARRAY( pdpGroupInfo );
  954.  
  955.         if( dwGroupNumber == 0 )
  956.             continue;
  957.  
  958.         if( dwGroupNumber == g_pPlayerLocal->ps.dwGroup )
  959.         {
  960.             g_LocalGroupDPNID = aGroupsDPNID[i];
  961.  
  962.             // Add player to this group
  963.             DPNHANDLE hAsync;
  964.             hr = g_pDP->AddPlayerToGroup( aGroupsDPNID[i], g_LocalPlayerDPNID, 
  965.                                                       NULL, &hAsync, 0 );
  966.             if( FAILED( hr ) ) 
  967.                 return DXTRACE_ERR( TEXT("AddPlayerToGroup"), hr );
  968.         }
  969.  
  970.         if( dwGroupNumber == g_pPlayerLocal->ps.dwTarget )
  971.         {
  972.             // Talk to just this group
  973.             hr = pVoiceClient->SetTransmitTargets( &aGroupsDPNID[i], 1, 0 );
  974.             if( FAILED( hr ) ) 
  975.                 return DXTRACE_ERR( TEXT("SetTransmitTargets"), hr );
  976.         }
  977.     }
  978.  
  979.     SAFE_DELETE_ARRAY( aGroupsDPNID );
  980.  
  981.     return S_OK;
  982. }
  983.  
  984.  
  985.  
  986.  
  987. //-----------------------------------------------------------------------------
  988. // Name: DirectPlayMessageHandler
  989. // Desc: Handler for DirectPlay messages.  This function is called by
  990. //       the DirectPlay message handler pool of threads, so be care of thread
  991. //       synchronization problems with shared memory
  992. //-----------------------------------------------------------------------------
  993. HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, 
  994.                                          DWORD dwMessageId, 
  995.                                          PVOID pMsgBuffer )
  996. {
  997.     // Try not to stay in this message handler for too long, otherwise
  998.     // there will be a backlog of data.  The best solution is to 
  999.     // queue data as it comes in, and then handle it on other threads.
  1000.     
  1001.     // This function is called by the DirectPlay message handler pool of 
  1002.     // threads, so be care of thread synchronization problems with shared memory
  1003.  
  1004.     switch( dwMessageId )
  1005.     {
  1006.         case DPN_MSGID_CREATE_PLAYER:
  1007.         {
  1008.             HRESULT hr;
  1009.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  1010.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER) pMsgBuffer;
  1011.  
  1012.             // Get the peer info and extract its name
  1013.             DWORD dwSize = 0;
  1014.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  1015.             hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );
  1016.             if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  1017.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  1018.             pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  1019.             ZeroMemory( pdpPlayerInfo, dwSize );
  1020.             pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  1021.             hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );
  1022.             if( FAILED(hr) )
  1023.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  1024.  
  1025.             // Create a new and fill in a APP_PLAYER_INFO
  1026.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  1027.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) );
  1028.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  1029.             pPlayerInfo->lRefCount   = 1;
  1030.  
  1031.             // This stores a extra TCHAR copy of the player name for 
  1032.             // easier access.  This will be redundent copy since DPlay 
  1033.             // also keeps a copy of the player name in GetPeerInfo()
  1034.             DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  1035.                                                pdpPlayerInfo->pwszName, MAX_PLAYER_NAME );
  1036.  
  1037.             // See if this is the local player
  1038.             if( (pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL) != 0 )
  1039.             {
  1040.                 g_pPlayerLocal = pPlayerInfo;
  1041.                 g_pPlayerLocal->ps.dwGroup  = 0;
  1042.                 g_pPlayerLocal->ps.dwTarget = 0;
  1043.                 g_LocalPlayerDPNID = pCreatePlayerMsg->dpnidPlayer;
  1044.             }
  1045.  
  1046.             SAFE_DELETE_ARRAY( pdpPlayerInfo );
  1047.  
  1048.             // Tell DirectPlay to store this pPlayerInfo 
  1049.             // pointer in the pvPlayerContext.
  1050.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  1051.  
  1052.             if( FAILED( hr = SendLocalStateToAll( g_hDlg ) ) )
  1053.                 return DXTRACE_ERR( TEXT("SendLocalStateToAll"), hr );
  1054.  
  1055.             // Post a message to the dialog thread to update the 
  1056.             // UI.  This keeps the DirectPlay message handler 
  1057.             // from blocking
  1058.             if( g_hDlg != NULL )
  1059.                 PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1060.             break;
  1061.         }
  1062.  
  1063.         case DPN_MSGID_DESTROY_PLAYER:
  1064.         {
  1065.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  1066.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  1067.  
  1068.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  1069.             
  1070.             PLAYER_LOCK();                  // enter player context CS
  1071.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1072.             PLAYER_UNLOCK();                // leave player context CS
  1073.  
  1074.             // Post a message to the dialog thread to update the 
  1075.             // UI.  This keeps the DirectPlay message handler 
  1076.             // from blocking
  1077.             if( g_hDlg != NULL )
  1078.                 PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1079.  
  1080.             break;
  1081.         }
  1082.  
  1083.         case DPN_MSGID_RECEIVE:
  1084.         {
  1085.             PDPNMSG_RECEIVE pReceiveMsg;
  1086.             pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
  1087.  
  1088.             GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
  1089.             if( pMsg->dwType == GAME_MSGID_PLAYERSTATECHANGE )
  1090.             {
  1091.                 GAMEMSG_PLAYERSTATECHANGE* pPlayerStateChangedMsg;
  1092.                 pPlayerStateChangedMsg = (GAMEMSG_PLAYERSTATECHANGE*) pMsg;
  1093.  
  1094.                 PLAYER_LOCK(); // enter player context CS
  1095.  
  1096.                 APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
  1097.  
  1098.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  1099.                 PLAYER_UNLOCK(); // leave player context CS
  1100.  
  1101.                 if( pPlayerInfo )
  1102.                     pPlayerInfo->ps = pPlayerStateChangedMsg->ps;
  1103.  
  1104.                 PLAYER_LOCK();
  1105.                 PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1106.                 PLAYER_UNLOCK();
  1107.  
  1108.                 // Post a message to the dialog thread to update the 
  1109.                 // UI.  This keeps the DirectPlay message handler 
  1110.                 // from blocking
  1111.                 if( g_hDlg != NULL )
  1112.                     PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1113.             }
  1114.             break;
  1115.         }
  1116.  
  1117.         case DPN_MSGID_TERMINATE_SESSION:
  1118.         {
  1119.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  1120.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  1121.  
  1122.             g_hrDialog = DPNERR_CONNECTIONLOST;
  1123.             EndDialog( g_hDlg, 0 );
  1124.             break;
  1125.         }
  1126.     }
  1127.  
  1128.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  1129.     // so it can be informed of messages such as DPN_MSGID_ENUM_HOSTS_RESPONSE.
  1130.     if( g_pNetConnectWizard )
  1131.         return g_pNetConnectWizard->MessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  1132.     
  1133.     return S_OK;
  1134. }
  1135.  
  1136.  
  1137.  
  1138.  
  1139. //-----------------------------------------------------------------------------
  1140. // Name: DirectPlayLobbyMessageHandler
  1141. // Desc: Handler for DirectPlay lobby messages.  This function is called by
  1142. //       the DirectPlay lobby message handler pool of threads, so be careful of 
  1143. //       thread synchronization problems with shared memory
  1144. //-----------------------------------------------------------------------------
  1145. HRESULT WINAPI DirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  1146.                                               DWORD dwMessageId, 
  1147.                                               PVOID pMsgBuffer )
  1148. {
  1149.     switch( dwMessageId )
  1150.     {
  1151.         case DPL_MSGID_CONNECT:
  1152.         {
  1153.             PDPL_MESSAGE_CONNECT pConnectMsg;
  1154.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  1155.  
  1156.             // The CNetConnectWizard will handle this message for us,
  1157.             // so there is nothing we need to do here for this simple
  1158.             // sample.
  1159.             break;
  1160.         }
  1161.  
  1162.         case DPL_MSGID_DISCONNECT:
  1163.         {
  1164.             PDPL_MESSAGE_DISCONNECT pDisconnectMsg;
  1165.             pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)pMsgBuffer;
  1166.  
  1167.             // We should free any data associated with the lobby 
  1168.             // client here, but there is none.
  1169.             break;
  1170.         }
  1171.  
  1172.         case DPL_MSGID_RECEIVE:
  1173.         {
  1174.             PDPL_MESSAGE_RECEIVE pReceiveMsg;
  1175.             pReceiveMsg = (PDPL_MESSAGE_RECEIVE)pMsgBuffer;
  1176.  
  1177.             // The lobby client sent us data.  This sample doesn't
  1178.             // expected data from the client, but it is useful 
  1179.             // for more complex apps.
  1180.             break;
  1181.         }
  1182.  
  1183.         case DPL_MSGID_CONNECTION_SETTINGS:
  1184.         {
  1185.             PDPL_MESSAGE_CONNECTION_SETTINGS pConnectionStatusMsg;
  1186.             pConnectionStatusMsg = (PDPL_MESSAGE_CONNECTION_SETTINGS)pMsgBuffer;
  1187.  
  1188.             // The lobby client has changed the connection settings.  
  1189.             // This simple sample doesn't handle this, but more complex apps may
  1190.             // want to.
  1191.             break;
  1192.         }
  1193.     }
  1194.  
  1195.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  1196.     // so the wizard can be informed of lobby messages such as DPL_MSGID_CONNECT
  1197.     if( g_pNetConnectWizard )
  1198.         return g_pNetConnectWizard->LobbyMessageHandler( pvUserContext, dwMessageId, 
  1199.                                                          pMsgBuffer );
  1200.     
  1201.     return S_OK;
  1202. }
  1203.  
  1204.  
  1205.  
  1206.  
  1207. //-----------------------------------------------------------------------------
  1208. // Name: DirectPlayVoiceServerMessageHandler()
  1209. // Desc: The callback for DirectPlayVoice server messages.  
  1210. //-----------------------------------------------------------------------------
  1211. HRESULT CALLBACK DirectPlayVoiceServerMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  1212.                                                       LPVOID lpMessage )
  1213. {
  1214.     // This simple sample doesn't respond to any server messages
  1215.     return S_OK;
  1216. }
  1217.  
  1218.  
  1219.  
  1220.  
  1221. //-----------------------------------------------------------------------------
  1222. // Name: DirectPlayVoiceClientMessageHandler()
  1223. // Desc: The callback for DirectPlayVoice client messages.  
  1224. //       This handles client messages and updates the UI the whenever a client 
  1225. //       starts or stops talking.  
  1226. //-----------------------------------------------------------------------------
  1227. HRESULT CALLBACK DirectPlayVoiceClientMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  1228.                                                       LPVOID lpMessage )
  1229. {
  1230.     // Try not to stay in this message handler for too long, otherwise
  1231.     // there will be a backlog of data.  The best solution is to 
  1232.     // queue data as it comes in, and then handle it on other threads.
  1233.     
  1234.     // This function is called by the DirectPlay message handler pool of 
  1235.     // threads, so be care of thread synchronization problems with shared memory
  1236.     HRESULT hr;
  1237.     HWND hDlg = (HWND) lpvUserContext;
  1238.  
  1239.     switch( dwMessageType )
  1240.     {
  1241.         case DVMSGID_CREATEVOICEPLAYER:
  1242.             {
  1243.                 DVMSG_CREATEVOICEPLAYER* pCreateVoicePlayerMsg = (DVMSG_CREATEVOICEPLAYER*) lpMessage;
  1244.                 APP_PLAYER_INFO* pPlayerInfo = NULL;
  1245.  
  1246.                 PLAYER_LOCK(); // enter player context CS
  1247.  
  1248.                 // Get the player context accosicated with this DPNID
  1249.                 hr = g_pDP->GetPlayerContext( pCreateVoicePlayerMsg->dvidPlayer, 
  1250.                                               (LPVOID* const) &pPlayerInfo,
  1251.                                               0);
  1252.  
  1253.                 if( FAILED(hr) || pPlayerInfo == NULL )
  1254.                 {
  1255.                     // The player who sent this may have gone away before this 
  1256.                     // message was handled, so just ignore it
  1257.                     PLAYER_UNLOCK();
  1258.                     break;
  1259.                 }
  1260.  
  1261.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, for voice context value
  1262.                 PLAYER_UNLOCK(); // leave player context CS
  1263.  
  1264.                 pPlayerInfo->bHalfDuplex = ((pCreateVoicePlayerMsg->dwFlags & DVPLAYERCAPS_HALFDUPLEX) != 0);
  1265.  
  1266.                 // Set voice context value
  1267.                 pCreateVoicePlayerMsg->pvPlayerContext = pPlayerInfo;                
  1268.  
  1269.                 // Post a message to the dialog thread to update the 
  1270.                 // UI.  This keeps the DirectPlay message handler 
  1271.                 // from blocking
  1272.                 if( g_hDlg != NULL )
  1273.                     PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1274.             }
  1275.             break;
  1276.  
  1277.         case DVMSGID_DELETEVOICEPLAYER:
  1278.         {
  1279.             DVMSG_DELETEVOICEPLAYER* pMsg = (DVMSG_DELETEVOICEPLAYER*) lpMessage;
  1280.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  1281.  
  1282.             // Don't update the dlg if this message is for the local 
  1283.             // client since the dlg will be gone.
  1284.             if( pMsg->dvidPlayer != g_LocalPlayerDPNID )
  1285.             {
  1286.                 // Post a message to the dialog thread to update the 
  1287.                 // UI.  This keeps the DirectPlay message handler 
  1288.                 // from blocking
  1289.                 if( hDlg != NULL )
  1290.                     PostMessage( hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  1291.             }
  1292.  
  1293.             // Release our extra reference on the player info that we have for the voice
  1294.             // context value.  
  1295.             //
  1296.             PLAYER_LOCK();
  1297.             PLAYER_RELEASE( pPlayerInfo );  
  1298.             PLAYER_UNLOCK();
  1299.             break;
  1300.         } 
  1301.  
  1302.         case DVMSGID_SESSIONLOST:
  1303.             g_hrDialog = DPNERR_CONNECTIONLOST;
  1304.             EndDialog( g_hDlg, 0 );
  1305.             break;
  1306.  
  1307.         case DVMSGID_HOSTMIGRATED:
  1308.         {
  1309.             DVMSG_HOSTMIGRATED* pMsg = (DVMSG_HOSTMIGRATED*) lpMessage;
  1310.  
  1311.             if( pMsg->pdvServerInterface != NULL )
  1312.             {           
  1313.                 // If we keep the pMsg->pdvServerInterface pointer around, then
  1314.                 // we must AddRef() it.  The CNetVoice::HostMigrate() automatically
  1315.                 // does this for us.
  1316.                 g_pNetVoice->HostMigrate( pMsg->pdvServerInterface );
  1317.  
  1318.                 g_bHostPlayer = TRUE;
  1319.                 SetWindowText( hDlg, TEXT("VoiceGroup (Session Host)") );
  1320.             }
  1321.             break;
  1322.         }
  1323.  
  1324.         case DVMSGID_GAINFOCUS:
  1325.         case DVMSGID_LOSTFOCUS:
  1326.         {
  1327.             TCHAR strWindowName[MAX_PATH];
  1328.             wsprintf( strWindowName, TEXT("%s%s%s"), g_strAppName,
  1329.                 (g_bHostPlayer)                      ? TEXT(" (Session Host)") : TEXT(""),
  1330.                 (dwMessageType == DVMSGID_LOSTFOCUS) ? TEXT(" (Focus Lost)") : TEXT("") );
  1331.  
  1332.             SetWindowText( hDlg, strWindowName );
  1333.             break;
  1334.         }
  1335.  
  1336.         case DVMSGID_RECORDSTART:             
  1337.         { 
  1338.             DVMSG_RECORDSTART* pMsg = (DVMSG_RECORDSTART*) lpMessage;
  1339.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext, TRUE );
  1340.             break;
  1341.         }
  1342.         case DVMSGID_RECORDSTOP:             
  1343.         {
  1344.             DVMSG_RECORDSTOP* pMsg = (DVMSG_RECORDSTOP*) lpMessage;
  1345.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext, FALSE );
  1346.             break;
  1347.         }
  1348.         case DVMSGID_PLAYERVOICESTART:
  1349.         {
  1350.             DVMSG_PLAYERVOICESTART* pMsg = (DVMSG_PLAYERVOICESTART*) lpMessage;
  1351.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvPlayerContext, TRUE );
  1352.             break;
  1353.         }
  1354.  
  1355.         case DVMSGID_PLAYERVOICESTOP:
  1356.         {
  1357.             DVMSG_PLAYERVOICESTOP* pMsg = (DVMSG_PLAYERVOICESTOP*) lpMessage;
  1358.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvPlayerContext, FALSE );            
  1359.             break;
  1360.         }
  1361.         
  1362.     }
  1363.  
  1364.     return S_OK;
  1365. }
  1366.  
  1367.  
  1368.  
  1369.  
  1370. //-----------------------------------------------------------------------------
  1371. // Name: SetPlayerTalking()
  1372. // Desc: Set player talking flag
  1373. //-----------------------------------------------------------------------------
  1374. void SetPlayerTalking( APP_PLAYER_INFO* pPlayerInfo, BOOL bTalking )
  1375. {
  1376.     if( pPlayerInfo )
  1377.         pPlayerInfo->bTalking = bTalking;     
  1378. }
  1379.  
  1380.  
  1381.  
  1382.  
  1383. //-----------------------------------------------------------------------------
  1384. // Name: VoiceConfigDlgProc()
  1385. // Desc: Prompt the user for DirectPlayVoice setup options
  1386. //-----------------------------------------------------------------------------
  1387. INT_PTR CALLBACK VoiceConfigDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  1388. {
  1389.     DWORD dwSliderPos;
  1390.  
  1391.     switch( msg ) 
  1392.     {
  1393.         case WM_INITDIALOG:
  1394.             // Set the range on the sliders
  1395.             SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER,       TBM_SETRANGE, FALSE, MAKELONG( 0, 100 ) );
  1396.             SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER,         TBM_SETRANGE, FALSE, MAKELONG( 0, 100 ) );
  1397.             SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER,        TBM_SETRANGE, FALSE, MAKELONG( DVBUFFERQUALITY_MIN, DVBUFFERQUALITY_MAX ) );
  1398.             SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER,    TBM_SETRANGE, FALSE, MAKELONG( DVTHRESHOLD_MIN,  DVTHRESHOLD_MAX ) );
  1399.             SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_SETRANGE, FALSE, MAKELONG( DVBUFFERAGGRESSIVENESS_MIN, DVBUFFERAGGRESSIVENESS_MAX ) );
  1400.  
  1401.             // Setup the dialog based on the globals 
  1402.  
  1403.             // Set the playback controls
  1404.             if( g_dvClientConfig.lPlaybackVolume == DVPLAYBACKVOLUME_DEFAULT )
  1405.             {
  1406.                 CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_DEFAULT );
  1407.             }
  1408.             else
  1409.             {
  1410.                 dwSliderPos = (DWORD) ( ( g_dvClientConfig.lPlaybackVolume - DSBVOLUME_MIN ) * 
  1411.                                           100.0f / (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1412.                 CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_SET );
  1413.                 SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER, TBM_SETPOS, TRUE, dwSliderPos );
  1414.             }
  1415.  
  1416.             // Set the record controls
  1417.             if( g_dvClientConfig.dwFlags & DVCLIENTCONFIG_AUTORECORDVOLUME )
  1418.             {
  1419.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_AUTO );
  1420.             }
  1421.             else if( g_dvClientConfig.lRecordVolume == DVPLAYBACKVOLUME_DEFAULT )
  1422.             {
  1423.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_DEFAULT );
  1424.             }
  1425.             else
  1426.             {
  1427.                 dwSliderPos = (DWORD) ( ( g_dvClientConfig.lRecordVolume - DSBVOLUME_MIN ) * 
  1428.                                           100.0f / (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1429.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_SET );
  1430.                 SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER, TBM_SETPOS, TRUE, dwSliderPos );
  1431.             }
  1432.  
  1433.             // Set the threshold controls
  1434.             if( g_dvClientConfig.dwFlags & DVCLIENTCONFIG_AUTOVOICEACTIVATED )
  1435.             {
  1436.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_AUTO );
  1437.             }
  1438.             else if( g_dvClientConfig.dwThreshold == DVTHRESHOLD_DEFAULT )
  1439.             {
  1440.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_DEFAULT );
  1441.             }
  1442.             else
  1443.             {
  1444.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_SET );
  1445.                 SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwThreshold );
  1446.             }
  1447.  
  1448.             // Set the quality controls
  1449.             if( g_dvClientConfig.dwBufferQuality == DVBUFFERQUALITY_DEFAULT )
  1450.             {
  1451.                 CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_DEFAULT );
  1452.             }
  1453.             else
  1454.             {
  1455.                 CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_SET );
  1456.                 SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwBufferQuality );
  1457.             }
  1458.  
  1459.             // Set the aggressiveness controls
  1460.             if( g_dvClientConfig.dwBufferAggressiveness == DVBUFFERAGGRESSIVENESS_DEFAULT )
  1461.             {
  1462.                 CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_DEFAULT );
  1463.             }
  1464.             else
  1465.             {
  1466.                 CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_SET );
  1467.                 SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwBufferAggressiveness );
  1468.             }
  1469.  
  1470.             if( !g_bHostPlayer || g_bVoiceSessionInProgress )
  1471.             {
  1472.                 // We are are not the host player then disable all the server only options 
  1473.                 EnableWindow( GetDlgItem( hDlg, IDC_COMPRESSION_COMBO ), FALSE );
  1474.                 EnableWindow( GetDlgItem( hDlg, IDC_SESSIONCOMPRESION_GROUP ), FALSE );
  1475.             }
  1476.             else
  1477.             {
  1478.                 VoiceConfigEnumCompressionCodecs( hDlg );   
  1479.                 EnableWindow( GetDlgItem( hDlg, IDCANCEL ), FALSE );
  1480.             }
  1481.  
  1482.             return TRUE;
  1483.  
  1484.         case WM_NOTIFY:
  1485.             #ifndef NM_RELEASEDCAPTURE
  1486.                 #define NM_RELEASEDCAPTURE (NM_FIRST-16)
  1487.             #endif
  1488.             if( ((LPNMHDR) lParam)->code == NM_RELEASEDCAPTURE )
  1489.             {
  1490.                 // If this is a release capture from a slider, then automatically check 
  1491.                 // its 'Set' radio button.
  1492.                 switch( ((LPNMHDR) lParam)->idFrom )
  1493.                 {
  1494.                 case IDC_PLAYBACK_SLIDER:
  1495.                     CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_SET );
  1496.                     break;
  1497.     
  1498.                 case IDC_RECORD_SLIDER:
  1499.                     CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_SET );
  1500.                     break;
  1501.     
  1502.                 case IDC_THRESHOLD_SLIDER:
  1503.                     CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_SET );
  1504.                     break;
  1505.     
  1506.                 case IDC_QUALITY_SLIDER:
  1507.                     CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_SET );
  1508.                     break;
  1509.     
  1510.                 case IDC_AGGRESSIVENESS_SLIDER:
  1511.                     CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_SET );
  1512.                     break;
  1513.                 }
  1514.             }
  1515.             return TRUE;            
  1516.  
  1517.         case WM_COMMAND:
  1518.             switch( LOWORD(wParam) )
  1519.             {
  1520.                 case IDOK:
  1521.                     VoiceConfigDlgOnOK( hDlg );
  1522.                     return TRUE;
  1523.  
  1524.                 case IDCANCEL:
  1525.                     EndDialog( hDlg, IDCANCEL );
  1526.                     return TRUE;
  1527.             }
  1528.             break;
  1529.  
  1530.         case WM_DESTROY:
  1531.         {
  1532.             GUID* pGuid;
  1533.             int nCount = (int)SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETCOUNT, 0, 0 );
  1534.             for( int i=0; i<nCount; i++ )
  1535.             {
  1536.                 pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETITEMDATA, i, 0 );
  1537.                 SAFE_DELETE( pGuid );
  1538.             }
  1539.             break;
  1540.         }
  1541.    }
  1542.  
  1543.     return FALSE; // Didn't handle message
  1544. }
  1545.  
  1546.  
  1547.  
  1548.  
  1549. //-----------------------------------------------------------------------------
  1550. // Name: VoiceConfigEnumCompressionCodecs()
  1551. // Desc: Asks DirectPlayVoice what voice compression codecs are availible
  1552. //       and fills the combo box thier names and GUIDs.
  1553. //-----------------------------------------------------------------------------
  1554. HRESULT VoiceConfigEnumCompressionCodecs( HWND hDlg )
  1555. {
  1556.     LPDIRECTPLAYVOICECLIENT pVoiceClient        = NULL;
  1557.     LPDVCOMPRESSIONINFO     pdvCompressionInfo  = NULL;
  1558.     LPGUID  pGuid         = NULL;
  1559.     LPBYTE  pBuffer       = NULL;
  1560.     DWORD   dwSize        = 0;
  1561.     DWORD   dwNumElements = 0;
  1562.     HWND    hPulldown     = GetDlgItem( hDlg, IDC_COMPRESSION_COMBO );
  1563.     HRESULT hr;
  1564.     LONG    lIndex;
  1565.     LONG    lFirst;
  1566.  
  1567.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  1568.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlayVoiceClient, NULL, 
  1569.                                        CLSCTX_INPROC_SERVER, IID_IDirectPlayVoiceClient, 
  1570.                                        (VOID**) &pVoiceClient ) ) )
  1571.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  1572.  
  1573.     hr = pVoiceClient->GetCompressionTypes( pBuffer, &dwSize, &dwNumElements, 0 );
  1574.     if( hr != DVERR_BUFFERTOOSMALL && FAILED(hr) )
  1575.         return DXTRACE_ERR( TEXT("GetCompressionTypes"), hr );
  1576.  
  1577.     pBuffer = new BYTE[dwSize];
  1578.     if( FAILED( hr = pVoiceClient->GetCompressionTypes( pBuffer, &dwSize, 
  1579.                                                         &dwNumElements, 0 ) ) )
  1580.         return DXTRACE_ERR( TEXT("GetCompressionTypes"), hr );
  1581.  
  1582.     SAFE_RELEASE( pVoiceClient );
  1583.     CoUninitialize();
  1584.  
  1585.     pdvCompressionInfo = (LPDVCOMPRESSIONINFO) pBuffer;
  1586.     for( DWORD dwIndex = 0; dwIndex < dwNumElements; dwIndex++ )
  1587.     {
  1588.         TCHAR strName[MAX_PATH];
  1589.  
  1590.         DXUtil_ConvertWideStringToGeneric( strName, pdvCompressionInfo[dwIndex].lpszName );
  1591.         lIndex = (LONG)SendMessage( hPulldown, CB_ADDSTRING, 0, (LPARAM) strName );
  1592.  
  1593.         pGuid = new GUID;
  1594.         (*pGuid) = pdvCompressionInfo[dwIndex].guidType;
  1595.         SendMessage( hPulldown, CB_SETITEMDATA, lIndex, (LPARAM) pGuid );
  1596.  
  1597.         if( pdvCompressionInfo[dwIndex].guidType == DPVCTGUID_SC03 )
  1598.             lFirst = lIndex;
  1599.     }
  1600.  
  1601.     SAFE_DELETE_ARRAY( pBuffer );
  1602.     SendMessage( hPulldown, CB_SETCURSEL, lFirst, 0 );
  1603.  
  1604.     return S_OK;
  1605. }
  1606.  
  1607.  
  1608.  
  1609.  
  1610. //-----------------------------------------------------------------------------
  1611. // Name: VoiceConfigDlgOnOK()
  1612. // Desc: Figure out all the DirectPlayVoice setup params from the dialog box,
  1613. //       and store them in global vars.
  1614. //-----------------------------------------------------------------------------
  1615. VOID VoiceConfigDlgOnOK( HWND hDlg )
  1616. {
  1617.     DWORD dwSliderPos;
  1618.  
  1619.     g_dvClientConfig.dwFlags = 0;
  1620.  
  1621.     // Figure out the playback params
  1622.     if( IsDlgButtonChecked( hDlg, IDC_PLAYBACK_DEFAULT ) )
  1623.     {
  1624.         g_dvClientConfig.lPlaybackVolume = DVPLAYBACKVOLUME_DEFAULT;
  1625.     }
  1626.     else 
  1627.     {
  1628.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER, TBM_GETPOS, 0, 0 );
  1629.         g_dvClientConfig.lPlaybackVolume = DSBVOLUME_MIN + (LONG) ( dwSliderPos / 100.0f * 
  1630.                                                                     (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1631.     }
  1632.  
  1633.     // Figure out the record params
  1634.     if( IsDlgButtonChecked( hDlg, IDC_RECORD_AUTO ) )
  1635.     {
  1636.         g_dvClientConfig.lRecordVolume = 0;
  1637.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_AUTORECORDVOLUME;
  1638.     }
  1639.     else if( IsDlgButtonChecked( hDlg, IDC_RECORD_DEFAULT ) )
  1640.     {
  1641.         g_dvClientConfig.lRecordVolume = DVPLAYBACKVOLUME_DEFAULT;
  1642.     }
  1643.     else 
  1644.     {
  1645.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER, TBM_GETPOS, 0, 0 );
  1646.         g_dvClientConfig.lRecordVolume = DSBVOLUME_MIN + (LONG) ( dwSliderPos / 100.0f * 
  1647.                                                                   (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1648.     }
  1649.  
  1650.     // Figure out the threshold params
  1651.     if( IsDlgButtonChecked( hDlg, IDC_THRESHOLD_AUTO ) )
  1652.     {
  1653.         g_dvClientConfig.dwThreshold = DVTHRESHOLD_UNUSED;
  1654.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_AUTOVOICEACTIVATED;
  1655.     }
  1656.     else if( IsDlgButtonChecked( hDlg, IDC_THRESHOLD_DEFAULT ) )
  1657.     {
  1658.         g_dvClientConfig.dwThreshold = DVTHRESHOLD_DEFAULT;
  1659.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_MANUALVOICEACTIVATED;
  1660.     }
  1661.     else 
  1662.     {
  1663.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER, TBM_GETPOS, 0, 0 );
  1664.         g_dvClientConfig.dwThreshold = dwSliderPos;
  1665.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_MANUALVOICEACTIVATED;
  1666.     }
  1667.  
  1668.     // Figure out the quality params
  1669.     if( IsDlgButtonChecked( hDlg, IDC_QUALITY_DEFAULT ) )
  1670.     {
  1671.         g_dvClientConfig.dwBufferQuality = DVBUFFERQUALITY_DEFAULT;
  1672.     }
  1673.     else 
  1674.     {
  1675.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER, TBM_GETPOS, 0, 0 );
  1676.         g_dvClientConfig.dwBufferQuality = dwSliderPos;
  1677.     }
  1678.  
  1679.     // Figure out the aggressiveness params
  1680.     if( IsDlgButtonChecked( hDlg, IDC_AGGRESSIVENESS_DEFAULT ) )
  1681.     {
  1682.         g_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  1683.     }
  1684.     else 
  1685.     {
  1686.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_GETPOS, 0, 0 );
  1687.         g_dvClientConfig.dwBufferAggressiveness = dwSliderPos;
  1688.     }
  1689.  
  1690.     if( g_bHostPlayer )
  1691.     {
  1692.         // Figure out the compression codec
  1693.         LONG lCurSelection;
  1694.         LPGUID pGuidCT;
  1695.  
  1696.         lCurSelection = (LONG)SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETCURSEL, 0, 0 );
  1697.         if( lCurSelection != CB_ERR )
  1698.         {
  1699.             pGuidCT = (LPGUID) SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, 
  1700.                                                    CB_GETITEMDATA, lCurSelection, 0 );
  1701.             if( pGuidCT != NULL )
  1702.                 g_guidDVSessionCT = (*pGuidCT);
  1703.         }
  1704.     }
  1705.  
  1706.     EndDialog( hDlg, IDOK );
  1707. }
  1708.  
  1709.  
  1710.  
  1711.  
  1712.