mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-11-21 19:41:17 +00:00
- 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
This commit is contained in:
parent
41ac8a232a
commit
2349148cf1
19 changed files with 403 additions and 241 deletions
|
@ -952,8 +952,8 @@ void CL_FirstSnapshot( void ) {
|
||||||
clc.speexInitialized = qtrue;
|
clc.speexInitialized = qtrue;
|
||||||
clc.voipMuteAll = qfalse;
|
clc.voipMuteAll = qfalse;
|
||||||
Cmd_AddCommand ("voip", CL_Voip_f);
|
Cmd_AddCommand ("voip", CL_Voip_f);
|
||||||
Cvar_Set("cl_voipSendTarget", "all");
|
Cvar_Set("cl_voipSendTarget", "spatial");
|
||||||
clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0x7FFFFFFF;
|
Com_Memset(clc.voipTargets, ~0, sizeof(clc.voipTargets));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1147,7 +1147,7 @@ redump:
|
||||||
case ZA_SOUND_MONO:
|
case ZA_SOUND_MONO:
|
||||||
if (!cinTable[currentHandle].silent) {
|
if (!cinTable[currentHandle].silent) {
|
||||||
ssize = RllDecodeMonoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
|
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;
|
break;
|
||||||
case ZA_SOUND_STEREO:
|
case ZA_SOUND_STEREO:
|
||||||
|
@ -1157,7 +1157,7 @@ redump:
|
||||||
s_rawend[0] = s_soundtime;
|
s_rawend[0] = s_soundtime;
|
||||||
}
|
}
|
||||||
ssize = RllDecodeStereoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
|
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;
|
break;
|
||||||
case ROQ_QUAD_INFO:
|
case ROQ_QUAD_INFO:
|
||||||
|
|
|
@ -799,83 +799,53 @@ void CL_WritePacket( void ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_VOIP
|
#ifdef USE_VOIP
|
||||||
if (clc.voipOutgoingDataSize > 0) { // only send if data.
|
if (clc.voipOutgoingDataSize > 0)
|
||||||
// Move cl_voipSendTarget from a string to the bitmasks if needed.
|
{
|
||||||
if (cl_voipSendTarget->modified) {
|
if((clc.voipFlags & VOIP_SPATIAL) || Com_IsVoipTarget(clc.voipTargets, sizeof(clc.voipTargets), -1))
|
||||||
char buffer[32];
|
{
|
||||||
const char *target = cl_voipSendTarget->string;
|
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) {
|
// If we're recording a demo, we have to fake a server packet with
|
||||||
int player = VM_Call( cgvm, CG_LAST_ATTACKER );
|
// this VoIP data so it gets to disk; the server doesn't send it
|
||||||
Com_sprintf(buffer, sizeof (buffer), "%d", player);
|
// back to us, and we might as well eliminate concerns about dropped
|
||||||
target = buffer;
|
// and misordered packets here.
|
||||||
} else if (Q_stricmp(target, "crosshair") == 0) {
|
if(clc.demorecording && !clc.demowaiting)
|
||||||
int player = VM_Call( cgvm, CG_CROSSHAIR_PLAYER );
|
{
|
||||||
Com_sprintf(buffer, sizeof (buffer), "%d", player);
|
const int voipSize = clc.voipOutgoingDataSize;
|
||||||
target = buffer;
|
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)) {
|
clc.voipOutgoingSequence += clc.voipOutgoingDataFrames;
|
||||||
const int all = 0x7FFFFFFF;
|
clc.voipOutgoingDataSize = 0;
|
||||||
clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = all;
|
clc.voipOutgoingDataFrames = 0;
|
||||||
} 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;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
MSG_WriteByte (&buf, clc_voip);
|
{
|
||||||
MSG_WriteByte (&buf, clc.voipOutgoingGeneration);
|
// We have data, but no targets. Silently discard all data
|
||||||
MSG_WriteLong (&buf, clc.voipOutgoingSequence);
|
clc.voipOutgoingDataSize = 0;
|
||||||
MSG_WriteByte (&buf, clc.voipOutgoingDataFrames);
|
clc.voipOutgoingDataFrames = 0;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
clc.voipOutgoingSequence += clc.voipOutgoingDataFrames;
|
|
||||||
clc.voipOutgoingDataSize = 0;
|
|
||||||
clc.voipOutgoingDataFrames = 0;
|
|
||||||
} else
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( count >= 1 ) {
|
if ( count >= 1 ) {
|
||||||
|
|
|
@ -291,6 +291,88 @@ void CL_VoipNewGeneration(void)
|
||||||
clc.voipOutgoingSequence = 0;
|
clc.voipOutgoingSequence = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
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
|
CL_CaptureVoip
|
||||||
|
@ -342,8 +424,9 @@ void CL_CaptureVoip(void)
|
||||||
|
|
||||||
cl_voipSend->modified = qfalse;
|
cl_voipSend->modified = qfalse;
|
||||||
|
|
||||||
if (dontCapture) {
|
if(dontCapture)
|
||||||
cl_voipSend->integer = 0;
|
{
|
||||||
|
Cvar_Set("cl_voipSend", "0");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,11 +445,12 @@ void CL_CaptureVoip(void)
|
||||||
S_MasterGain(cl_voipGainDuringCapture->value);
|
S_MasterGain(cl_voipGainDuringCapture->value);
|
||||||
S_StartCapture();
|
S_StartCapture();
|
||||||
CL_VoipNewGeneration();
|
CL_VoipNewGeneration();
|
||||||
|
CL_VoipParseTargets();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cl_voipSend->integer) || (finalFrame)) { // user wants to capture audio?
|
if ((cl_voipSend->integer) || (finalFrame)) { // user wants to capture audio?
|
||||||
int samples = S_AvailableCaptureSamples();
|
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?
|
// enough data buffered in audio hardware to process yet?
|
||||||
if (samples >= (clc.speexFrameSize * mult)) {
|
if (samples >= (clc.speexFrameSize * mult)) {
|
||||||
|
@ -378,8 +462,8 @@ void CL_CaptureVoip(void)
|
||||||
int wpos = 0;
|
int wpos = 0;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
||||||
if (samples > (clc.speexFrameSize * 12))
|
if (samples > (clc.speexFrameSize * 4))
|
||||||
samples = (clc.speexFrameSize * 12);
|
samples = (clc.speexFrameSize * 4);
|
||||||
|
|
||||||
// !!! FIXME: maybe separate recording from encoding, so voipPower
|
// !!! FIXME: maybe separate recording from encoding, so voipPower
|
||||||
// !!! FIXME: updates faster than 4Hz?
|
// !!! FIXME: updates faster than 4Hz?
|
||||||
|
@ -3420,7 +3504,7 @@ void CL_Init( void ) {
|
||||||
|
|
||||||
#ifdef USE_VOIP
|
#ifdef USE_VOIP
|
||||||
cl_voipSend = Cvar_Get ("cl_voipSend", "0", 0);
|
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_voipGainDuringCapture = Cvar_Get ("cl_voipGainDuringCapture", "0.2", CVAR_ARCHIVE);
|
||||||
cl_voipCaptureMult = Cvar_Get ("cl_voipCaptureMult", "2.0", CVAR_ARCHIVE);
|
cl_voipCaptureMult = Cvar_Get ("cl_voipCaptureMult", "2.0", CVAR_ARCHIVE);
|
||||||
cl_voipUseVAD = Cvar_Get ("cl_voipUseVAD", "0", CVAR_ARCHIVE);
|
cl_voipUseVAD = Cvar_Get ("cl_voipUseVAD", "0", CVAR_ARCHIVE);
|
||||||
|
|
|
@ -663,6 +663,29 @@ qboolean CL_ShouldIgnoreVoipSender(int sender)
|
||||||
return qfalse;
|
return qfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=====================
|
||||||
|
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
|
CL_ParseVoip
|
||||||
|
@ -679,6 +702,7 @@ void CL_ParseVoip ( msg_t *msg ) {
|
||||||
const int sequence = MSG_ReadLong(msg);
|
const int sequence = MSG_ReadLong(msg);
|
||||||
const int frames = MSG_ReadByte(msg);
|
const int frames = MSG_ReadByte(msg);
|
||||||
const int packetsize = MSG_ReadShort(msg);
|
const int packetsize = MSG_ReadShort(msg);
|
||||||
|
const int flags = MSG_ReadBits(msg, VOIP_FLAGCNT);
|
||||||
char encoded[1024];
|
char encoded[1024];
|
||||||
int seqdiff = sequence - clc.voipIncomingSequence[sender];
|
int seqdiff = sequence - clc.voipIncomingSequence[sender];
|
||||||
int written = 0;
|
int written = 0;
|
||||||
|
@ -769,8 +793,8 @@ void CL_ParseVoip ( msg_t *msg ) {
|
||||||
if ((written + clc.speexFrameSize) * 2 > sizeof (decoded)) {
|
if ((written + clc.speexFrameSize) * 2 > sizeof (decoded)) {
|
||||||
Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
|
Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
|
||||||
written * 2, written, i);
|
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;
|
written = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -793,10 +817,8 @@ void CL_ParseVoip ( msg_t *msg ) {
|
||||||
Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
|
Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
|
||||||
written * 2, written, i);
|
written * 2, written, i);
|
||||||
|
|
||||||
if (written > 0) {
|
if(written > 0)
|
||||||
S_RawSamples(sender + 1, written, clc.speexSampleRate, 2, 1,
|
CL_PlayVoip(sender, written, (const byte *) decoded, flags);
|
||||||
(const byte *) decoded, clc.voipGain[sender]);
|
|
||||||
}
|
|
||||||
|
|
||||||
clc.voipIncomingSequence[sender] = sequence + frames;
|
clc.voipIncomingSequence[sender] = sequence + frames;
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,9 +250,10 @@ typedef struct {
|
||||||
qboolean voipMuteAll;
|
qboolean voipMuteAll;
|
||||||
|
|
||||||
// outgoing data...
|
// outgoing data...
|
||||||
int voipTarget1; // these three ints make up a bit mask of 92 bits.
|
// if voipTargets[i / 8] & (1 << (i % 8)),
|
||||||
int voipTarget2; // the bits say who a VoIP pack is addressed to:
|
// then we are sending to clientnum i.
|
||||||
int voipTarget3; // (1 << clientnum). See cl_voipSendTarget cvar.
|
uint8_t voipTargets[(MAX_CLIENTS + 7) / 8];
|
||||||
|
uint8_t voipFlags;
|
||||||
SpeexPreprocessState *speexPreprocessor;
|
SpeexPreprocessState *speexPreprocessor;
|
||||||
SpeexBits speexEncoderBits;
|
SpeexBits speexEncoderBits;
|
||||||
void *speexEncoder;
|
void *speexEncoder;
|
||||||
|
|
|
@ -916,7 +916,8 @@ S_Base_RawSamples
|
||||||
Music streaming
|
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 i;
|
||||||
int src, dst;
|
int src, dst;
|
||||||
float scale;
|
float scale;
|
||||||
|
@ -927,9 +928,16 @@ void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_chan
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(entityNum >= 0)
|
||||||
|
{
|
||||||
|
// FIXME: support spatialized raw streams, e.g. for VoIP
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ( (stream < 0) || (stream >= MAX_RAW_STREAMS) ) {
|
if ( (stream < 0) || (stream >= MAX_RAW_STREAMS) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rawsamples = s_rawsamples[stream];
|
rawsamples = s_rawsamples[stream];
|
||||||
|
|
||||||
if(s_muted->integer)
|
if(s_muted->integer)
|
||||||
|
@ -1395,8 +1403,8 @@ void S_UpdateBackgroundTrack( void ) {
|
||||||
if(r > 0)
|
if(r > 0)
|
||||||
{
|
{
|
||||||
// add to raw buffer
|
// add to raw buffer
|
||||||
S_Base_RawSamples( 0, fileSamples, s_backgroundStream->info.rate,
|
S_Base_RawSamples(0, fileSamples, s_backgroundStream->info.rate,
|
||||||
s_backgroundStream->info.width, s_backgroundStream->info.channels, raw, s_musicVolume->value );
|
s_backgroundStream->info.width, s_backgroundStream->info.channels, raw, s_musicVolume->value, -1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -125,7 +125,7 @@ typedef struct
|
||||||
void (*StartLocalSound)( sfxHandle_t sfx, int channelNum );
|
void (*StartLocalSound)( sfxHandle_t sfx, int channelNum );
|
||||||
void (*StartBackgroundTrack)( const char *intro, const char *loop );
|
void (*StartBackgroundTrack)( const char *intro, const char *loop );
|
||||||
void (*StopBackgroundTrack)( void );
|
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 (*StopAllSounds)( void );
|
||||||
void (*ClearLoopingSounds)( qboolean killall );
|
void (*ClearLoopingSounds)( qboolean killall );
|
||||||
void (*AddLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
|
void (*AddLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
|
||||||
|
@ -186,7 +186,7 @@ extern vec3_t listener_up;
|
||||||
extern dma_t dma;
|
extern dma_t dma;
|
||||||
|
|
||||||
#define MAX_RAW_SAMPLES 16384
|
#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 portable_samplepair_t s_rawsamples[MAX_RAW_STREAMS][MAX_RAW_SAMPLES];
|
||||||
extern int s_rawend[MAX_RAW_STREAMS];
|
extern int s_rawend[MAX_RAW_STREAMS];
|
||||||
|
|
||||||
|
|
|
@ -129,11 +129,10 @@ S_RawSamples
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
void S_RawSamples (int stream, int samples, int rate, int width, int channels,
|
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 ) {
|
if(si.RawSamples)
|
||||||
si.RawSamples( stream, samples, rate, width, channels, data, volume );
|
si.RawSamples(stream, samples, rate, width, channels, data, volume, entityNum);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -521,6 +521,7 @@ typedef struct src_s
|
||||||
qboolean isLocked; // This is locked (un-allocatable)
|
qboolean isLocked; // This is locked (un-allocatable)
|
||||||
qboolean isLooping; // Is this a looping effect (attached to an entity)
|
qboolean isLooping; // Is this a looping effect (attached to an entity)
|
||||||
qboolean isTracking; // Is this object tracking its owner
|
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 curGain; // gain employed if source is within maxdistance.
|
||||||
float scaleGain; // Last gain value for this source. 0 if muted.
|
float scaleGain; // Last gain value for this source. 0 if muted.
|
||||||
|
@ -744,13 +745,8 @@ S_AL_SrcSetup
|
||||||
static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t priority,
|
static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t priority,
|
||||||
int entity, int channel, qboolean local)
|
int entity, int channel, qboolean local)
|
||||||
{
|
{
|
||||||
ALuint buffer;
|
|
||||||
src_t *curSource;
|
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
|
// Set up src struct
|
||||||
curSource = &srcList[src];
|
curSource = &srcList[src];
|
||||||
|
|
||||||
|
@ -763,12 +759,19 @@ static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t prio
|
||||||
curSource->isLocked = qfalse;
|
curSource->isLocked = qfalse;
|
||||||
curSource->isLooping = qfalse;
|
curSource->isLooping = qfalse;
|
||||||
curSource->isTracking = qfalse;
|
curSource->isTracking = qfalse;
|
||||||
|
curSource->isStream = qfalse;
|
||||||
curSource->curGain = s_alGain->value * s_volume->value;
|
curSource->curGain = s_alGain->value * s_volume->value;
|
||||||
curSource->scaleGain = curSource->curGain;
|
curSource->scaleGain = curSource->curGain;
|
||||||
curSource->local = local;
|
curSource->local = local;
|
||||||
|
|
||||||
// Set up OpenAL source
|
// 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);
|
qalSourcef(curSource->alSource, AL_PITCH, 1.0f);
|
||||||
S_AL_Gain(curSource->alSource, curSource->curGain);
|
S_AL_Gain(curSource->alSource, curSource->curGain);
|
||||||
qalSourcefv(curSource->alSource, AL_POSITION, vec3_origin);
|
qalSourcefv(curSource->alSource, AL_POSITION, vec3_origin);
|
||||||
|
@ -1320,7 +1323,7 @@ static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx,
|
||||||
VectorClear(sorigin);
|
VectorClear(sorigin);
|
||||||
|
|
||||||
qalSourcefv(curSource->alSource, AL_POSITION, sorigin);
|
qalSourcefv(curSource->alSource, AL_POSITION, sorigin);
|
||||||
qalSourcefv(curSource->alSource, AL_VELOCITY, sorigin);
|
qalSourcefv(curSource->alSource, AL_VELOCITY, vec3_origin);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1343,8 +1346,8 @@ static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx,
|
||||||
else
|
else
|
||||||
VectorClear(svelocity);
|
VectorClear(svelocity);
|
||||||
|
|
||||||
qalSourcefv( curSource->alSource, AL_POSITION, (ALfloat *)sorigin );
|
qalSourcefv(curSource->alSource, AL_POSITION, (ALfloat *) sorigin);
|
||||||
qalSourcefv( curSource->alSource, AL_VELOCITY, (ALfloat *)velocity );
|
qalSourcefv(curSource->alSource, AL_VELOCITY, (ALfloat *) svelocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1557,14 +1560,17 @@ void S_AL_SrcUpdate( void )
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's done, and flag it
|
if(!curSource->isStream)
|
||||||
qalGetSourcei(curSource->alSource, AL_SOURCE_STATE, &state);
|
|
||||||
if(state == AL_STOPPED)
|
|
||||||
{
|
{
|
||||||
curSource->isPlaying = qfalse;
|
// Check if it's done, and flag it
|
||||||
S_AL_SrcKill(i);
|
qalGetSourcei(curSource->alSource, AL_SOURCE_STATE, &state);
|
||||||
continue;
|
if(state == AL_STOPPED)
|
||||||
}
|
{
|
||||||
|
curSource->isPlaying = qfalse;
|
||||||
|
S_AL_SrcKill(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Query relativity of source, don't move if it's true
|
// Query relativity of source, don't move if it's true
|
||||||
qalGetSourcei(curSource->alSource, AL_SOURCE_RELATIVE, &state);
|
qalGetSourcei(curSource->alSource, AL_SOURCE_RELATIVE, &state);
|
||||||
|
@ -1614,32 +1620,57 @@ static ALuint streamSources[MAX_RAW_STREAMS];
|
||||||
S_AL_AllocateStreamChannel
|
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))
|
if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Allocate a streamSource at high priority
|
if(entityNum >= 0)
|
||||||
streamSourceHandles[stream] = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
|
{
|
||||||
if(streamSourceHandles[stream] == -1)
|
// This is a stream that tracks an entity
|
||||||
return;
|
// 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_SrcSetup(cursrc, -1, SRCPRI_ENTITY, entityNum, 0, qfalse);
|
||||||
S_AL_SrcLock(streamSourceHandles[stream]);
|
alsrc = S_AL_SrcGet(cursrc);
|
||||||
streamSources[stream] = S_AL_SrcGet(streamSourceHandles[stream]);
|
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
|
// Allocate a streamSource at high priority
|
||||||
// volume up prematurely for this source
|
cursrc = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
|
||||||
srcList[streamSourceHandles[stream]].scaleGain = 0.0f;
|
if(cursrc < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
// Set some streamSource parameters
|
alsrc = S_AL_SrcGet(cursrc);
|
||||||
qalSourcei (streamSources[stream], AL_BUFFER, 0 );
|
|
||||||
qalSourcei (streamSources[stream], AL_LOOPING, AL_FALSE );
|
// Lock the streamSource so nobody else can use it, and get the raw streamSource
|
||||||
qalSource3f(streamSources[stream], AL_POSITION, 0.0, 0.0, 0.0);
|
S_AL_SrcLock(cursrc);
|
||||||
qalSource3f(streamSources[stream], AL_VELOCITY, 0.0, 0.0, 0.0);
|
|
||||||
qalSource3f(streamSources[stream], AL_DIRECTION, 0.0, 0.0, 0.0);
|
// make sure that after unmuting the S_AL_Gain in S_Update() does not turn
|
||||||
qalSourcef (streamSources[stream], AL_ROLLOFF_FACTOR, 0.0 );
|
// volume up prematurely for this source
|
||||||
qalSourcei (streamSources[stream], AL_SOURCE_RELATIVE, AL_TRUE );
|
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 @@ static void S_AL_FreeStreamChannel( int stream )
|
||||||
|
|
||||||
// Release the output streamSource
|
// Release the output streamSource
|
||||||
S_AL_SrcUnlock(streamSourceHandles[stream]);
|
S_AL_SrcUnlock(streamSourceHandles[stream]);
|
||||||
|
S_AL_SrcKill(streamSourceHandles[stream]);
|
||||||
streamSources[stream] = 0;
|
streamSources[stream] = 0;
|
||||||
streamSourceHandles[stream] = -1;
|
streamSourceHandles[stream] = -1;
|
||||||
}
|
}
|
||||||
|
@ -1664,7 +1696,7 @@ S_AL_RawSamples
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
static
|
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 buffer;
|
||||||
ALuint format;
|
ALuint format;
|
||||||
|
@ -1677,7 +1709,7 @@ void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels,
|
||||||
// Create the streamSource if necessary
|
// Create the streamSource if necessary
|
||||||
if(streamSourceHandles[stream] == -1)
|
if(streamSourceHandles[stream] == -1)
|
||||||
{
|
{
|
||||||
S_AL_AllocateStreamChannel(stream);
|
S_AL_AllocateStreamChannel(stream, entityNum);
|
||||||
|
|
||||||
// Failed?
|
// Failed?
|
||||||
if(streamSourceHandles[stream] == -1)
|
if(streamSourceHandles[stream] == -1)
|
||||||
|
@ -1694,8 +1726,11 @@ void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels,
|
||||||
// Shove the data onto the streamSource
|
// Shove the data onto the streamSource
|
||||||
qalSourceQueueBuffers(streamSources[stream], 1, &buffer);
|
qalSourceQueueBuffers(streamSources[stream], 1, &buffer);
|
||||||
|
|
||||||
// Volume
|
if(entityNum < 0)
|
||||||
S_AL_Gain (streamSources[stream], volume * s_volume->value * s_alGain->value);
|
{
|
||||||
|
// Volume
|
||||||
|
S_AL_Gain (streamSources[stream], volume * s_volume->value * s_alGain->value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2106,7 +2141,6 @@ S_AL_Respatialize
|
||||||
static
|
static
|
||||||
void S_AL_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater )
|
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];
|
float orientation[6];
|
||||||
vec3_t sorigin;
|
vec3_t sorigin;
|
||||||
|
|
||||||
|
@ -2124,7 +2158,7 @@ void S_AL_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int
|
||||||
|
|
||||||
// Set OpenAL listener paramaters
|
// Set OpenAL listener paramaters
|
||||||
qalListenerfv(AL_POSITION, (ALfloat *)sorigin);
|
qalListenerfv(AL_POSITION, (ALfloat *)sorigin);
|
||||||
qalListenerfv(AL_VELOCITY, velocity);
|
qalListenerfv(AL_VELOCITY, vec3_origin);
|
||||||
qalListenerfv(AL_ORIENTATION, orientation);
|
qalListenerfv(AL_ORIENTATION, orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,8 @@ void S_StopBackgroundTrack( void );
|
||||||
|
|
||||||
// cinematics and voice-over-network will send raw samples
|
// cinematics and voice-over-network will send raw samples
|
||||||
// 1.0 volume will be direct output of source samples
|
// 1.0 volume will be direct output of source samples
|
||||||
void S_RawSamples (int stream, int samples, int rate, int width, int channels,
|
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);
|
||||||
|
|
||||||
// stop all sounds and the background track
|
// stop all sounds and the background track
|
||||||
void S_StopAllSounds( void );
|
void S_StopAllSounds( void );
|
||||||
|
|
|
@ -3585,3 +3585,33 @@ void Com_RandomBytes( byte *string, int len )
|
||||||
string[i] = (unsigned char)( rand() % 255 );
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -928,6 +928,23 @@ typedef struct {
|
||||||
char string[MAX_CVAR_VALUE_STRING];
|
char string[MAX_CVAR_VALUE_STRING];
|
||||||
} vmCvar_t;
|
} 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
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============================================================
|
==============================================================
|
||||||
|
|
||||||
|
|
|
@ -252,7 +252,7 @@ PROTOCOL
|
||||||
==============================================================
|
==============================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PROTOCOL_VERSION 70
|
#define PROTOCOL_VERSION 71
|
||||||
#define PROTOCOL_LEGACY_VERSION 68
|
#define PROTOCOL_LEGACY_VERSION 68
|
||||||
// 1.31 - 67
|
// 1.31 - 67
|
||||||
|
|
||||||
|
@ -834,6 +834,8 @@ int Com_RealTime(qtime_t *qtime);
|
||||||
qboolean Com_SafeMode( void );
|
qboolean Com_SafeMode( void );
|
||||||
void Com_RunAndTimeServerPacket(netadr_t *evFrom, msg_t *buf);
|
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 );
|
void Com_StartupVariable( const char *match );
|
||||||
// checks for and removes command line "+set var arg" constructs
|
// checks for and removes command line "+set var arg" constructs
|
||||||
// if match is NULL, all set commands will be executed, otherwise
|
// if match is NULL, all set commands will be executed, otherwise
|
||||||
|
|
|
@ -43,6 +43,7 @@ typedef struct voipServerPacket_s
|
||||||
int frames;
|
int frames;
|
||||||
int len;
|
int len;
|
||||||
int sender;
|
int sender;
|
||||||
|
int flags;
|
||||||
byte data[1024];
|
byte data[1024];
|
||||||
} voipServerPacket_t;
|
} voipServerPacket_t;
|
||||||
#endif
|
#endif
|
||||||
|
@ -362,10 +363,6 @@ int SV_WriteDownloadToClient(client_t *cl , msg_t *msg);
|
||||||
int SV_SendDownloadMessages(void);
|
int SV_SendDownloadMessages(void);
|
||||||
int SV_SendQueuedMessages(void);
|
int SV_SendQueuedMessages(void);
|
||||||
|
|
||||||
#ifdef USE_VOIP
|
|
||||||
void SV_WriteVoipToClient( client_t *cl, msg_t *msg );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// sv_ccmds.c
|
// sv_ccmds.c
|
||||||
|
|
|
@ -1176,56 +1176,6 @@ int SV_SendDownloadMessages(void)
|
||||||
return numDLs;
|
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
|
SV_Disconnect_f
|
||||||
|
@ -1800,8 +1750,15 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) {
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_VOIP
|
#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)
|
if (!sv_voip->integer)
|
||||||
return qtrue; // VoIP disabled on this server.
|
return qtrue; // VoIP disabled on this server.
|
||||||
|
@ -1814,33 +1771,25 @@ qboolean SV_ShouldIgnoreVoipSender(const client_t *cl)
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void SV_UserVoip( client_t *cl, msg_t *msg ) {
|
void SV_UserVoip(client_t *cl, msg_t *msg)
|
||||||
const int sender = (int) (cl - svs.clients);
|
{
|
||||||
const int generation = MSG_ReadByte(msg);
|
int sender, generation, sequence, frames, packetsize;
|
||||||
const int sequence = MSG_ReadLong(msg);
|
uint8_t recips[(MAX_CLIENTS + 7) / 8];
|
||||||
const int frames = MSG_ReadByte(msg);
|
int flags;
|
||||||
const int recip1 = MSG_ReadLong(msg);
|
|
||||||
const int recip2 = MSG_ReadLong(msg);
|
|
||||||
const int recip3 = MSG_ReadLong(msg);
|
|
||||||
const int packetsize = MSG_ReadShort(msg);
|
|
||||||
byte encoded[sizeof(cl->voipPacket[0]->data)];
|
byte encoded[sizeof(cl->voipPacket[0]->data)];
|
||||||
client_t *client = NULL;
|
client_t *client = NULL;
|
||||||
voipServerPacket_t *packet = NULL;
|
voipServerPacket_t *packet = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (generation < 0)
|
sender = cl - svs.clients;
|
||||||
return; // short/invalid packet, bail.
|
generation = MSG_ReadByte(msg);
|
||||||
else if (sequence < 0)
|
sequence = MSG_ReadLong(msg);
|
||||||
return; // short/invalid packet, bail.
|
frames = MSG_ReadByte(msg);
|
||||||
else if (frames < 0)
|
MSG_ReadData(msg, recips, sizeof(recips));
|
||||||
return; // short/invalid packet, bail.
|
flags = MSG_ReadByte(msg);
|
||||||
else if (recip1 < 0)
|
packetsize = MSG_ReadShort(msg);
|
||||||
return; // short/invalid packet, bail.
|
|
||||||
else if (recip2 < 0)
|
if (msg->readcount > msg->cursize)
|
||||||
return; // short/invalid packet, bail.
|
|
||||||
else if (recip3 < 0)
|
|
||||||
return; // short/invalid packet, bail.
|
|
||||||
else if (packetsize < 0)
|
|
||||||
return; // short/invalid packet, bail.
|
return; // short/invalid packet, bail.
|
||||||
|
|
||||||
if (packetsize > sizeof (encoded)) { // overlarge packet?
|
if (packetsize > sizeof (encoded)) { // overlarge packet?
|
||||||
|
@ -1865,10 +1814,6 @@ void SV_UserVoip( client_t *cl, msg_t *msg ) {
|
||||||
// !!! FIXME: reject if not speex narrowband codec.
|
// !!! FIXME: reject if not speex narrowband codec.
|
||||||
// !!! FIXME: decide if this is bogus data?
|
// !!! 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...
|
// decide who needs this VoIP packet sent to them...
|
||||||
for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {
|
for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {
|
||||||
if (client->state != CS_ACTIVE)
|
if (client->state != CS_ACTIVE)
|
||||||
|
@ -1876,18 +1821,20 @@ void SV_UserVoip( client_t *cl, msg_t *msg ) {
|
||||||
else if (i == sender)
|
else if (i == sender)
|
||||||
continue; // don't send voice packet back to original author.
|
continue; // don't send voice packet back to original author.
|
||||||
else if (!client->hasVoip)
|
else if (!client->hasVoip)
|
||||||
continue; // no VoIP support, or support disabled.
|
continue; // no VoIP support, or unsupported protocol
|
||||||
else if (client->muteAllVoip)
|
else if (client->muteAllVoip)
|
||||||
continue; // client is ignoring everyone.
|
continue; // client is ignoring everyone.
|
||||||
else if (client->ignoreVoipFromClient[sender])
|
else if (client->ignoreVoipFromClient[sender])
|
||||||
continue; // client is ignoring this talker.
|
continue; // client is ignoring this talker.
|
||||||
else if (*cl->downloadName) // !!! FIXME: possible to DoS?
|
else if (*cl->downloadName) // !!! FIXME: possible to DoS?
|
||||||
continue; // no VoIP allowed if downloading, to save bandwidth.
|
continue; // no VoIP allowed if downloading, to save bandwidth.
|
||||||
else if ( ((i >= 0) && (i < 31)) && ((recip1 & (1 << (i-0))) == 0) )
|
|
||||||
continue; // not addressed to this player.
|
if(Com_IsVoipTarget(recips, sizeof(recips), i))
|
||||||
else if ( ((i >= 31) && (i < 62)) && ((recip2 & (1 << (i-31))) == 0) )
|
flags |= VOIP_DIRECT;
|
||||||
continue; // not addressed to this player.
|
else
|
||||||
else if ( ((i >= 62) && (i < 93)) && ((recip3 & (1 << (i-62))) == 0) )
|
flags &= ~VOIP_DIRECT;
|
||||||
|
|
||||||
|
if (!(flags & (VOIP_SPATIAL | VOIP_DIRECT)))
|
||||||
continue; // not addressed to this player.
|
continue; // not addressed to this player.
|
||||||
|
|
||||||
// Transmit this packet to the client.
|
// Transmit this packet to the client.
|
||||||
|
@ -1902,6 +1849,7 @@ void SV_UserVoip( client_t *cl, msg_t *msg ) {
|
||||||
packet->len = packetsize;
|
packet->len = packetsize;
|
||||||
packet->generation = generation;
|
packet->generation = generation;
|
||||||
packet->sequence = sequence;
|
packet->sequence = sequence;
|
||||||
|
packet->flags = flags;
|
||||||
memcpy(packet->data, encoded, packetsize);
|
memcpy(packet->data, encoded, packetsize);
|
||||||
|
|
||||||
client->voipPacket[(client->queuedVoipIndex + client->queuedVoipPackets) % ARRAY_LEN(client->voipPacket)] = packet;
|
client->voipPacket[(client->queuedVoipIndex + client->queuedVoipPackets) % ARRAY_LEN(client->voipPacket)] = packet;
|
||||||
|
|
|
@ -653,8 +653,8 @@ void SV_Init (void)
|
||||||
sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM );
|
sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM );
|
||||||
sv_pure = Cvar_Get ("sv_pure", "1", CVAR_SYSTEMINFO );
|
sv_pure = Cvar_Get ("sv_pure", "1", CVAR_SYSTEMINFO );
|
||||||
#ifdef USE_VOIP
|
#ifdef USE_VOIP
|
||||||
sv_voip = Cvar_Get ("sv_voip", "1", CVAR_SYSTEMINFO | CVAR_LATCH);
|
sv_voip = Cvar_Get("sv_voip", "1", CVAR_SYSTEMINFO | CVAR_LATCH);
|
||||||
Cvar_CheckRange( sv_voip, 0, 1, qtrue );
|
Cvar_CheckRange(sv_voip, 0, 1, qtrue);
|
||||||
#endif
|
#endif
|
||||||
Cvar_Get ("sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM );
|
Cvar_Get ("sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM );
|
||||||
Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );
|
Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );
|
||||||
|
|
|
@ -521,6 +521,53 @@ static void SV_BuildClientSnapshot( client_t *client ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
SV_SendMessageToClient
|
||||||
|
@ -610,11 +657,11 @@ void SV_SendClientMessages(void)
|
||||||
if(*c->downloadName)
|
if(*c->downloadName)
|
||||||
continue; // Client is downloading, don't send snapshots
|
continue; // Client is downloading, don't send snapshots
|
||||||
|
|
||||||
if(c->netchan.unsentFragments || c->netchan_start_queue)
|
if(c->netchan.unsentFragments || c->netchan_start_queue)
|
||||||
{
|
{
|
||||||
c->rateDelayed = qtrue;
|
c->rateDelayed = qtrue;
|
||||||
continue; // Drop this snapshot if the packet queue is still full or delta compression will break
|
continue; // Drop this snapshot if the packet queue is still full or delta compression will break
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(c->netchan.remoteAddress.type == NA_LOOPBACK ||
|
if(!(c->netchan.remoteAddress.type == NA_LOOPBACK ||
|
||||||
(sv_lanForceRate->integer && Sys_IsLANAddress(c->netchan.remoteAddress))))
|
(sv_lanForceRate->integer && Sys_IsLANAddress(c->netchan.remoteAddress))))
|
||||||
|
|
|
@ -49,9 +49,12 @@ s_alCapture: set to "1" (the default) to have the audio layer open an OpenAL
|
||||||
cl_voipSendTarget: a string: "all" to broadcast to everyone, "none" to send
|
cl_voipSendTarget: a string: "all" to broadcast to everyone, "none" to send
|
||||||
to no one, "attacker" to send to the last person that hit
|
to no one, "attacker" to send to the last person that hit
|
||||||
you, "crosshair" to send to the people currently in your
|
you, "crosshair" to send to the people currently in your
|
||||||
crosshair, or a comma-separated list of client numbers, like
|
crosshair, "spatial" to talk to all people in hearing
|
||||||
"0,7,2,23" ... an empty string is treated like "all". This
|
range or a comma-separated list of client numbers, like
|
||||||
is reset to "all" when connecting to a new server.
|
"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
|
Presumably mods will manage this cvar, not people, but
|
||||||
keybind could be useful for the general cases. To send to
|
keybind could be useful for the general cases. To send to
|
||||||
just your team, or the opposing team, or a buddy list, you
|
just your team, or the opposing team, or a buddy list, you
|
||||||
|
|
Loading…
Reference in a new issue