//============================================================================= // FILE: VoiceParser.cpp // // Description: DirectPlay Service Provider Parser // // // Modification History: // // Michael Milirud 08/Aug/2000 Created //============================================================================= //==================// // Standard headers // //==================// #include #include #include // DVoice.h, included by DVProt.h, will _define_ the Compression Type GUIDs. #include //=====================// // 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(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(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 DVPROTOCOLMSG_FULLMESSAGE& rVoiceFrame = *reinterpret_cast(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(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(&rVoiceFrame.dvPlayerList + 1); // Make sure the list doesn't overflow the boundaries of the frame DWORD dwNumEntries = rVoiceFrame.dvPlayerList.dwNumEntries; if ( reinterpret_cast(pPlayerEntry + dwNumEntries) - i_upbyVoiceFrame > static_cast(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(&rVoiceFrame.dvSpeechWithTarget + 1); // Make sure the list doesn't overflow the boundaries of the frame int nNumTargets = rVoiceFrame.dvSpeechWithTarget.dwNumTargets; if ( reinterpret_cast(pTargetID + nNumTargets) - i_upbyVoiceFrame > static_cast(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(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