You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1462 lines
53 KiB
1462 lines
53 KiB
//=============================================================================
|
|
// FILE: VoiceParser.cpp
|
|
//
|
|
// Description: DirectPlay Service Provider Parser
|
|
//
|
|
//
|
|
// Modification History:
|
|
//
|
|
// Michael Milirud 08/Aug/2000 Created
|
|
//=============================================================================
|
|
|
|
|
|
//==================//
|
|
// Standard headers //
|
|
//==================//
|
|
#include <string>
|
|
#include <winsock2.h>
|
|
#include <wsipx.h>
|
|
|
|
// DVoice.h, included by DVProt.h, will _define_ the Compression Type GUIDs.
|
|
#include <initguid.h>
|
|
|
|
|
|
//=====================//
|
|
// Proprietary headers //
|
|
//=====================//
|
|
|
|
// Prototypes
|
|
#include "VoiceParser.hpp"
|
|
|
|
// Voice protocol header
|
|
#include "DVoice.h"
|
|
#include "DVProt.h"
|
|
|
|
|
|
namespace
|
|
{
|
|
HPROTOCOL g_hVoiceProtocol;
|
|
|
|
|
|
//====================//
|
|
// Message Type field //---------------------------------------------------------------------------------------------
|
|
//====================//
|
|
LABELED_BYTE g_arr_MessageTypeByteLabels[] = { { DVMSGID_CONNECTREQUEST, "Establishing connection" },
|
|
{ DVMSGID_CONNECTREFUSE, "Connection request rejected" },
|
|
{ DVMSGID_CONNECTACCEPT, "Connection request granted" },
|
|
{ DVMSGID_SETTINGSCONFIRM, "Confirming support for the connection settings" },
|
|
{ DVMSGID_PLAYERLIST, "List of players in the session" },
|
|
{ DVMSGID_SPEECH, "Audio data" },
|
|
{ DVMSGID_SPEECHWITHTARGET, "Targeted audio data" },
|
|
{ DVMSGID_SPEECHWITHFROM, "Proxied audio data" },
|
|
{ DVMSGID_SETTARGETS, "Setting client's target" },
|
|
{ DVMSGID_CREATEVOICEPLAYER, "New player joined the session" },
|
|
{ DVMSGID_DELETEVOICEPLAYER, "Player left the session" },
|
|
{ DVMSGID_SESSIONLOST, "Session is lost" },
|
|
{ DVMSGID_DISCONNECTCONFIRM, "Disconnection notification acknowledged" },
|
|
{ DVMSGID_DISCONNECT, "Disconnecting" },
|
|
{ DVMSGID_PLAYERLIST, "Players list" } };
|
|
|
|
SET g_LabeledMessageTypeByteSet = { sizeof(g_arr_MessageTypeByteLabels) / sizeof(LABELED_BYTE), g_arr_MessageTypeByteLabels };
|
|
|
|
|
|
|
|
//===================//
|
|
// Result Code field //----------------------------------------------------------------------------------------------
|
|
//===================//
|
|
LABELED_DWORD g_arr_ResultCodeDWordLabels[] = { { DVERR_BUFFERTOOSMALL, "Buffer is too small" },
|
|
{ DVERR_EXCEPTION, "Exception was thrown" },
|
|
{ DVERR_GENERIC, "Generic error" },
|
|
{ DVERR_INVALIDFLAGS, "Invalid flags" },
|
|
{ DVERR_INVALIDOBJECT, "Invalid object" },
|
|
{ DVERR_INVALIDPARAM, "Invalid parameter(s)" },
|
|
{ DVERR_INVALIDPLAYER, "Invalid player" },
|
|
{ DVERR_INVALIDGROUP, "Invalid group" },
|
|
{ DVERR_INVALIDHANDLE, "Invalid handle" },
|
|
{ DVERR_INVALIDPOINTER, "Invalid pointer" },
|
|
{ DVERR_OUTOFMEMORY, "Out of memory" },
|
|
{ DVERR_CONNECTABORTING, "Aborting connection" },
|
|
{ DVERR_CONNECTIONLOST, "Connection lost" },
|
|
{ DVERR_CONNECTABORTED, "Connection aborted" },
|
|
{ DVERR_CONNECTED, "Connected" },
|
|
{ DVERR_NOTCONNECTED, "Not connected" },
|
|
{ DVERR_NOTINITIALIZED, "Not initialized" },
|
|
{ DVERR_NOVOICESESSION, "No voice session" },
|
|
{ DVERR_NOTALLOWED, "Not allowed" },
|
|
{ DVERR_NOTHOSTING, "Not hosting" },
|
|
{ DVERR_NOTSUPPORTED, "Not supported" },
|
|
{ DVERR_NOINTERFACE, "No interface" },
|
|
{ DVERR_NOTBUFFERED, "Not buffered" },
|
|
{ DVERR_NOTRANSPORT, "No transport" },
|
|
{ DVERR_NOCALLBACK, "No callback" },
|
|
{ DVERR_NO3DSOUND, "No 3D sound" },
|
|
{ DVERR_NORECVOLAVAILABLE, "No recording volume available" },
|
|
{ DVERR_SESSIONLOST, "Session lost" },
|
|
{ DVERR_PENDING, "Pending" },
|
|
{ DVERR_INVALIDTARGET, "Invalid target" },
|
|
{ DVERR_TRANSPORTNOTHOST, "Transport is not hosting" },
|
|
{ DVERR_COMPRESSIONNOTSUPPORTED, "Compression is not supported" },
|
|
{ DVERR_ALREADYPENDING, "Already pending" },
|
|
{ DVERR_SOUNDINITFAILURE, "Sound initialization failed" },
|
|
{ DVERR_TIMEOUT, "Timeout" },
|
|
{ DVERR_ALREADYBUFFERED, "Already buffered" },
|
|
{ DVERR_HOSTING, "Hosting" },
|
|
{ DVERR_INVALIDDEVICE, "Invalid device" },
|
|
{ DVERR_RECORDSYSTEMERROR, "Record system error" },
|
|
{ DVERR_PLAYBACKSYSTEMERROR, "Playback system error" },
|
|
{ DVERR_SENDERROR, "Send error" },
|
|
{ DVERR_USERCANCEL, "Cancelled by user" },
|
|
{ DVERR_RUNSETUP, "Run setup" },
|
|
{ DVERR_INCOMPATIBLEVERSION, "Incompatible version" },
|
|
{ DVERR_INITIALIZED, "Initialized" },
|
|
{ DVERR_TRANSPORTNOTINIT, "Transport not initialized" },
|
|
{ DVERR_TRANSPORTNOSESSION, "Transport is not hosting or connecting" },
|
|
{ DVERR_TRANSPORTNOPLAYER, "Legacy DirectPlay local player has not yet been created" },
|
|
{ DVERR_USERBACK, "Back button was used improperly in the wizard" },
|
|
{ DVERR_INVALIDBUFFER, "Invalid buffer" },
|
|
{ DV_OK, "Success" } };
|
|
|
|
SET g_LabeledResultCodeDWordSet = { sizeof(g_arr_ResultCodeDWordLabels) / sizeof(LABELED_DWORD), g_arr_ResultCodeDWordLabels };
|
|
|
|
|
|
//====================//
|
|
// Session Type field //---------------------------------------------------------------------------------------------
|
|
//====================//
|
|
LABELED_DWORD g_arr_SessionTypeDWordLabels[] = { { DVSESSIONTYPE_PEER, "Peer to peer" },
|
|
{ DVSESSIONTYPE_MIXING, "Mixing server" },
|
|
{ DVSESSIONTYPE_FORWARDING, "Forwarding server" },
|
|
{ DVSESSIONTYPE_ECHO, "Loopback" } };
|
|
|
|
SET g_LabeledSessionTypeDWordSet = { sizeof(g_arr_SessionTypeDWordLabels) / sizeof(LABELED_DWORD), g_arr_SessionTypeDWordLabels };
|
|
|
|
|
|
//====================//
|
|
// Session Flags field //--------------------------------------------------------------------------------------------
|
|
//====================//
|
|
LABELED_BIT g_arr_SessionFlagsBitLabels[] = { { 1, "Host Migration enabled", "No Host Migration" }, // DVSESSION_NOHOSTMIGRATION
|
|
{ 2, "No Server Control Target mode", "Server Control Target mode" } }; // DVSESSION_SERVERCONTROLTARGET
|
|
|
|
SET g_LabeledSessionFlagsBitSet = { sizeof(g_arr_SessionFlagsBitLabels) / sizeof(LABELED_BIT), g_arr_SessionFlagsBitLabels };
|
|
|
|
|
|
//====================//
|
|
// Player Flags field //---------------------------------------------------------------------------------------------
|
|
//====================//
|
|
LABELED_BIT g_arr_PlayerFlagsBitLabels[] = { { 1, "Player supports full-duplex connection", "Player only supports half-duplex connection" } }; // DVPLAYERCAPS_HALFDUPLEX
|
|
|
|
SET g_LabeledPlayerFlagsBitSet = { sizeof(g_arr_PlayerFlagsBitLabels) / sizeof(LABELED_BIT), g_arr_PlayerFlagsBitLabels };
|
|
|
|
|
|
//=====================//
|
|
// Host Order ID field //--------------------------------------------------------------------------------------------
|
|
//=====================//
|
|
LABELED_DWORD g_arr_HostOrderDWordLabels[] = { { -1, "Hasn't been assigned by the host yet" } };
|
|
|
|
SET g_LabeledHostOrderIDDWordSet = { sizeof(g_arr_HostOrderDWordLabels) / sizeof(LABELED_DWORD), g_arr_HostOrderDWordLabels };
|
|
|
|
|
|
////////////////////////////////
|
|
// Custom Property Formatters //=====================================================================================
|
|
////////////////////////////////
|
|
|
|
// DESCRIPTION: Custom description formatter for the Voice packet summary
|
|
//
|
|
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
|
|
//
|
|
// RETURNS: NOTHING
|
|
//
|
|
VOID WINAPIV FormatPropertyInstance_VoiceSummary( LPPROPERTYINST io_pProperyInstance )
|
|
{
|
|
std::string strSummary;
|
|
char arr_cBuffer[10];
|
|
|
|
DVPROTOCOLMSG_FULLMESSAGE& rVoiceFrame = *reinterpret_cast<DVPROTOCOLMSG_FULLMESSAGE*>(io_pProperyInstance->lpData);
|
|
|
|
DWORD dwType = rVoiceFrame.dvGeneric.dwType;
|
|
|
|
|
|
// Message classification
|
|
switch ( dwType )
|
|
{
|
|
case DVMSGID_CONNECTREQUEST:
|
|
case DVMSGID_CONNECTREFUSE:
|
|
case DVMSGID_CONNECTACCEPT:
|
|
case DVMSGID_DISCONNECT:
|
|
case DVMSGID_DISCONNECTCONFIRM:
|
|
case DVMSGID_SETTINGSCONFIRM:
|
|
{
|
|
strSummary = "Connection Control : ";
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_SPEECH:
|
|
case DVMSGID_SPEECHWITHTARGET:
|
|
case DVMSGID_SPEECHWITHFROM:
|
|
{
|
|
strSummary = "Speech : ";
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_PLAYERLIST:
|
|
case DVMSGID_SETTARGETS:
|
|
case DVMSGID_CREATEVOICEPLAYER:
|
|
case DVMSGID_DELETEVOICEPLAYER:
|
|
case DVMSGID_SESSIONLOST:
|
|
{
|
|
strSummary = "Session Control : ";
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
strSummary = "INVALID";
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Message title
|
|
switch ( dwType )
|
|
{
|
|
case DVMSGID_CREATEVOICEPLAYER:
|
|
{
|
|
strSummary += "Player ";
|
|
strSummary += _itoa(rVoiceFrame.dvPlayerJoin.dvidID, arr_cBuffer, 16);
|
|
strSummary += " joined the session";
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
for ( int n = 0; n < sizeof(g_arr_MessageTypeByteLabels) / sizeof(LABELED_BYTE); ++n )
|
|
{
|
|
if ( g_arr_MessageTypeByteLabels[n].Value == dwType )
|
|
{
|
|
strSummary += g_arr_MessageTypeByteLabels[n].Label;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Message highlights
|
|
switch ( dwType )
|
|
{
|
|
case DVMSGID_PLAYERLIST:
|
|
{
|
|
strSummary += " (";
|
|
strSummary += _itoa(rVoiceFrame.dvPlayerList.dwNumEntries, arr_cBuffer, 10);
|
|
strSummary += " players)";
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_CONNECTACCEPT:
|
|
{
|
|
strSummary += " (";
|
|
for ( int n = 0; n < sizeof(g_arr_SessionTypeDWordLabels)/sizeof(LABELED_DWORD); ++n )
|
|
{
|
|
if ( g_arr_SessionTypeDWordLabels[n].Value == rVoiceFrame.dvConnectAccept.dwSessionType )
|
|
{
|
|
strSummary += g_arr_SessionTypeDWordLabels[n].Label;
|
|
break;
|
|
}
|
|
}
|
|
strSummary += ")";
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_SPEECH:
|
|
case DVMSGID_SPEECHWITHTARGET:
|
|
case DVMSGID_SPEECHWITHFROM:
|
|
{
|
|
strSummary += " [";
|
|
strSummary += _itoa(rVoiceFrame.dvSpeech.bMsgNum, arr_cBuffer, 10);
|
|
strSummary += ".";
|
|
strSummary += _itoa(rVoiceFrame.dvSpeech.bSeqNum, arr_cBuffer, 10);
|
|
strSummary += "]";
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcpy(io_pProperyInstance->szPropertyText, strSummary.c_str());
|
|
|
|
} // FormatPropertyInstance_VoiceSummary
|
|
|
|
|
|
|
|
// DESCRIPTION: Custom description formatter for the Compression Type field
|
|
//
|
|
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
|
|
//
|
|
// RETURNS: NOTHING
|
|
//
|
|
VOID WINAPIV FormatPropertyInstance_CompressionType( LPPROPERTYINST io_pProperyInstance )
|
|
{
|
|
|
|
std::string strSummary = "Compression Type = ";
|
|
|
|
// Check what Voice frame we are dealing with
|
|
REFGUID rguidCompressionType = *reinterpret_cast<GUID*>(io_pProperyInstance->lpData);
|
|
|
|
if ( IsEqualGUID(rguidCompressionType, DPVCTGUID_TRUESPEECH) )
|
|
{
|
|
strSummary += "TrueSpeech(TM) (8.6kbps) ";
|
|
}
|
|
else if ( IsEqualGUID(rguidCompressionType, DPVCTGUID_GSM) )
|
|
{
|
|
strSummary += "Microsoft GSM 6.10 (13kbps) ";
|
|
}
|
|
else if ( IsEqualGUID(rguidCompressionType, DPVCTGUID_NONE) )
|
|
{
|
|
strSummary += "None ";
|
|
}
|
|
else if ( IsEqualGUID(rguidCompressionType, DPVCTGUID_ADPCM) )
|
|
{
|
|
strSummary += "Microsoft ADPCM (32.8kbps) ";
|
|
}
|
|
else if ( IsEqualGUID(rguidCompressionType, DPVCTGUID_SC03) )
|
|
{
|
|
strSummary += "Voxware SC03 (3.2kbps) ";
|
|
}
|
|
else if ( IsEqualGUID(rguidCompressionType, DPVCTGUID_SC06) )
|
|
{
|
|
strSummary += "Voxware SC06 (6.4kbps) ";
|
|
}
|
|
else if ( IsEqualGUID(rguidCompressionType, DPVCTGUID_VR12) )
|
|
{
|
|
strSummary += "Voxware VR12 (1.4kbps) ";
|
|
}
|
|
else
|
|
{
|
|
strSummary += "Uknown";
|
|
}
|
|
|
|
|
|
enum
|
|
{
|
|
nMAX_GUID_STRING = 50 // more than enough characters for a symbolic representation of a GUID
|
|
};
|
|
|
|
OLECHAR arr_wcGUID[nMAX_GUID_STRING];
|
|
StringFromGUID2(rguidCompressionType, arr_wcGUID, sizeof(arr_wcGUID)/sizeof(TCHAR));
|
|
|
|
char arr_cGUID[nMAX_GUID_STRING];
|
|
WideCharToMultiByte(CP_ACP, 0, arr_wcGUID, -1, arr_cGUID, sizeof(arr_cGUID), NULL, NULL);
|
|
strSummary += arr_cGUID;
|
|
|
|
|
|
strcpy(io_pProperyInstance->szPropertyText, strSummary.c_str());
|
|
|
|
} // FormatPropertyInstance_CompressionType
|
|
|
|
|
|
|
|
// DESCRIPTION: Custom description formatter for the Players List summary
|
|
//
|
|
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
|
|
//
|
|
// RETURNS: NOTHING
|
|
//
|
|
VOID WINAPIV FormatPropertyInstance_PlayersListSummary( LPPROPERTYINST io_pProperyInstance )
|
|
{
|
|
|
|
sprintf(io_pProperyInstance->szPropertyText, "List of %d players in the session", io_pProperyInstance->lpPropertyInstEx->Dword[0]);
|
|
|
|
} // FormatPropertyInstance_PlayersListSummary
|
|
|
|
|
|
|
|
// DESCRIPTION: Custom description formatter for the Player's Entry summary
|
|
//
|
|
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
|
|
//
|
|
// RETURNS: NOTHING
|
|
//
|
|
VOID WINAPIV FormatPropertyInstance_PlayerEntrySummary( LPPROPERTYINST io_pProperyInstance )
|
|
{
|
|
|
|
DWORD* pdwData = io_pProperyInstance->lpPropertyInstEx->Dword;
|
|
sprintf(io_pProperyInstance->szPropertyText, "Player %d out of %d", pdwData[0], pdwData[1]);
|
|
|
|
} // FormatPropertyInstance_PlayerEntrySummary
|
|
|
|
|
|
|
|
// DESCRIPTION: Custom description formatter for the Session Flags summary
|
|
//
|
|
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
|
|
//
|
|
// RETURNS: NOTHING
|
|
//
|
|
VOID WINAPIV FormatPropertyInstance_SessionFlagsSummary( LPPROPERTYINST io_pProperyInstance )
|
|
{
|
|
|
|
std::string strSummary;
|
|
|
|
if ( (*io_pProperyInstance->lpDword & DVSESSION_NOHOSTMIGRATION) == DVSESSION_NOHOSTMIGRATION )
|
|
{
|
|
strSummary = g_arr_SessionFlagsBitLabels[0].LabelOn;
|
|
}
|
|
else
|
|
{
|
|
strSummary = g_arr_SessionFlagsBitLabels[0].LabelOff;
|
|
}
|
|
|
|
|
|
strSummary += ", ";
|
|
|
|
if ( (*io_pProperyInstance->lpDword & DVSESSION_SERVERCONTROLTARGET) == DVSESSION_SERVERCONTROLTARGET )
|
|
{
|
|
strSummary += g_arr_SessionFlagsBitLabels[1].LabelOn;
|
|
}
|
|
else
|
|
{
|
|
strSummary += g_arr_SessionFlagsBitLabels[1].LabelOff;
|
|
}
|
|
|
|
strcpy(io_pProperyInstance->szPropertyText, strSummary.c_str());
|
|
|
|
} // FormatPropertyInstance_SessionFlagsSummary
|
|
|
|
|
|
// DESCRIPTION: Custom description formatter for the Player's Entry summary
|
|
//
|
|
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
|
|
//
|
|
// RETURNS: NOTHING
|
|
//
|
|
VOID WINAPIV FormatPropertyInstance_PlayerFlagsSummary( LPPROPERTYINST io_pProperyInstance )
|
|
{
|
|
|
|
std::string strSummary;
|
|
|
|
if ( (*io_pProperyInstance->lpDword & DVSESSION_NOHOSTMIGRATION) == DVSESSION_NOHOSTMIGRATION )
|
|
{
|
|
strSummary = g_arr_PlayerFlagsBitLabels[0].LabelOn;
|
|
}
|
|
else
|
|
{
|
|
strSummary = g_arr_PlayerFlagsBitLabels[0].LabelOff;
|
|
}
|
|
|
|
strcpy(io_pProperyInstance->szPropertyText, strSummary.c_str());
|
|
|
|
} // FormatPropertyInstance_PlayerFlagsSummary
|
|
|
|
|
|
//==================//
|
|
// Properties table //-----------------------------------------------------------------------------------------------
|
|
//==================//
|
|
|
|
PROPERTYINFO g_arr_VoiceProperties[] =
|
|
{
|
|
|
|
// VOICE packet summary property (VOICE_SUMMARY)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"", // label
|
|
"DPlay Voice packet", // status-bar comment
|
|
PROP_TYPE_SUMMARY, // data type
|
|
PROP_QUAL_NONE, // data type qualifier
|
|
NULL, // labeled bit set
|
|
512, // description's maximum length
|
|
FormatPropertyInstance_VoiceSummary // generic formatter
|
|
},
|
|
|
|
// Message Type property (VOICE_UNPARSABLEFRAGMENT)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"This is a non-initial part of the fragmented Transport layer message and can not be parsed", // label
|
|
"Unparsable fragment summary", // status-bar comment
|
|
PROP_TYPE_SUMMARY, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
128, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Message Type property ((VOICE_INCOMPLETEMESSAGE)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"The rest of the data needed to parse this message has been sent in a separate fragment and can not be parsed", // label
|
|
"Incomplete message summary", // status-bar comment
|
|
PROP_TYPE_SUMMARY, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
128, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Message Type property (VOICE_MESSAGETYPE)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Message Type", // label
|
|
"Message Type field", // status-bar comment
|
|
PROP_TYPE_BYTE, // data type
|
|
PROP_QUAL_LABELED_SET, // data type qualifier.
|
|
&g_LabeledMessageTypeByteSet, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Major Version property (VOICE_MAJORVERSION)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Major Version", // label
|
|
"Major Version field", // status-bar comment
|
|
PROP_TYPE_BYTE, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Minor Version property (VOICE_MINORVERSION)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Minor Version", // label
|
|
"Minor Version field", // status-bar comment
|
|
PROP_TYPE_BYTE, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Build Version property (VOICE_BUILDVERSION)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Build Version", // label
|
|
"Build Version field", // status-bar comment
|
|
PROP_TYPE_DWORD, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Result Code property (VOICE_RESULTCODE)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Result Code", // label
|
|
"Result Code field", // status-bar comment
|
|
PROP_TYPE_DWORD, // data type (HRESULT)
|
|
PROP_QUAL_LABELED_SET, // data type qualifier.
|
|
&g_LabeledResultCodeDWordSet, // labeled byte set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Session Type property (VOICE_SESSIONTYPE)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Session Type", // label
|
|
"Session Type field", // status-bar comment
|
|
PROP_TYPE_DWORD, // data type
|
|
PROP_QUAL_LABELED_SET, // data type qualifier.
|
|
&g_LabeledSessionTypeDWordSet, // labeled byte set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Session Flags property (VOICE_SESSIONFLAGS_SUMMARY)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"", // label
|
|
"Session Flags summary", // status-bar comment
|
|
PROP_TYPE_SUMMARY, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled byte set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance_SessionFlagsSummary // generic formatter
|
|
},
|
|
|
|
// Session Flags property (VOICE_SESSIONFLAGS)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Session Flags", // label
|
|
"Session Flags field", // status-bar comment
|
|
PROP_TYPE_DWORD, // data type
|
|
PROP_QUAL_FLAGS, // data type qualifier.
|
|
&g_LabeledSessionFlagsBitSet, // labeled byte set
|
|
512, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Session Flags property (VOICE_PLAYERFLAGS_SUMMARY)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"", // label
|
|
"Player Flags summary", // status-bar comment
|
|
PROP_TYPE_SUMMARY, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled byte set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance_PlayerFlagsSummary // generic formatter
|
|
},
|
|
|
|
// Session Flags property (VOICE_PLAYERFLAGS)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Player Flags", // label
|
|
"Player Flags field", // status-bar comment
|
|
PROP_TYPE_DWORD, // data type
|
|
PROP_QUAL_FLAGS, // data type qualifier.
|
|
&g_LabeledPlayerFlagsBitSet, // labeled byte set
|
|
512, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Number of Targets property (VOICE_NUMBEROFTARGETS)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Number of Targets", // label
|
|
"Number of Targets field", // status-bar comment
|
|
PROP_TYPE_DWORD, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Compression Type property (VOICE_COMPRESSIONTYPE)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Compression Type", // label
|
|
"Compression Type field", // status-bar comment
|
|
PROP_TYPE_RAW_DATA, // data type (GUID)
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance_CompressionType // generic formatter
|
|
},
|
|
|
|
// Host Migration Sequence Number property (VOICE_HOSTORDERID)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Host Migration Sequence Number", // label
|
|
"Host Migration Sequence Number field", // status-bar comment
|
|
PROP_TYPE_DWORD, // data type
|
|
PROP_QUAL_LABELED_SET, // data type qualifier.
|
|
&g_LabeledHostOrderIDDWordSet, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Number of Players property (VOICE_NUMBEROFPLAYERS)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Number of Players", // label
|
|
"Number of Players field", // status-bar comment
|
|
PROP_TYPE_DWORD, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Player's summary property (VOICE_PLAYERLISTSUMMARY)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"", // label
|
|
"Player's list summary", // status-bar comment
|
|
PROP_TYPE_SUMMARY, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance_PlayersListSummary // generic formatter
|
|
},
|
|
|
|
// Player's summary property (VOICE_PLAYERSUMMARY)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"", // label
|
|
"Player's summary", // status-bar comment
|
|
PROP_TYPE_SUMMARY, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance_PlayerEntrySummary // generic formatter
|
|
},
|
|
|
|
// Player's ID property (VOICE_PLAYERID)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Player ID", // label
|
|
"Player ID field", // status-bar comment
|
|
PROP_TYPE_DWORD, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Player's ID property (VOICE_TARGETID)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Target ID", // label
|
|
"Target ID field", // status-bar comment
|
|
PROP_TYPE_DWORD, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Message Number property (VOICE_MESSAGENUMBER)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Message #", // label
|
|
"Message Number field", // status-bar comment
|
|
PROP_TYPE_BYTE, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Fragment Number property (VOICE_FRAGMENTNUMBER)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Fragment #", // label
|
|
"Fragment Number field", // status-bar comment
|
|
PROP_TYPE_BYTE, // data type
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
},
|
|
|
|
// Audio Data (VOICE_AUDIODATA)
|
|
{
|
|
0, // handle placeholder (MBZ)
|
|
0, // reserved (MBZ)
|
|
"Audio Data", // label
|
|
"Audio Data", // status-bar comment
|
|
PROP_TYPE_RAW_DATA, // data type (GUID)
|
|
PROP_QUAL_NONE, // data type qualifier.
|
|
NULL, // labeled bit set
|
|
64, // description's maximum length
|
|
FormatPropertyInstance // generic formatter
|
|
}
|
|
};
|
|
|
|
enum
|
|
{
|
|
nNUM_OF_VOICE_PROPS = sizeof(g_arr_VoiceProperties) / sizeof(PROPERTYINFO)
|
|
};
|
|
|
|
|
|
// Properties' indices
|
|
enum
|
|
{
|
|
VOICE_SUMMARY = 0,
|
|
VOICE_UNPARSABLEFRAGMENT,
|
|
VOICE_INCOMPLETEMESSAGE,
|
|
|
|
VOICE_MESSAGETYPE,
|
|
VOICE_MAJORVERSION,
|
|
VOICE_MINORVERSION,
|
|
VOICE_BUILDVERSION,
|
|
|
|
VOICE_RESULTCODE,
|
|
VOICE_SESSIONTYPE,
|
|
|
|
VOICE_SESSIONFLAGS_SUMMARY,
|
|
VOICE_SESSIONFLAGS,
|
|
|
|
VOICE_PLAYERFLAGS_SUMMARY,
|
|
VOICE_PLAYERFLAGS,
|
|
|
|
VOICE_NUMBEROFTARGETS,
|
|
VOICE_COMPRESSIONTYPE,
|
|
VOICE_HOSTORDERID,
|
|
VOICE_NUMBEROFPLAYERS,
|
|
|
|
VOICE_PLAYERLIST_SUMMARY,
|
|
VOICE_PLAYERSUMMARY,
|
|
|
|
VOICE_PLAYERID,
|
|
VOICE_TARGETID,
|
|
|
|
VOICE_MESSAGENUMBER,
|
|
VOICE_FRAGMENTNUMBER,
|
|
|
|
VOICE_AUDIODATA
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// DESCRIPTION: Creates and fills-in a properties database for the protocol.
|
|
// Network Monitor uses this database to determine which properties the protocol supports.
|
|
//
|
|
// ARGUMENTS: i_hVoiceProtocol - The handle of the protocol provided by the Network Monitor.
|
|
//
|
|
// RETURNS: NOTHING
|
|
//
|
|
DPLAYPARSER_API VOID BHAPI VoiceRegister( HPROTOCOL i_hVoiceProtocol )
|
|
{
|
|
|
|
CreatePropertyDatabase(i_hVoiceProtocol, nNUM_OF_VOICE_PROPS);
|
|
|
|
// Add the properties to the database
|
|
for( int nProp=0; nProp < nNUM_OF_VOICE_PROPS; ++nProp )
|
|
{
|
|
AddProperty(i_hVoiceProtocol, &g_arr_VoiceProperties[nProp]);
|
|
}
|
|
|
|
} // VoiceRegister
|
|
|
|
|
|
|
|
// DESCRIPTION: Frees the resources used to create the protocol property database.
|
|
//
|
|
// ARGUMENTS: i_hVoiceProtocol - The handle of the protocol provided by the Network Monitor.
|
|
//
|
|
// RETURNS: NOTHING
|
|
//
|
|
DPLAYPARSER_API VOID WINAPI VoiceDeregister( HPROTOCOL i_hProtocol )
|
|
{
|
|
|
|
DestroyPropertyDatabase(i_hProtocol);
|
|
|
|
} // VoiceDeregister
|
|
|
|
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
// DESCRIPTION: Parses the Voice frame to find its size (in bytes) NOT including the user data
|
|
//
|
|
// ARGUMENTS: i_pbVoiceFrame - Pointer to the start of the unclaimed data. Typically, the unclaimed data is located
|
|
// in the middle of a frame because a previous parser has claimed data before this parser.
|
|
//
|
|
// RETURNS: Size of the Voiceecified Voice frame (in bytes)
|
|
//
|
|
int VoiceHeaderSize( LPBYTE i_pbVoiceFrame )
|
|
{
|
|
|
|
// Check what Voice frame we are dealing with
|
|
const DVPROTOCOLMSG_FULLMESSAGE& rVoiceFrame = *reinterpret_cast<DVPROTOCOLMSG_FULLMESSAGE*>(i_pbVoiceFrame);
|
|
|
|
switch ( rVoiceFrame.dvGeneric.dwType )
|
|
{
|
|
case DVMSGID_CONNECTREQUEST:
|
|
{
|
|
return sizeof(rVoiceFrame.dvConnectRequest);
|
|
}
|
|
|
|
case DVMSGID_CONNECTREFUSE:
|
|
{
|
|
return sizeof(rVoiceFrame.dvConnectRefuse);
|
|
}
|
|
|
|
case DVMSGID_CONNECTACCEPT:
|
|
{
|
|
return sizeof(rVoiceFrame.dvConnectAccept);
|
|
}
|
|
|
|
case DVMSGID_SETTINGSCONFIRM:
|
|
{
|
|
return sizeof(rVoiceFrame.dvSettingsConfirm);
|
|
}
|
|
|
|
case DVMSGID_PLAYERLIST:
|
|
{
|
|
return sizeof(rVoiceFrame.dvPlayerList);
|
|
}
|
|
|
|
case DVMSGID_SPEECH:
|
|
{
|
|
return sizeof(rVoiceFrame.dvSpeech);
|
|
}
|
|
|
|
case DVMSGID_SPEECHWITHTARGET:
|
|
{
|
|
return sizeof(rVoiceFrame.dvSpeechWithTarget);
|
|
}
|
|
|
|
case DVMSGID_SPEECHWITHFROM:
|
|
{
|
|
return sizeof(rVoiceFrame.dvSpeechWithFrom);
|
|
}
|
|
|
|
case DVMSGID_SETTARGETS:
|
|
{
|
|
return sizeof(rVoiceFrame.dvSetTarget);
|
|
}
|
|
|
|
case DVMSGID_CREATEVOICEPLAYER:
|
|
{
|
|
return sizeof(rVoiceFrame.dvPlayerJoin);
|
|
}
|
|
|
|
case DVMSGID_DELETEVOICEPLAYER:
|
|
{
|
|
return sizeof(rVoiceFrame.dvPlayerQuit);
|
|
}
|
|
|
|
case DVMSGID_SESSIONLOST:
|
|
{
|
|
return sizeof(rVoiceFrame.dvSessionLost);
|
|
}
|
|
|
|
case DVMSGID_DISCONNECTCONFIRM:
|
|
case DVMSGID_DISCONNECT:
|
|
{
|
|
return sizeof(rVoiceFrame.dvDisconnect);
|
|
}
|
|
|
|
default:
|
|
{
|
|
return -1; // TODO: DPF(0, "Unknown voice frame!");
|
|
}
|
|
}
|
|
|
|
} // VoiceHeaderSize
|
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
|
|
// DESCRIPTION: Indicates whether a piece of data is recognized as the protocol that the parser detects.
|
|
//
|
|
// ARGUMENTS: i_hFrame - The handle to the frame that contains the data.
|
|
// i_pbMacFrame - The pointer to the first byte of the frame; the pointer provides a way to view
|
|
// the data that the other parsers recognize.
|
|
// i_pbVoiceFrame - Pointer to the start of the unclaimed data. Typically, the unclaimed data is located
|
|
// in the middle of a frame because a previous parser has claimed data before this parser.
|
|
// i_dwMacType - MAC value of the first protocol in a frame. Typically, the i_dwMacType value is used
|
|
// when the parser must identify the first protocol in the frame. Can be one of the following:
|
|
// MAC_TYPE_ETHERNET = 802.3, MAC_TYPE_TOKENRING = 802.5, MAC_TYPE_FDDI ANSI = X3T9.5.
|
|
// i_dwBytesLeft - The remaining number of bytes from a location in the frame to the end of the frame.
|
|
// i_hPrevProtocol - Handle of the previous protocol.
|
|
// i_dwPrevProtOffset - Offset of the previous protocol (from the beginning of the frame).
|
|
// o_pdwProtocolStatus - Protocol status indicator. Must be one of the following: PROTOCOL_STATUS_RECOGNIZED,
|
|
// PROTOCOL_STATUS_NOT_RECOGNIZED, PROTOCOL_STATUS_CLAIMED, PROTOCOL_STATUS_NEXT_PROTOCOL.
|
|
// o_phNextProtocol - Placeholder for the handle of the next protocol. This parameter is set when the parser identifies
|
|
// the protocol that follows its own protocol.
|
|
// io_pdwptrInstData - On input, a pointer to the instance data from the previous protocol.
|
|
// On output, a pointer to the instance data for the current protocol.
|
|
//
|
|
// RETURNS: If the function is successful, the return value is a pointer to the first byte after the recognized parser data.
|
|
// If the parser claims all the remaining data, the return value is NULL. If the function is unsuccessful, the return
|
|
// value is the initial value of the i_pbVoiceFrame parameter.
|
|
//
|
|
DPLAYPARSER_API LPBYTE BHAPI VoiceRecognizeFrame( HFRAME i_hFrame,
|
|
ULPBYTE i_upbMacFrame,
|
|
ULPBYTE i_upbyVoiceFrame,
|
|
DWORD i_dwMacType,
|
|
DWORD i_dwBytesLeft,
|
|
HPROTOCOL i_hPrevProtocol,
|
|
DWORD i_dwPrevProtOffset,
|
|
LPDWORD o_pdwProtocolStatus,
|
|
LPHPROTOCOL o_phNextProtocol,
|
|
PDWORD_PTR io_pdwptrInstData )
|
|
{
|
|
|
|
// Validate the amount of unclaimed data
|
|
enum
|
|
{
|
|
// TODO: CHANGE TO PROPER MIN SIZE
|
|
nMIN_VoiceHeaderSize = sizeof(_DVPROTOCOLMSG_GENERIC),
|
|
nNUMBER_OF_MSG_TYPES = sizeof(g_arr_MessageTypeByteLabels) / sizeof(LABELED_BYTE)
|
|
};
|
|
|
|
for ( int nTypeIndex = 0; nTypeIndex < nNUMBER_OF_MSG_TYPES; ++nTypeIndex )
|
|
{
|
|
if ( g_arr_MessageTypeByteLabels[nTypeIndex].Value == *i_upbyVoiceFrame )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Validate the packet as DPlay Session type
|
|
if ( ((i_dwBytesLeft >= nMIN_VoiceHeaderSize) && (nTypeIndex < nNUMBER_OF_MSG_TYPES)) || (*io_pdwptrInstData == 0) )
|
|
{
|
|
// Claim the remaining data
|
|
*o_pdwProtocolStatus = PROTOCOL_STATUS_CLAIMED;
|
|
return NULL;
|
|
}
|
|
|
|
// Assume the unclaimed data is not recognizable
|
|
*o_pdwProtocolStatus = PROTOCOL_STATUS_NOT_RECOGNIZED;
|
|
return i_upbyVoiceFrame;
|
|
|
|
} // VoiceRecognizeFrame
|
|
|
|
|
|
|
|
// DESCRIPTION: Maps the properties that exist in a piece of recognized data to Voiceecific locations.
|
|
//
|
|
// ARGUMENTS: i_hFrame - Handle of the frame that is being parsed.
|
|
// i_pbMacFram - Pointer to the first byte in the frame.
|
|
// i_pbVoiceFrame - Pointer to the start of the recognized data.
|
|
// i_dwMacType - MAC value of the first protocol in a frame. Typically, the i_dwMacType value is used
|
|
// when the parser must identify the first protocol in the frame. Can be one of the following:
|
|
// MAC_TYPE_ETHERNET = 802.3, MAC_TYPE_TOKENRING = 802.5, MAC_TYPE_FDDI ANSI = X3T9.5.
|
|
// i_dwBytesLeft - The remaining number of bytes in a frame (starting from the beginning of the recognized data).
|
|
// i_hPrevProtocol - Handle of the previous protocol.
|
|
// i_dwPrevProtOffset - Offset of the previous protocol (starting from the beginning of the frame).
|
|
// i_dwptrInstData - Pointer to the instance data that the previous protocol provides.
|
|
//
|
|
// RETURNS: Must return NULL
|
|
//
|
|
DPLAYPARSER_API LPBYTE BHAPI VoiceAttachProperties( HFRAME i_hFrame,
|
|
ULPBYTE i_upbyMacFrame,
|
|
ULPBYTE i_upbyVoiceFrame,
|
|
DWORD i_dwMacType,
|
|
DWORD i_dwBytesLeft,
|
|
HPROTOCOL i_hPrevProtocol,
|
|
DWORD i_dwPrevProtOffset,
|
|
DWORD_PTR i_dwptrInstData )
|
|
{
|
|
//===================//
|
|
// Attach Properties //
|
|
//===================//
|
|
|
|
if ( i_dwptrInstData == 0 )
|
|
{
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_UNPARSABLEFRAGMENT].hProperty,
|
|
i_dwBytesLeft, i_upbyVoiceFrame, 0, 0, 0);
|
|
return NULL;
|
|
}
|
|
|
|
// Summary line
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_SUMMARY].hProperty,
|
|
VoiceHeaderSize(i_upbyVoiceFrame), i_upbyVoiceFrame, 0, 0, 0);
|
|
|
|
// Check what Voice frame we are dealing with
|
|
DVPROTOCOLMSG_FULLMESSAGE& rVoiceFrame = *reinterpret_cast<DVPROTOCOLMSG_FULLMESSAGE*>(i_upbyVoiceFrame);
|
|
|
|
// Message type field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_MESSAGETYPE].hProperty,
|
|
sizeof(rVoiceFrame.dvGeneric.dwType), &rVoiceFrame.dvGeneric.dwType, 0, 1, 0);
|
|
|
|
__try
|
|
{
|
|
|
|
switch ( rVoiceFrame.dvGeneric.dwType )
|
|
{
|
|
case DVMSGID_CONNECTREQUEST:
|
|
{
|
|
// Major Version field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_MAJORVERSION].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectRequest.ucVersionMajor), &rVoiceFrame.dvConnectRequest.ucVersionMajor, 0, 1, 0);
|
|
|
|
// Minor Version field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_MINORVERSION].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectRequest.ucVersionMinor), &rVoiceFrame.dvConnectRequest.ucVersionMinor, 0, 1, 0);
|
|
|
|
// Build Version field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_BUILDVERSION].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectRequest.dwVersionBuild), &rVoiceFrame.dvConnectRequest.dwVersionBuild, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_CONNECTREFUSE:
|
|
{
|
|
// Result Code field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_RESULTCODE].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectRefuse.hresResult), &rVoiceFrame.dvConnectRefuse.hresResult, 0, 1, 0);
|
|
|
|
// Major Version field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_MAJORVERSION].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectRefuse.ucVersionMajor), &rVoiceFrame.dvConnectRefuse.ucVersionMajor, 0, 1, 0);
|
|
|
|
// Minor Version field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_MINORVERSION].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectRefuse.ucVersionMinor), &rVoiceFrame.dvConnectRefuse.ucVersionMinor, 0, 1, 0);
|
|
|
|
// Build Version field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_BUILDVERSION].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectRefuse.dwVersionBuild), &rVoiceFrame.dvConnectRefuse.dwVersionBuild, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_CONNECTACCEPT:
|
|
{
|
|
// Session Type field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_SESSIONTYPE].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectAccept.dwSessionType), &rVoiceFrame.dvConnectAccept.dwSessionType, 0, 1, 0);
|
|
|
|
// Major Version field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_MAJORVERSION].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectAccept.ucVersionMajor), &rVoiceFrame.dvConnectAccept.ucVersionMajor, 0, 1, 0);
|
|
|
|
// Minor Version field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_MINORVERSION].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectAccept.ucVersionMinor), &rVoiceFrame.dvConnectAccept.ucVersionMinor, 0, 1, 0);
|
|
|
|
// Build Version field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_BUILDVERSION].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectAccept.dwVersionBuild), &rVoiceFrame.dvConnectAccept.dwVersionBuild, 0, 1, 0);
|
|
|
|
// Session Flags summary
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_SESSIONFLAGS_SUMMARY].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectAccept.dwSessionFlags), &rVoiceFrame.dvConnectAccept.dwSessionFlags, 0, 1, 0);
|
|
|
|
// Session Flags field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_SESSIONFLAGS].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectAccept.dwSessionFlags), &rVoiceFrame.dvConnectAccept.dwSessionFlags, 0, 2, 0);
|
|
|
|
// Compression Type field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_COMPRESSIONTYPE].hProperty,
|
|
sizeof(rVoiceFrame.dvConnectAccept.guidCT), &rVoiceFrame.dvConnectAccept.guidCT, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_SETTINGSCONFIRM:
|
|
{
|
|
// Player's Flags summary
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERFLAGS_SUMMARY].hProperty,
|
|
sizeof(rVoiceFrame.dvSettingsConfirm.dwFlags), &rVoiceFrame.dvSettingsConfirm.dwFlags, 0, 1, 0);
|
|
|
|
// Client Flags field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERFLAGS].hProperty,
|
|
sizeof(rVoiceFrame.dvSettingsConfirm.dwFlags), &rVoiceFrame.dvSettingsConfirm.dwFlags, 0, 2, 0);
|
|
|
|
// Host Migration Sequence Number field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_HOSTORDERID].hProperty,
|
|
sizeof(rVoiceFrame.dvSettingsConfirm.dwHostOrderID), &rVoiceFrame.dvSettingsConfirm.dwHostOrderID, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_PLAYERLIST:
|
|
{
|
|
// Host Order ID field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_HOSTORDERID].hProperty,
|
|
sizeof(rVoiceFrame.dvPlayerList.dwHostOrderID), &rVoiceFrame.dvPlayerList.dwHostOrderID, 0, 1, 0);
|
|
|
|
// Number of Players field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_NUMBEROFPLAYERS].hProperty,
|
|
sizeof(rVoiceFrame.dvPlayerList.dwNumEntries), &rVoiceFrame.dvPlayerList.dwNumEntries, 0, 1, 0);
|
|
|
|
|
|
// Player entries are following after the header
|
|
DVPROTOCOLMSG_PLAYERLIST_ENTRY* pPlayerEntry =
|
|
reinterpret_cast<DVPROTOCOLMSG_PLAYERLIST_ENTRY*>(&rVoiceFrame.dvPlayerList + 1);
|
|
|
|
// Make sure the list doesn't overflow the boundaries of the frame
|
|
DWORD dwNumEntries = rVoiceFrame.dvPlayerList.dwNumEntries;
|
|
if ( reinterpret_cast<LPBYTE>(pPlayerEntry + dwNumEntries) - i_upbyVoiceFrame > static_cast<int>(i_dwBytesLeft) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Player list summary
|
|
AttachPropertyInstanceEx(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERLIST_SUMMARY].hProperty,
|
|
dwNumEntries * sizeof(*pPlayerEntry), pPlayerEntry,
|
|
sizeof(DWORD), &dwNumEntries,
|
|
0, 1, 0);
|
|
|
|
// For every player entry in the list
|
|
for ( int nEntry = 1; nEntry <= dwNumEntries; ++nEntry, ++pPlayerEntry )
|
|
{
|
|
// Player's summary
|
|
struct
|
|
{
|
|
DWORD dwPlayerNum;
|
|
DWORD dwTotalPlayer;
|
|
}
|
|
PlayerEntryData = { nEntry, dwNumEntries };
|
|
|
|
AttachPropertyInstanceEx(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERSUMMARY].hProperty,
|
|
sizeof(*pPlayerEntry), pPlayerEntry,
|
|
sizeof(PlayerEntryData), &PlayerEntryData,
|
|
0, 2, 0);
|
|
|
|
// Player's ID field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERID].hProperty,
|
|
sizeof(pPlayerEntry->dvidID), &pPlayerEntry->dvidID, 0, 3, 0);
|
|
|
|
// Player's Flags summary
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERFLAGS_SUMMARY].hProperty,
|
|
sizeof(pPlayerEntry->dwPlayerFlags), &pPlayerEntry->dwPlayerFlags, 0, 3, 0);
|
|
|
|
// Player's Flags field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERFLAGS].hProperty,
|
|
sizeof(pPlayerEntry->dwPlayerFlags), &pPlayerEntry->dwPlayerFlags, 0, 4, 0);
|
|
|
|
// Host Migration Sequence Number field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_HOSTORDERID].hProperty,
|
|
sizeof(pPlayerEntry->dwHostOrderID), &pPlayerEntry->dwHostOrderID, 0, 3, 0);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_SPEECH:
|
|
{
|
|
// Message Number field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_MESSAGENUMBER].hProperty,
|
|
sizeof(rVoiceFrame.dvSpeech.bMsgNum), &rVoiceFrame.dvSpeech.bMsgNum, 0, 1, 0);
|
|
|
|
// Sequence Number field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_FRAGMENTNUMBER].hProperty,
|
|
sizeof(rVoiceFrame.dvSpeech.bSeqNum), &rVoiceFrame.dvSpeech.bSeqNum, 0, 1, 0);
|
|
|
|
// Audio Data
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_AUDIODATA].hProperty,
|
|
i_dwBytesLeft-sizeof(rVoiceFrame.dvSpeech), &rVoiceFrame.dvSpeech + 1, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_SPEECHWITHTARGET:
|
|
{
|
|
// Message Number field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_MESSAGENUMBER].hProperty,
|
|
sizeof(rVoiceFrame.dvSpeechWithTarget.dvHeader.bMsgNum), &rVoiceFrame.dvSpeechWithTarget.dvHeader.bMsgNum, 0, 1, 0);
|
|
|
|
// Sequence Number field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_FRAGMENTNUMBER].hProperty,
|
|
sizeof(rVoiceFrame.dvSpeechWithTarget.dvHeader.bSeqNum), &rVoiceFrame.dvSpeechWithTarget.dvHeader.bSeqNum, 0, 1, 0);
|
|
|
|
// Number of Targets field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_NUMBEROFTARGETS].hProperty,
|
|
sizeof(rVoiceFrame.dvSpeechWithTarget.dwNumTargets), &rVoiceFrame.dvSpeechWithTarget.dwNumTargets, 0, 1, 0);
|
|
|
|
|
|
// Target ID entries are following after the header
|
|
DVID* pTargetID = reinterpret_cast<DVID*>(&rVoiceFrame.dvSpeechWithTarget + 1);
|
|
|
|
// Make sure the list doesn't overflow the boundaries of the frame
|
|
int nNumTargets = rVoiceFrame.dvSpeechWithTarget.dwNumTargets;
|
|
if ( reinterpret_cast<LPBYTE>(pTargetID + nNumTargets) - i_upbyVoiceFrame > static_cast<int>(i_dwBytesLeft) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
// For every target ID entry in the list...
|
|
for ( ; nNumTargets; --nNumTargets, ++pTargetID )
|
|
{
|
|
// Target's ID field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_TARGETID].hProperty,
|
|
sizeof(*pTargetID), pTargetID, 0, 1, 0);
|
|
}
|
|
|
|
// Audio Data
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_AUDIODATA].hProperty,
|
|
i_dwBytesLeft-sizeof(rVoiceFrame.dvSpeechWithTarget), &rVoiceFrame.dvSpeechWithTarget + 1, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_SPEECHWITHFROM:
|
|
{
|
|
// Message Number field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_MESSAGENUMBER].hProperty,
|
|
sizeof(rVoiceFrame.dvSpeechWithFrom.dvHeader.bMsgNum), &rVoiceFrame.dvSpeechWithFrom.dvHeader.bMsgNum, 0, 1, 0);
|
|
|
|
// Sequence Number field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_FRAGMENTNUMBER].hProperty,
|
|
sizeof(rVoiceFrame.dvSpeechWithFrom.dvHeader.bSeqNum), &rVoiceFrame.dvSpeechWithFrom.dvHeader.bSeqNum, 0, 1, 0);
|
|
|
|
// Speaking Player's ID field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERID].hProperty,
|
|
sizeof(rVoiceFrame.dvSpeechWithFrom.dvidFrom), &rVoiceFrame.dvSpeechWithFrom.dvidFrom, 0, 1, 0);
|
|
|
|
// Audio Data
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_AUDIODATA].hProperty,
|
|
i_dwBytesLeft-sizeof(rVoiceFrame.dvSpeechWithFrom),
|
|
&rVoiceFrame.dvSpeechWithFrom + 1, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_SETTARGETS:
|
|
{
|
|
// Number of Targets field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_NUMBEROFTARGETS].hProperty,
|
|
sizeof(rVoiceFrame.dvSetTarget.dwNumTargets), &rVoiceFrame.dvSetTarget.dwNumTargets, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_CREATEVOICEPLAYER:
|
|
{
|
|
// Player ID field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERID].hProperty,
|
|
sizeof(rVoiceFrame.dvPlayerJoin.dvidID), &rVoiceFrame.dvPlayerJoin.dvidID, 0, 1, 0);
|
|
|
|
// Player's Flags summary
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERFLAGS_SUMMARY].hProperty,
|
|
sizeof(rVoiceFrame.dvPlayerJoin.dwFlags), &rVoiceFrame.dvPlayerJoin.dwFlags, 0, 1, 0);
|
|
|
|
// Player's Flags field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERFLAGS].hProperty,
|
|
sizeof(rVoiceFrame.dvPlayerJoin.dwFlags), &rVoiceFrame.dvPlayerJoin.dwFlags, 0, 2, 0);
|
|
|
|
// Host Order ID field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_HOSTORDERID].hProperty,
|
|
sizeof(rVoiceFrame.dvPlayerJoin.dwHostOrderID), &rVoiceFrame.dvPlayerJoin.dwHostOrderID, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_DELETEVOICEPLAYER:
|
|
{
|
|
// Player ID field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_PLAYERID].hProperty,
|
|
sizeof(rVoiceFrame.dvPlayerJoin.dvidID), &rVoiceFrame.dvPlayerJoin.dvidID, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_SESSIONLOST:
|
|
{
|
|
// Result Code field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_RESULTCODE].hProperty,
|
|
sizeof(rVoiceFrame.dvSessionLost.hresReason), &rVoiceFrame.dvSessionLost.hresReason, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
case DVMSGID_DISCONNECTCONFIRM:
|
|
case DVMSGID_DISCONNECT:
|
|
{
|
|
// Result Code field
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_RESULTCODE].hProperty,
|
|
sizeof(rVoiceFrame.dvDisconnect.hresDisconnect), &rVoiceFrame.dvDisconnect.hresDisconnect, 0, 1, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
break; // TODO: DPF(0, "Unknown voice frame!");
|
|
}
|
|
}
|
|
|
|
}
|
|
__except ( GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH )
|
|
{
|
|
AttachPropertyInstance(i_hFrame, g_arr_VoiceProperties[VOICE_INCOMPLETEMESSAGE].hProperty,
|
|
i_dwBytesLeft, i_upbyVoiceFrame, 0, 1, 0);
|
|
}
|
|
|
|
|
|
return NULL;
|
|
|
|
} // VoiceAttachProperties
|
|
|
|
|
|
|
|
|
|
|
|
// DESCRIPTION: Formats the data that is diVoicelayed in the details pane of the Network Monitor UI.
|
|
//
|
|
// ARGUMENTS: i_hFrame - Handle of the frame that is being parsed.
|
|
// i_pbMacFrame - Pointer to the first byte of a frame.
|
|
// i_pbCoreFrame - Pointer to the beginning of the protocol data in a frame.
|
|
// i_dwPropertyInsts - Number of PROPERTYINST structures provided by lpPropInst.
|
|
// i_pPropInst - Pointer to an array of PROPERTYINST structures.
|
|
//
|
|
// RETURNS: If the function is successful, the return value is a pointer to the first byte after the recognized data in a frame,
|
|
// or NULL if the recognized data is the last piece of data in a frame. If the function is unsuccessful, the return value
|
|
// is the initial value of i_upbyVoiceFrame.
|
|
//
|
|
DPLAYPARSER_API DWORD BHAPI VoiceFormatProperties( HFRAME i_hFrame,
|
|
ULPBYTE i_upbyMacFrame,
|
|
ULPBYTE i_upbyVoiceFrame,
|
|
DWORD i_dwPropertyInsts,
|
|
LPPROPERTYINST i_pPropInst )
|
|
{
|
|
|
|
// Loop through the property instances...
|
|
while( i_dwPropertyInsts-- > 0)
|
|
{
|
|
// ...and call the formatter for each
|
|
reinterpret_cast<FORMAT>(i_pPropInst->lpPropertyInfo->InstanceData)(i_pPropInst);
|
|
++i_pPropInst;
|
|
}
|
|
|
|
// TODO: MAKE SURE THIS SHOULD NOT BE TRUE
|
|
return NMERR_SUCCESS;
|
|
|
|
} // VoiceFormatProperties
|
|
|
|
|
|
|
|
|
|
// DESCRIPTION: Notifies Network Monitor that DNET protocol parser exists.
|
|
//
|
|
// ARGUMENTS: NONE
|
|
//
|
|
// RETURNS: TRUE - success, FALSE - failure
|
|
//
|
|
bool CreateVoiceProtocol( void )
|
|
{
|
|
|
|
// The entry points to the export functions that Network Monitor uses to operate the parser
|
|
ENTRYPOINTS VoiceEntryPoints =
|
|
{
|
|
// VoiceParser Entry Points
|
|
VoiceRegister,
|
|
VoiceDeregister,
|
|
VoiceRecognizeFrame,
|
|
VoiceAttachProperties,
|
|
VoiceFormatProperties
|
|
};
|
|
|
|
// The first active instance of this parser needs to register with the kernel
|
|
g_hVoiceProtocol = CreateProtocol("DPLAYVOICE", &VoiceEntryPoints, ENTRYPOINTS_SIZE);
|
|
|
|
return (g_hVoiceProtocol ? TRUE : FALSE);
|
|
|
|
} // CreateVoiceProtocol
|
|
|
|
|
|
|
|
// DESCRIPTION: Removes the DNET protocol parser from the Network Monitor's database of parsers
|
|
//
|
|
// ARGUMENTS: NONE
|
|
//
|
|
// RETURNS: NOTHING
|
|
//
|
|
void DestroyVoiceProtocol( void )
|
|
{
|
|
|
|
DestroyProtocol(g_hVoiceProtocol);
|
|
|
|
} // DestroyVoiceProtocol
|