Voice activation detection for voicechat, with a few cvars for it.

Added mic level indicator.
Able to record voice into mvds.
Fixed mvd recording.
Fixed mvd player sizes.
Fixed interpolation.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3665 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2010-11-20 22:01:16 +00:00
parent 4d145039d2
commit 540830d955
20 changed files with 488 additions and 234 deletions

View File

@ -2330,7 +2330,7 @@ void CL_ParsePlayerinfo (void)
state->weaponframe = MSG_ReadByte (); state->weaponframe = MSG_ReadByte ();
state->hullnum = 1; state->hullnum = 1;
state->scale = 1*16; state->scale = 1;
state->alpha = 255; state->alpha = 255;
state->fatness = 0; state->fatness = 0;

View File

@ -1460,14 +1460,6 @@ void CL_SendCmd (double frametime, qboolean mainloop)
curtime = Sys_DoubleTime(); curtime = Sys_DoubleTime();
frametime = curtime - lasttime; frametime = curtime - lasttime;
lasttime = curtime; lasttime = curtime;
/* for (plnum = 0; plnum < cl.splitclients; plnum++)
{
CL_AdjustAngles(plnum, frametime);
IN_Move(mousemovements[plnum], plnum);
}
return;
*/
} }
CL_ProxyMenuHooks(); CL_ProxyMenuHooks();
@ -1492,7 +1484,11 @@ void CL_SendCmd (double frametime, qboolean mainloop)
cmd = &cl.frames[i].cmd[0]; cmd = &cl.frames[i].cmd[0];
memset(cmd, 0, sizeof(*cmd)); memset(cmd, 0, sizeof(*cmd));
cmd->msec = frametime*1000; msecs += frametime*1000;
if (msecs > 50)
msecs = 50;
cmd->msec = msecs;
msecs -= cmd->msec;
independantphysics[0].msec = 0; independantphysics[0].msec = 0;
CL_AdjustAngles (plnum, frametime); CL_AdjustAngles (plnum, frametime);
@ -1510,7 +1506,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
if (cl.spectator) if (cl.spectator)
Cam_Track(plnum, cmd); Cam_Track(plnum, cmd);
CL_FinishMove(cmd, (int)(frametime*1000), plnum); CL_FinishMove(cmd, cmd->msec, plnum);
Cam_FinishMove(plnum, cmd); Cam_FinishMove(plnum, cmd);
} }
@ -1770,7 +1766,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
#ifdef PEXT2_VOICECHAT #ifdef PEXT2_VOICECHAT
if (cls.fteprotocolextensions2 & PEXT2_VOICECHAT) if (cls.fteprotocolextensions2 & PEXT2_VOICECHAT)
S_TransmitVoiceChat(clc_voicechat, &buf); S_Voip_Transmit(clc_voicechat, &buf);
#endif #endif
// //

View File

@ -4967,7 +4967,7 @@ void CL_ParseServerMessage (void)
#ifdef PEXT2_VOICECHAT #ifdef PEXT2_VOICECHAT
case svcfte_voicechat: case svcfte_voicechat:
S_ParseVoiceChat(); S_Voip_Parse();
break; break;
#endif #endif

View File

