[quake3-commits] r2102 - in trunk: . code/client code/qcommon code/server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Wed Jul 27 11:47:30 EDT 2011


Author: thilo
Date: 2011-07-27 11:47:29 -0400 (Wed, 27 Jul 2011)
New Revision: 2102

Modified:
   trunk/code/client/cl_cgame.c
   trunk/code/client/cl_cin.c
   trunk/code/client/cl_input.c
   trunk/code/client/cl_main.c
   trunk/code/client/cl_parse.c
   trunk/code/client/client.h
   trunk/code/client/snd_dma.c
   trunk/code/client/snd_local.h
   trunk/code/client/snd_main.c
   trunk/code/client/snd_openal.c
   trunk/code/client/snd_public.h
   trunk/code/qcommon/common.c
   trunk/code/qcommon/q_shared.h
   trunk/code/qcommon/qcommon.h
   trunk/code/server/server.h
   trunk/code/server/sv_client.c
   trunk/code/server/sv_init.c
   trunk/code/server/sv_snapshot.c
   trunk/voip-readme.txt
Log:
- Apply parts of Ben Millwood's target bitfield patch (#3787)
- Fix Ryan's FIXME and have voip packet buffer on the server dynamically allocated via Z_Malloc and store pointers in a circular buffer
- Improve voip target parsing on top of Ben Millwood's patch
- Add new "spatial" target where speaker is spatialized in 3d space and can be heard by all clients in hearing range (s_alMaxDistance)
  (#4467)
- Decrease voip sound lengths from 240ms to 80ms per voip packet to mitigate udp packet loss and decrease latency
- Protocol version incremented to 71


Modified: trunk/code/client/cl_cgame.c
===================================================================
--- trunk/code/client/cl_cgame.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/client/cl_cgame.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -952,8 +952,8 @@
 		clc.speexInitialized = qtrue;
 		clc.voipMuteAll = qfalse;
 		Cmd_AddCommand ("voip", CL_Voip_f);
-		Cvar_Set("cl_voipSendTarget", "all");
-		clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0x7FFFFFFF;
+		Cvar_Set("cl_voipSendTarget", "spatial");
+		Com_Memset(clc.voipTargets, ~0, sizeof(clc.voipTargets));
 	}
 #endif
 }

Modified: trunk/code/client/cl_cin.c
===================================================================
--- trunk/code/client/cl_cin.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/client/cl_cin.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -1147,7 +1147,7 @@
 		case	ZA_SOUND_MONO:
 			if (!cinTable[currentHandle].silent) {
 				ssize = RllDecodeMonoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
-                                S_RawSamples( 0, ssize, 22050, 2, 1, (byte *)sbuf, 1.0f );
+                                S_RawSamples(0, ssize, 22050, 2, 1, (byte *)sbuf, 1.0f, -1);
 			}
 			break;
 		case	ZA_SOUND_STEREO:
@@ -1157,7 +1157,7 @@
 					s_rawend[0] = s_soundtime;
 				}
 				ssize = RllDecodeStereoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
-                                S_RawSamples( 0, ssize, 22050, 2, 2, (byte *)sbuf, 1.0f );
+                                S_RawSamples(0, ssize, 22050, 2, 2, (byte *)sbuf, 1.0f, -1);
 			}
 			break;
 		case	ROQ_QUAD_INFO:

Modified: trunk/code/client/cl_input.c
===================================================================
--- trunk/code/client/cl_input.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/client/cl_input.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -799,83 +799,53 @@
 	}
 
 #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 (clc.voipOutgoingDataSize > 0)
