Microsoft DirectX 9.0

Tutorial 8: Direct Play Voice

Microsoft?DirectPlay?Voice is a full-voice communications application programming interface (API) that uses DirectPlay for network session management and network transport. This tutorial extends the preceding tutorials to describe how to add voice communications to a peer-to-peer network application. Much of this information also applies to client/server applications. For further discussion of DirectPlay Voice, see DirectPlay Voice. The complete sample code for this tutorial is included with the Microsoft DirectX® software development kit (SDK) and can be found at (SDK root)\Samples\C++\DirectPlay\Tutorials\Tut08_Voice.

Refer to the preceding tutorials for a discussion of the initial steps in the process.

Note  The error handling code for the examples in this document has been deleted for clarity. See the tutorial sample for a complete version of the code.

User's Guide

When you run this tutorial sample, a window opens and you have the choice to either Host or Connect.

If you choose Host:

  1. A window will open and you should enter a session name. Select the Migrate Host box to allow host migration to take place in this session. Then click OK. If you have not used your sound hardware before, DirectPlay may run the Sound Hardware Test Wizard before you can start a session. Once you are hosting, the session status will change to 'Hosting Session "YourSessionName".'
  2. You can now choose to send a message, disconnect, or speak to other players. If you choose to send a message, enter a text string and click Send. To speak to other players, start talking into your microphone, voice recording starts automatically. If you choose to disconnect, click Disconnect and the session ends.
  3. Click Exit to end the sample

If you choose Connect:

  1. The Connect to Session window will open and you should enter an Internet Protocol (IP) address and click Search. If any sessions are found at that address, they will be listed in the Detected Sessions box. Select a session and click Connect. If the address does not exist, a message box opens with an error message.
  2. Once connected, your session status will change to 'Connected to Session "YourSessionName".' You can now choose to send a message, disconnect, or speak to other players. If you choose to send a message, enter a text string and click Send. To speak to other players, start talking into your microphone, voice recording starts automatically. If you choose to disconnect, click Disconnect.
  3. Click Exit to end the sample.

You can run this sample twice—once to host a session and once to connect. When connecting, enter your computer's IP address. Once you start a session and have at least two players connected (the host and a client), the voice recording starts automatically. Speak into a microphone and your voice will play out on the speakers.

Preparing for a DirectPlay Voice Session

Before you can start up a DirectPlay Voice session, you must have a valid DirectPlay object connected to or hosting a session. For full details on creating, connecting and hosting DirectPlay objects, see previous tutorials.

Creating a Voice Session Host

To enable voice communications, one peer in the session must become the Voice session host. To become the host, you must create a Voice server object and obtain a pointer to its IDirectPlayVoiceServer interface. You use this interface to perform host-specific tasks during the Voice session. You must then call IDirectPlayVoiceServer::Initialize to initialize the object. As with most DirectPlay objects, the primary purpose of initialization is to provide DirectPlay with a pointer to your Voice server callback message handler.

Note  The Voice server host can be a different peer than the session host.

The following excerpt from the tutorial sample illustrates how to create and initialize a Voice server object.

IDirectPlayVoiceServer*  g_pVoiceServer = NULL;
// Create the Voice server object.
   hr = CoCreateInstance(CLSID_DirectPlayVoiceServer, NULL, 
                         (LPVOID*) &g_pVoiceServer );		

// Initialize the object.
   hr = g_pVoiceServer->Initialize(g_pDP, 
                                   NULL, 0, 0 ) ;

Starting a Voice Session

Before any clients can connect to a Voice session, the Voice session host must start the session by calling IDirectPlayVoiceServer::StartSession. Once the session has been started, Voice clients can connect to the Voice session.

The DVSESSIONDESC structure that you pass to this method contains the information DirectPlay needs to start the session. In particular, you must specify which of several DirectPlay Voice topologies you want to use. This tutorial uses the peer-to-peer topology. For further information about this subject, see DirectPlay Voice Topologies.

The following excerpt from the tutorial sample illustrates how to start a peer-to-peer session using the default CODEC.

IDirectPlayVoiceServer* 	g_pVoiceServer = NULL;
ZeroMemory(&dvSessionDesc, sizeof(DVSESSIONDESC));
dvSessionDesc.dwSize = sizeof(DVSESSIONDESC);
dvSessionDesc.dwSessionType = DVSESSIONTYPE_PEER;
dvSessionDesc.dwBufferQuality = DVBUFFERQUALITY_DEFAULT;
dvSessionDesc.guidCT = DPVCTGUID_DEFAULT;
dvSessionDesc.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;

hr = g_pVoiceServer->StartSession(&dvSessionDesc, 0 ); 

Testing the Voice Setup

Before connecting a Voice client to a Voice session, you must test the audio configuration. To do so, you must to create an IDirectPlayVoiceTest object and call IDirectPlayVoiceTest::CheckAudioSetup. Call the method first with the DVFLAGS_QUERYONLY set to determine whether the test has already been run.

If the test has not been run, the method returns DVERR_RUNSETUP. You should then call the function again without the DVFLAGS_QUERYONLY flag, and DirectPlay will launch the Sound Hardware Test Wizard. If the method returns a success code, you can continue. Otherwise, you must first handle the error condition. After testing is complete, release the IDirectPlayVoiceTest object. When the audio configuration has been tested, your client can connect to the Voice session.

The following excerpt from the tutorial sample illustrates how to test voice setup.

