//-----------------------------------------------------------------------------
// 
// Sample Name: VoiceConnect Sample
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
//-----------------------------------------------------------------------------


Description
===========
  VoiceConnect shows how to network other players using DirectPlay to
  start a DirectPlay Voice chat session.  After joining or creating a 
  session, the players may use computer microphone to talk to one other.  
  Other players may join the game in progress at any time.  

Path
====
  Source:     DXSDV\Samples\C++\DirectPlay\VoiceConnect 
  Executable: DXSDV\Samples\C++\DirectPlay\Bin

User's Guide
============
  Refer to User's Guide section of the SimplePeer sample for information
  on how to connect.  After connecting, the host will be presented with a 
  dialog to select the voice codec to use.  Typical voice applications will
  what automatically select one, or present this to the user in some other 
  fashion.  Once the chat session has begin, any client may alter the playback
  or capture settings by clicking on "Setup".

Programming Notes
=================
  The VoiceConnect sample is very similar in form to the SimplePeer sample.  For 
  detailed programming notes on the basics this sample, refer to Programming 
  Notes section of the SimplePeer sample.

  The VoiceConnect differs by letting clients use DirectPlay Voice to talk
  to each other using a computer microphone.  Here's how this is done:
  
  * Initialize DirectPlayVoice.  See NetVoice.cpp 
       Before using voice you need a to establish a DirectPlay Voice session.
       So after the DirectPlay session as been created, we call 
       CNetVoice::Init().  In this simple sample, we this when
       the main dialog is initializes.  This does the following:
       
         - Tests the audio setup with DirectPlay Voice. 
           See VoiceSessionTestAudioSetup() in NetVoice.cpp. 
              1. Creates a IDirectPlayVoiceTest with CoCreateInstance()
              2. Calls IDirectPlayVoiceTest::CheckAudioSetup() with the 
                 DVFLAGS_QUERYONLY flag.  This will return DVERR_RUNSETUP 
                 if the setup wizard needs to be run.  If it happens then 
                 we call IDirectPlayVoiceTest::CheckAudioSetup() without
                 the DVFLAGS_QUERYONLY flag.  This will run the dialog
                 based DirectPlay Voice setup wizard.  If it returns success 
                 then we can continue on, otherwise handle the error in
                 some fashion.
              3. Release the IDirectPlayVoiceTest
              
         - If hosting, then we create the voice session:  
           See VoiceSessionCreate() in NetVoice.cpp
              1. Create a IDirectPlayVoiceServer with CoCreateInstance().
                 Keep this interface around since we'll need it later on.
              2. Call IDirectPlayVoiceServer::Initialize to register the 
                 voice server message handler.  We also pass in the 
                 DirectPlay interface here.
              3. Fill out a DVSESSIONDESC struct with the session type, and
                 the desired voice codec.
              4. Call IDirectPlayVoiceServer::StartSession() passing in
                 the DVSESSIONDESC struct.
          
          - If either hosting or joining, then connect to the session. 
            See VoiceSessionConnect() in NetVoice.cpp
            
              1. Create a IDirectPlayVoiceClient with CoCreateInstance()
                 Keep this interface around since we'll need it later on.
              2. Call IDirectPlayVoiceClient::Initialize to register the 
                 voice client message handler.  We also pass in the 
                 DirectPlay interface here.
              3. Fill out a DVSOUNDDEVICECONFIG struct with the guids
                 for the DirectSound playback and capture devices.
              3. Fill out a DVCLIENTCONFIG struct.  This struct is 
                 filled out when with setup dlg.  More complex apps
                 may want to do this a different way.  See VoiceConfigDlgProc() 
                 in VoiceConnect.cpp.
              4. Call IDirectPlayVoiceClient::Connect() with the 
                 DVSOUNDDEVICECONFIG struct and the DVCLIENTCONFIG struct.
              5. Call IDirectPlayVoiceClient::SetTransmitTargets()
                 to the desired default target.  This sample sets the
                 target to DVID_ALLPLAYERS.
              6. Call IDirectPlayVoiceClient::GetSoundDeviceConfig() and
                 check for DVSOUNDCONFIG_HALFDUPLEX to figure out if this 
                 client is in half-duplex mode.  In half-duplex mode, the 
                 client can not talk, but only listen. 

  * Handle voice client messages.  See DirectPlayVoiceClientMessageHandler                 
      - Upon DVMSGID_CREATEVOICEPLAYER:
            1. Since DPN_MSGID_CREATE_PLAYER set a player context, and that message
               is guaranteed to be processed first.  We call GetPlayerContext()
               to get the player's context value and cast the pointer into a 
               player struct.  We enter a global CS lock here and everytime
               we access a player struct.  This is needed to make the struct 
               thread safe, since the same player struct may be accessed by
               multiple threads at the same time.               
            2. Now that we have the player's struct we addref it.  This 
               extra count will be for voice layer.  Upon DVMSGID_DELETEVOICEPLAYER
               we will release it.  This ensures that any voice messages
               that come in will be working with a valid player struct.  
            3. We check the DVMSG_CREATEVOICEPLAYER for DVPLAYERCAPS_HALFDUPLEX
               to see if this player is in half-duplex mode.  If so, then
               we store that value in the player's struct.  Later
               we will update the UI according.  See DisplayPlayersInChat()
               for how this is done.
            4. Similar to DirectPlay, DirectPlay Voice stores 
               context values for each voice player.  So in this sample we 
               store the same value in both locations by setting 
               pCreateVoicePlayerMsg->pvPlayerContext.
       - Upon DVMSGID_DELETEVOICEPLAYER:
            1. We update the UI accordingly if the local player isn't going away.                              
            2. We release the player's struct since we addref'ed it 
               in DVMSGID_CREATEVOICEPLAYER
       - Upon DVMSGID_HOSTMIGRATED:
            1. If DVMSG_HOSTMIGRATED has a non-NULL pdvServerInterface, then
               we have become the new host.  The sample updates the UI to 
               show this.
       - Upon DVMSGID_GAINFOCUS and DVMSGID_LOSTFOCUS:
            This means that the app has gained or lost focus.  Apps that 
            have lost focus can not talk.  When focus is re-gained they can.
            In this sample, it updates the UI accordingly.
       - Upon DVMSGID_RECORDSTART
              DVMSGID_RECORDSTOP, 
              DVMSGID_PLAYERVOICESTART,
              DVMSGID_PLAYERVOICESTOP:
            These message lets us know when talking has stopped or started for 
            the local client, and for remove clients.  This sample handles
            these messages by updating the UI accordingly.
      
  * Clean up DirectPlay Voice.  See bottom of CNetVoice::Free in NetVoice.cpp
        1. Disconnect from the voice session.  See VoiceSessionDisconnect()
            - Calls IDirectPlayVoiceClient::Disconnect()
            - Releases the IDirectPlayVoiceClient
        2. Destroy the voice session if this is the host.  See VoiceSessionDestroy() 
            - Calls IDirectPlayVoiceServer::StopSession()
            - Releases the IDirectPlayVoiceServer
           