+	{
+		if((clc.voipFlags & VOIP_SPATIAL) || Com_IsVoipTarget(clc.voipTargets, sizeof(clc.voipTargets), -1))
+		{
+			MSG_WriteByte (&buf, clc_voip);
+			MSG_WriteByte (&buf, clc.voipOutgoingGeneration);
+			MSG_WriteLong (&buf, clc.voipOutgoingSequence);
+			MSG_WriteByte (&buf, clc.voipOutgoingDataFrames);
+			MSG_WriteData (&buf, clc.voipTargets, sizeof(clc.voipTargets));
+			MSG_WriteByte(&buf, clc.voipFlags);
+			MSG_WriteShort (&buf, clc.voipOutgoingDataSize);
+			MSG_WriteData (&buf, clc.voipOutgoingData, clc.voipOutgoingDataSize);
 
-			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 we're recording a demo, we have to fake a server packet with
+			//  this VoIP data so it gets to disk; the server doesn't send it
+			//  back to us, and we might as well eliminate concerns about dropped
+			//  and misordered packets here.
+			if(clc.demorecording && !clc.demowaiting)
+			{
+				const int voipSize = clc.voipOutgoingDataSize;
+				msg_t fakemsg;
+				byte fakedata[MAX_MSGLEN];
+				MSG_Init (&fakemsg, fakedata, sizeof (fakedata));
+				MSG_Bitstream (&fakemsg);
+				MSG_WriteLong (&fakemsg, clc.reliableAcknowledge);
+				MSG_WriteByte (&fakemsg, svc_voip);
+				MSG_WriteShort (&fakemsg, clc.clientNum);
+				MSG_WriteByte (&fakemsg, clc.voipOutgoingGeneration);
+				MSG_WriteLong (&fakemsg, clc.voipOutgoingSequence);
+				MSG_WriteByte (&fakemsg, clc.voipOutgoingDataFrames);
+				MSG_WriteShort (&fakemsg, clc.voipOutgoingDataSize );
+				MSG_WriteData (&fakemsg, clc.voipOutgoingData, voipSize);
+				MSG_WriteByte (&fakemsg, svc_EOF);
+				CL_WriteDemoMessage (&fakemsg, 0);
 			}
 
-			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 {
-				const char *ptr = target;
-				clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0;
-				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;
+			clc.voipOutgoingSequence += clc.voipOutgoingDataFrames;
+			clc.voipOutgoingDataSize = 0;
+			clc.voipOutgoingDataFrames = 0;
 		}
-
-		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_WriteShort (&buf, clc.voipOutgoingDataSize);
-		MSG_WriteData (&buf, clc.voipOutgoingData, clc.voipOutgoingDataSize);
-
-		// If we're recording a demo, we have to fake a server packet with
-		//  this VoIP data so it gets to disk; the server doesn't send it
-		//  back to us, and we might as well eliminate concerns about dropped
-		//  and misordered packets here.
-		if ( clc.demorecording && !clc.demowaiting ) {
-			const int voipSize = clc.voipOutgoingDataSize;
-			msg_t fakemsg;
-			byte fakedata[MAX_MSGLEN];
-			MSG_Init (&fakemsg, fakedata, sizeof (fakedata));
-			MSG_Bitstream (&fakemsg);
-			MSG_WriteLong (&fakemsg, clc.reliableAcknowledge);
-			MSG_WriteByte (&fakemsg, svc_voip);
-			MSG_WriteShort (&fakemsg, clc.clientNum);
-			MSG_WriteByte (&fakemsg, clc.voipOutgoingGeneration);
-			MSG_WriteLong (&fakemsg, clc.voipOutgoingSequence);
-			MSG_WriteByte (&fakemsg, clc.voipOutgoingDataFrames);
-			MSG_WriteShort (&fakemsg, clc.voipOutgoingDataSize );
-			MSG_WriteData (&fakemsg, clc.voipOutgoingData, voipSize);
-			MSG_WriteByte (&fakemsg, svc_EOF);
-			CL_WriteDemoMessage (&fakemsg, 0);
+		else
+		{
+			// We have data, but no targets. Silently discard all data
+			clc.voipOutgoingDataSize = 0;
+			clc.voipOutgoingDataFrames = 0;
 		}
-
-		clc.voipOutgoingSequence += clc.voipOutgoingDataFrames;
-		clc.voipOutgoingDataSize = 0;
-		clc.voipOutgoingDataFrames = 0;
-	} else
+	}
 #endif
 
 	if ( count >= 1 ) {

Modified: trunk/code/client/cl_main.c
===================================================================
--- trunk/code/client/cl_main.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/client/cl_main.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -293,6 +293,88 @@
 
 /*
 ===============
+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)
+{
+	const char *target = cl_voipSendTarget->string;
+	char *end;
+	int val;
+
+	Com_Memset(clc.voipTargets, 0, sizeof(clc.voipTargets));
+	clc.voipFlags &= ~VOIP_SPATIAL;
+
+	while(target)
+	{
+		while(*target == ',' || *target == ' ')
+			target++;
+
+		if(!*target)
+			break;
+		
+		if(isdigit(*target))
+		{
+			val = strtol(target, &end, 10);
+			target = end;
+		}
+		else
+		{
+			if(!Q_stricmpn(target, "all", 3))
+			{
+				Com_Memset(clc.voipTargets, ~0, sizeof(clc.voipTargets));
+				return;
+			}
+			if(!Q_stricmpn(target, "spatial", 7))
+			{
+				clc.voipFlags |= VOIP_SPATIAL;
+				target += 7;
+				continue;
+			}
+			else
+			{
+				if(!Q_stricmpn(target, "attacker", 8))
+				{
+					val = VM_Call(cgvm, CG_LAST_ATTACKER);
+					target += 8;
+				}
+				else if(!Q_stricmpn(target, "crosshair", 9))
+				{
+					val = VM_Call(cgvm, CG_CROSSHAIR_PLAYER);
+					target += 9;
+				}
+				else
+				{
+					while(*target && *target != ',' && *target != ' ')
+						target++;
+
+					continue;
+				}
+
+				if(val < 0)
+					continue;
+			}
+		}
+
+		if(val < 0 || val >= MAX_CLIENTS)
+		{
+			Com_Printf(S_COLOR_YELLOW "WARNING: VoIP "
+				   "target %d is not a valid client "
+				   "number\n", val);
+
+			continue;
+		}
+
+		clc.voipTargets[val / 8] |= 1 << (val % 8);
+	}
+}
+
+/*
+===============
 CL_CaptureVoip
 
 Record more audio from the hardware if required and encode it into Speex
@@ -342,8 +424,9 @@
 
 		cl_voipSend->modified = qfalse;
 
-		if (dontCapture) {
-			cl_voipSend->integer = 0;
+		if(dontCapture)
+		{
+			Cvar_Set("cl_voipSend", "0");
 			return;
 		}
 
@@ -362,11 +445,12 @@
 		S_MasterGain(cl_voipGainDuringCapture->value);
 		S_StartCapture();
 		CL_VoipNewGeneration();
+		CL_VoipParseTargets();
 	}
 
 	if ((cl_voipSend->integer) || (finalFrame)) { // user wants to capture audio?
 		int samples = S_AvailableCaptureSamples();
-		const int mult = (finalFrame) ? 1 : 12; // 12 == 240ms of audio.
+		const int mult = (finalFrame) ? 1 : 4; // 4 == 80ms of audio.
 
 		// enough data buffered in audio hardware to process yet?
 		if (samples >= (clc.speexFrameSize * mult)) {
@@ -378,8 +462,8 @@
 			int wpos = 0;
 			int pos = 0;
 
-			if (samples > (clc.speexFrameSize * 12))
-				samples = (clc.speexFrameSize * 12);
+			if (samples > (clc.speexFrameSize * 4))
+				samples = (clc.speexFrameSize * 4);
 
 			// !!! FIXME: maybe separate recording from encoding, so voipPower
 			// !!! FIXME:  updates faster than 4Hz?
@@ -3420,7 +3504,7 @@
 
 #ifdef USE_VOIP
 	cl_voipSend = Cvar_Get ("cl_voipSend", "0", 0);
-	cl_voipSendTarget = Cvar_Get ("cl_voipSendTarget", "all", 0);
+	cl_voipSendTarget = Cvar_Get ("cl_voipSendTarget", "spatial", 0);
 	cl_voipGainDuringCapture = Cvar_Get ("cl_voipGainDuringCapture", "0.2", CVAR_ARCHIVE);
 	cl_voipCaptureMult = Cvar_Get ("cl_voipCaptureMult", "2.0", CVAR_ARCHIVE);
 	cl_voipUseVAD = Cvar_Get ("cl_voipUseVAD", "0", CVAR_ARCHIVE);

Modified: trunk/code/client/cl_parse.c
===================================================================
--- trunk/code/client/cl_parse.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/client/cl_parse.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -665,6 +665,29 @@
 
 /*
 =====================
+CL_PlayVoip
+
+Play raw data
+=====================
+*/
+
+static void CL_PlayVoip(int sender, int samplecnt, const byte *data, int flags)
+{
+	if(flags & VOIP_DIRECT)
+	{
+		S_RawSamples(sender + 1, samplecnt, clc.speexSampleRate, 2, 1,
+	             data, clc.voipGain[sender], -1);
+	}
+
+	if(flags & VOIP_SPATIAL)
+	{
+		S_RawSamples(sender + MAX_CLIENTS + 1, samplecnt, clc.speexSampleRate, 2, 1,
+	             data, 1.0f, sender);
+	}
+}
+
+/*
+=====================
 CL_ParseVoip
 
 A VoIP message has been received from the server
@@ -679,6 +702,7 @@
 	const int sequence = MSG_ReadLong(msg);
 	const int frames = MSG_ReadByte(msg);
 	const int packetsize = MSG_ReadShort(msg);
+	const int flags = MSG_ReadBits(msg, VOIP_FLAGCNT);
 	char encoded[1024];
 	int seqdiff = sequence - clc.voipIncomingSequence[sender];
 	int written = 0;
@@ -769,8 +793,8 @@
 		if ((written + clc.speexFrameSize) * 2 > sizeof (decoded)) {
 			Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
 			            written * 2, written, i);
-			S_RawSamples(sender + 1, written, clc.speexSampleRate, 2, 1,
-			             (const byte *) decoded, clc.voipGain[sender]);
+			
+			CL_PlayVoip(sender, written, (const byte *) decoded, flags);
 			written = 0;
 		}
 
@@ -793,10 +817,8 @@
 	Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
 	            written * 2, written, i);
 
-	if (written > 0) {
-		S_RawSamples(sender + 1, written, clc.speexSampleRate, 2, 1,
-		             (const byte *) decoded, clc.voipGain[sender]);
-	}
+	if(written > 0)
+		CL_PlayVoip(sender, written, (const byte *) decoded, flags);
 
 	clc.voipIncomingSequence[sender] = sequence + frames;
 }

Modified: trunk/code/client/client.h
===================================================================
--- trunk/code/client/client.h	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/client/client.h	2011-07-27 15:47:29 UTC (rev 2102)
@@ -250,9 +250,10 @@
 	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];
+	uint8_t voipFlags;
 	SpeexPreprocessState *speexPreprocessor;
 	SpeexBits speexEncoderBits;
 	void *speexEncoder;

Modified: trunk/code/client/snd_dma.c
===================================================================
--- trunk/code/client/snd_dma.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/client/snd_dma.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -916,7 +916,8 @@
 Music streaming
 ============
 */
-void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_channels, const byte *data, float volume ) {
+void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_channels, const byte *data, float volume, int entityNum)
+{
 	int		i;
 	int		src, dst;
 	float	scale;
@@ -927,9 +928,16 @@
 		return;
 	}
 
+	if(entityNum >= 0)
+	{
+		// FIXME: support spatialized raw streams, e.g. for VoIP
+		return;
+	}
+
 	if ( (stream < 0) || (stream >= MAX_RAW_STREAMS) ) {
 		return;
 	}
+	
 	rawsamples = s_rawsamples[stream];
 
 	if(s_muted->integer)
@@ -1395,8 +1403,8 @@
 		if(r > 0)
 		{
 			// add to raw buffer
-			S_Base_RawSamples( 0, fileSamples, s_backgroundStream->info.rate,
-				s_backgroundStream->info.width, s_backgroundStream->info.channels, raw, s_musicVolume->value );
+			S_Base_RawSamples(0, fileSamples, s_backgroundStream->info.rate,
+				s_backgroundStream->info.width, s_backgroundStream->info.channels, raw, s_musicVolume->value, -1);
 		}
 		else
 		{

Modified: trunk/code/client/snd_local.h
===================================================================
--- trunk/code/client/snd_local.h	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/client/snd_local.h	2011-07-27 15:47:29 UTC (rev 2102)
@@ -125,7 +125,7 @@
 	void (*StartLocalSound)( sfxHandle_t sfx, int channelNum );
 	void (*StartBackgroundTrack)( const char *intro, const char *loop );
 	void (*StopBackgroundTrack)( void );
-	void (*RawSamples)(int stream, int samples, int rate, int width, int channels, const byte *data, float volume);
+	void (*RawSamples)(int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum);
 	void (*StopAllSounds)( void );
 	void (*ClearLoopingSounds)( qboolean killall );
 	void (*AddLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
@@ -186,7 +186,7 @@
 extern	dma_t	dma;
 
 #define	MAX_RAW_SAMPLES	16384
-#define MAX_RAW_STREAMS 128
+#define MAX_RAW_STREAMS (MAX_CLIENTS * 2 + 1)
 extern	portable_samplepair_t s_rawsamples[MAX_RAW_STREAMS][MAX_RAW_SAMPLES];
 extern	int		s_rawend[MAX_RAW_STREAMS];
 

Modified: trunk/code/client/snd_main.c
===================================================================
--- trunk/code/client/snd_main.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/client/snd_main.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -129,11 +129,10 @@
 =================
 */
 void S_RawSamples (int stream, int samples, int rate, int width, int channels,
-		   const byte *data, float volume)
+		   const byte *data, float volume, int entityNum)
 {
-	if( si.RawSamples ) {
-		si.RawSamples( stream, samples, rate, width, channels, data, volume );
-	}
+	if(si.RawSamples)
+		si.RawSamples(stream, samples, rate, width, channels, data, volume, entityNum);
 }
 
 /*

Modified: trunk/code/client/snd_openal.c
===================================================================
--- trunk/code/client/snd_openal.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/client/snd_openal.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -521,6 +521,7 @@
 	qboolean	isLocked;		// This is locked (un-allocatable)
 	qboolean	isLooping;		// Is this a looping effect (attached to an entity)
 	qboolean	isTracking;		// Is this object tracking its owner
+	qboolean	isStream;		// Is this source a stream
 
 	float		curGain;		// gain employed if source is within maxdistance.
 	float		scaleGain;		// Last gain value for this source. 0 if muted.
@@ -744,13 +745,8 @@
 static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t priority,
 		int entity, int channel, qboolean local)
 {
-	ALuint buffer;
 	src_t *curSource;
 
-	// Mark the SFX as used, and grab the raw AL buffer
-	S_AL_BufferUse(sfx);
-	buffer = S_AL_BufferGet(sfx);
-
 	// Set up src struct
 	curSource = &srcList[src];
 	
@@ -763,12 +759,19 @@
 	curSource->isLocked = qfalse;
 	curSource->isLooping = qfalse;
 	curSource->isTracking = qfalse;
+	curSource->isStream = qfalse;
 	curSource->curGain = s_alGain->value * s_volume->value;
 	curSource->scaleGain = curSource->curGain;
 	curSource->local = local;
 
 	// Set up OpenAL source
-	qalSourcei(curSource->alSource, AL_BUFFER, buffer);
+	if(sfx >= 0)
+	{
+        	// Mark the SFX as used, and grab the raw AL buffer
+        	S_AL_BufferUse(sfx);
+        	qalSourcei(curSource->alSource, AL_BUFFER, S_AL_BufferGet(sfx));
+	}
+
 	qalSourcef(curSource->alSource, AL_PITCH, 1.0f);
 	S_AL_Gain(curSource->alSource, curSource->curGain);
 	qalSourcefv(curSource->alSource, AL_POSITION, vec3_origin);
@@ -1320,7 +1323,7 @@
 		VectorClear(sorigin);
 
 		qalSourcefv(curSource->alSource, AL_POSITION, sorigin);
-		qalSourcefv(curSource->alSource, AL_VELOCITY, sorigin);
+		qalSourcefv(curSource->alSource, AL_VELOCITY, vec3_origin);
 	}
 	else
 	{
@@ -1343,8 +1346,8 @@
 		else
 			VectorClear(svelocity);
 
-		qalSourcefv( curSource->alSource, AL_POSITION, (ALfloat *)sorigin );
-		qalSourcefv( curSource->alSource, AL_VELOCITY, (ALfloat *)velocity );
+		qalSourcefv(curSource->alSource, AL_POSITION, (ALfloat *) sorigin);
+		qalSourcefv(curSource->alSource, AL_VELOCITY, (ALfloat *) svelocity);
 	}
 }
 
@@ -1557,14 +1560,17 @@
 			continue;
 		}
 
-		// Check if it's done, and flag it
-		qalGetSourcei(curSource->alSource, AL_SOURCE_STATE, &state);
-		if(state == AL_STOPPED)
+		if(!curSource->isStream)
 		{
-			curSource->isPlaying = qfalse;
-			S_AL_SrcKill(i);
-			continue;
-		}
+        		// Check if it's done, and flag it
+	        	qalGetSourcei(curSource->alSource, AL_SOURCE_STATE, &state);
+	        	if(state == AL_STOPPED)
+        		{
+	        		curSource->isPlaying = qfalse;
+		        	S_AL_SrcKill(i);
+		        	continue;
+        		}
+                }
 
 		// Query relativity of source, don't move if it's true
 		qalGetSourcei(curSource->alSource, AL_SOURCE_RELATIVE, &state);
@@ -1614,32 +1620,57 @@
 S_AL_AllocateStreamChannel
 =================
 */
-static void S_AL_AllocateStreamChannel( int stream )
+static void S_AL_AllocateStreamChannel(int stream, int entityNum)
 {
+        srcHandle_t cursrc;
+        ALuint alsrc;
+        
 	if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
 		return;
 
-	// Allocate a streamSource at high priority
-	streamSourceHandles[stream] = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
-	if(streamSourceHandles[stream] == -1)
-		return;
+        if(entityNum >= 0)
+        {
+                // This is a stream that tracks an entity
+        	// Allocate a streamSource at normal priority
+        	cursrc = S_AL_SrcAlloc(SRCPRI_ENTITY, entityNum, 0);
+        	if(cursrc < 0)
+	        	return;
 
-	// Lock the streamSource so nobody else can use it, and get the raw streamSource
-	S_AL_SrcLock(streamSourceHandles[stream]);
-	streamSources[stream] = S_AL_SrcGet(streamSourceHandles[stream]);
+        	S_AL_SrcSetup(cursrc, -1, SRCPRI_ENTITY, entityNum, 0, qfalse);
+        	alsrc = S_AL_SrcGet(cursrc);
+        	srcList[cursrc].isTracking = qtrue;
+        	srcList[cursrc].isStream = qtrue;
+        }
+        else
+        {
+                // Unspatialized stream source
 
-	// make sure that after unmuting the S_AL_Gain in S_Update() does not turn
-	// volume up prematurely for this source
-	srcList[streamSourceHandles[stream]].scaleGain = 0.0f;
+        	// Allocate a streamSource at high priority
+        	cursrc = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
+        	if(cursrc < 0)
+	        	return;
 
-	// Set some streamSource parameters
-	qalSourcei (streamSources[stream], AL_BUFFER,          0            );
-	qalSourcei (streamSources[stream], AL_LOOPING,         AL_FALSE     );
-	qalSource3f(streamSources[stream], AL_POSITION,        0.0, 0.0, 0.0);
-	qalSource3f(streamSources[stream], AL_VELOCITY,        0.0, 0.0, 0.0);
-	qalSource3f(streamSources[stream], AL_DIRECTION,       0.0, 0.0, 0.0);
-	qalSourcef (streamSources[stream], AL_ROLLOFF_FACTOR,  0.0          );
-	qalSourcei (streamSources[stream], AL_SOURCE_RELATIVE, AL_TRUE      );
+        	alsrc = S_AL_SrcGet(cursrc);
+
+        	// Lock the streamSource so nobody else can use it, and get the raw streamSource
+        	S_AL_SrcLock(cursrc);
+        
+        	// make sure that after unmuting the S_AL_Gain in S_Update() does not turn
+        	// volume up prematurely for this source
+        	srcList[cursrc].scaleGain = 0.0f;
+
+        	// Set some streamSource parameters
+        	qalSourcei (alsrc, AL_BUFFER,          0            );
+        	qalSourcei (alsrc, AL_LOOPING,         AL_FALSE     );
+        	qalSource3f(alsrc, AL_POSITION,        0.0, 0.0, 0.0);
+        	qalSource3f(alsrc, AL_VELOCITY,        0.0, 0.0, 0.0);
+        	qalSource3f(alsrc, AL_DIRECTION,       0.0, 0.0, 0.0);
+        	qalSourcef (alsrc, AL_ROLLOFF_FACTOR,  0.0          );
+        	qalSourcei (alsrc, AL_SOURCE_RELATIVE, AL_TRUE      );
+        }
+
+        streamSourceHandles[stream] = cursrc;
+       	streamSources[stream] = alsrc;
 }
 
 /*
@@ -1654,6 +1685,7 @@
 
 	// Release the output streamSource
 	S_AL_SrcUnlock(streamSourceHandles[stream]);
+	S_AL_SrcKill(streamSourceHandles[stream]);
 	streamSources[stream] = 0;
 	streamSourceHandles[stream] = -1;
 }
@@ -1664,7 +1696,7 @@
 =================
 */
 static
-void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels, const byte *data, float volume)
+void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum)
 {
 	ALuint buffer;
 	ALuint format;
@@ -1677,7 +1709,7 @@
 	// Create the streamSource if necessary
 	if(streamSourceHandles[stream] == -1)
 	{
-		S_AL_AllocateStreamChannel(stream);
+		S_AL_AllocateStreamChannel(stream, entityNum);
 	
 		// Failed?
 		if(streamSourceHandles[stream] == -1)
@@ -1694,8 +1726,11 @@
 	// Shove the data onto the streamSource
 	qalSourceQueueBuffers(streamSources[stream], 1, &buffer);
 
-	// Volume
-	S_AL_Gain (streamSources[stream], volume * s_volume->value * s_alGain->value);
+	if(entityNum < 0)
+	{
+        	// Volume
+        	S_AL_Gain (streamSources[stream], volume * s_volume->value * s_alGain->value);
+        }
 }
 
 /*
@@ -2106,7 +2141,6 @@
 static
 void S_AL_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater )
 {
-	float		velocity[3] = {0.0f, 0.0f, 0.0f};
 	float		orientation[6];
 	vec3_t	sorigin;
 
@@ -2124,7 +2158,7 @@
 
 	// Set OpenAL listener paramaters
 	qalListenerfv(AL_POSITION, (ALfloat *)sorigin);
-	qalListenerfv(AL_VELOCITY, velocity);
+	qalListenerfv(AL_VELOCITY, vec3_origin);
 	qalListenerfv(AL_ORIENTATION, orientation);
 }
 

Modified: trunk/code/client/snd_public.h
===================================================================
--- trunk/code/client/snd_public.h	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/client/snd_public.h	2011-07-27 15:47:29 UTC (rev 2102)
@@ -33,8 +33,8 @@
 
 // cinematics and voice-over-network will send raw samples
 // 1.0 volume will be direct output of source samples
-void S_RawSamples (int stream, int samples, int rate, int width, int channels,
-				   const byte *data, float volume);
+void S_RawSamples(int stream, int samples, int rate, int width, int channels,
+				   const byte *data, float volume, int entityNum);
 
 // stop all sounds and the background track
 void S_StopAllSounds( void );

Modified: trunk/code/qcommon/common.c
===================================================================
--- trunk/code/qcommon/common.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/qcommon/common.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -3585,3 +3585,33 @@
 		string[i] = (unsigned char)( rand() % 255 );
 }
 
+
+/*
+==================
+Com_IsVoipTarget
+
+Returns non-zero if given clientNum is enabled in voipTargets, zero otherwise.
+If clientNum is negative return if any bit is set.
+==================
+*/
+qboolean Com_IsVoipTarget(uint8_t *voipTargets, int voipTargetsSize, int clientNum)
+{
+	int index;
+	if(clientNum < 0)
+	{
+		for(index = 0; index < voipTargetsSize; index++)
+		{
+			if(voipTargets[index])
+				return qtrue;
+		}
+		
+		return qfalse;
+	}
+
+	index = clientNum >> 3;
+	
+	if(index < voipTargetsSize)
+		return (voipTargets[index] & (1 << (clientNum & 0x07)));
+
+	return qfalse;
+}

Modified: trunk/code/qcommon/q_shared.h
===================================================================
--- trunk/code/qcommon/q_shared.h	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/qcommon/q_shared.h	2011-07-27 15:47:29 UTC (rev 2102)
@@ -928,9 +928,26 @@
 	char		string[MAX_CVAR_VALUE_STRING];
 } vmCvar_t;
 