IDirectPlayVoiceTest*   pVoiceTest = NULL;	
// Create the IDirectPlayVoiceTest Object.
   hr = CoCreateInstance(CLSID_DirectPlayVoiceTest, NULL, 
                                 (LPVOID*) &pVoiceTest );

guidPlayback = DSDEVID_DefaultVoicePlayback;
guidCapture = DSDEVID_DefaultVoiceCapture;
hr = pVoiceTest->CheckAudioSetup(&guidPlayback,
                                 NULL, DVFLAGS_QUERYONLY);
	// The test has not been run yet.
     hr = pVoiceTest->CheckAudioSetup(&guidPlayback,
                                      g_hDlg, DVFLAGS_ALLOWBACK );
else if( FAILED( hr))
	/* Handle Errors */
	// The test has been passed, proceed.

Creating a DirectPlay Voice Client Object

All clients that want to participate in the voice session must connect to the session, including the host. The first step in connecting to a voice session is to create and initialize a voice client object (CLSID_DirectPlayVoiceClient).

Once you have created the object, initialize it by calling IDirectPlayVoiceClient::Initialize. Pass this method a pointer to your voice callback message handler. This message handler receives voice-related messages from DirectPlay Voice during the voice session. You must also pass the method a pointer to an IDirectPlay8Peer interface. The DirectPlay object that exposes this interface must be either connected to or hosting a session before you call IDirectPlayVoiceClient::Initialize.

The following excerpt from the tutorial sample illustrates how to create and initialize a voice client object.

// Create the IDirectPlayVoiceClient object.
IDirectPlayVoiceClient* 	g_pVoiceClient = NULL;
hr = CoCreateInstance(CLSID_DirectPlayVoiceClient, NULL, 
                                  (LPVOID*) &g_pVoiceClient );
// Initialize the object.
hr = g_pVoiceClient->Initialize(g_pDP,
                                NULL, 0, 0 );

Connecting to a DirectPlay Voice Client Session

Once the IDirectPlayVoiceClient object is created and initialized, you can connect your client to the voice session by calling IDirectPlayVoiceClient::Connect. You need to pass two structures to this method: DVSOUNDDEVICECONFIG and DVCLIENTCONFIG. The structure contains information about the sound device configuration. The structure is used to configure run-time parameters. When you have initialized the structures, connect to the voice session by passing the structures to IDirectPlayVoiceClient::Connect.

The following excerpt from the tutorial sample illustrates how to initialize a structure. In this example, the default voice capture device and default voice playback device are used for audio capture and playback. Additionally, this example enables automatic microphone selection.

ZeroMemory(&dvSoundDeviceConfig, sizeof(DVSOUNDDEVICECONFIG));
dvSoundDeviceConfig.dwSize = sizeof(DVSOUNDDEVICECONFIG);
dvSoundDeviceConfig.dwFlags = DVSOUNDCONFIG_AUTOSELECT;
dvSoundDeviceConfig.guidPlaybackDevice = DSDEVID_DefaultVoicePlayback;
dvSoundDeviceConfig.lpdsPlaybackDevice = NULL;
dvSoundDeviceConfig.guidCaptureDevice = DSDEVID_DefaultVoiceCapture;
dvSoundDeviceConfig.lpdsCaptureDevice = NULL;
dvSoundDeviceConfig.hwndAppWindow = g_hDlg;
dvSoundDeviceConfig.lpdsMainBuffer = NULL;
dvSoundDeviceConfig.dwMainBufferFlags = 0;
dvSoundDeviceConfig.dwMainBufferPriority = 0;	

The following excerpt from the tutorial sample illustrates how to initialize a structure. In this example the system is configured for automatic voice activation and automatic gain control.

dvClientConfig.dwSize = sizeof(DVCLIENTCONFIG);
dvClientConfig.lRecordVolume = DVRECORDVOLUME_LAST;
dvClientConfig.lPlaybackVolume = DVPLAYBACKVOLUME_DEFAULT;
dvClientConfig.dwThreshold = DVTHRESHOLD_UNUSED;
dvClientConfig.dwBufferQuality = DVBUFFERQUALITY_DEFAULT;
dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
dvClientConfig.dwNotifyPeriod = 0;

Setting the Transmission Targets List

Before transmitting audio to other voice session clients you must first create a transmission targets list that specifies who should receive audio transmissions. You can send audio to any combination of individual players and/or groups of players. Sending to a group allows you to reach multiple players with a single send. Each player or group is identified by a DVID value, which corresponds to equivalent DirectPlay 8 DPNID value. The transmission targets list may contain up to 64 players and/or groups. If no targets are specified, no audio data is transmitted.

If voice activation is enabled, voice transmission begins when the voice activation module detects speech activity. If voice activation is disabled voice transmission begins when valid set of targets is specified.

The following excerpt from the tutorial sample illustrates how to set a client's transmission targets to all players in the voice session.

hr = g_pVoiceClient->SetTransmitTargets(&dvid, 1, 0 );

Terminating a Voice Session

Once the session is over, clients, including the host, must shut down their voice client objects. To do so, the client must disconnect from the DirectPlay Voice session by calling IDirectPlayVoiceClient::Disconnect. They can then release the voice client object.

A voice session host terminates a voice session by calling . The session host must then release the DirectPlay Voice server object.

The following excerpt from the tutorial sample illustrates how to terminate a voice session and shut down the voice server and client objects.

// Shut down the voice client object.
hr = g_pVoiceClient->Disconnect( 0 );

// Terminate the voice session.			
hr = g_pVoiceServer->StopSession( 0 );

© 2002 Microsoft Corporation. All rights reserved.