@ -823,7 +823,7 @@ void CL_PredictMovePNum (int pnum)
} }
if (((cl_nopred.value && cls.demoplayback!=DPB_MVD && cls.demoplayback != DPB_EZTV)|| cl.fixangle)) if (((cl_nopred.value && cls.demoplayback!=DPB_MVD && cls.demoplayback != DPB_EZTV)|| cl.fixangle[pnum]))
{ {
fixedorg: fixedorg:
VectorCopy (vel, cl.simvel[pnum]); VectorCopy (vel, cl.simvel[pnum]);

View File

@ -2204,6 +2204,49 @@ qboolean Sbar_UpdateTeamStatus(player_info_t *player, char *status)
return false; return false;
} }
static void Sbar_Voice(int y)
{
#ifdef VOICECHAT
char st[64];
int loudness;
if (!cl_voip_showmeter.ival)
return;
loudness = S_Voip_Loudness(cl_voip_showmeter.ival==2);
if (loudness >= 0)
{
int x=0,t;
int s, i;
float range = loudness/100.0f;
Font_BeginString(font_conchar, x, y, &t, &t);
x = vid.width;
x -= Font_CharWidth(0xe080 | CON_WHITEMASK);
x -= Font_CharWidth(0xe081 | CON_WHITEMASK)*16;
x -= Font_CharWidth(0xe082 | CON_WHITEMASK);
x /= 2;
x -= Font_CharWidth('M' | CON_WHITEMASK);
x -= Font_CharWidth('i' | CON_WHITEMASK);
x -= Font_CharWidth('c' | CON_WHITEMASK);
x -= Font_CharWidth(' ' | CON_WHITEMASK);
y = sbar_rect.y + y+ sbar_rect.height-SBAR_HEIGHT;
Font_BeginString(font_conchar, x, y, &x, &y);
x = Font_DrawChar(x, y, 'M' | CON_WHITEMASK);
x = Font_DrawChar(x, y, 'i' | CON_WHITEMASK);
x = Font_DrawChar(x, y, 'c' | CON_WHITEMASK);
x = Font_DrawChar(x, y, ' ' | CON_WHITEMASK);
x = Font_DrawChar(x, y, 0xe080 | CON_WHITEMASK);
s = x;
for (i=0 ; i<16 ; i++)
x = Font_DrawChar(x, y, 0xe081 | CON_WHITEMASK);
Font_DrawChar(x, y, 0xe082 | CON_WHITEMASK);
Font_DrawChar(s + (x-s) * range - Font_CharWidth(0xe083 | CON_WHITEMASK)/2, y, 0xe083 | CON_WHITEMASK);
Font_EndString(font_conchar);
}
#endif
}
/* /*
=============== ===============
Sbar_Draw Sbar_Draw
@ -2297,6 +2340,8 @@ void Sbar_Draw (void)
Sbar_DrawString (0, -8, va("Health: %i", cl.stats[pnum][STAT_HEALTH])); Sbar_DrawString (0, -8, va("Health: %i", cl.stats[pnum][STAT_HEALTH]));
Sbar_DrawString (0, -16, va(" Armor: %i", cl.stats[pnum][STAT_ARMOR])); Sbar_DrawString (0, -16, va(" Armor: %i", cl.stats[pnum][STAT_ARMOR]));
Sbar_Voice(-24);
continue; continue;
} }
@ -2352,6 +2397,13 @@ void Sbar_Draw (void)
else else
Sbar_DrawNormal (pnum); Sbar_DrawNormal (pnum);
} }
if (sb_lines > 24)
Sbar_Voice(-32);
else if (sb_lines > 0)
Sbar_Voice(-8);
else
Sbar_Voice(16);
} }
#ifdef GLQUAKE #ifdef GLQUAKE
@ -2790,7 +2842,9 @@ if (showcolumns & (1<<COLUMN##title)) \
// Electro's scoreboard eyecandy: red vs blue are common teams, force the colours // Electro's scoreboard eyecandy: red vs blue are common teams, force the colours
Q_strncpyz (team, Info_ValueForKey(s->userinfo, "team"), sizeof(team)); Q_strncpyz (team, Info_ValueForKey(s->userinfo, "team"), sizeof(team));
if (!(strcmp("red", team))) if (S_Voip_Speaking(k))
background_color = 0x00ff00;
else if (!(strcmp("red", team)))
background_color = 4; // forced red background_color = 4; // forced red
else if (!(strcmp("blue", team))) else if (!(strcmp("blue", team)))
background_color = 13; // forced blue background_color = 13; // forced blue
@ -2799,6 +2853,8 @@ if (showcolumns & (1<<COLUMN##title)) \
Sbar_FillPCDark (startx - 2, y, rank_width - 3, skip, background_color); Sbar_FillPCDark (startx - 2, y, rank_width - 3, skip, background_color);
} }
else if (S_Voip_Speaking(k))
Sbar_FillPCDark (startx - 2, y, rank_width - 3, skip, 0x00ff00);
else else
Draw_Fill (startx - 2, y, rank_width - 3, skip, 2); Draw_Fill (startx - 2, y, rank_width - 3, skip, 2);

View File

@ -893,24 +893,26 @@ int (*pDSOUND_InitCard) (soundcardinfo_t *sc, int cardnum) = &DSOUND_InitCard;
#if defined(VOICECHAT) && defined(AVAIL_DSOUND) && !defined(__MINGW32__) #if defined(VOICECHAT) && defined(AVAIL_DSOUND) && !defined(__MINGW32__)
typedef struct
LPDIRECTSOUNDCAPTURE DSCapture;
LPDIRECTSOUNDCAPTUREBUFFER DSCaptureBuffer;
long lastreadpos;
long bufferbytes = 1024*1024;
long inputwidth = 2;
static WAVEFORMATEX wfxFormat;
qboolean SNDDMA_InitCapture (void)
{ {
DWORD capturePos; LPDIRECTSOUNDCAPTURE DSCapture;
LPDIRECTSOUNDCAPTUREBUFFER DSCaptureBuffer;
long lastreadpos;
} dsndcapture_t;
const long bufferbytes = 1024*1024;
const long inputwidth = 2;
void *DSOUND_Capture_Init (int rate)
{
dsndcapture_t *result;
DSCBUFFERDESC bufdesc; DSCBUFFERDESC bufdesc;
WAVEFORMATEX wfxFormat;
wfxFormat.wFormatTag = WAVE_FORMAT_PCM; wfxFormat.wFormatTag = WAVE_FORMAT_PCM;
wfxFormat.nChannels = 1; wfxFormat.nChannels = 1;
wfxFormat.nSamplesPerSec = 11025; wfxFormat.nSamplesPerSec = rate;
wfxFormat.wBitsPerSample = 8*inputwidth; wfxFormat.wBitsPerSample = 8*inputwidth;
wfxFormat.nBlockAlign = wfxFormat.nChannels * (wfxFormat.wBitsPerSample / 8); wfxFormat.nBlockAlign = wfxFormat.nChannels * (wfxFormat.wBitsPerSample / 8);
wfxFormat.nAvgBytesPerSec = wfxFormat.nSamplesPerSec * wfxFormat.nBlockAlign; wfxFormat.nAvgBytesPerSec = wfxFormat.nSamplesPerSec * wfxFormat.nBlockAlign;
@ -922,19 +924,7 @@ qboolean SNDDMA_InitCapture (void)
bufdesc.dwReserved = 0; bufdesc.dwReserved = 0;
bufdesc.lpwfxFormat = &wfxFormat; bufdesc.lpwfxFormat = &wfxFormat;
if (DSCaptureBuffer) /*probably already inited*/
{
IDirectSoundCaptureBuffer_Stop(DSCaptureBuffer);
IDirectSoundCaptureBuffer_Release(DSCaptureBuffer);
DSCaptureBuffer=NULL;
}
if (DSCapture)
{
IDirectSoundCapture_Release(DSCapture);
DSCapture=NULL;
}
if (!hInstDS) if (!hInstDS)
{ {
hInstDS = LoadLibrary("dsound.dll"); hInstDS = LoadLibrary("dsound.dll");
@ -942,10 +932,10 @@ qboolean SNDDMA_InitCapture (void)
if (hInstDS == NULL) if (hInstDS == NULL)
{ {
Con_SafePrintf ("Couldn't load dsound.dll\n"); Con_SafePrintf ("Couldn't load dsound.dll\n");
return false; return NULL;
} }
} }
/*global pointer, used only in this function*/
if (!pDirectSoundCaptureCreate) if (!pDirectSoundCaptureCreate)
{ {
pDirectSoundCaptureCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCaptureCreate"); pDirectSoundCaptureCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCaptureCreate");
@ -953,31 +943,61 @@ qboolean SNDDMA_InitCapture (void)
if (!pDirectSoundCaptureCreate) if (!pDirectSoundCaptureCreate)
{ {
Con_SafePrintf ("Couldn't get DS proc addr\n"); Con_SafePrintf ("Couldn't get DS proc addr\n");
return false; return NULL;
} }
// pDirectSoundCaptureEnumerate = (void *)GetProcAddress(hInstDS,"DirectSoundCaptureEnumerateA"); // pDirectSoundCaptureEnumerate = (void *)GetProcAddress(hInstDS,"DirectSoundCaptureEnumerateA");
} }
pDirectSoundCaptureCreate(NULL, &DSCapture, NULL);
if (FAILED(IDirectSoundCapture_CreateCaptureBuffer(DSCapture, &bufdesc, &DSCaptureBuffer, NULL))) result = Z_Malloc(sizeof(*result));
if (!FAILED(pDirectSoundCaptureCreate(NULL, &result->DSCapture, NULL)))
{ {
if (!FAILED(IDirectSoundCapture_CreateCaptureBuffer(result->DSCapture, &bufdesc, &result->DSCaptureBuffer, NULL)))
{
return result;
}
IDirectSoundCapture_Release(result->DSCapture);
Con_SafePrintf ("Couldn't create a capture buffer\n"); Con_SafePrintf ("Couldn't create a capture buffer\n");
IDirectSoundCapture_Release(DSCapture);
DSCapture=NULL;
return false;
} }
Z_Free(result);
return NULL;
}
IDirectSoundCaptureBuffer_Start(DSCaptureBuffer, DSBPLAY_LOOPING); void DSOUND_Capture_Start(void *ctx)
{
DWORD capturePos;
dsndcapture_t *c = ctx;
IDirectSoundCaptureBuffer_Start(c->DSCaptureBuffer, DSBPLAY_LOOPING);
lastreadpos = 0; c->lastreadpos = 0;
IDirectSoundCaptureBuffer_GetCurrentPosition(DSCaptureBuffer, &capturePos, &lastreadpos); IDirectSoundCaptureBuffer_GetCurrentPosition(c->DSCaptureBuffer, &capturePos, &c->lastreadpos);
return true; }
void DSOUND_Capture_Stop(void *ctx)
{
dsndcapture_t *c = ctx;
IDirectSoundCaptureBuffer_Stop(c->DSCaptureBuffer);
}
void DSOUND_Capture_Shutdown(void *ctx)
{
dsndcapture_t *c = ctx;
if (c->DSCaptureBuffer)
{
IDirectSoundCaptureBuffer_Stop(c->DSCaptureBuffer);
IDirectSoundCaptureBuffer_Release(c->DSCaptureBuffer);
}
if (c->DSCapture)
{
IDirectSoundCapture_Release(c->DSCapture);
}
Z_Free(ctx);
} }
/*minsamples is a hint*/ /*minsamples is a hint*/
unsigned int DSOUND_UpdateCapture(qboolean enable, unsigned char *buffer, unsigned int minbytes, unsigned int maxbytes) unsigned int DSOUND_Capture_Update(void *ctx, unsigned char *buffer, unsigned int minbytes, unsigned int maxbytes)
{ {
dsndcapture_t *c = ctx;
HRESULT hr; HRESULT hr;
LPBYTE lpbuf1 = NULL; LPBYTE lpbuf1 = NULL;
LPBYTE lpbuf2 = NULL; LPBYTE lpbuf2 = NULL;
@ -988,35 +1008,15 @@ unsigned int DSOUND_UpdateCapture(qboolean enable, unsigned char *buffer, unsign
DWORD readPos; DWORD readPos;
long filled; long filled;
if (!enable)
{
if (DSCaptureBuffer)
{
IDirectSoundCaptureBuffer_Stop(DSCaptureBuffer);
IDirectSoundCaptureBuffer_Release(DSCaptureBuffer);
DSCaptureBuffer=NULL;
}
if (DSCapture)
{
IDirectSoundCapture_Release(DSCapture);
DSCapture=NULL;
}
return 0;
}
else if (!DSCaptureBuffer)
{
SNDDMA_InitCapture();
return 0;
}
// Query to see how much data is in buffer. // Query to see how much data is in buffer.
hr = IDirectSoundCaptureBuffer_GetCurrentPosition( DSCaptureBuffer, &capturePos, &readPos ); hr = IDirectSoundCaptureBuffer_GetCurrentPosition(c->DSCaptureBuffer, &capturePos, &readPos);
if( hr != DS_OK ) if (hr != DS_OK)
{ {
return 0; return 0;
} }
filled = readPos - lastreadpos; filled = readPos - c->lastreadpos;
if( filled < 0 ) filled += bufferbytes; // unwrap offset if (filled < 0)
filled += bufferbytes; // unwrap offset
if (filled > maxbytes) //figure out how much we need to empty it by, and if that's enough to be worthwhile. if (filled > maxbytes) //figure out how much we need to empty it by, and if that's enough to be worthwhile.
filled = maxbytes; filled = maxbytes;
@ -1027,7 +1027,7 @@ unsigned int DSOUND_UpdateCapture(qboolean enable, unsigned char *buffer, unsign
// filled *= inputwidth; // filled *= inputwidth;
// Lock free space in the DS // Lock free space in the DS
hr = IDirectSoundCaptureBuffer_Lock(DSCaptureBuffer, lastreadpos, filled, (void **) &lpbuf1, &dwsize1, (void **) &lpbuf2, &dwsize2, 0); hr = IDirectSoundCaptureBuffer_Lock(c->DSCaptureBuffer, c->lastreadpos, filled, (void **) &lpbuf1, &dwsize1, (void **) &lpbuf2, &dwsize2, 0);
if (hr == DS_OK) if (hr == DS_OK)
{ {
// Copy from DS to the buffer // Copy from DS to the buffer
@ -1037,8 +1037,8 @@ unsigned int DSOUND_UpdateCapture(qboolean enable, unsigned char *buffer, unsign
memcpy(buffer+dwsize1, lpbuf2, dwsize2); memcpy(buffer+dwsize1, lpbuf2, dwsize2);
} }
// Update our buffer offset and unlock sound buffer // Update our buffer offset and unlock sound buffer
lastreadpos = (lastreadpos + dwsize1 + dwsize2) % bufferbytes; c->lastreadpos = (c->lastreadpos + dwsize1 + dwsize2) % bufferbytes;
IDirectSoundCaptureBuffer_Unlock(DSCaptureBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); IDirectSoundCaptureBuffer_Unlock(c->DSCaptureBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
} }
else else
{ {
@ -1046,5 +1046,12 @@ unsigned int DSOUND_UpdateCapture(qboolean enable, unsigned char *buffer, unsign
} }
return filled; return filled;
} }
unsigned int (*pDSOUND_UpdateCapture) (qboolean enable, unsigned char *buffer, unsigned int minbytes, unsigned int maxbytes) = &DSOUND_UpdateCapture; snd_capture_driver_t DSOUND_Capture =
{
DSOUND_Capture_Init,
DSOUND_Capture_Start,
DSOUND_Capture_Update,
DSOUND_Capture_Stop,
DSOUND_Capture_Shutdown
};
#endif #endif

View File

@ -82,7 +82,7 @@ cvar_t snd_khz = CVARAF( "s_khz", "11",
"snd_khz", CVAR_ARCHIVE); "snd_khz", CVAR_ARCHIVE);
cvar_t snd_inactive = CVARAF( "s_inactive", "0", cvar_t snd_inactive = CVARAF( "s_inactive", "0",
"snd_inactive", 0); //set if you want sound even when tabbed out. "snd_inactive", 0); //set if you want sound even when tabbed out.
cvar_t _snd_mixahead = CVARAF( "s_mixahead", "0.2", cvar_t _snd_mixahead = CVARAF( "s_mixahead", "0.08",
"_snd_mixahead", CVAR_ARCHIVE); "_snd_mixahead", CVAR_ARCHIVE);
cvar_t snd_leftisright = CVARAF( "s_swapstereo", "0", cvar_t snd_leftisright = CVARAF( "s_swapstereo", "0",
"snd_leftisright", CVAR_ARCHIVE); "snd_leftisright", CVAR_ARCHIVE);
@ -107,9 +107,14 @@ cvar_t snd_usemultipledevices = CVARAF( "s_multipledevices", "0",
#ifdef VOICECHAT #ifdef VOICECHAT
static void S_Voip_Play_Callback(cvar_t *var, char *oldval); static void S_Voip_Play_Callback(cvar_t *var, char *oldval);
cvar_t cl_voip_send = CVAR("cl_voip_send", "0"); cvar_t cl_voip_send = CVARD("cl_voip_send", "0", "Sends voice-over-ip data to the server whenever it is set");
cvar_t cl_voip_play = CVARC("cl_voip_play", "1", S_Voip_Play_Callback); cvar_t cl_voip_vad_threshhold = CVARD("cl_voip_vad_threshhold", "15", "This is the threshhold for voice-activation-detection when sending voip data");
cvar_t cl_voip_micamp = CVAR("cl_voip_micamp", "2"); cvar_t cl_voip_vad_delay = CVARD("cl_voip_vad_delay", "0.3", "Keeps sending voice data for this many seconds after voice activation would normally stop");
cvar_t cl_voip_capturingvol = CVARD("cl_voip_capturingvol", "0.5", "Volume multiplier applied while capturing, to avoid your audio from being heard by others");
cvar_t cl_voip_showmeter = CVARD("cl_voip_showmeter", "1", "Shows your speach volume above the hud. 0=hide, 1=show when transmitting, 2=ignore voice-activation disable");
cvar_t cl_voip_play = CVARCD("cl_voip_play", "1", S_Voip_Play_Callback, "Enables voip playback.");
cvar_t cl_voip_micamp = CVARD("cl_voip_micamp", "2", "Amplifies your microphone when using voip.");
#endif #endif
extern vfsfile_t *rawwritefile; extern vfsfile_t *rawwritefile;
@ -175,8 +180,22 @@ static struct
SpeexBits decbits[MAX_CLIENTS]; SpeexBits decbits[MAX_CLIENTS];
void *decoder[MAX_CLIENTS]; void *decoder[MAX_CLIENTS];
unsigned char decseq[MAX_CLIENTS]; unsigned char decseq[MAX_CLIENTS]; /*sender's sequence, to detect+cover minor packetloss*/
float decamp[MAX_CLIENTS]; unsigned char decgen[MAX_CLIENTS]; /*last generation. if it changes, we flush speex to reset packet loss*/
float decamp[MAX_CLIENTS]; /*amplify them by this*/
float lastspoke[MAX_CLIENTS]; /*time when they're no longer considered talking. if future, they're talking*/
unsigned char capturebuf[32768]; /*pending data*/
unsigned int capturepos;/*amount of pending data*/
unsigned int encsequence;/*the outgoing sequence count*/
unsigned int generation;/*incremented whenever capture is restarted*/
qboolean wantsend; /*set if we're capturing data to send*/
float voiplevel; /*your own voice level*/
unsigned int dumps; /*trigger a new generation thing after a bit*/
unsigned int keeps; /*for vad_delay*/
snd_capture_driver_t *driver;/*capture driver's functions*/
void *driverctx; /*capture driver context*/
} s_speex; } s_speex;
static const SpeexMode *(VARGS *qspeex_lib_get_mode)(int mode); static const SpeexMode *(VARGS *qspeex_lib_get_mode)(int mode);
@ -222,6 +241,8 @@ static dllfunction_t qspeexdspfuncs[] =
{NULL} {NULL}
}; };
snd_capture_driver_t DSOUND_Capture;
static qboolean S_Speex_Init(void) static qboolean S_Speex_Init(void)
{ {
int i; int i;
@ -254,6 +275,8 @@ static qboolean S_Speex_Init(void)
qspeex_encoder_ctl(s_speex.encoder, SPEEX_GET_FRAME_SIZE, &s_speex.framesize); qspeex_encoder_ctl(s_speex.encoder, SPEEX_GET_FRAME_SIZE, &s_speex.framesize);
qspeex_encoder_ctl(s_speex.encoder, SPEEX_GET_SAMPLING_RATE, &s_speex.samplerate); qspeex_encoder_ctl(s_speex.encoder, SPEEX_GET_SAMPLING_RATE, &s_speex.samplerate);
s_speex.samplerate = 11025;
qspeex_encoder_ctl(s_speex.encoder, SPEEX_SET_SAMPLING_RATE, &s_speex.samplerate);
s_speex.preproc = qspeex_preprocess_state_init(s_speex.framesize, s_speex.samplerate); s_speex.preproc = qspeex_preprocess_state_init(s_speex.framesize, s_speex.samplerate);
@ -274,19 +297,22 @@ static qboolean S_Speex_Init(void)
return s_speex.loaded; return s_speex.loaded;
} }
void S_ParseVoiceChat(void) void S_Voip_Parse(void)
{ {
unsigned int sender = MSG_ReadByte(); unsigned int sender;
int bytes; int bytes;
unsigned char data[1024], *start; unsigned char data[1024], *start;
short decodebuf[1024]; short decodebuf[1024];
unsigned int decodesamps, len, newseq, drops; unsigned int decodesamps, len, newseq, drops;
unsigned char seq; unsigned char seq, gen;
float amp = 1; float amp = 1;
unsigned int i; unsigned int i;
sender = MSG_ReadByte();
gen = MSG_ReadByte();
seq = MSG_ReadByte(); seq = MSG_ReadByte();
bytes = MSG_ReadShort(); bytes = MSG_ReadShort();
if (bytes > sizeof(data) || !cl_voip_play.ival) if (bytes > sizeof(data) || !cl_voip_play.ival || !S_Speex_Init() || (sender & 0xc0))
{ {
MSG_ReadSkip(bytes); MSG_ReadSkip(bytes);
return; return;
@ -301,11 +327,20 @@ void S_ParseVoiceChat(void)
newseq = 0; newseq = 0;
drops = 0; drops = 0;
start = data; start = data;
s_speex.lastspoke[sender] = realtime + 0.5;
if (s_speex.decgen[sender] != gen)
{
qspeex_bits_reset(&s_speex.decbits[sender]);
s_speex.decgen[sender] = gen;
s_speex.decseq[sender] = seq;
}
while (bytes > 0) while (bytes > 0)
{ {
if (decodesamps + s_speex.framesize > sizeof(decodebuf)/sizeof(decodebuf[0])) if (decodesamps + s_speex.framesize > sizeof(decodebuf)/sizeof(decodebuf[0]))
{ {
S_RawAudio(sender, (qbyte*)decodebuf, 11025, decodesamps, 1, 2); S_RawAudio(sender, (qbyte*)decodebuf, s_speex.samplerate, decodesamps, 1, 2);
decodesamps = 0; decodesamps = 0;
} }
@ -338,88 +373,191 @@ void S_ParseVoiceChat(void)
Con_DPrintf("%i dropped audio frames\n", drops); Con_DPrintf("%i dropped audio frames\n", drops);
if (decodesamps > 0) if (decodesamps > 0)
S_RawAudio(sender, (qbyte*)decodebuf, 11025, decodesamps, 1, 2); S_RawAudio(sender, (qbyte*)decodebuf, s_speex.samplerate, decodesamps, 1, 2);
} }
unsigned int (*pDSOUND_UpdateCapture) (qboolean enable, unsigned char *buffer, unsigned int minbytes, unsigned int maxbytes); void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf)
void S_TransmitVoiceChat(unsigned char clc, sizebuf_t *buf)
{ {
static unsigned char capturebuf[32768];
static unsigned int capturepos;//in bytes
static unsigned int encsequence;//in frames
unsigned char outbuf[1024]; unsigned char outbuf[1024];
unsigned int outpos;//in bytes unsigned int outpos;//in bytes
unsigned int encpos;//in bytes unsigned int encpos;//in bytes
unsigned short *start; short *start;
unsigned char initseq;//in frames unsigned char initseq;//in frames
unsigned int i; unsigned int i;
unsigned int samps;
float level, f;
float micamp = cl_voip_micamp.value; float micamp = cl_voip_micamp.value;
qboolean voipsendenable = true;
//add new drivers in order or desirability. /*if you're sending sound, you should be prepared to accept others yelling at you to shut up*/
if (pDSOUND_UpdateCapture) if (!cl_voip_play.ival)
voipsendenable = false;
if (!(cls.fteprotocolextensions2 & PEXT2_VOICECHAT))
voipsendenable = false;
if (!voipsendenable)
{ {
capturepos += pDSOUND_UpdateCapture(1, (unsigned char*)capturebuf + capturepos, 64, sizeof(capturebuf) - capturepos); if (s_speex.driver)
{
if (s_speex.wantsend)
s_speex.driver->Stop(s_speex.driverctx);
s_speex.driver->Shutdown(s_speex.driverctx);
s_speex.driverctx = NULL;
s_speex.driver = NULL;
}
return;
} }
else
voipsendenable = cl_voip_send.ival>0;
if (!s_speex.driver)
{
s_speex.voiplevel = -1;
/*only init the first time capturing is requested*/
if (!voipsendenable)
return;
/*Add new drivers in order of priority*/
if (!s_speex.driver)
s_speex.driver = &DSOUND_Capture;
/*no way to capture audio, give up*/
if (!s_speex.driver)
return;
/*see if we can init speex...*/
if (!S_Speex_Init())
return;
s_speex.driverctx = s_speex.driver->Init(s_speex.samplerate);
}
/*couldn't init a driver?*/
if (!s_speex.driverctx)
{ {
return; return;
} }
if (!cl_voip_send.ival) if (!voipsendenable && s_speex.wantsend)
{ {
capturepos = 0; s_speex.wantsend = false;
s_speex.capturepos += s_speex.driver->Update(s_speex.driverctx, (unsigned char*)s_speex.capturebuf + s_speex.capturepos, 1, sizeof(s_speex.capturebuf) - s_speex.capturepos);
s_speex.driver->Stop(s_speex.driverctx);
/*note: we still grab audio to flush everything that was captured while it was active*/
}
else if (voipsendenable && !s_speex.wantsend)
{
s_speex.wantsend = true;
if (!s_speex.capturepos)
{ /*if we were actually still sending, it was probably only off for a single frame, in which case don't reset it*/
s_speex.dumps = 0;
s_speex.generation++;
s_speex.encsequence = 0;
qspeex_bits_reset(&s_speex.encbits);
}
else
{
s_speex.capturepos += s_speex.driver->Update(s_speex.driverctx, (unsigned char*)s_speex.capturebuf + s_speex.capturepos, 1, sizeof(s_speex.capturebuf) - s_speex.capturepos);
}
s_speex.driver->Start(s_speex.driverctx);
voicevolumemod = cl_voip_capturingvol.value;
}
s_speex.capturepos += s_speex.driver->Update(s_speex.driverctx, (unsigned char*)s_speex.capturebuf + s_speex.capturepos, s_speex.framesize*2, sizeof(s_speex.capturebuf) - s_speex.capturepos);
if (!s_speex.wantsend && s_speex.capturepos < s_speex.framesize*2)
{
s_speex.voiplevel = -1;
s_speex.capturepos = 0;
voicevolumemod = 1;
return; return;
} }
if (!S_Speex_Init()) initseq = s_speex.encsequence;
return; level = 0;
samps=0;
initseq = encsequence; for (encpos = 0, outpos = 0; s_speex.capturepos-encpos >= s_speex.framesize*2 && sizeof(outbuf)-outpos > 64; s_speex.encsequence++)
for (encpos = 0, outpos = 0; capturepos-encpos >= s_speex.framesize*2 && sizeof(outbuf)-outpos > 64; )
{ {
start = (short*)(capturebuf + encpos); start = (short*)(s_speex.capturebuf + encpos);
qspeex_preprocess_run(s_speex.preproc, start); qspeex_preprocess_run(s_speex.preproc, start);
if (micamp != 1) for (i = 0; i < s_speex.framesize; i++)
{ {
for (i = 0; i < s_speex.framesize; i++) f = start[i] * micamp;
{ start[i] = f;
start[i] *= micamp; f = fabs(start[i]);
} level += f*f;
} }
samps+=s_speex.framesize;
qspeex_bits_reset(&s_speex.encbits); qspeex_bits_reset(&s_speex.encbits);
qspeex_encode_int(s_speex.encoder, start, &s_speex.encbits); qspeex_encode_int(s_speex.encoder, start, &s_speex.encbits);
outbuf[outpos] = qspeex_bits_write(&s_speex.encbits, outbuf+outpos+1, sizeof(outbuf) - (outpos+1)); outbuf[outpos] = qspeex_bits_write(&s_speex.encbits, outbuf+outpos+1, sizeof(outbuf) - (outpos+1));
outpos += 1+outbuf[outpos]; outpos += 1+outbuf[outpos];
encpos += s_speex.framesize*2; encpos += s_speex.framesize*2;
encsequence++; }
if (samps)
{
float nl;
nl = (3000*level) / (32767.0f*32767*samps);
s_speex.voiplevel = (s_speex.voiplevel*7 + nl)/8;
if (s_speex.voiplevel < cl_voip_vad_threshhold.ival && !(cl_voip_send.ival & 2))
{
/*try and dump it, it was too quiet, and they're not pressing +voip*/
if (s_speex.keeps > samps)
{
/*but not instantly*/
s_speex.keeps -= samps;
}
else
{
outpos = 0;
s_speex.dumps += samps;
s_speex.keeps = 0;
}
}
else
s_speex.keeps = s_speex.samplerate * cl_voip_vad_delay.value;
if (outpos)
{
if (s_speex.dumps > s_speex.samplerate/4)
s_speex.generation++;
s_speex.dumps = 0;
}
} }
if (outpos && buf->maxsize - buf->cursize >= outpos+4) if (outpos && buf->maxsize - buf->cursize >= outpos+4)
{ {
MSG_WriteByte(buf, clc); MSG_WriteByte(buf, clc);
MSG_WriteByte(buf, (s_speex.generation & 0x3f)); /*gonna leave two bits clear here...*/
MSG_WriteByte(buf, initseq); MSG_WriteByte(buf, initseq);
MSG_WriteShort(buf, outpos); MSG_WriteShort(buf, outpos);
SZ_Write(buf, outbuf, outpos); SZ_Write(buf, outbuf, outpos);
} }
/*remove sent data*/ /*remove sent data*/
memmove(capturebuf, capturebuf + encpos, capturepos-encpos); memmove(s_speex.capturebuf, s_speex.capturebuf + encpos, s_speex.capturepos-encpos);
capturepos -= encpos; s_speex.capturepos -= encpos;
} }
static void S_Voip_Enable_f(void) static void S_Voip_Enable_f(void)
{ {
Cvar_Set(&cl_voip_send, "1"); Cvar_SetValue(&cl_voip_send, cl_voip_send.ival | 2);
} }
static void S_Voip_Disable_f(void) static void S_Voip_Disable_f(void)
{ {
Cvar_Set(&cl_voip_send, "0"); Cvar_SetValue(&cl_voip_send, cl_voip_send.ival & ~2);
} }
static void S_Voip_f(void) static void S_Voip_f(void)
{ {
int i;
if (!strcmp(Cmd_Argv(1), "maxgain"))
{
i = atoi(Cmd_Argv(2));
qspeex_preprocess_ctl(s_speex.preproc, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &i);
}
} }
static void S_Voip_Play_Callback(cvar_t *var, char *oldval) static void S_Voip_Play_Callback(cvar_t *var, char *oldval)
{ {
@ -435,6 +573,20 @@ void S_Voip_MapChange(void)
{ {
Cvar_ForceCallback(&cl_voip_play); Cvar_ForceCallback(&cl_voip_play);
} }
int S_Voip_Loudness(qboolean ignorevad)
{
if (s_speex.voiplevel > 100)
return 100;
if (!s_speex.driverctx || (!ignorevad && s_speex.dumps))
return -1;
return s_speex.voiplevel;
}
qboolean S_Voip_Speaking(unsigned int plno)
{
if (plno >= MAX_CLIENTS)
return false;
return s_speex.lastspoke[plno] > realtime;
}
#endif #endif
@ -839,10 +991,15 @@ void S_Init (void)
#ifdef VOICECHAT #ifdef VOICECHAT
Cvar_Register(&cl_voip_send, "Voice Chat"); Cvar_Register(&cl_voip_send, "Voice Chat");
Cvar_Register(&cl_voip_vad_threshhold, "Voice Chat");
Cvar_Register(&cl_voip_vad_delay, "Voice Chat");
Cvar_Register(&cl_voip_capturingvol, "Voice Chat");
Cvar_Register(&cl_voip_showmeter, "Voice Chat");
Cvar_Register(&cl_voip_play, "Voice Chat"); Cvar_Register(&cl_voip_play, "Voice Chat");
Cvar_Register(&cl_voip_micamp, "Voice Chat"); Cvar_Register(&cl_voip_micamp, "Voice Chat");
Cmd_AddCommand("+voip", S_Voip_Enable_f); Cmd_AddCommand("+voip", S_Voip_Enable_f);
Cmd_AddCommand("-voip", S_Voip_Disable_f); Cmd_AddCommand("-voip", S_Voip_Disable_f);
Cmd_AddCommand("voip", S_Voip_f);
#endif #endif
Cvar_Register(&snd_inactive, "Sound controls"); Cvar_Register(&snd_inactive, "Sound controls");
@ -1201,7 +1358,7 @@ void S_StartSoundCard(soundcardinfo_t *sc, int entnum, int entchannel, sfx_t *sf
startpos = scache->length - snd_speed*10; startpos = scache->length - snd_speed*10;
} }
target_chan->sfx = sfx; target_chan->sfx = sfx;
target_chan->rate = ((1<<PITCHSHIFT) * pitchadj) / 100; target_chan->rate = ((1<<PITCHSHIFT) * pitchadj) / 100; /*pitchadj is a percentage*/
target_chan->pos = startpos*target_chan->rate; target_chan->pos = startpos*target_chan->rate;
target_chan->end = sc->paintedtime + ((scache->length - startpos)<<PITCHSHIFT)/target_chan->rate; target_chan->end = sc->paintedtime + ((scache->length - startpos)<<PITCHSHIFT)/target_chan->rate;
target_chan->looping = false; target_chan->looping = false;
@ -1439,7 +1596,7 @@ void S_Music_Seek(float time)
if (sc->channel[i].pos < 0) if (sc->channel[i].pos < 0)
{ //clamp to the start of the track { //clamp to the start of the track
sc->channel[i].end -= sc->channel[i].pos; sc->channel[i].end -= sc->channel[i].pos/sc->channel[i].rate;
sc->channel[i].pos=0; sc->channel[i].pos=0;
} }
//if we seek over the end, ignore it. The sound playing code will spot that. //if we seek over the end, ignore it. The sound playing code will spot that.
@ -1895,21 +2052,6 @@ typedef struct {
#define MAX_RAW_SOURCES (MAX_CLIENTS+1) #define MAX_RAW_SOURCES (MAX_CLIENTS+1)
streaming_t s_streamers[MAX_RAW_SOURCES]; streaming_t s_streamers[MAX_RAW_SOURCES];
/*
qboolean S_IsPlayingSomewhere(sfx_t *s)
{
soundcardinfo_t *si;
int i;
for (si = sndcardinfo; si; si=si->next)
{
for (i = 0; i < scard->total_chans; i++)
if (si->channel[i].sfx == s)
return true;
}
return false;
}*/
#undef free
void S_ClearRaw(void) void S_ClearRaw(void)
{ {
memset(s_streamers, 0, sizeof(s_streamers)); memset(s_streamers, 0, sizeof(s_streamers));
@ -1996,8 +2138,8 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
for (i = 0; i < si->total_chans; i++) for (i = 0; i < si->total_chans; i++)
if (si->channel[i].sfx == &s->sfx) if (si->channel[i].sfx == &s->sfx)
{ {
if (prepadl > (si->channel[i].pos>>8)) if (prepadl > (si->channel[i].pos>>PITCHSHIFT))
prepadl = (si->channel[i].pos>>8); prepadl = (si->channel[i].pos>>PITCHSHIFT);
break; break;
} }
} }
@ -2007,7 +2149,7 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
if (snd_show.ival) if (snd_show.ival)
Con_Printf("Wasn't playing\n"); Con_Printf("Wasn't playing\n");
prepadl = 0; prepadl = 0;
spare = s->sfxcache->length; spare = 0;
if (spare > snd_speed) if (spare > snd_speed)
{ {
Con_DPrintf("Sacrificed raw sound stream\n"); Con_DPrintf("Sacrificed raw sound stream\n");
@ -2016,11 +2158,13 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
} }
else else
{ {
if (prepadl < 0)
prepadl = 0;
spare = s->sfxcache->length - prepadl; spare = s->sfxcache->length - prepadl;
if (spare < 0) //remaining samples since last time if (spare < 0) //remaining samples since last time
spare = 0; spare = 0;
if (s->sfxcache->length > snd_speed*2) // more than 2 seconds of sound if (spare > snd_speed*2) // more than 2 seconds of sound
{ {
Con_DPrintf("Sacrificed raw sound stream\n"); Con_DPrintf("Sacrificed raw sound stream\n");
spare = 0; //too far out. sacrifice it all spare = 0; //too far out. sacrifice it all
@ -2051,7 +2195,7 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
snd_linearresample_stream.ival); snd_linearresample_stream.ival);
} }
s->sfxcache->loopstart = s->sfxcache->length; s->sfxcache->loopstart = -1;//s->sfxcache->length;
for (si = sndcardinfo; si; si=si->next) for (si = sndcardinfo; si; si=si->next)
{ {
@ -2059,7 +2203,6 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
if (si->channel[i].sfx == &s->sfx) if (si->channel[i].sfx == &s->sfx)
{ {
si->channel[i].pos -= prepadl*si->channel[i].rate; si->channel[i].pos -= prepadl*si->channel[i].rate;
// si->channel[i].end -= prepadl;
si->channel[i].end += outsamples; si->channel[i].end += outsamples;
if (si->channel[i].end < si->paintedtime) if (si->channel[i].end < si->paintedtime)
@ -2071,10 +2214,8 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels,
} }
if (i == si->total_chans) //this one wasn't playing. if (i == si->total_chans) //this one wasn't playing.
{ {
S_StartSoundCard(si, -1, 0, &s->sfx, r_origin, 1, 32767, 500, 0); /*slight delay to try to avoid frame rate/etc stops/starts*/
// Con_Printf("Restarted\n"); S_StartSoundCard(si, -1, 0, &s->sfx, r_origin, 1, 32767, -snd_speed*0.02, 0);
} }
} }
// Con_Printf("Stripped %i, added %i (length %i)\n", prepadl, samples, s->sfxcache->length);
} }

View File

@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PAINTBUFFER_SIZE 2048 #define PAINTBUFFER_SIZE 2048
float voicevolumemod = 1;
portable_samplegroup_t paintbuffer[PAINTBUFFER_SIZE]; portable_samplegroup_t paintbuffer[PAINTBUFFER_SIZE];
int *snd_p, snd_vol; int *snd_p, snd_vol;
@ -70,7 +71,7 @@ void S_TransferPaintBuffer(soundcardinfo_t *sc, int endtime)
count = (endtime - sc->paintedtime) * sc->sn.numchannels; count = (endtime - sc->paintedtime) * sc->sn.numchannels;
outlimit = sc->sn.samples; outlimit = sc->sn.samples;
startidx = out_idx = (sc->paintedtime * sc->sn.numchannels) % outlimit; startidx = out_idx = (sc->paintedtime * sc->sn.numchannels) % outlimit;
snd_vol = volume.value*256; snd_vol = (volume.value*voicevolumemod)*256;
pbuf = sc->Lock(sc); pbuf = sc->Lock(sc);
if (!pbuf) if (!pbuf)
@ -169,7 +170,7 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime)
if ((ch->pos>>PITCHSHIFT) > scache->length) //cache was flushed and gamedir changed. if ((ch->pos>>PITCHSHIFT) > scache->length) //cache was flushed and gamedir changed.
{ {
ch->pos = scache->length*ch->rate; ch->pos = scache->length*ch->rate;
ch->end = scache->length; ch->end = sc->paintedtime;
} }

View File

@ -148,9 +148,15 @@ void S_DefaultSpeakerConfiguration(soundcardinfo_t *sc);
void S_ResetFailedLoad(void); void S_ResetFailedLoad(void);
#ifdef VOICECHAT #ifdef VOICECHAT
void S_ParseVoiceChat(void); extern cvar_t cl_voip_showmeter;
void S_TransmitVoiceChat(unsigned char clc, sizebuf_t *buf); void S_Voip_Parse(void);
void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf);
void S_Voip_MapChange(void); void S_Voip_MapChange(void);
int S_Voip_Loudness(qboolean ignorevad); //-1 for not capturing, otherwise between 0 and 100
qboolean S_Voip_Speaking(unsigned int plno);
#else
#define S_Voip_Loudness() -1
#define S_Voip_Speaking(p) false
#endif #endif
qboolean S_IsPlayingSomewhere(sfx_t *s); qboolean S_IsPlayingSomewhere(sfx_t *s);
@ -222,6 +228,8 @@ extern cvar_t bgmvolume;
extern cvar_t volume; extern cvar_t volume;
extern cvar_t snd_capture; extern cvar_t snd_capture;
extern float voicevolumemod;
extern qboolean snd_initialized; extern qboolean snd_initialized;
extern cvar_t snd_usemultipledevices; extern cvar_t snd_usemultipledevices;
@ -294,6 +302,13 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound
extern soundcardinfo_t *sndcardinfo; extern soundcardinfo_t *sndcardinfo;
typedef struct
{
void *(*Init) (int samplerate); /*create a new context*/
void (*Start) (void *ctx); /*begin grabbing new data, old data is potentially flushed*/
unsigned int (*Update) (void *ctx, unsigned char *buffer, unsigned int minbytes, unsigned int maxbytes); /*grab the data into a different buffer*/
void (*Stop) (void *ctx); /*stop grabbing new data, old data may remain*/
void (*Shutdown) (void *ctx); /*destroy everything*/
} snd_capture_driver_t;
#endif #endif