+
 /*
 ==============================================================
 
+VoIP
+
+==============================================================
+*/
+
+// if you change the count of flags be sure to also change VOIP_FLAGNUM
+#define VOIP_SPATIAL		0x01		// spatialized voip message
+#define VOIP_DIRECT		0x02		// non-spatialized voip message
+
+// number of flags voip knows. You will have to bump protocol version number if you
+// change this.
+#define VOIP_FLAGCNT		2
+
+/*
+==============================================================
+
 COLLISION DETECTION
 
 ==============================================================

Modified: trunk/code/qcommon/qcommon.h
===================================================================
--- trunk/code/qcommon/qcommon.h	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/qcommon/qcommon.h	2011-07-27 15:47:29 UTC (rev 2102)
@@ -252,7 +252,7 @@
 ==============================================================
 */
 
-#define	PROTOCOL_VERSION	70
+#define	PROTOCOL_VERSION	71
 #define PROTOCOL_LEGACY_VERSION	68
 // 1.31 - 67
 
@@ -834,6 +834,8 @@
 qboolean	Com_SafeMode( void );
 void		Com_RunAndTimeServerPacket(netadr_t *evFrom, msg_t *buf);
 
+qboolean	Com_IsVoipTarget(uint8_t *voipTargets, int voipTargetsSize, int clientNum);
+
 void		Com_StartupVariable( const char *match );
 // checks for and removes command line "+set var arg" constructs
 // if match is NULL, all set commands will be executed, otherwise

