682 lines
17 KiB
C++
682 lines
17 KiB
C++
|
/*==========================================================================
|
||
|
*
|
||
|
* Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* File: loopback.cpp
|
||
|
* Content: Implements the loopback portion of the full duplex test
|
||
|
*
|
||
|
* History:
|
||
|
* Date By Reason
|
||
|
* ==== == ======
|
||
|
* 09/10/99 pnewson Created
|
||
|
* 10/25/99 rodtoll Removed lpszVoicePassword member from sessiondesc
|
||
|
* 10/27/99 pnewson Fix: Bug #113936 - Wizard should reset the AGC level before loopback test
|
||
|
* Note: this fix adds the DVCLIENTCONFIG_AUTOVOLUMERESET flag
|
||
|
* 10/28/99 pnewson Bug #114176 updated DVSOUNDDEVICECONFIG struct
|
||
|
* 11/04/99 pnewson Bug #115279 changed SendMessage to PostMessage to resolve some deadlocks
|
||
|
* 11/30/99 pnewson use default codec
|
||
|
* use devices passed to CheckAudioSetup, instead of default devices
|
||
|
* 12/01/99 rodtoll Added flag to cause wizard to auto-select the microphone
|
||
|
* 01/14/2000 rodtoll Updated with API changes
|
||
|
* 01/21/2000 pnewson Updated for UI revisions
|
||
|
* Updated to support use of loopback tests for full duplex testing
|
||
|
* 01/27/2000 rodtoll Updated with API changes
|
||
|
* 02/08/2000 rodtoll Bug #131496 - Selecting DVTHRESHOLD_DEFAULT results in voice
|
||
|
* never being detected
|
||
|
* 03/03/2000 rodtoll Updated to handle alternative gamevoice build.
|
||
|
* 04/19/2000 pnewson Error handling cleanup
|
||
|
* 04/21/2000 rodtoll Bug #32952 Does not run on Win95 GOLD w/o IE4 installed
|
||
|
* 06/21/2000 rodtoll Updated to use new parameters
|
||
|
* 06/28/2000 rodtoll Prefix Bug #38022
|
||
|
* 07/31/2000 rodtoll Bug #39590 - SB16 class soundcards are passing when they should fail
|
||
|
* Half duplex code was being ignored in mic test portion.
|
||
|
* 08/28/2000 masonb Voice Merge: Changed ccomutil.h to ccomutil.h
|
||
|
* 08/31/2000 rodtoll Bug #43804 - DVOICE: dwSensitivity structure member is confusing - should be dwThreshold
|
||
|
* 11/29/2000 rodtoll Bug #48348 - DPVOICE: Modify wizard to make use of DirectPlay8 as the transport.
|
||
|
* NOTE: Now requires a TCP/IP adapter to be present (or at least loopback)
|
||
|
* 02/04/2001 simonpow Bug #354859 PREfast spotted errors (PostMessage return codes incorrectly
|
||
|
* treated as HRESULTs)
|
||
|
* 04/12/2001 kareemc WINBUG #360971 - Wizard Memory Leaks
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
#include "dxvtlibpch.h"
|
||
|
|
||
|
|
||
|
#undef DPF_SUBCOMP
|
||
|
#define DPF_SUBCOMP DN_SUBCOMP_VOICE
|
||
|
|
||
|
|
||
|
// application defined message ids
|
||
|
//#define WMAPP_LOOPBACKRUNNING WM_USER + 1
|
||
|
//#define WMAPP_INPUTVOLUME WM_USER + 2
|
||
|
|
||
|
// {53CA3FB7-4FD5-4a67-99E4-6F2496E6FEC2}
|
||
|
static const GUID GUID_LOOPBACKTEST =
|
||
|
{ 0x53ca3fb7, 0x4fd5, 0x4a67, { 0x99, 0xe4, 0x6f, 0x24, 0x96, 0xe6, 0xfe, 0xc2 } };
|
||
|
|
||
|
HRESULT StartDirectPlay( PDIRECTPLAY8SERVER* lplpdp8 );
|
||
|
HRESULT StopDirectPlay( PDIRECTPLAY8SERVER lpdp8 );
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "DVMessageHandlerServer"
|
||
|
HRESULT PASCAL DVMessageHandlerServer(
|
||
|
LPVOID lpvUserContext,
|
||
|
DWORD dwMessageType,
|
||
|
LPVOID lpMessage
|
||
|
)
|
||
|
{
|
||
|
DPF_ENTER();
|
||
|
switch( dwMessageType )
|
||
|
{
|
||
|
case DVMSGID_CREATEVOICEPLAYER:
|
||
|
break;
|
||
|
case DVMSGID_DELETEVOICEPLAYER:
|
||
|
break;
|
||
|
case DVMSGID_SESSIONLOST:
|
||
|
break;
|
||
|
case DVMSGID_PLAYERVOICESTART:
|
||
|
break;
|
||
|
case DVMSGID_PLAYERVOICESTOP:
|
||
|
break;
|
||
|
case DVMSGID_RECORDSTART:
|
||
|
break;
|
||
|
case DVMSGID_RECORDSTOP:
|
||
|
break;
|
||
|
case DVMSGID_CONNECTRESULT:
|
||
|
break;
|
||
|
case DVMSGID_DISCONNECTRESULT:
|
||
|
break;
|
||
|
case DVMSGID_INPUTLEVEL:
|
||
|
break;
|
||
|
case DVMSGID_OUTPUTLEVEL:
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DPF_EXIT();
|
||
|
return DV_OK;
|
||
|
}
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "DVMessageHandlerClient"
|
||
|
HRESULT PASCAL DVMessageHandlerClient(
|
||
|
LPVOID lpvUserContext,
|
||
|
DWORD dwMessageType,
|
||
|
LPVOID lpMessage
|
||
|
)
|
||
|
{
|
||
|
DPF_EXIT();
|
||
|
|
||
|
HWND hwndDialog;
|
||
|
HWND hwndPeakMeter;
|
||
|
HWND hwndSlider;
|
||
|
LONG lRet;
|
||
|
HRESULT hr;
|
||
|
CSupervisorInfo* lpsinfo;
|
||
|
PDVMSG_INPUTLEVEL pdvInputLevel;
|
||
|
PDVMSG_OUTPUTLEVEL pdvOutputLevel;
|
||
|
|
||
|
lpsinfo = (CSupervisorInfo*)lpvUserContext;
|
||
|
|
||
|
if( lpsinfo )
|
||
|
{
|
||
|
if( !lpsinfo->GetLoopbackRunning() )
|
||
|
return DV_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
switch( dwMessageType )
|
||
|
{
|
||
|
case DVMSGID_CREATEVOICEPLAYER:
|
||
|
break;
|
||
|
case DVMSGID_DELETEVOICEPLAYER:
|
||
|
break;
|
||
|
case DVMSGID_SESSIONLOST:
|
||
|
break;
|
||
|
case DVMSGID_PLAYERVOICESTART:
|
||
|
break;
|
||
|
case DVMSGID_PLAYERVOICESTOP:
|
||
|
break;
|
||
|
case DVMSGID_RECORDSTART:
|
||
|
if (lpsinfo == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// forward the message along to the appropriate window
|
||
|
lpsinfo->GetHWNDDialog(&hwndDialog);
|
||
|
if (!PostMessage(hwndDialog, WM_APP_RECORDSTART, 0, 0))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "PostMessage failed, code: %i", GetLastError());
|
||
|
break; // no error return, just continue
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case DVMSGID_RECORDSTOP:
|
||
|
if (lpsinfo == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// forward the message along to the appropriate window
|
||
|
lpsinfo->GetHWNDDialog(&hwndDialog);
|
||
|
if (!PostMessage(hwndDialog, WM_APP_RECORDSTOP, 0, 0))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "PostMessage failed, code: %i", GetLastError());
|
||
|
break; // no error return, just continue
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case DVMSGID_CONNECTRESULT:
|
||
|
break;
|
||
|
case DVMSGID_DISCONNECTRESULT:
|
||
|
break;
|
||
|
case DVMSGID_INPUTLEVEL:
|
||
|
if (lpsinfo == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
// update the peak meter
|
||
|
lpsinfo->GetHWNDInputPeak(&hwndPeakMeter);
|
||
|
if (IsWindow(hwndPeakMeter))
|
||
|
{
|
||
|
pdvInputLevel = (PDVMSG_INPUTLEVEL) lpMessage;
|
||
|
if (!PostMessage(hwndPeakMeter, PM_SETCUR, 0, pdvInputLevel->dwPeakLevel ))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "PostMessage failed, code: %i", GetLastError());
|
||
|
break; // no error return, just continue
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// update the volume slider
|
||
|
lpsinfo->GetHWNDInputVolumeSlider(&hwndSlider);
|
||
|
if (IsWindow(hwndSlider))
|
||
|
{
|
||
|
pdvInputLevel = (PDVMSG_INPUTLEVEL) lpMessage;
|
||
|
if (!PostMessage(hwndSlider, TBM_SETPOS, 1, DBToAmpFactor(DSBVOLUME_MAX)-DBToAmpFactor(pdvInputLevel->lRecordVolume)))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "PostMessage failed, code: %i", GetLastError());
|
||
|
break; // no error return, just continue
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case DVMSGID_OUTPUTLEVEL:
|
||
|
if (lpsinfo == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
// update the peak meter
|
||
|
lpsinfo->GetHWNDOutputPeak(&hwndPeakMeter);
|
||
|
if (IsWindow(hwndPeakMeter))
|
||
|
{
|
||
|
pdvOutputLevel = (PDVMSG_OUTPUTLEVEL) lpMessage;
|
||
|
if (!PostMessage(hwndPeakMeter, PM_SETCUR, 0, pdvOutputLevel->dwPeakLevel ))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "PostMessage failed, code: %i", GetLastError());
|
||
|
break; // no error return, just continue
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// update the volume slider
|
||
|
lpsinfo->GetHWNDOutputVolumeSlider(&hwndSlider);
|
||
|
if (IsWindow(hwndSlider))
|
||
|
{
|
||
|
DWORD dwVolume = 0; // Set to 0 to avoid PREFIX bug
|
||
|
|
||
|
// Get the current waveOut volume and set the slider to that position
|
||
|
hr = lpsinfo->GetWaveOutVolume(&dwVolume);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
// couldn't get the volume - set the slider to top
|
||
|
PostMessage(hwndSlider, TBM_SETPOS, 1, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX));
|
||
|
// disable the slider
|
||
|
PostMessage(hwndSlider, WM_CANCELMODE, 0, 0 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PostMessage(hwndSlider, TBM_SETPOS, 1, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN)) - dwVolume);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DPF_EXIT();
|
||
|
return DV_OK;
|
||
|
}
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "StartDirectPlay"
|
||
|
HRESULT StartDirectPlay( PDIRECTPLAY8SERVER* lplpdp8 )
|
||
|
{
|
||
|
HRESULT hr = DPN_OK;
|
||
|
LONG lRet = S_OK;
|
||
|
PDIRECTPLAY8ADDRESS pDeviceAddress = NULL;
|
||
|
PDIRECTPLAY8SERVER pdp8Server = NULL;
|
||
|
DPN_APPLICATION_DESC dpnApplicationDesc;
|
||
|
|
||
|
DPF_ENTER();
|
||
|
|
||
|
*lplpdp8 = NULL;
|
||
|
|
||
|
hr = COM_CoCreateInstance(
|
||
|
CLSID_DirectPlay8Server,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IDirectPlay8Server,
|
||
|
(void **)lplpdp8);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
*lplpdp8 = NULL;
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "CoCreateInstance for DirectPlay failed, code: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
pdp8Server = *lplpdp8;
|
||
|
|
||
|
hr = COM_CoCreateInstance(
|
||
|
CLSID_DirectPlay8Address,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IDirectPlay8Address,
|
||
|
(void **)&pDeviceAddress );
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
pDeviceAddress = NULL;
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "CoCreateInstance for DirectPlay8Address failed, code: 0x%x", hr );
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NOTE: This now causes the wizard to require TCP/IP to be installed.
|
||
|
// (doesn't have to be dialed up -- as long as local loopback is available)
|
||
|
//
|
||
|
// Eventually build a loopback SP for directplay8.
|
||
|
//
|
||
|
// TODO: Allow this to fall back to other SPs or use loopback SP
|
||
|
//
|
||
|
hr = pDeviceAddress->SetSP( &CLSID_DP8SP_TCPIP );
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed setting SP for address, code: 0x%x", hr );
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
hr = pdp8Server->Initialize( NULL, DVMessageHandlerServer, 0 );
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed initializing directplay layer, code: 0x%x", hr );
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
ZeroMemory( &dpnApplicationDesc, sizeof( DPN_APPLICATION_DESC ) );
|
||
|
dpnApplicationDesc.dwSize = sizeof( DPN_APPLICATION_DESC );
|
||
|
dpnApplicationDesc.guidApplication = GUID_LOOPBACKTEST;
|
||
|
dpnApplicationDesc.dwFlags = DPNSESSION_NODPNSVR | DPNSESSION_CLIENT_SERVER;
|
||
|
|
||
|
hr = pdp8Server->Host(
|
||
|
&dpnApplicationDesc,
|
||
|
&pDeviceAddress,
|
||
|
1,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
0 );
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to host on directplay layer, code: 0x%x", hr );
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
pDeviceAddress->Release();
|
||
|
|
||
|
DPF_EXIT();
|
||
|
return S_OK;
|
||
|
|
||
|
error_cleanup:
|
||
|
if (*lplpdp8 != NULL)
|
||
|
{
|
||
|
pdp8Server->Close(0);
|
||
|
pdp8Server->Release();
|
||
|
*lplpdp8 = NULL;
|
||
|
}
|
||
|
|
||
|
if( pDeviceAddress )
|
||
|
{
|
||
|
pDeviceAddress->Release();
|
||
|
}
|
||
|
|
||
|
DPF_EXIT();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "StopDirectPlay"
|
||
|
HRESULT StopDirectPlay(PDIRECTPLAY8SERVER lpdp8)
|
||
|
{
|
||
|
|
||
|
DPF_ENTER();
|
||
|
|
||
|
// Kill the session
|
||
|
if (lpdp8 != NULL)
|
||
|
{
|
||
|
lpdp8->Close(0);
|
||
|
|
||
|
lpdp8->Release();
|
||
|
}
|
||
|
|
||
|
|
||
|
DPF_EXIT();
|
||
|
return S_OK;
|
||
|
|
||
|
}
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "StartLoopback"
|
||
|
HRESULT StartLoopback(
|
||
|
LPDIRECTPLAYVOICESERVER* lplpdvs,
|
||
|
LPDIRECTPLAYVOICECLIENT* lplpdvc,
|
||
|
PDIRECTPLAY8SERVER* lplpdp8,
|
||
|
LPVOID lpvCallbackContext,
|
||
|
HWND hwndAppWindow,
|
||
|
GUID guidCaptureDevice,
|
||
|
GUID guidRenderDevice,
|
||
|
DWORD dwFlags)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
DWORD dwSize = 0;
|
||
|
DVCLIENTCONFIG dvcc;
|
||
|
DVSOUNDDEVICECONFIG dvsdc;
|
||
|
DVID dvidAllPlayers = DVID_ALLPLAYERS;
|
||
|
PBYTE pDeviceConfigBuffer = NULL;
|
||
|
PDVSOUNDDEVICECONFIG pdvsdc = NULL;
|
||
|
BOOL fVoiceSessionStarted = FALSE;
|
||
|
BOOL fClientConnected = FALSE;
|
||
|
|
||
|
DPF_ENTER();
|
||
|
|
||
|
*lplpdvs = NULL;
|
||
|
*lplpdvc = NULL;
|
||
|
|
||
|
hr = COM_CoCreateInstance(
|
||
|
DPVOICE_CLSID_DPVOICE,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IDirectPlayVoiceServer,
|
||
|
(void **)lplpdvs);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
*lplpdvs = NULL;
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "CoCreateInstance failed, code: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
hr = (*lplpdvs)->Initialize(*lplpdp8, DVMessageHandlerServer, lpvCallbackContext, NULL, 0);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceServer::Initialize failed, code: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
DVSESSIONDESC dvSessionDesc;
|
||
|
|
||
|
dvSessionDesc.dwSize = sizeof( DVSESSIONDESC );
|
||
|
dvSessionDesc.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
|
||
|
dvSessionDesc.dwBufferQuality = DVBUFFERQUALITY_DEFAULT;
|
||
|
dvSessionDesc.dwFlags = 0;
|
||
|
dvSessionDesc.dwSessionType = DVSESSIONTYPE_ECHO;
|
||
|
// Note this compression type is used for its short frame size so
|
||
|
// we can quickly detect lockups.
|
||
|
dvSessionDesc.guidCT = DPVCTGUID_NONE;
|
||
|
|
||
|
hr = (*lplpdvs)->StartSession( &dvSessionDesc, 0 );
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceServer::StartSession failed, code: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
fVoiceSessionStarted = TRUE;
|
||
|
|
||
|
hr = COM_CoCreateInstance(
|
||
|
DPVOICE_CLSID_DPVOICE,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IDirectPlayVoiceClient,
|
||
|
(void **)lplpdvc);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
*lplpdvc = NULL;
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "CoCreateInstance failed, code: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
hr = (*lplpdvc)->Initialize(*lplpdp8, DVMessageHandlerClient, lpvCallbackContext, NULL, 0);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::Initialize failed, code: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
dvsdc.dwSize = sizeof( DVSOUNDDEVICECONFIG );
|
||
|
dvsdc.hwndAppWindow = hwndAppWindow;
|
||
|
dvsdc.dwFlags = DVSOUNDCONFIG_AUTOSELECT;
|
||
|
if (dwFlags & DVSOUNDCONFIG_HALFDUPLEX)
|
||
|
{
|
||
|
// The caller wants a half duplex session.
|
||
|
dvsdc.dwFlags |= DVSOUNDCONFIG_HALFDUPLEX;
|
||
|
}
|
||
|
if (dwFlags & DVSOUNDCONFIG_TESTMODE)
|
||
|
{
|
||
|
// The caller wants a test mode session.
|
||
|
dvsdc.dwFlags |= DVSOUNDCONFIG_TESTMODE;
|
||
|
}
|
||
|
dvsdc.guidCaptureDevice = guidCaptureDevice;
|
||
|
dvsdc.guidPlaybackDevice = guidRenderDevice;
|
||
|
dvsdc.lpdsPlaybackDevice = NULL;
|
||
|
dvsdc.lpdsCaptureDevice = NULL;
|
||
|
dvsdc.dwMainBufferFlags = 0;
|
||
|
dvsdc.dwMainBufferPriority = 0;
|
||
|
dvsdc.lpdsMainBuffer = NULL;
|
||
|
|
||
|
dvcc.dwSize = sizeof( DVCLIENTCONFIG );
|
||
|
dvcc.dwFlags =
|
||
|
DVCLIENTCONFIG_AUTOVOICEACTIVATED |
|
||
|
DVCLIENTCONFIG_AUTORECORDVOLUME | DVCLIENTCONFIG_AUTOVOLUMERESET |
|
||
|
DVCLIENTCONFIG_PLAYBACKMUTE; // we don't want the user to hear his/her voice right away
|
||
|
dvcc.dwThreshold = DVTHRESHOLD_UNUSED;
|
||
|
dvcc.lPlaybackVolume = DSBVOLUME_MAX;
|
||
|
dvcc.lRecordVolume = DSBVOLUME_MAX;
|
||
|
dvcc.dwNotifyPeriod = 50;
|
||
|
dvcc.dwBufferQuality = DVBUFFERQUALITY_DEFAULT;
|
||
|
dvcc.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
|
||
|
|
||
|
hr = (*lplpdvc)->Connect( &dvsdc, &dvcc, DVFLAGS_SYNC|DVFLAGS_NOQUERY );
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::Connect failed, code: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
fClientConnected = TRUE;
|
||
|
|
||
|
hr = (*lplpdvc)->SetTransmitTargets(&dvidAllPlayers, 1 , 0);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::SetTransmitTargets failed, code: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
dwSize = 0;
|
||
|
hr = (*lplpdvc)->GetSoundDeviceConfig(pdvsdc, &dwSize);
|
||
|
if( hr != DVERR_BUFFERTOOSMALL )
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::GetSoundDeviceConfig failed, hr: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
pDeviceConfigBuffer = new BYTE[dwSize];
|
||
|
if( pDeviceConfigBuffer == NULL )
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "Memory alloc failure" );
|
||
|
hr = DVERR_OUTOFMEMORY;
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
pdvsdc = (PDVSOUNDDEVICECONFIG) pDeviceConfigBuffer;
|
||
|
pdvsdc->dwSize = sizeof( DVSOUNDDEVICECONFIG );
|
||
|
|
||
|
hr = (*lplpdvc)->GetSoundDeviceConfig(pdvsdc, &dwSize );
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::GetSoundDeviceConfig failed, hr: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
// If we're looking for full duplex fail and notify caller if we get half duplex
|
||
|
if( !(dwFlags & DVSOUNDCONFIG_HALFDUPLEX) )
|
||
|
{
|
||
|
if (pdvsdc->dwFlags & DVSOUNDCONFIG_HALFDUPLEX)
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "We received a half duplex when we expected full duplex" );
|
||
|
// It only started up in half duplex. Notify the caller.
|
||
|
hr = DV_HALFDUPLEX;
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( pdvsdc->dwFlags & DVSOUNDCONFIG_HALFDUPLEX )
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_INFOLEVEL, "StartLoopBack() returning DV_HALFDUPLEX flags=0x%x dwFlags = 0x%x", pdvsdc->dwFlags, dwFlags );
|
||
|
// it started in fullduplex, notify the caller
|
||
|
delete [] pDeviceConfigBuffer;
|
||
|
DPF_EXIT();
|
||
|
return DV_HALFDUPLEX;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_INFOLEVEL, "StartLoopBack() returning DV_FULLDUPLEX flags=0x%x dwFlags = 0x%x", pdvsdc->dwFlags, dwFlags );
|
||
|
// it started in fullduplex, notify the caller
|
||
|
delete [] pDeviceConfigBuffer;
|
||
|
DPF_EXIT();
|
||
|
return DV_FULLDUPLEX;
|
||
|
}
|
||
|
|
||
|
error_cleanup:
|
||
|
|
||
|
if (pDeviceConfigBuffer != NULL)
|
||
|
{
|
||
|
delete [] pDeviceConfigBuffer;
|
||
|
pDeviceConfigBuffer = NULL;
|
||
|
}
|
||
|
|
||
|
if (*lplpdvc != NULL)
|
||
|
{
|
||
|
if (fClientConnected)
|
||
|
{
|
||
|
(*lplpdvc)->Disconnect(DVFLAGS_SYNC);
|
||
|
fClientConnected = FALSE;
|
||
|
}
|
||
|
(*lplpdvc)->Release();
|
||
|
*lplpdvc = NULL;
|
||
|
}
|
||
|
|
||
|
if (*lplpdvs != NULL)
|
||
|
{
|
||
|
if (fVoiceSessionStarted)
|
||
|
{
|
||
|
(*lplpdvs)->StopSession(0);
|
||
|
fVoiceSessionStarted = FALSE;
|
||
|
}
|
||
|
(*lplpdvs)->Release();
|
||
|
*lplpdvs = NULL;
|
||
|
}
|
||
|
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "StartLoopback() returning hr=0x%x", hr );
|
||
|
|
||
|
DPF_EXIT();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "StopLoopback"
|
||
|
HRESULT StopLoopback(
|
||
|
LPDIRECTPLAYVOICESERVER lpdvs,
|
||
|
LPDIRECTPLAYVOICECLIENT lpdvc,
|
||
|
PDIRECTPLAY8SERVER lpdp8 )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
LONG lRet;
|
||
|
BOOL fRet;
|
||
|
BOOL fClientConnected = TRUE;
|
||
|
BOOL fVoiceSessionRunning = TRUE;
|
||
|
|
||
|
DPF_ENTER();
|
||
|
|
||
|
if (lpdvc != NULL)
|
||
|
{
|
||
|
hr = lpdvc->Disconnect(DVFLAGS_SYNC);
|
||
|
fClientConnected = FALSE;
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::Disconnect failed, hr: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
|
||
|
lpdvc->Release();
|
||
|
lpdvc = NULL;
|
||
|
}
|
||
|
|
||
|
if (lpdvs != NULL)
|
||
|
{
|
||
|
hr = lpdvs->StopSession(0);
|
||
|
fVoiceSessionRunning = FALSE;
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceServer::StopSession failed, hr: %i", hr);
|
||
|
goto error_cleanup;
|
||
|
}
|
||
|
lpdvs->Release();
|
||
|
lpdvs = NULL;
|
||
|
}
|
||
|
|
||
|
DPF_EXIT();
|
||
|
return S_OK;
|
||
|
|
||
|
error_cleanup:
|
||
|
if (lpdvc != NULL)
|
||
|
{
|
||
|
if (fClientConnected)
|
||
|
{
|
||
|
lpdvc->Disconnect(DVFLAGS_SYNC);
|
||
|
fClientConnected = FALSE;
|
||
|
}
|
||
|
lpdvc->Release();
|
||
|
lpdvc = NULL;
|
||
|
}
|
||
|
|
||
|
if (lpdvs != NULL)
|
||
|
{
|
||
|
if (fVoiceSessionRunning)
|
||
|
{
|
||
|
lpdvs->StopSession(0);
|
||
|
fVoiceSessionRunning = FALSE;
|
||
|
}
|
||
|
lpdvs->Release();
|
||
|
lpdvs = NULL;
|
||
|
}
|
||
|
|
||
|
DPF_EXIT();
|
||
|
return hr;
|
||
|
}
|
||
|
|