View File

@ -1336,6 +1336,8 @@ char *MSG_ReadStringLine (void)
float MSG_ReadCoord (void) float MSG_ReadCoord (void)
{ {
coorddata c = {{0}}; coorddata c = {{0}};
if (!net_message.prim.coordsize)
net_message.prim.coordsize = 2;
MSG_ReadData(&c, net_message.prim.coordsize); MSG_ReadData(&c, net_message.prim.coordsize);
return MSG_FromCoord(c, net_message.prim.coordsize); return MSG_FromCoord(c, net_message.prim.coordsize);
} }
@ -1401,6 +1403,9 @@ float MSG_ReadAngle16 (void)
} }
float MSG_ReadAngle (void) float MSG_ReadAngle (void)
{ {
if (!net_message.prim.anglesize)
net_message.prim.anglesize = 1;
switch(net_message.prim.anglesize) switch(net_message.prim.anglesize)
{ {
case 2: case 2:

View File

@ -85,13 +85,14 @@ typedef struct cvar_s
} cvar_t; } cvar_t;
#define CVARAFDC(ConsoleName,Value,ConsoleName2,Flags,Description,Callback) {ConsoleName, Value, NULL, Flags, 0, 0, 0, ConsoleName2, Callback, Description} #define CVARAFDC(ConsoleName,Value,ConsoleName2,Flags,Description,Callback) {ConsoleName, Value, NULL, Flags, 0, 0, 0, ConsoleName2, Callback, Description}
#define CVARAFC(ConsoleName,Value,ConsoleName2,Flags,Callback) CVARAFC(ConsoleName, Value, ConsoleName2, Flags, NULL, Callback)
#define CVARAFD(ConsoleName,Value,ConsoleName2,Flags,Description)CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, Description, NULL) #define CVARAFD(ConsoleName,Value,ConsoleName2,Flags,Description)CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, Description, NULL)
#define CVARAFC(ConsoleName,Value,ConsoleName2,Flags,Callback) CVARAFC(ConsoleName, Value, ConsoleName2, Flags, NULL, Callback)
#define CVARAF(ConsoleName,Value,ConsoleName2,Flags) CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, NULL, NULL) #define CVARAF(ConsoleName,Value,ConsoleName2,Flags) CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, NULL, NULL)
#define CVARFC(ConsoleName,Value,Flags,Callback) CVARAFDC(ConsoleName, Value, NULL, Flags, NULL, Callback) #define CVARFC(ConsoleName,Value,Flags,Callback) CVARAFDC(ConsoleName, Value, NULL, Flags, NULL, Callback)
#define CVARFD(ConsoleName,Value,Flags,Description) CVARAFDC(ConsoleName, Value, NULL, Flags, Description, NULL) #define CVARFD(ConsoleName,Value,Flags,Description) CVARAFDC(ConsoleName, Value, NULL, Flags, Description, NULL)
#define CVARF(ConsoleName,Value,Flags) CVARFC(ConsoleName, Value, Flags, NULL) #define CVARF(ConsoleName,Value,Flags) CVARFC(ConsoleName, Value, Flags, NULL)
#define CVARC(ConsoleName,Value,Callback) CVARFC(ConsoleName, Value, 0, Callback) #define CVARC(ConsoleName,Value,Callback) CVARFC(ConsoleName, Value, 0, Callback)
#define CVARCD(ConsoleName,Value,Callback,Description) CVARAFDC(ConsoleName, Value, NULL, 0, Description, Callback)
#define CVARD(ConsoleName,Value,Description) CVARAFDC(ConsoleName, Value, NULL, 0, Description, NULL) #define CVARD(ConsoleName,Value,Description) CVARAFDC(ConsoleName, Value, NULL, 0, Description, NULL)
#define CVAR(ConsoleName,Value) CVARD(ConsoleName, Value, NULL) #define CVAR(ConsoleName,Value) CVARD(ConsoleName, Value, NULL)

View File

@ -154,7 +154,7 @@ inrange:
if (reliable) if (reliable)
{ {
MVDWrite_Begin(dem_all, 0, sv.multicast.cursize); MVDWrite_Begin(dem_all, 0, sv.multicast.cursize);
SZ_Write((sizebuf_t*)demo.dbuf, sv.multicast.data, sv.multicast.cursize); SZ_Write(&demo.dbuf->sb, sv.multicast.data, sv.multicast.cursize);
} else } else
SZ_Write(&demo.datagram, sv.multicast.data, sv.multicast.cursize); SZ_Write(&demo.datagram, sv.multicast.data, sv.multicast.cursize);
}*/ }*/