Modified: trunk/code/server/server.h
===================================================================
--- trunk/code/server/server.h	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/server/server.h	2011-07-27 15:47:29 UTC (rev 2102)
@@ -43,6 +43,7 @@
 	int frames;
 	int len;
 	int sender;
+	int flags;
 	byte data[1024];
 } voipServerPacket_t;
 #endif
@@ -362,11 +363,7 @@
 int SV_SendDownloadMessages(void);
 int SV_SendQueuedMessages(void);
 
-#ifdef USE_VOIP
-void SV_WriteVoipToClient( client_t *cl, msg_t *msg );
-#endif
 
-
 //
 // sv_ccmds.c
 //

Modified: trunk/code/server/sv_client.c
===================================================================
--- trunk/code/server/sv_client.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/server/sv_client.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -1176,57 +1176,7 @@
 	return numDLs;
 }
 
-#ifdef USE_VOIP
 /*
-==================
-SV_WriteVoipToClient
-
-Check to see if there is any VoIP queued for a client, and send if there is.
-==================
-*/
-void SV_WriteVoipToClient( client_t *cl, msg_t *msg )
-{
-	if(*cl->downloadName)
-	{
-		cl->queuedVoipPackets = 0;
-		return;  // no VoIP allowed if download is going, to save bandwidth.
-	}
-
-	if(cl->queuedVoipPackets)
-	{
-		int totalbytes = 0;
-		int i;
-		voipServerPacket_t *packet;
-
-		// Write as many VoIP packets as we reasonably can...
-		for(i = cl->queuedVoipIndex; i < cl->queuedVoipPackets; i++)
-		{
-			packet = cl->voipPacket[i % ARRAY_LEN(cl->voipPacket)];
-			
-			totalbytes += packet->len;
-			if (totalbytes > (msg->maxsize - msg->cursize) / 2)
-				break;
-
-			MSG_WriteByte(msg, svc_voip);
-			MSG_WriteShort(msg, packet->sender);
-			MSG_WriteByte(msg, (byte) packet->generation);
-			MSG_WriteLong(msg, packet->sequence);
-			MSG_WriteByte(msg, packet->frames);
-			MSG_WriteShort(msg, packet->len);
-			MSG_WriteData(msg, packet->data, packet->len);
-			
-			Z_Free(packet);
-		}
-
-		cl->queuedVoipPackets -= i;
-		cl->queuedVoipIndex += i;
-		cl->queuedVoipIndex %= ARRAY_LEN(cl->voipPacket);
-	}
-}
-#endif
-
-
-/*
 =================
 SV_Disconnect_f
 
@@ -1800,8 +1750,15 @@
 
 
 #ifdef USE_VOIP
-static
-qboolean SV_ShouldIgnoreVoipSender(const client_t *cl)
+/*
+==================
+SV_ShouldIgnoreVoipSender
+
+Blocking of voip packets based on source client
+==================
+*/
+
+static qboolean SV_ShouldIgnoreVoipSender(const client_t *cl)
 {
 	if (!sv_voip->integer)
 		return qtrue;  // VoIP disabled on this server.
@@ -1814,34 +1771,26 @@
 }
 
 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);
