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->hullnum = 1;
state->scale = 1*16;
state->scale = 1;
state->alpha = 255;
state->fatness = 0;

View File

@ -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
//

View File

@ -4967,7 +4967,7 @@ void CL_ParseServerMessage (void)
#ifdef PEXT2_VOICECHAT
case svcfte_voicechat:
S_ParseVoiceChat();
S_Voip_Parse();
break;
#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:
VectorCopy (vel, cl.simvel[pnum]);

View File

@ -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<<COLUMN##title)) \
// Electro's scoreboard eyecandy: red vs blue are common teams, force the colours
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
else if (!(strcmp("blue", team)))
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);
}
else if (S_Voip_Speaking(k))
Sbar_FillPCDark (startx - 2, y, rank_width - 3, skip, 0x00ff00);
else
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__)
LPDIRECTSOUNDCAPTURE DSCapture;
LPDIRECTSOUNDCAPTUREBUFFER DSCaptureBuffer;
long lastreadpos;
long bufferbytes = 1024*1024;
long inputwidth = 2;
static WAVEFORMATEX wfxFormat;
qboolean SNDDMA_InitCapture (void)
typedef struct
{
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;
WAVEFORMATEX wfxFormat;
wfxFormat.wFormatTag = WAVE_FORMAT_PCM;
wfxFormat.nChannels = 1;
wfxFormat.nSamplesPerSec = 11025;
wfxFormat.nSamplesPerSec = rate;
wfxFormat.wBitsPerSample = 8*inputwidth;
wfxFormat.nBlockAlign = wfxFormat.nChannels * (wfxFormat.wBitsPerSample / 8);
wfxFormat.nAvgBytesPerSec = wfxFormat.nSamplesPerSec * wfxFormat.nBlockAlign;
@ -922,19 +924,7 @@ qboolean SNDDMA_InitCapture (void)
bufdesc.dwReserved = 0;
bufdesc.lpwfxFormat = &wfxFormat;
if (DSCaptureBuffer)
{
IDirectSoundCaptureBuffer_Stop(DSCaptureBuffer);
IDirectSoundCaptureBuffer_Release(DSCaptureBuffer);
DSCaptureBuffer=NULL;
}
if (DSCapture)
{
IDirectSoundCapture_Release(DSCapture);
DSCapture=NULL;
}
/*probably already inited*/
if (!hInstDS)
{
hInstDS = LoadLibrary("dsound.dll");
@ -942,10 +932,10 @@ qboolean SNDDMA_InitCapture (void)
if (hInstDS == NULL)
{
Con_SafePrintf ("Couldn't load dsound.dll\n");
return false;
return NULL;
}
}
/*global pointer, used only in this function*/
if (!pDirectSoundCaptureCreate)
{
pDirectSoundCaptureCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCaptureCreate");
@ -953,31 +943,61 @@ qboolean SNDDMA_InitCapture (void)
if (!pDirectSoundCaptureCreate)
{
Con_SafePrintf ("Couldn't get DS proc addr\n");
return false;
return NULL;
}
// 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");
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

View File

@ -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<<PITCHSHIFT) * pitchadj) / 100;
target_chan->rate = ((1<<PITCHSHIFT) * pitchadj) / 100; /*pitchadj is a percentage*/
target_chan->pos = startpos*target_chan->rate;
target_chan->end = sc->paintedtime + ((scache->length - startpos)<<PITCHSHIFT)/target_chan->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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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);
}*/

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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);
}
}

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_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);

View File

@ -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);

View File

@ -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.

View File

@ -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);
}

View File

@ -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);
}
}