View File

@ -3209,8 +3209,8 @@ void PF_stuffcmd (progfuncs_t *prinst, struct globalvars_s *pr_globals)
if (sv.mvdrecording) if (sv.mvdrecording)
{ {
MVDWrite_Begin (dem_single, entnum - 1, 2 + slen); MVDWrite_Begin (dem_single, entnum - 1, 2 + slen);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_stufftext); MSG_WriteByte (&demo.dbuf->sb, svc_stufftext);
MSG_WriteString ((sizebuf_t*)demo.dbuf, str); MSG_WriteString (&demo.dbuf->sb, str);
} }
} }

View File

@ -593,11 +593,7 @@ typedef struct {
typedef struct typedef struct
{ {
qboolean allowoverflow; // if false, do a Sys_Error sizebuf_t sb;
qboolean overflowed; // set to true if the buffer size failed
qbyte *data;
int maxsize;
int cursize;
int bufsize; int bufsize;
header_t *h; header_t *h;
} demobuf_t; } demobuf_t;
@ -607,7 +603,6 @@ typedef struct
demo_client_t clients[MAX_CLIENTS]; demo_client_t clients[MAX_CLIENTS];
double time; double time;
demobuf_t buf; demobuf_t buf;
} demo_frame_t; } demo_frame_t;
typedef struct { typedef struct {

View File

@ -1556,9 +1556,9 @@ void SV_ConSay_f(void)
if (sv.mvdrecording) if (sv.mvdrecording)
{ {
MVDWrite_Begin (dem_all, 0, strlen(text)+3); MVDWrite_Begin (dem_all, 0, strlen(text)+3);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_print); MSG_WriteByte (&demo.dbuf->sb, svc_print);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, PRINT_CHAT); MSG_WriteByte (&demo.dbuf->sb, PRINT_CHAT);
MSG_WriteString ((sizebuf_t*)demo.dbuf, text); MSG_WriteString (&demo.dbuf->sb, text);
} }
} }