+void SV_UserVoip(client_t *cl, msg_t *msg)
+{
+	int sender, generation, sequence, frames, packetsize;
+	uint8_t recips[(MAX_CLIENTS + 7) / 8];
+	int flags;
 	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));
+	flags = MSG_ReadByte(msg);
+	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;
@@ -1865,10 +1814,6 @@
 	// !!! 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)
@@ -1876,19 +1821,21 @@
 		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.
+			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) )
+
+		if(Com_IsVoipTarget(recips, sizeof(recips), i))
+			flags |= VOIP_DIRECT;
+		else
+			flags &= ~VOIP_DIRECT;
+
+		if (!(flags & (VOIP_SPATIAL | VOIP_DIRECT)))
 			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.
 		if (client->queuedVoipPackets >= ARRAY_LEN(client->voipPacket)) {
@@ -1902,6 +1849,7 @@
 		packet->len = packetsize;
 		packet->generation = generation;
 		packet->sequence = sequence;
+		packet->flags = flags;
 		memcpy(packet->data, encoded, packetsize);
 
 		client->voipPacket[(client->queuedVoipIndex + client->queuedVoipPackets) % ARRAY_LEN(client->voipPacket)] = packet;

Modified: trunk/code/server/sv_init.c
===================================================================
--- trunk/code/server/sv_init.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/server/sv_init.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -653,8 +653,8 @@
 	sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM );
 	sv_pure = Cvar_Get ("sv_pure", "1", CVAR_SYSTEMINFO );
 #ifdef USE_VOIP
