From 540830d9553d3cd32c61198e46caf435b8190922 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sat, 20 Nov 2010 22:01:16 +0000 Subject: [PATCH] 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 --- engine/client/cl_ents.c | 2 +- engine/client/cl_input.c | 18 +-- engine/client/cl_parse.c | 2 +- engine/client/cl_pred.c | 2 +- engine/client/sbar.c | 58 +++++++- engine/client/snd_directx.c | 143 +++++++++--------- engine/client/snd_dma.c | 275 ++++++++++++++++++++++++++--------- engine/client/snd_mix.c | 5 +- engine/client/sound.h | 21 ++- engine/common/common.c | 5 + engine/common/cvar.h | 3 +- engine/server/net_preparse.c | 2 +- engine/server/pr_cmds.c | 4 +- engine/server/server.h | 7 +- engine/server/sv_ccmds.c | 6 +- engine/server/sv_main.c | 2 - engine/server/sv_mvd.c | 67 +++++---- engine/server/sv_phys.c | 2 +- engine/server/sv_send.c | 53 +++---- engine/server/sv_user.c | 45 +++++- 20 files changed, 488 insertions(+), 234 deletions(-) diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 966839b97..0a35afef4 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -2330,7 +2330,7 @@ void CL_ParsePlayerinfo (void) state->weaponframe = MSG_ReadByte (); state->hullnum = 1; - state->scale = 1*16; + state->scale = 1; state->alpha = 255; state->fatness = 0; diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 1d9ce59f8..54b756dfc 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1460,14 +1460,6 @@ void CL_SendCmd (double frametime, qboolean mainloop) curtime = Sys_DoubleTime(); frametime = curtime - lasttime; lasttime = curtime; - -/* for (plnum = 0; plnum < cl.splitclients; plnum++) - { - CL_AdjustAngles(plnum, frametime); - IN_Move(mousemovements[plnum], plnum); - } - return; -*/ } CL_ProxyMenuHooks(); @@ -1492,7 +1484,11 @@ void CL_SendCmd (double frametime, qboolean mainloop) cmd = &cl.frames[i].cmd[0]; 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; CL_AdjustAngles (plnum, frametime); @@ -1510,7 +1506,7 @@ void CL_SendCmd (double frametime, qboolean mainloop) if (cl.spectator) Cam_Track(plnum, cmd); - CL_FinishMove(cmd, (int)(frametime*1000), plnum); + CL_FinishMove(cmd, cmd->msec, plnum); Cam_FinishMove(plnum, cmd); } @@ -1770,7 +1766,7 @@ void CL_SendCmd (double frametime, qboolean mainloop) #ifdef PEXT2_VOICECHAT if (cls.fteprotocolextensions2 & PEXT2_VOICECHAT) - S_TransmitVoiceChat(clc_voicechat, &buf); + S_Voip_Transmit(clc_voicechat, &buf); #endif // diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 19bb9a988..651194a43 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -4967,7 +4967,7 @@ void CL_ParseServerMessage (void) #ifdef PEXT2_VOICECHAT case svcfte_voicechat: - S_ParseVoiceChat(); + S_Voip_Parse(); break; #endif diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 0c03b0384..34b136d59 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -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: VectorCopy (vel, cl.simvel[pnum]); diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 294480fe7..0442ba5c9 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -2204,6 +2204,49 @@ qboolean Sbar_UpdateTeamStatus(player_info_t *player, char *status) 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 @@ -2297,6 +2340,8 @@ void Sbar_Draw (void) 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_Voice(-24); continue; } @@ -2352,6 +2397,13 @@ void Sbar_Draw (void) else Sbar_DrawNormal (pnum); } + + if (sb_lines > 24) + Sbar_Voice(-32); + else if (sb_lines > 0) + Sbar_Voice(-8); + else + Sbar_Voice(16); } #ifdef GLQUAKE @@ -2790,7 +2842,9 @@ if (showcolumns & (1<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 else if (!(strcmp("blue", team))) background_color = 13; // forced blue @@ -2799,6 +2853,8 @@ if (showcolumns & (1<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"); - 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; - IDirectSoundCaptureBuffer_GetCurrentPosition(DSCaptureBuffer, &capturePos, &lastreadpos); - return true; + c->lastreadpos = 0; + IDirectSoundCaptureBuffer_GetCurrentPosition(c->DSCaptureBuffer, &capturePos, &c->lastreadpos); +} + +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*/ -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; LPBYTE lpbuf1 = NULL; LPBYTE lpbuf2 = NULL; @@ -988,35 +1008,15 @@ unsigned int DSOUND_UpdateCapture(qboolean enable, unsigned char *buffer, unsign DWORD readPos; 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. - hr = IDirectSoundCaptureBuffer_GetCurrentPosition( DSCaptureBuffer, &capturePos, &readPos ); - if( hr != DS_OK ) + hr = IDirectSoundCaptureBuffer_GetCurrentPosition(c->DSCaptureBuffer, &capturePos, &readPos); + if (hr != DS_OK) { return 0; } - filled = readPos - lastreadpos; - if( filled < 0 ) filled += bufferbytes; // unwrap offset + filled = readPos - c->lastreadpos; + 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. filled = maxbytes; @@ -1027,7 +1027,7 @@ unsigned int DSOUND_UpdateCapture(qboolean enable, unsigned char *buffer, unsign // filled *= inputwidth; // 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) { // 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); } // Update our buffer offset and unlock sound buffer - lastreadpos = (lastreadpos + dwsize1 + dwsize2) % bufferbytes; - IDirectSoundCaptureBuffer_Unlock(DSCaptureBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); + c->lastreadpos = (c->lastreadpos + dwsize1 + dwsize2) % bufferbytes; + IDirectSoundCaptureBuffer_Unlock(c->DSCaptureBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); } else { @@ -1046,5 +1046,12 @@ unsigned int DSOUND_UpdateCapture(qboolean enable, unsigned char *buffer, unsign } 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 diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 1d3e7db3e..79346cff2 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -82,7 +82,7 @@ cvar_t snd_khz = CVARAF( "s_khz", "11", "snd_khz", CVAR_ARCHIVE); cvar_t snd_inactive = CVARAF( "s_inactive", "0", "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); cvar_t snd_leftisright = CVARAF( "s_swapstereo", "0", "snd_leftisright", CVAR_ARCHIVE); @@ -107,9 +107,14 @@ cvar_t snd_usemultipledevices = CVARAF( "s_multipledevices", "0", #ifdef VOICECHAT 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_play = CVARC("cl_voip_play", "1", S_Voip_Play_Callback); -cvar_t cl_voip_micamp = CVAR("cl_voip_micamp", "2"); +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_vad_threshhold = CVARD("cl_voip_vad_threshhold", "15", "This is the threshhold for voice-activation-detection when sending voip data"); +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 extern vfsfile_t *rawwritefile; @@ -175,8 +180,22 @@ static struct SpeexBits decbits[MAX_CLIENTS]; void *decoder[MAX_CLIENTS]; - unsigned char decseq[MAX_CLIENTS]; - float decamp[MAX_CLIENTS]; + unsigned char decseq[MAX_CLIENTS]; /*sender's sequence, to detect+cover minor packetloss*/ + 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; static const SpeexMode *(VARGS *qspeex_lib_get_mode)(int mode); @@ -222,6 +241,8 @@ static dllfunction_t qspeexdspfuncs[] = {NULL} }; +snd_capture_driver_t DSOUND_Capture; + static qboolean S_Speex_Init(void) { 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_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); @@ -274,19 +297,22 @@ static qboolean S_Speex_Init(void) return s_speex.loaded; } -void S_ParseVoiceChat(void) +void S_Voip_Parse(void) { - unsigned int sender = MSG_ReadByte(); + unsigned int sender; int bytes; unsigned char data[1024], *start; short decodebuf[1024]; unsigned int decodesamps, len, newseq, drops; - unsigned char seq; + unsigned char seq, gen; float amp = 1; unsigned int i; + + sender = MSG_ReadByte(); + gen = MSG_ReadByte(); seq = MSG_ReadByte(); 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); return; @@ -301,11 +327,20 @@ void S_ParseVoiceChat(void) newseq = 0; drops = 0; 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) { 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; } @@ -338,88 +373,191 @@ void S_ParseVoiceChat(void) Con_DPrintf("%i dropped audio frames\n", drops); 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_TransmitVoiceChat(unsigned char clc, sizebuf_t *buf) +void S_Voip_Transmit(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 int outpos;//in bytes unsigned int encpos;//in bytes - unsigned short *start; + short *start; unsigned char initseq;//in frames unsigned int i; + unsigned int samps; + float level, f; float micamp = cl_voip_micamp.value; + qboolean voipsendenable = true; - //add new drivers in order or desirability. - if (pDSOUND_UpdateCapture) + /*if you're sending sound, you should be prepared to accept others yelling at you to shut up*/ + 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; } - 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; } - if (!S_Speex_Init()) - return; - - initseq = encsequence; - for (encpos = 0, outpos = 0; capturepos-encpos >= s_speex.framesize*2 && sizeof(outbuf)-outpos > 64; ) + initseq = s_speex.encsequence; + level = 0; + samps=0; + for (encpos = 0, outpos = 0; s_speex.capturepos-encpos >= s_speex.framesize*2 && sizeof(outbuf)-outpos > 64; s_speex.encsequence++) { - start = (short*)(capturebuf + encpos); + start = (short*)(s_speex.capturebuf + encpos); 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++) - { - start[i] *= micamp; - } + f = start[i] * micamp; + start[i] = f; + f = fabs(start[i]); + level += f*f; } + samps+=s_speex.framesize; qspeex_bits_reset(&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)); outpos += 1+outbuf[outpos]; 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) { MSG_WriteByte(buf, clc); + MSG_WriteByte(buf, (s_speex.generation & 0x3f)); /*gonna leave two bits clear here...*/ MSG_WriteByte(buf, initseq); MSG_WriteShort(buf, outpos); SZ_Write(buf, outbuf, outpos); } /*remove sent data*/ - memmove(capturebuf, capturebuf + encpos, capturepos-encpos); - capturepos -= encpos; + memmove(s_speex.capturebuf, s_speex.capturebuf + encpos, s_speex.capturepos-encpos); + s_speex.capturepos -= encpos; } 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) { - Cvar_Set(&cl_voip_send, "0"); + Cvar_SetValue(&cl_voip_send, cl_voip_send.ival & ~2); } 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) { @@ -435,6 +573,20 @@ void S_Voip_MapChange(void) { 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 @@ -839,10 +991,15 @@ void S_Init (void) #ifdef VOICECHAT 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_micamp, "Voice Chat"); Cmd_AddCommand("+voip", S_Voip_Enable_f); Cmd_AddCommand("-voip", S_Voip_Disable_f); + Cmd_AddCommand("voip", S_Voip_f); #endif 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; } target_chan->sfx = sfx; - target_chan->rate = ((1<rate = ((1<pos = startpos*target_chan->rate; target_chan->end = sc->paintedtime + ((scache->length - startpos)<rate; target_chan->looping = false; @@ -1439,7 +1596,7 @@ void S_Music_Seek(float time) if (sc->channel[i].pos < 0) { //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; } //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) 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) { 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++) if (si->channel[i].sfx == &s->sfx) { - if (prepadl > (si->channel[i].pos>>8)) - prepadl = (si->channel[i].pos>>8); + if (prepadl > (si->channel[i].pos>>PITCHSHIFT)) + prepadl = (si->channel[i].pos>>PITCHSHIFT); break; } } @@ -2007,7 +2149,7 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, if (snd_show.ival) Con_Printf("Wasn't playing\n"); prepadl = 0; - spare = s->sfxcache->length; + spare = 0; if (spare > snd_speed) { 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 { + if (prepadl < 0) + prepadl = 0; spare = s->sfxcache->length - prepadl; if (spare < 0) //remaining samples since last time 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"); 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); } - s->sfxcache->loopstart = s->sfxcache->length; + s->sfxcache->loopstart = -1;//s->sfxcache->length; 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) { si->channel[i].pos -= prepadl*si->channel[i].rate; -// si->channel[i].end -= prepadl; si->channel[i].end += outsamples; 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. { - S_StartSoundCard(si, -1, 0, &s->sfx, r_origin, 1, 32767, 500, 0); -// Con_Printf("Restarted\n"); + /*slight delay to try to avoid frame rate/etc stops/starts*/ + 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); } diff --git a/engine/client/snd_mix.c b/engine/client/snd_mix.c index 3a904c490..b344add27 100644 --- a/engine/client/snd_mix.c +++ b/engine/client/snd_mix.c @@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PAINTBUFFER_SIZE 2048 +float voicevolumemod = 1; portable_samplegroup_t paintbuffer[PAINTBUFFER_SIZE]; int *snd_p, snd_vol; @@ -70,7 +71,7 @@ void S_TransferPaintBuffer(soundcardinfo_t *sc, int endtime) count = (endtime - sc->paintedtime) * sc->sn.numchannels; outlimit = sc->sn.samples; startidx = out_idx = (sc->paintedtime * sc->sn.numchannels) % outlimit; - snd_vol = volume.value*256; + snd_vol = (volume.value*voicevolumemod)*256; pbuf = sc->Lock(sc); 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. { ch->pos = scache->length*ch->rate; - ch->end = scache->length; + ch->end = sc->paintedtime; } diff --git a/engine/client/sound.h b/engine/client/sound.h index 07f4a7012..14c47ffa6 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -148,9 +148,15 @@ void S_DefaultSpeakerConfiguration(soundcardinfo_t *sc); void S_ResetFailedLoad(void); #ifdef VOICECHAT -void S_ParseVoiceChat(void); -void S_TransmitVoiceChat(unsigned char clc, sizebuf_t *buf); +extern cvar_t cl_voip_showmeter; +void S_Voip_Parse(void); +void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf); 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 qboolean S_IsPlayingSomewhere(sfx_t *s); @@ -222,6 +228,8 @@ extern cvar_t bgmvolume; extern cvar_t volume; extern cvar_t snd_capture; +extern float voicevolumemod; + extern qboolean snd_initialized; extern cvar_t snd_usemultipledevices; @@ -294,6 +302,13 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound 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 diff --git a/engine/common/common.c b/engine/common/common.c index dc6b4350b..aec68ded1 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -1336,6 +1336,8 @@ char *MSG_ReadStringLine (void) float MSG_ReadCoord (void) { coorddata c = {{0}}; + if (!net_message.prim.coordsize) + net_message.prim.coordsize = 2; MSG_ReadData(&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) { + if (!net_message.prim.anglesize) + net_message.prim.anglesize = 1; + switch(net_message.prim.anglesize) { case 2: diff --git a/engine/common/cvar.h b/engine/common/cvar.h index 9a00683d5..6bfa8d615 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -85,13 +85,14 @@ typedef struct cvar_s } cvar_t; #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 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 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 CVARF(ConsoleName,Value,Flags) CVARFC(ConsoleName, Value, Flags, NULL) #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 CVAR(ConsoleName,Value) CVARD(ConsoleName, Value, NULL) diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index 30acdb3b4..80260bbd0 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -154,7 +154,7 @@ inrange: if (reliable) { 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 SZ_Write(&demo.datagram, sv.multicast.data, sv.multicast.cursize); }*/ diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index de71a7386..44ecf721b 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -3209,8 +3209,8 @@ void PF_stuffcmd (progfuncs_t *prinst, struct globalvars_s *pr_globals) if (sv.mvdrecording) { MVDWrite_Begin (dem_single, entnum - 1, 2 + slen); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_stufftext); - MSG_WriteString ((sizebuf_t*)demo.dbuf, str); + MSG_WriteByte (&demo.dbuf->sb, svc_stufftext); + MSG_WriteString (&demo.dbuf->sb, str); } } diff --git a/engine/server/server.h b/engine/server/server.h index 5b1d64787..4fe567133 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -593,11 +593,7 @@ typedef struct { typedef struct { - qboolean allowoverflow; // if false, do a Sys_Error - qboolean overflowed; // set to true if the buffer size failed - qbyte *data; - int maxsize; - int cursize; + sizebuf_t sb; int bufsize; header_t *h; } demobuf_t; @@ -607,7 +603,6 @@ typedef struct demo_client_t clients[MAX_CLIENTS]; double time; demobuf_t buf; - } demo_frame_t; typedef struct { diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 02df302d4..2287813e4 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -1556,9 +1556,9 @@ void SV_ConSay_f(void) if (sv.mvdrecording) { MVDWrite_Begin (dem_all, 0, strlen(text)+3); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_print); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, PRINT_CHAT); - MSG_WriteString ((sizebuf_t*)demo.dbuf, text); + MSG_WriteByte (&demo.dbuf->sb, svc_print); + MSG_WriteByte (&demo.dbuf->sb, PRINT_CHAT); + MSG_WriteString (&demo.dbuf->sb, text); } } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 8e9e8fd44..f9ae82d5f 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -153,7 +153,6 @@ cvar_t sv_pupglow = CVARF("sv_pupglow", "", CVAR_SERVERINFO); cvar_t sv_master = CVAR("sv_master", "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_csqcdebug = CVAR("sv_csqcdebug", "0"); 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 (&sv_voicechat, cvargroup_servercontrol); Cvar_Register (&sv_maxrate, cvargroup_servercontrol); Cvar_Register (&sv_maxdrate, cvargroup_servercontrol); Cvar_Register (&sv_minping, cvargroup_servercontrol); diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 1c28babe5..f2e8dc758 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -766,12 +766,12 @@ void SV_MVDPings (void) continue; MVDWrite_Begin (dem_all, 0, 7); - MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updateping); - MSG_WriteByte((sizebuf_t*)demo.dbuf, j); - MSG_WriteShort((sizebuf_t*)demo.dbuf, SV_CalcPing(client, false)); - MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updatepl); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, j); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, client->lossage); + MSG_WriteByte(&demo.dbuf->sb, svc_updateping); + MSG_WriteByte(&demo.dbuf->sb, j); + MSG_WriteShort(&demo.dbuf->sb, SV_CalcPing(client, false)); + MSG_WriteByte(&demo.dbuf->sb, svc_updatepl); + MSG_WriteByte (&demo.dbuf->sb, j); + 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, // we won't be able to write there anymore if (prev != NULL) - prev->maxsize = prev->bufsize; + prev->sb.maxsize = prev->bufsize; demo.dbuf = cur; memset(demo.dbuf, 0, sizeof(*demo.dbuf)); - demo.dbuf->data = demobuffer->data + demobuffer->end; - demo.dbuf->maxsize = MAXSIZE; + demo.dbuf->sb.data = demobuffer->data + demobuffer->end; + 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; sizebuf_t msg; - p = (header_t *)demo.dbuf->data; + p = (header_t *)demo.dbuf->sb.data; demo.dbuf->h = NULL; 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 - if (demo.dbuf->data != (qbyte*)p) - memmove(demo.dbuf->data + size + header, demo.dbuf->data, (qbyte*)p - demo.dbuf->data); + if (demo.dbuf->sb.data != (qbyte*)p) + memmove(demo.dbuf->sb.data + size + header, demo.dbuf->sb.data, (qbyte*)p - demo.dbuf->sb.data); demo.dbuf->bufsize -= size + header; - demo.dbuf->data += size + header; + demo.dbuf->sb.data += size + header; pos -= size + header; - demo.dbuf->maxsize -= size + header; + demo.dbuf->sb.maxsize -= size + header; demobuffer->start += size + header; } // move along @@ -865,7 +866,7 @@ void SV_MVDWriteToDisk(int type, int to, float time) if (demobuffer->start == demobuffer->end) { demobuffer->end = 0; // demobuffer is empty - demo.dbuf->data = demobuffer->data; + demo.dbuf->sb.data = demobuffer->data; } // go back to begining of the buffer @@ -887,7 +888,7 @@ static void MVDSetBuf(qbyte type, int to) header_t *p; int pos = 0; - p = (header_t *)demo.dbuf->data; + p = (header_t *)demo.dbuf->sb.data; 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) { - demo.dbuf->cursize = pos; + demo.dbuf->sb.cursize = pos; demo.dbuf->h = p; return; } @@ -910,7 +911,7 @@ static void MVDSetBuf(qbyte type, int to) p->full = 0; demo.dbuf->bufsize += header; - demo.dbuf->cursize = demo.dbuf->bufsize; + demo.dbuf->sb.cursize = demo.dbuf->bufsize; demobuffer->end += header; demo.dbuf->h = p; } @@ -921,11 +922,11 @@ void MVDMoveBuf(void) demobuffer->last = demobuffer->end - demo.dbuf->bufsize; // move buffer to the begining of demo buffer - memmove(demobuffer->data, demo.dbuf->data, demo.dbuf->bufsize); - demo.dbuf->data = demobuffer->data; + memmove(demobuffer->data, demo.dbuf->sb.data, demo.dbuf->bufsize); + demo.dbuf->sb.data = demobuffer->data; demobuffer->end = demo.dbuf->bufsize; 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) @@ -934,7 +935,7 @@ qboolean MVDWrite_Begin(qbyte type, int to, int size) qboolean move = false; // 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 (!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 - if (demo.dbuf->cursize != demo.dbuf->bufsize) { - p = demo.dbuf->data + demo.dbuf->cursize; - memmove(p+size, p, demo.dbuf->bufsize - demo.dbuf->cursize); + if (demo.dbuf->sb.cursize != demo.dbuf->bufsize) { + p = demo.dbuf->sb.data + demo.dbuf->sb.cursize; + memmove(p+size, p, demo.dbuf->bufsize - demo.dbuf->sb.cursize); } demo.dbuf->bufsize += size; @@ -1092,6 +1093,7 @@ qboolean SV_MVDWritePackets (int num) if (!sv.mvdrecording) return false; + msg.prim = svs.netprim; msg.data = msg_buf; msg.maxsize = sizeof(msg_buf); @@ -1228,7 +1230,7 @@ qboolean SV_MVDWritePackets (int num) demo.lastwritten = demo.parsecount; 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; } @@ -1384,6 +1386,7 @@ mvddest_t *SV_InitRecordFile (char *name) else FS_Remove(path, FS_GAMEONLY); + FS_FlushFSHash(); return dst; } @@ -1458,12 +1461,12 @@ void SV_MVDStop (int reason, qboolean mvdonly) // write a disconnect message to the demo file // clearup to be sure message will fit - demo.dbuf->cursize = 0; + demo.dbuf->sb.cursize = 0; demo.dbuf->h = NULL; demo.dbuf->bufsize = 0; MVDWrite_Begin(dem_all, 0, 2+strlen("EndOfDemo")); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_disconnect); - MSG_WriteString ((sizebuf_t*)demo.dbuf, "EndOfDemo"); + MSG_WriteByte (&demo.dbuf->sb, svc_disconnect); + MSG_WriteString (&demo.dbuf->sb, "EndOfDemo"); SV_MVDWritePackets(demo.parsecount - demo.lastwritten + 1); // finish up @@ -1587,17 +1590,20 @@ static qboolean SV_MVD_Record (mvddest_t *dest) memset(&demo, 0, sizeof(demo)); demo.recorder.frameunion.frames = demo_frames; demo.recorder.protocol = SCP_QUAKEWORLD; + demo.recorder.netchan.netprim = sv.datagram.prim; for (i = 0; i < UPDATE_BACKUP; i++) { demo.recorder.frameunion.frames[i].entities.max_entities = MAX_MVDPACKET_ENTITIES; 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)); MVDSetMsgBuf(NULL, &demo.frames[0].buf); demo.datagram.maxsize = sizeof(demo.datagram_data); demo.datagram.data = demo.datagram_data; + demo.datagram.prim = demo.recorder.netchan.netprim; } // else // SV_WriteRecordMVDMessage(&buf, dem_read); @@ -1637,6 +1643,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest) memset(&buf, 0, sizeof(buf)); buf.data = buf_data; buf.maxsize = sizeof(buf_data); + buf.prim = svs.netprim; // send the serverdata @@ -1645,7 +1652,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest) gamedir = "qw"; 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, PEXT_FLOATCOORDS); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 7592d2e3a..1e85518e8 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -2175,7 +2175,7 @@ qboolean SV_Physics (void) SV_RunEntity (ent); 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)); World_LinkEdict (&sv.world, (wedict_t*)ent, true); // a change of solidity should always relink the edict. someone messed up. diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index f69478a48..9020aa9be 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -292,9 +292,9 @@ void VARGS SV_ClientPrintf (client_t *cl, int level, char *fmt, ...) if (sv.mvdrecording) { MVDWrite_Begin (dem_single, cl - svs.clients, strlen(string)+3); - MSG_WriteByte ((sizebuf_t *)demo.dbuf, svc_print); - MSG_WriteByte ((sizebuf_t *)demo.dbuf, level); - MSG_WriteString ((sizebuf_t *)demo.dbuf, string); + MSG_WriteByte (&demo.dbuf->sb, svc_print); + MSG_WriteByte (&demo.dbuf->sb, level); + MSG_WriteString (&demo.dbuf->sb, string); } if (cl->controller) @@ -322,9 +322,9 @@ void VARGS SV_ClientTPrintf (client_t *cl, int level, translation_t stringnum, . if (sv.mvdrecording) { MVDWrite_Begin (dem_single, cl - svs.clients, strlen(string)+3); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_print); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, level); - MSG_WriteString ((sizebuf_t*)demo.dbuf, string); + MSG_WriteByte (&demo.dbuf->sb, svc_print); + MSG_WriteByte (&demo.dbuf->sb, level); + MSG_WriteString (&demo.dbuf->sb, string); } SV_PrintToClient(cl, level, string); @@ -371,9 +371,9 @@ void VARGS SV_BroadcastPrintf (int level, char *fmt, ...) if (sv.mvdrecording) { MVDWrite_Begin (dem_all, 0, strlen(string)+3); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_print); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, level); - MSG_WriteString ((sizebuf_t*)demo.dbuf, string); + MSG_WriteByte (&demo.dbuf->sb, svc_print); + MSG_WriteByte (&demo.dbuf->sb, level); + 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) { 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 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) { MVDWrite_Begin (dem_single, cl - svs.clients, 2 + strlen(s)); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_centerprint); - MSG_WriteString ((sizebuf_t*)demo.dbuf, s); + MSG_WriteByte (&demo.dbuf->sb, svc_centerprint); + MSG_WriteString (&demo.dbuf->sb, s); } } @@ -1871,9 +1871,9 @@ void SV_UpdateToReliableMessages (void) if (sv.mvdrecording) { MVDWrite_Begin(dem_all, 0, 4); - MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updatefrags); - MSG_WriteByte((sizebuf_t*)demo.dbuf, i); - MSG_WriteShort((sizebuf_t*)demo.dbuf, host_client->edict->v->frags); + MSG_WriteByte(&demo.dbuf->sb, svc_updatefrags); + MSG_WriteByte(&demo.dbuf->sb, i); + MSG_WriteShort(&demo.dbuf->sb, 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) { MVDWrite_Begin(dem_all, 0, 4); - MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updatefrags); - MSG_WriteByte((sizebuf_t*)demo.dbuf, i); - MSG_WriteShort((sizebuf_t*)demo.dbuf, curfrags); + MSG_WriteByte(&demo.dbuf->sb, svc_updatefrags); + MSG_WriteByte(&demo.dbuf->sb, i); + MSG_WriteShort(&demo.dbuf->sb, curfrags); } host_client->old_frags = curfrags; @@ -2363,16 +2363,16 @@ void SV_SendMVDMessage(void) if (stats[j] >=0 && stats[j] <= 255) { MVDWrite_Begin(dem_stats, i, 3); - MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updatestat); - MSG_WriteByte((sizebuf_t*)demo.dbuf, j); - MSG_WriteByte((sizebuf_t*)demo.dbuf, stats[j]); + MSG_WriteByte(&demo.dbuf->sb, svc_updatestat); + MSG_WriteByte(&demo.dbuf->sb, j); + MSG_WriteByte(&demo.dbuf->sb, stats[j]); } else { MVDWrite_Begin(dem_stats, i, 6); - MSG_WriteByte((sizebuf_t*)demo.dbuf, svc_updatestatlong); - MSG_WriteByte((sizebuf_t*)demo.dbuf, j); - MSG_WriteLong((sizebuf_t*)demo.dbuf, stats[j]); + MSG_WriteByte(&demo.dbuf->sb, svc_updatestatlong); + MSG_WriteByte(&demo.dbuf->sb, j); + MSG_WriteLong(&demo.dbuf->sb, stats[j]); } } } @@ -2381,6 +2381,7 @@ void SV_SendMVDMessage(void) // this will include clients, a packetentities, and // possibly a nails update msg.cursize = 0; + msg.prim = demo.recorder.netchan.netprim; if (!demo.recorder.delta_sequence) demo.recorder.delta_sequence = -1; @@ -2389,12 +2390,12 @@ void SV_SendMVDMessage(void) if (!MVDWrite_Begin(dem_all, 0, msg.cursize)) 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 // for this client out to the message if (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); } diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 6e281ecbc..430f28284 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -96,6 +96,7 @@ cvar_t sv_realip_timeout = SCVAR("sv_realip_timeout", "10"); #ifdef VOICECHAT 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."); #endif @@ -2100,6 +2101,7 @@ struct { unsigned int sender; unsigned char receiver[MAX_CLIENTS/8]; + unsigned char gen; unsigned char seq; unsigned int datalen; unsigned char data[1024]; @@ -2112,6 +2114,7 @@ void SV_VoiceReadPacket(void) struct voice_ring_s *ring; unsigned short bytes; client_t *cl; + unsigned char gen = MSG_ReadByte(); unsigned char seq = MSG_ReadByte(); /*read the data from the client*/ bytes = MSG_ReadShort(); @@ -2126,8 +2129,10 @@ void SV_VoiceReadPacket(void) voice.write++; MSG_ReadData(ring->data, bytes); } + ring->datalen = bytes; ring->sender = host_client - svs.clients; + ring->gen = gen; ring->seq = seq; /*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); } + + 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) { @@ -2215,6 +2245,7 @@ void SV_VoiceSendPacket(client_t *client, sizebuf_t *buf) break; MSG_WriteByte(buf, svcfte_voicechat); MSG_WriteByte(buf, ring->sender); + MSG_WriteByte(buf, ring->gen); MSG_WriteByte(buf, ring->seq); MSG_WriteShort(buf, ring->datalen); SZ_Write(buf, ring->data, ring->datalen); @@ -2899,9 +2930,9 @@ void SV_Say (qboolean team) else MVDWrite_Begin (dem_multiple, cls, strlen(text)+3); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_print); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, PRINT_CHAT); - MSG_WriteString ((sizebuf_t*)demo.dbuf, text); + MSG_WriteByte (&demo.dbuf->sb, svc_print); + MSG_WriteByte (&demo.dbuf->sb, PRINT_CHAT); + MSG_WriteString (&demo.dbuf->sb, text); } @@ -3324,10 +3355,10 @@ void SV_SetInfo_f (void) if (sv.mvdrecording) { MVDWrite_Begin (dem_all, 0, strlen(key)+strlen(val)+4); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, svc_setinfo); - MSG_WriteByte ((sizebuf_t*)demo.dbuf, i); - MSG_WriteString ((sizebuf_t*)demo.dbuf, key); - MSG_WriteString ((sizebuf_t*)demo.dbuf, val); + MSG_WriteByte (&demo.dbuf->sb, svc_setinfo); + MSG_WriteByte (&demo.dbuf->sb, i); + MSG_WriteString (&demo.dbuf->sb, key); + MSG_WriteString (&demo.dbuf->sb, val); } }