View File

@ -153,7 +153,6 @@ cvar_t sv_pupglow = CVARF("sv_pupglow", "", CVAR_SERVERINFO);
cvar_t sv_master = CVAR("sv_master", "0"); cvar_t sv_master = CVAR("sv_master", "0");
cvar_t sv_masterport = CVAR("sv_masterport", "0"); cvar_t sv_masterport = CVAR("sv_masterport", "0");
cvar_t sv_voicechat = CVAR("sv_voicechat", "0"); //still development.
cvar_t sv_gamespeed = CVAR("sv_gamespeed", "1"); cvar_t sv_gamespeed = CVAR("sv_gamespeed", "1");
cvar_t sv_csqcdebug = CVAR("sv_csqcdebug", "0"); cvar_t sv_csqcdebug = CVAR("sv_csqcdebug", "0");
cvar_t sv_csqc_progname = CVAR("sv_csqc_progname", "csprogs.dat"); cvar_t sv_csqc_progname = CVAR("sv_csqc_progname", "csprogs.dat");
@ -3774,7 +3773,6 @@ void SV_InitLocal (void)
Cvar_Register (&pausable, cvargroup_servercontrol); Cvar_Register (&pausable, cvargroup_servercontrol);
Cvar_Register (&sv_voicechat, cvargroup_servercontrol);
Cvar_Register (&sv_maxrate, cvargroup_servercontrol); Cvar_Register (&sv_maxrate, cvargroup_servercontrol);
Cvar_Register (&sv_maxdrate, cvargroup_servercontrol); Cvar_Register (&sv_maxdrate, cvargroup_servercontrol);
Cvar_Register (&sv_minping, cvargroup_servercontrol); Cvar_Register (&sv_minping, cvargroup_servercontrol);