-	sv_voip = Cvar_Get ("sv_voip", "1", CVAR_SYSTEMINFO | CVAR_LATCH);
-	Cvar_CheckRange( sv_voip, 0, 1, qtrue );
+	sv_voip = Cvar_Get("sv_voip", "1", CVAR_SYSTEMINFO | CVAR_LATCH);
+	Cvar_CheckRange(sv_voip, 0, 1, qtrue);
 #endif
 	Cvar_Get ("sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM );
 	Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );

Modified: trunk/code/server/sv_snapshot.c
===================================================================
--- trunk/code/server/sv_snapshot.c	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/code/server/sv_snapshot.c	2011-07-27 15:47:29 UTC (rev 2102)
@@ -521,7 +521,54 @@
 	}
 }
 
+#ifdef USE_VOIP
 /*
+==================
+SV_WriteVoipToClient
+
+Check to see if there is any VoIP queued for a client, and send if there is.
+==================
+*/
+static void SV_WriteVoipToClient(client_t *cl, msg_t *msg)
+{
+	int totalbytes = 0;
+	int i;
+	voipServerPacket_t *packet;
+
+	if(cl->queuedVoipPackets)
+	{
+		// Write as many VoIP packets as we reasonably can...
+		for(i = 0; i < cl->queuedVoipPackets; i++)
+		{
+			packet = cl->voipPacket[(i + cl->queuedVoipIndex) % ARRAY_LEN(cl->voipPacket)];
+
+			if(!*cl->downloadName)
+			{
+        			totalbytes += packet->len;
+	        		if (totalbytes > (msg->maxsize - msg->cursize) / 2)
+		        		break;
+
+        			MSG_WriteByte(msg, svc_voip);
+        			MSG_WriteShort(msg, packet->sender);
+	        		MSG_WriteByte(msg, (byte) packet->generation);
+		        	MSG_WriteLong(msg, packet->sequence);
+		        	MSG_WriteByte(msg, packet->frames);
+        			MSG_WriteShort(msg, packet->len);
+        			MSG_WriteBits(msg, packet->flags, VOIP_FLAGCNT);
+	        		MSG_WriteData(msg, packet->data, packet->len);
+                        }
+
+			Z_Free(packet);
+		}
+
+		cl->queuedVoipPackets -= i;
+		cl->queuedVoipIndex += i;
+		cl->queuedVoipIndex %= ARRAY_LEN(cl->voipPacket);
+	}
+}
+#endif
+
+/*
 =======================
 SV_SendMessageToClient
 
@@ -610,11 +657,11 @@
 		if(*c->downloadName)
 			continue;		// Client is downloading, don't send snapshots
 
-        	if(c->netchan.unsentFragments || c->netchan_start_queue)
-        	{
-        	        c->rateDelayed = qtrue;
+		if(c->netchan.unsentFragments || c->netchan_start_queue)
+		{
+			c->rateDelayed = qtrue;
 			continue;		// Drop this snapshot if the packet queue is still full or delta compression will break
-                }
+		}
 
 		if(!(c->netchan.remoteAddress.type == NA_LOOPBACK ||
 		     (sv_lanForceRate->integer && Sys_IsLANAddress(c->netchan.remoteAddress))))

Modified: trunk/voip-readme.txt
===================================================================
--- trunk/voip-readme.txt	2011-07-27 00:04:29 UTC (rev 2101)
+++ trunk/voip-readme.txt	2011-07-27 15:47:29 UTC (rev 2102)
@@ -49,9 +49,12 @@
 cl_voipSendTarget: a string: "all" to broadcast to everyone, "none" to send
                    to no one, "attacker" to send to the last person that hit
                    you, "crosshair" to send to the people currently in your
-                   crosshair, or a comma-separated list of client numbers, like
-                   "0,7,2,23" ... an empty string is treated like "all". This
-                   is reset to "all" when connecting to a new server.
+                   crosshair, "spatial" to talk to all people in hearing
+                   range or a comma-separated list of client numbers, like
+                   "0,7,2,23" ... an empty string is treated like "spatial".
+                   You can also use a mixed string like
+                   "0, spatial, 2, crosshair".
+                   This is reset to "spatial" when connecting to a new server.
                    Presumably mods will manage this cvar, not people, but
                    keybind could be useful for the general cases. To send to
                    just your team, or the opposing team, or a buddy list, you



More information about the quake3-commits mailing list