Index: code/server/sv_client.c =================================================================== --- code/server/sv_client.c (revision 1471) +++ code/server/sv_client.c (working copy) @@ -1382,7 +1382,7 @@ // in the future, (val) will be a protocol version string, so only // accept explicitly 1, not generally non-zero. val = Info_ValueForKey (cl->userinfo, "cl_voip"); - cl->hasVoip = (atoi(val) == 1) ? qtrue : qfalse; + cl->voipProtocol = atoi(val); #endif // TTimo @@ -1698,7 +1698,7 @@ { if (!sv_voip->integer) return qtrue; // VoIP disabled on this server. - else if (!cl->hasVoip) // client doesn't have VoIP support?! + else if (!VOIP_PROTOCOL_OK(cl->voipProtocol)) // client uses unsupported protocol return qtrue; // !!! FIXME: implement player blacklist. @@ -1708,33 +1708,22 @@ static void SV_UserVoip( client_t *cl, msg_t *msg ) { - const int sender = (int) (cl - svs.clients); - const int generation = MSG_ReadByte(msg); - const int sequence = MSG_ReadLong(msg); - const int frames = MSG_ReadByte(msg); - const int recip1 = MSG_ReadLong(msg); - const int recip2 = MSG_ReadLong(msg); - const int recip3 = MSG_ReadLong(msg); - const int packetsize = MSG_ReadShort(msg); + int sender, generation, sequence, frames, packetsize; + uint8_t recips[(MAX_CLIENTS + 7) / 8]; byte encoded[sizeof (cl->voipPacket[0].data)]; client_t *client = NULL; voipServerPacket_t *packet = NULL; int i; - if (generation < 0) + sender = cl - svs.clients; + generation = MSG_ReadByte(msg); + sequence = MSG_ReadLong(msg); + frames = MSG_ReadByte(msg); + MSG_ReadData(msg, recips, sizeof(recips)); + packetsize = MSG_ReadShort(msg); + + if (msg->readcount > msg->cursize) return; // short/invalid packet, bail. - else if (sequence < 0) - return; // short/invalid packet, bail. - else if (frames < 0) - return; // short/invalid packet, bail. - else if (recip1 < 0) - return; // short/invalid packet, bail. - else if (recip2 < 0) - return; // short/invalid packet, bail. - else if (recip3 < 0) - return; // short/invalid packet, bail. - else if (packetsize < 0) - return; // short/invalid packet, bail. if (packetsize > sizeof (encoded)) { // overlarge packet? int bytesleft = packetsize; @@ -1758,30 +1747,22 @@ // !!! FIXME: reject if not speex narrowband codec. // !!! FIXME: decide if this is bogus data? - // (the three recip* values are 31 bits each (ignores sign bit so we can - // get a -1 error from MSG_ReadLong() ... ), allowing for 93 clients.) - assert( sv_maxclients->integer < 93 ); - // decide who needs this VoIP packet sent to them... for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) { if (client->state != CS_ACTIVE) continue; // not in the game yet, don't send to this guy. else if (i == sender) continue; // don't send voice packet back to original author. - else if (!client->hasVoip) - continue; // no VoIP support, or support disabled. + else if (!VOIP_PROTOCOL_OK(client->voipProtocol)) + continue; // no VoIP support, or unsupported protocol else if (client->muteAllVoip) continue; // client is ignoring everyone. else if (client->ignoreVoipFromClient[sender]) continue; // client is ignoring this talker. else if (*cl->downloadName) // !!! FIXME: possible to DoS? continue; // no VoIP allowed if downloading, to save bandwidth. - else if ( ((i >= 0) && (i < 31)) && ((recip1 & (1 << (i-0))) == 0) ) + else if ( !( recips[i / 8] & (1 << (i % 8)) ) ) continue; // not addressed to this player. - else if ( ((i >= 31) && (i < 62)) && ((recip2 & (1 << (i-31))) == 0) ) - continue; // not addressed to this player. - else if ( ((i >= 62) && (i < 93)) && ((recip3 & (1 << (i-62))) == 0) ) - continue; // not addressed to this player. // Transmit this packet to the client. // !!! FIXME: I don't like this queueing system. Index: code/server/server.h =================================================================== --- code/server/server.h (revision 1471) +++ code/server/server.h (working copy) @@ -180,7 +180,7 @@ netchan_buffer_t **netchan_end_queue; #ifdef USE_VOIP - qboolean hasVoip; + int voipProtocol; qboolean muteAllVoip; qboolean ignoreVoipFromClient[MAX_CLIENTS]; voipServerPacket_t voipPacket[64]; // !!! FIXME: WAY too much memory! Index: code/qcommon/qcommon.h =================================================================== --- code/qcommon/qcommon.h (revision 1471) +++ code/qcommon/qcommon.h (working copy) @@ -235,6 +235,11 @@ #define PROTOCOL_VERSION 68 // 1.31 - 67 +#ifdef USE_VOIP +// an array of allowed protocols would be more sensible but this is easier +#define VOIP_PROTOCOL_OK(x) ((x) == 1) +#endif + // maintain a list of compatible protocols for demo playing // NOTE: that stuff only works with two digits protocols extern int demo_protocols[]; Index: code/client/cl_input.c =================================================================== --- code/client/cl_input.c (revision 1471) +++ code/client/cl_input.c (working copy) @@ -760,55 +760,13 @@ #ifdef USE_VOIP if (clc.voipOutgoingDataSize > 0) { // only send if data. - // Move cl_voipSendTarget from a string to the bitmasks if needed. - if (cl_voipSendTarget->modified) { - char buffer[32]; - const char *target = cl_voipSendTarget->string; - - if (Q_stricmp(target, "attacker") == 0) { - int player = VM_Call( cgvm, CG_LAST_ATTACKER ); - Com_sprintf(buffer, sizeof (buffer), "%d", player); - target = buffer; - } else if (Q_stricmp(target, "crosshair") == 0) { - int player = VM_Call( cgvm, CG_CROSSHAIR_PLAYER ); - Com_sprintf(buffer, sizeof (buffer), "%d", player); - target = buffer; - } - - if ((*target == '\0') || (Q_stricmp(target, "all") == 0)) { - const int all = 0x7FFFFFFF; - clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = all; - } else if (Q_stricmp(target, "none") == 0) { - clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0; - } else { - clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0; - const char *ptr = target; - do { - if ((*ptr == ',') || (*ptr == '\0')) { - const int val = atoi(target); - target = ptr + 1; - if ((val >= 0) && (val < 31)) { - clc.voipTarget1 |= (1 << (val-0)); - } else if ((val >= 31) && (val < 62)) { - clc.voipTarget2 |= (1 << (val-31)); - } else if ((val >= 62) && (val < 93)) { - clc.voipTarget3 |= (1 << (val-62)); - } - } - } while (*(ptr++)); - } - cl_voipSendTarget->modified = qfalse; - } - MSG_WriteByte (&buf, clc_EOF); // placate legacy servers. MSG_WriteByte (&buf, clc_extension); MSG_WriteByte (&buf, clc_voip); MSG_WriteByte (&buf, clc.voipOutgoingGeneration); MSG_WriteLong (&buf, clc.voipOutgoingSequence); MSG_WriteByte (&buf, clc.voipOutgoingDataFrames); - MSG_WriteLong (&buf, clc.voipTarget1); - MSG_WriteLong (&buf, clc.voipTarget2); - MSG_WriteLong (&buf, clc.voipTarget3); + MSG_WriteData (&buf, clc.voipTargets, sizeof(clc.voipTargets)); MSG_WriteShort (&buf, clc.voipOutgoingDataSize); MSG_WriteData (&buf, clc.voipOutgoingData, clc.voipOutgoingDataSize); Index: code/client/cl_scrn.c =================================================================== --- code/client/cl_scrn.c (revision 1471) +++ code/client/cl_scrn.c (working copy) @@ -360,7 +360,7 @@ return; // not recording at the moment. else if (cls.state != CA_ACTIVE) return; // not connected to a server. - else if (!cl_connectedToVoipServer) + else if (!VOIP_PROTOCOL_OK(cl_voipServerProtocol)) return; // server doesn't support VoIP. else if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) return; // single player game. Index: code/client/client.h =================================================================== --- code/client/client.h (revision 1471) +++ code/client/client.h (working copy) @@ -246,9 +246,9 @@ qboolean voipMuteAll; // outgoing data... - int voipTarget1; // these three ints make up a bit mask of 92 bits. - int voipTarget2; // the bits say who a VoIP pack is addressed to: - int voipTarget3; // (1 << clientnum). See cl_voipSendTarget cvar. + // if voipTargets[i / 8] & (1 << (i % 8)), + // then we are sending to clientnum i + uint8_t voipTargets[(MAX_CLIENTS + 7) / 8]; SpeexPreprocessState *speexPreprocessor; SpeexBits speexEncoderBits; void *speexEncoder; @@ -501,7 +501,7 @@ extern int cl_connectedToCheatServer; #ifdef USE_VOIP -extern int cl_connectedToVoipServer; +extern int cl_voipServerProtocol; void CL_Voip_f( void ); #endif Index: code/client/cl_parse.c =================================================================== --- code/client/cl_parse.c (revision 1471) +++ code/client/cl_parse.c (working copy) @@ -331,7 +331,7 @@ int cl_connectedToCheatServer; #ifdef USE_VOIP -int cl_connectedToVoipServer; +int cl_voipServerProtocol; #endif /* @@ -363,10 +363,8 @@ } #ifdef USE_VOIP - // in the future, (val) will be a protocol version string, so only - // accept explicitly 1, not generally non-zero. s = Info_ValueForKey( systemInfo, "sv_voip" ); - cl_connectedToVoipServer = (atoi( s ) == 1); + cl_voipServerProtocol = atoi( s ); #endif s = Info_ValueForKey( systemInfo, "sv_cheats" ); Index: code/client/cl_main.c =================================================================== --- code/client/cl_main.c (revision 1471) +++ code/client/cl_main.c (working copy) @@ -219,8 +219,8 @@ reason = "Not connected to a server"; else if (!clc.speexInitialized) reason = "Speex not initialized"; - else if (!cl_connectedToVoipServer) - reason = "Server doesn't support VoIP"; + else if (!VOIP_PROTOCOL_OK(cl_voipServerProtocol)) + reason = "VoIP protocol unsupported by server"; else if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) reason = "running in single-player mode"; @@ -261,6 +261,66 @@ /* =============== +CL_VoipParseTargets + +sets clc.voipTargets according to cl_voipSendTarget +Generally we don't want who's listening to change during a transmission, +so this is only called when the key is first pressed +=============== +*/ +void CL_VoipParseTargets(void) +{ + char buffer[32]; + const char *target = cl_voipSendTarget->string; + + if( Q_stricmp( target, "attacker" ) == 0 ) + { + int player = VM_Call( cgvm, CG_LAST_ATTACKER ); + if( player < 0 ) + Q_strncpyz( buffer, "none", sizeof( buffer ) ); + else + Com_sprintf( buffer, sizeof( buffer ), "%d", player ); + target = buffer; + } + else if( Q_stricmp( target, "crosshair" ) == 0 ) + { + int player = VM_Call( cgvm, CG_LAST_ATTACKER ); + if( player < 0 ) + Q_strncpyz( buffer, "none", sizeof( buffer ) ); + else + Com_sprintf( buffer, sizeof( buffer ), "%d", player ); + target = buffer; + } + + if( !target[0] || Q_stricmp( target, "all" ) == 0 ) + Com_Memset( clc.voipTargets, ~0, sizeof( clc.voipTargets ) ); + else if( Q_stricmp( target, "none" ) == 0 ) + Com_Memset( clc.voipTargets, 0, sizeof( clc.voipTargets ) ); + else + { + char *end; + int val; + Com_Memset( clc.voipTargets, 0, sizeof( clc.voipTargets ) ); + while( 1 ) + { + while( *target && !isdigit( *target ) ) + target++; + if( !*target ) + break; + val = strtol( target, &end, 10 ); + if( val < 0 || val >= MAX_CLIENTS ) + Com_Printf( S_COLOR_YELLOW "WARNING: VoIP " + "target %d is not a valid client " + "number\n", val ); + else + clc.voipTargets[val / 8] |= 1 << (val % 8); + target = end; + } + } +} + +/* +=============== CL_CaptureVoip Record more audio from the hardware if required and encode it into Speex @@ -299,8 +359,8 @@ qboolean dontCapture = qfalse; if (cls.state != CA_ACTIVE) dontCapture = qtrue; // not connected to a server. - else if (!cl_connectedToVoipServer) - dontCapture = qtrue; // server doesn't support VoIP. + else if (!VOIP_PROTOCOL_OK(cl_voipServerProtocol)) + dontCapture = qtrue; // protocol unsupported else if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) dontCapture = qtrue; // single player game. else if (clc.demoplaying) @@ -332,6 +392,7 @@ S_MasterGain(cl_voipGainDuringCapture->value); S_StartCapture(); CL_VoipNewGeneration(); + CL_VoipParseTargets(); } if ((cl_voipSend->integer) || (finalFrame)) { // user wants to capture audio? @@ -1222,7 +1283,7 @@ #ifdef USE_VOIP // not connected to voip server anymore. - cl_connectedToVoipServer = qfalse; + cl_voipServerProtocol = 0; #endif // Stop recording any video Index: code/client/cl_cgame.c =================================================================== --- code/client/cl_cgame.c (revision 1471) +++ code/client/cl_cgame.c (working copy) @@ -952,7 +952,7 @@ clc.voipMuteAll = qfalse; Cmd_AddCommand ("voip", CL_Voip_f); Cvar_Set("cl_voipSendTarget", "all"); - clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0x7FFFFFFF; + Com_Memset(clc.voipTargets, ~0, sizeof(clc.voipTargets)); } #endif }