View File

@ -766,12 +766,12 @@ void SV_MVDPings (void)
continue; continue;
MVDWrite_Begin (dem_all, 0, 7); MVDWrite_Begin (dem_all, 0, 7);
MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updateping); MSG_WriteByte(&demo.dbuf->sb, svc_updateping);
MSG_WriteByte((sizebuf_t*)demo.dbuf, j); MSG_WriteByte(&demo.dbuf->sb, j);
MSG_WriteShort((sizebuf_t*)demo.dbuf, SV_CalcPing(client, false)); MSG_WriteShort(&demo.dbuf->sb, SV_CalcPing(client, false));
MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updatepl); MSG_WriteByte(&demo.dbuf->sb, svc_updatepl);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, j); MSG_WriteByte (&demo.dbuf->sb, j);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, client->lossage); MSG_WriteByte (&demo.dbuf->sb, client->lossage);
} }
} }
@ -799,13 +799,14 @@ void MVDSetMsgBuf(demobuf_t *prev,demobuf_t *cur)
// fix the maxsize of previous msg buffer, // fix the maxsize of previous msg buffer,
// we won't be able to write there anymore // we won't be able to write there anymore
if (prev != NULL) if (prev != NULL)
prev->maxsize = prev->bufsize; prev->sb.maxsize = prev->bufsize;
demo.dbuf = cur; demo.dbuf = cur;
memset(demo.dbuf, 0, sizeof(*demo.dbuf)); memset(demo.dbuf, 0, sizeof(*demo.dbuf));
demo.dbuf->data = demobuffer->data + demobuffer->end; demo.dbuf->sb.data = demobuffer->data + demobuffer->end;
demo.dbuf->maxsize = MAXSIZE; demo.dbuf->sb.maxsize = MAXSIZE;
demo.dbuf->sb.prim = demo.recorder.netchan.netprim;
} }
/* /*
@ -825,7 +826,7 @@ void SV_MVDWriteToDisk(int type, int to, float time)
int size; int size;
sizebuf_t msg; sizebuf_t msg;
p = (header_t *)demo.dbuf->data; p = (header_t *)demo.dbuf->sb.data;
demo.dbuf->h = NULL; demo.dbuf->h = NULL;
oldm = demo.dbuf->bufsize; oldm = demo.dbuf->bufsize;
@ -847,13 +848,13 @@ void SV_MVDWriteToDisk(int type, int to, float time)
} }
// data is written so it need to be cleard from demobuf // data is written so it need to be cleard from demobuf
if (demo.dbuf->data != (qbyte*)p) if (demo.dbuf->sb.data != (qbyte*)p)
memmove(demo.dbuf->data + size + header, demo.dbuf->data, (qbyte*)p - demo.dbuf->data); memmove(demo.dbuf->sb.data + size + header, demo.dbuf->sb.data, (qbyte*)p - demo.dbuf->sb.data);
demo.dbuf->bufsize -= size + header; demo.dbuf->bufsize -= size + header;
demo.dbuf->data += size + header; demo.dbuf->sb.data += size + header;
pos -= size + header; pos -= size + header;
demo.dbuf->maxsize -= size + header; demo.dbuf->sb.maxsize -= size + header;
demobuffer->start += size + header; demobuffer->start += size + header;
} }
// move along // move along
@ -865,7 +866,7 @@ void SV_MVDWriteToDisk(int type, int to, float time)
if (demobuffer->start == demobuffer->end) if (demobuffer->start == demobuffer->end)
{ {
demobuffer->end = 0; // demobuffer is empty demobuffer->end = 0; // demobuffer is empty
demo.dbuf->data = demobuffer->data; demo.dbuf->sb.data = demobuffer->data;
} }
// go back to begining of the buffer // go back to begining of the buffer
@ -887,7 +888,7 @@ static void MVDSetBuf(qbyte type, int to)
header_t *p; header_t *p;
int pos = 0; int pos = 0;
p = (header_t *)demo.dbuf->data; p = (header_t *)demo.dbuf->sb.data;
while (pos < demo.dbuf->bufsize) while (pos < demo.dbuf->bufsize)
{ {
@ -895,7 +896,7 @@ static void MVDSetBuf(qbyte type, int to)
if (type == p->type && to == p->to && !p->full) if (type == p->type && to == p->to && !p->full)
{ {
demo.dbuf->cursize = pos; demo.dbuf->sb.cursize = pos;
demo.dbuf->h = p; demo.dbuf->h = p;
return; return;
} }
@ -910,7 +911,7 @@ static void MVDSetBuf(qbyte type, int to)
p->full = 0; p->full = 0;
demo.dbuf->bufsize += header; demo.dbuf->bufsize += header;
demo.dbuf->cursize = demo.dbuf->bufsize; demo.dbuf->sb.cursize = demo.dbuf->bufsize;
demobuffer->end += header; demobuffer->end += header;
demo.dbuf->h = p; demo.dbuf->h = p;
} }
@ -921,11 +922,11 @@ void MVDMoveBuf(void)
demobuffer->last = demobuffer->end - demo.dbuf->bufsize; demobuffer->last = demobuffer->end - demo.dbuf->bufsize;
// move buffer to the begining of demo buffer // move buffer to the begining of demo buffer
memmove(demobuffer->data, demo.dbuf->data, demo.dbuf->bufsize); memmove(demobuffer->data, demo.dbuf->sb.data, demo.dbuf->bufsize);
demo.dbuf->data = demobuffer->data; demo.dbuf->sb.data = demobuffer->data;
demobuffer->end = demo.dbuf->bufsize; demobuffer->end = demo.dbuf->bufsize;
demo.dbuf->h = NULL; // it will be setup again demo.dbuf->h = NULL; // it will be setup again
demo.dbuf->maxsize = MAXSIZE + demo.dbuf->bufsize; demo.dbuf->sb.maxsize = MAXSIZE + demo.dbuf->bufsize;
} }
qboolean MVDWrite_Begin(qbyte type, int to, int size) qboolean MVDWrite_Begin(qbyte type, int to, int size)
@ -934,7 +935,7 @@ qboolean MVDWrite_Begin(qbyte type, int to, int size)
qboolean move = false; qboolean move = false;
// will it fit? // will it fit?
while (demo.dbuf->bufsize + size + header > demo.dbuf->maxsize) while (demo.dbuf->bufsize + size + header > demo.dbuf->sb.maxsize)
{ {
// if we reached the end of buffer move msgbuf to the begining // if we reached the end of buffer move msgbuf to the begining
if (!move && demobuffer->end > demobuffer->start) if (!move && demobuffer->end > demobuffer->start)
@ -958,9 +959,9 @@ qboolean MVDWrite_Begin(qbyte type, int to, int size)
} }
// we have to make room for new data // we have to make room for new data
if (demo.dbuf->cursize != demo.dbuf->bufsize) { if (demo.dbuf->sb.cursize != demo.dbuf->bufsize) {
p = demo.dbuf->data + demo.dbuf->cursize; p = demo.dbuf->sb.data + demo.dbuf->sb.cursize;
memmove(p+size, p, demo.dbuf->bufsize - demo.dbuf->cursize); memmove(p+size, p, demo.dbuf->bufsize - demo.dbuf->sb.cursize);
} }
demo.dbuf->bufsize += size; demo.dbuf->bufsize += size;
@ -1092,6 +1093,7 @@ qboolean SV_MVDWritePackets (int num)
if (!sv.mvdrecording) if (!sv.mvdrecording)
return false; return false;
msg.prim = svs.netprim;
msg.data = msg_buf; msg.data = msg_buf;
msg.maxsize = sizeof(msg_buf); msg.maxsize = sizeof(msg_buf);
@ -1228,7 +1230,7 @@ qboolean SV_MVDWritePackets (int num)
demo.lastwritten = demo.parsecount; demo.lastwritten = demo.parsecount;
demo.dbuf = &demo.frames[demo.parsecount&DEMO_FRAMES_MASK].buf; demo.dbuf = &demo.frames[demo.parsecount&DEMO_FRAMES_MASK].buf;
demo.dbuf->maxsize = MAXSIZE + demo.dbuf->bufsize; demo.dbuf->sb.maxsize = MAXSIZE + demo.dbuf->bufsize;
return true; return true;
} }
@ -1384,6 +1386,7 @@ mvddest_t *SV_InitRecordFile (char *name)
else else
FS_Remove(path, FS_GAMEONLY); FS_Remove(path, FS_GAMEONLY);
FS_FlushFSHash();
return dst; return dst;
} }
@ -1458,12 +1461,12 @@ void SV_MVDStop (int reason, qboolean mvdonly)
// write a disconnect message to the demo file // write a disconnect message to the demo file
// clearup to be sure message will fit // clearup to be sure message will fit
demo.dbuf->cursize = 0; demo.dbuf->sb.cursize = 0;
demo.dbuf->h = NULL; demo.dbuf->h = NULL;
demo.dbuf->bufsize = 0; demo.dbuf->bufsize = 0;
MVDWrite_Begin(dem_all, 0, 2+strlen("EndOfDemo")); MVDWrite_Begin(dem_all, 0, 2+strlen("EndOfDemo"));
MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_disconnect); MSG_WriteByte (&demo.dbuf->sb, svc_disconnect);
MSG_WriteString ((sizebuf_t*)demo.dbuf, "EndOfDemo"); MSG_WriteString (&demo.dbuf->sb, "EndOfDemo");
SV_MVDWritePackets(demo.parsecount - demo.lastwritten + 1); SV_MVDWritePackets(demo.parsecount - demo.lastwritten + 1);
// finish up // finish up
@ -1587,17 +1590,20 @@ static qboolean SV_MVD_Record (mvddest_t *dest)
memset(&demo, 0, sizeof(demo)); memset(&demo, 0, sizeof(demo));
demo.recorder.frameunion.frames = demo_frames; demo.recorder.frameunion.frames = demo_frames;
demo.recorder.protocol = SCP_QUAKEWORLD; demo.recorder.protocol = SCP_QUAKEWORLD;
demo.recorder.netchan.netprim = sv.datagram.prim;
for (i = 0; i < UPDATE_BACKUP; i++) for (i = 0; i < UPDATE_BACKUP; i++)
{ {
demo.recorder.frameunion.frames[i].entities.max_entities = MAX_MVDPACKET_ENTITIES; demo.recorder.frameunion.frames[i].entities.max_entities = MAX_MVDPACKET_ENTITIES;
demo.recorder.frameunion.frames[i].entities.entities = demo_entities[i]; demo.recorder.frameunion.frames[i].entities.entities = demo_entities[i];
} }
demo.recorder.max_net_ents = MAX_MVDPACKET_ENTITIES;
MVDBuffer_Init(&demo.dbuffer, demo.buffer, sizeof(demo.buffer)); MVDBuffer_Init(&demo.dbuffer, demo.buffer, sizeof(demo.buffer));
MVDSetMsgBuf(NULL, &demo.frames[0].buf); MVDSetMsgBuf(NULL, &demo.frames[0].buf);
demo.datagram.maxsize = sizeof(demo.datagram_data); demo.datagram.maxsize = sizeof(demo.datagram_data);
demo.datagram.data = demo.datagram_data; demo.datagram.data = demo.datagram_data;
demo.datagram.prim = demo.recorder.netchan.netprim;
} }
// else // else
// SV_WriteRecordMVDMessage(&buf, dem_read); // SV_WriteRecordMVDMessage(&buf, dem_read);
@ -1637,6 +1643,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest)
memset(&buf, 0, sizeof(buf)); memset(&buf, 0, sizeof(buf));
buf.data = buf_data; buf.data = buf_data;
buf.maxsize = sizeof(buf_data); buf.maxsize = sizeof(buf_data);
buf.prim = svs.netprim;
// send the serverdata // send the serverdata
@ -1645,7 +1652,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest)
gamedir = "qw"; gamedir = "qw";
MSG_WriteByte (&buf, svc_serverdata); MSG_WriteByte (&buf, svc_serverdata);
if (svs.netprim.coordsize == 4) //sorry. if (buf.prim.coordsize == 4) //sorry.
{ {
MSG_WriteLong (&buf, PROTOCOL_VERSION_FTE); MSG_WriteLong (&buf, PROTOCOL_VERSION_FTE);
MSG_WriteLong (&buf, PEXT_FLOATCOORDS); MSG_WriteLong (&buf, PEXT_FLOATCOORDS);

View File

@ -2175,7 +2175,7 @@ qboolean SV_Physics (void)
SV_RunEntity (ent); SV_RunEntity (ent);
SV_RunNewmis (); SV_RunNewmis ();
if (ent->solidtype != ent->v->solid) if (ent->solidtype != ent->v->solid && !ent->isfree)
{ {
Con_DPrintf("Entity \"%s\" improperly changed solid type\n", PR_GetString(svprogfuncs, ent->v->classname)); Con_DPrintf("Entity \"%s\" improperly changed solid type\n", PR_GetString(svprogfuncs, ent->v->classname));
World_LinkEdict (&sv.world, (wedict_t*)ent, true); // a change of solidity should always relink the edict. someone messed up. World_LinkEdict (&sv.world, (wedict_t*)ent, true); // a change of solidity should always relink the edict. someone messed up.

View File

@ -292,9 +292,9 @@ void VARGS SV_ClientPrintf (client_t *cl, int level, char *fmt, ...)
if (sv.mvdrecording) if (sv.mvdrecording)
{ {
MVDWrite_Begin (dem_single, cl - svs.clients, strlen(string)+3); MVDWrite_Begin (dem_single, cl - svs.clients, strlen(string)+3);
MSG_WriteByte ((sizebuf_t *)demo.dbuf, svc_print); MSG_WriteByte (&demo.dbuf->sb, svc_print);
MSG_WriteByte ((sizebuf_t *)demo.dbuf, level); MSG_WriteByte (&demo.dbuf->sb, level);
MSG_WriteString ((sizebuf_t *)demo.dbuf, string); MSG_WriteString (&demo.dbuf->sb, string);
} }
if (cl->controller) if (cl->controller)
@ -322,9 +322,9 @@ void VARGS SV_ClientTPrintf (client_t *cl, int level, translation_t stringnum, .
if (sv.mvdrecording) if (sv.mvdrecording)
{ {
MVDWrite_Begin (dem_single, cl - svs.clients, strlen(string)+3); MVDWrite_Begin (dem_single, cl - svs.clients, strlen(string)+3);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_print); MSG_WriteByte (&demo.dbuf->sb, svc_print);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, level); MSG_WriteByte (&demo.dbuf->sb, level);
MSG_WriteString ((sizebuf_t*)demo.dbuf, string); MSG_WriteString (&demo.dbuf->sb, string);
} }
SV_PrintToClient(cl, level, string); SV_PrintToClient(cl, level, string);
@ -371,9 +371,9 @@ void VARGS SV_BroadcastPrintf (int level, char *fmt, ...)
if (sv.mvdrecording) if (sv.mvdrecording)
{ {
MVDWrite_Begin (dem_all, 0, strlen(string)+3); MVDWrite_Begin (dem_all, 0, strlen(string)+3);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_print); MSG_WriteByte (&demo.dbuf->sb, svc_print);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, level); MSG_WriteByte (&demo.dbuf->sb, level);
MSG_WriteString ((sizebuf_t*)demo.dbuf, string); MSG_WriteString (&demo.dbuf->sb, string);
} }
} }
@ -755,7 +755,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
if (reliable) if (reliable)
{ {
MVDWrite_Begin(dem_all, 0, sv.multicast.cursize); MVDWrite_Begin(dem_all, 0, sv.multicast.cursize);
SZ_Write((sizebuf_t*)demo.dbuf, sv.multicast.data, sv.multicast.cursize); SZ_Write(&demo.dbuf->sb, sv.multicast.data, sv.multicast.cursize);
} else } else
SZ_Write(&demo.datagram, sv.multicast.data, sv.multicast.cursize); SZ_Write(&demo.datagram, sv.multicast.data, sv.multicast.cursize);
} }
@ -1069,8 +1069,8 @@ void SV_WriteCenterPrint(client_t *cl, char *s)
if (sv.mvdrecording) if (sv.mvdrecording)
{ {
MVDWrite_Begin (dem_single, cl - svs.clients, 2 + strlen(s)); MVDWrite_Begin (dem_single, cl - svs.clients, 2 + strlen(s));
MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_centerprint); MSG_WriteByte (&demo.dbuf->sb, svc_centerprint);
MSG_WriteString ((sizebuf_t*)demo.dbuf, s); MSG_WriteString (&demo.dbuf->sb, s);
} }
} }
@ -1871,9 +1871,9 @@ void SV_UpdateToReliableMessages (void)
if (sv.mvdrecording) if (sv.mvdrecording)
{ {
MVDWrite_Begin(dem_all, 0, 4); MVDWrite_Begin(dem_all, 0, 4);
MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updatefrags); MSG_WriteByte(&demo.dbuf->sb, svc_updatefrags);
MSG_WriteByte((sizebuf_t*)demo.dbuf, i); MSG_WriteByte(&demo.dbuf->sb, i);
MSG_WriteShort((sizebuf_t*)demo.dbuf, host_client->edict->v->frags); MSG_WriteShort(&demo.dbuf->sb, host_client->edict->v->frags);
} }
host_client->old_frags = host_client->edict->v->frags; host_client->old_frags = host_client->edict->v->frags;
@ -1932,9 +1932,9 @@ void SV_UpdateToReliableMessages (void)
if (sv.mvdrecording) if (sv.mvdrecording)
{ {
MVDWrite_Begin(dem_all, 0, 4); MVDWrite_Begin(dem_all, 0, 4);
MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updatefrags); MSG_WriteByte(&demo.dbuf->sb, svc_updatefrags);
MSG_WriteByte((sizebuf_t*)demo.dbuf, i); MSG_WriteByte(&demo.dbuf->sb, i);
MSG_WriteShort((sizebuf_t*)demo.dbuf, curfrags); MSG_WriteShort(&demo.dbuf->sb, curfrags);
} }
host_client->old_frags = curfrags; host_client->old_frags = curfrags;
@ -2363,16 +2363,16 @@ void SV_SendMVDMessage(void)
if (stats[j] >=0 && stats[j] <= 255) if (stats[j] >=0 && stats[j] <= 255)
{ {
MVDWrite_Begin(dem_stats, i, 3); MVDWrite_Begin(dem_stats, i, 3);
MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updatestat); MSG_WriteByte(&demo.dbuf->sb, svc_updatestat);
MSG_WriteByte((sizebuf_t*)demo.dbuf, j); MSG_WriteByte(&demo.dbuf->sb, j);
MSG_WriteByte((sizebuf_t*)demo.dbuf, stats[j]); MSG_WriteByte(&demo.dbuf->sb, stats[j]);
} }
else else
{ {
MVDWrite_Begin(dem_stats, i, 6); MVDWrite_Begin(dem_stats, i, 6);
MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updatestatlong); MSG_WriteByte(&demo.dbuf->sb, svc_updatestatlong);
MSG_WriteByte((sizebuf_t*)demo.dbuf, j); MSG_WriteByte(&demo.dbuf->sb, j);
MSG_WriteLong((sizebuf_t*)demo.dbuf, stats[j]); MSG_WriteLong(&demo.dbuf->sb, stats[j]);
} }
} }
} }
@ -2381,6 +2381,7 @@ void SV_SendMVDMessage(void)
// this will include clients, a packetentities, and // this will include clients, a packetentities, and
// possibly a nails update // possibly a nails update
msg.cursize = 0; msg.cursize = 0;
msg.prim = demo.recorder.netchan.netprim;
if (!demo.recorder.delta_sequence) if (!demo.recorder.delta_sequence)
demo.recorder.delta_sequence = -1; demo.recorder.delta_sequence = -1;
@ -2389,12 +2390,12 @@ void SV_SendMVDMessage(void)
if (!MVDWrite_Begin(dem_all, 0, msg.cursize)) if (!MVDWrite_Begin(dem_all, 0, msg.cursize))
return; return;
SZ_Write ((sizebuf_t*)demo.dbuf, msg.data, msg.cursize); SZ_Write (&demo.dbuf->sb, msg.data, msg.cursize);
// copy the accumulated multicast datagram // copy the accumulated multicast datagram
// for this client out to the message // for this client out to the message
if (demo.datagram.cursize) { if (demo.datagram.cursize) {
MVDWrite_Begin(dem_all, 0, demo.datagram.cursize); MVDWrite_Begin(dem_all, 0, demo.datagram.cursize);
SZ_Write ((sizebuf_t*)demo.dbuf, demo.datagram.data, demo.datagram.cursize); SZ_Write (&demo.dbuf->sb, demo.datagram.data, demo.datagram.cursize);
SZ_Clear (&demo.datagram); SZ_Clear (&demo.datagram);
} }

View File

@ -96,6 +96,7 @@ cvar_t sv_realip_timeout = SCVAR("sv_realip_timeout", "10");
#ifdef VOICECHAT #ifdef VOICECHAT
cvar_t sv_voip = CVARD("sv_voip", "1", "Enable reception of voice packets."); cvar_t sv_voip = CVARD("sv_voip", "1", "Enable reception of voice packets.");
cvar_t sv_voip_record = CVARD("sv_voip_record", "0", "Record voicechat into mvds. Requires player support.");
cvar_t sv_voip_echo = CVARD("sv_voip_echo", "0", "Echo voice packets back to their sender, a debug/test setting."); cvar_t sv_voip_echo = CVARD("sv_voip_echo", "0", "Echo voice packets back to their sender, a debug/test setting.");
#endif #endif
@ -2100,6 +2101,7 @@ struct
{ {
unsigned int sender; unsigned int sender;
unsigned char receiver[MAX_CLIENTS/8]; unsigned char receiver[MAX_CLIENTS/8];
unsigned char gen;
unsigned char seq; unsigned char seq;
unsigned int datalen; unsigned int datalen;
unsigned char data[1024]; unsigned char data[1024];
@ -2112,6 +2114,7 @@ void SV_VoiceReadPacket(void)
struct voice_ring_s *ring; struct voice_ring_s *ring;
unsigned short bytes; unsigned short bytes;
client_t *cl; client_t *cl;
unsigned char gen = MSG_ReadByte();
unsigned char seq = MSG_ReadByte(); unsigned char seq = MSG_ReadByte();
/*read the data from the client*/ /*read the data from the client*/
bytes = MSG_ReadShort(); bytes = MSG_ReadShort();
@ -2126,8 +2129,10 @@ void SV_VoiceReadPacket(void)
voice.write++; voice.write++;
MSG_ReadData(ring->data, bytes); MSG_ReadData(ring->data, bytes);
} }
ring->datalen = bytes; ring->datalen = bytes;
ring->sender = host_client - svs.clients; ring->sender = host_client - svs.clients;
ring->gen = gen;
ring->seq = seq; ring->seq = seq;
/*figure out which team members are meant to receive it*/ /*figure out which team members are meant to receive it*/
@ -2167,6 +2172,31 @@ void SV_VoiceReadPacket(void)
ring->receiver[cln>>3] |= 1<<(cln&3); ring->receiver[cln>>3] |= 1<<(cln&3);
} }
if (sv.mvdrecording && sv_voip_record.ival)
{
// non-team messages should be seen always, even if not tracking any player
if (!teamplay.ival)
{
MVDWrite_Begin (dem_all, 0, ring->datalen+6);
}
else
{
unsigned int cls;
cls = ring->receiver[0] |
(ring->receiver[1]<<8) |
(ring->receiver[2]<<16) |
(ring->receiver[3]<<24);
MVDWrite_Begin (dem_multiple, cls, ring->datalen+6);
}
MSG_WriteByte( &demo.dbuf->sb, svcfte_voicechat);
MSG_WriteByte( &demo.dbuf->sb, ring->sender);
MSG_WriteByte( &demo.dbuf->sb, ring->gen);
MSG_WriteByte( &demo.dbuf->sb, ring->seq);
MSG_WriteShort(&demo.dbuf->sb, ring->datalen);
SZ_Write( &demo.dbuf->sb, ring->data, ring->datalen);
}
} }
void SV_VoiceInitClient(client_t *client) void SV_VoiceInitClient(client_t *client)
{ {
@ -2215,6 +2245,7 @@ void SV_VoiceSendPacket(client_t *client, sizebuf_t *buf)
break; break;
MSG_WriteByte(buf, svcfte_voicechat); MSG_WriteByte(buf, svcfte_voicechat);
MSG_WriteByte(buf, ring->sender); MSG_WriteByte(buf, ring->sender);
MSG_WriteByte(buf, ring->gen);
MSG_WriteByte(buf, ring->seq); MSG_WriteByte(buf, ring->seq);
MSG_WriteShort(buf, ring->datalen); MSG_WriteShort(buf, ring->datalen);
SZ_Write(buf, ring->data, ring->datalen); SZ_Write(buf, ring->data, ring->datalen);
@ -2899,9 +2930,9 @@ void SV_Say (qboolean team)
else else
MVDWrite_Begin (dem_multiple, cls, strlen(text)+3); MVDWrite_Begin (dem_multiple, cls, strlen(text)+3);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_print); MSG_WriteByte (&demo.dbuf->sb, svc_print);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, PRINT_CHAT); MSG_WriteByte (&demo.dbuf->sb, PRINT_CHAT);
MSG_WriteString ((sizebuf_t*)demo.dbuf, text); MSG_WriteString (&demo.dbuf->sb, text);
} }
@ -3324,10 +3355,10 @@ void SV_SetInfo_f (void)
if (sv.mvdrecording) if (sv.mvdrecording)
{ {
MVDWrite_Begin (dem_all, 0, strlen(key)+strlen(val)+4); MVDWrite_Begin (dem_all, 0, strlen(key)+strlen(val)+4);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_setinfo); MSG_WriteByte (&demo.dbuf->sb, svc_setinfo);
MSG_WriteByte ((sizebuf_t*)demo.dbuf, i); MSG_WriteByte (&demo.dbuf->sb, i);
MSG_WriteString ((sizebuf_t*)demo.dbuf, key); MSG_WriteString (&demo.dbuf->sb, key);
MSG_WriteString ((sizebuf_t*)demo.dbuf, val); MSG_WriteString (&demo.dbuf->sb, val);
} }
} }