diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 60093e009..40ab7f27f 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1688,7 +1688,7 @@ qboolean CLQW_SendCmd (sizebuf_t *buf, qboolean actuallysend) void CL_SendCmd (double frametime, qboolean mainloop) { sizebuf_t buf; - qbyte data[1024]; + qbyte data[MAX_DATAGRAM]; int i, plnum; usercmd_t *cmd; float wantfps; diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index a2fbb8726..ba2c170a7 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -417,7 +417,7 @@ void CL_ConnectToDarkPlaces(char *challenge, netadr_t *adr) connectinfo.time = realtime; // for retransmit requests - Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5 FITZ NEHAHRABJP NEHAHRABJP2 NEHAHRABJP3 QUAKE\\challenge\\%s", 255, 255, 255, 255, challenge); + Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP NEHAHRABJP2 NEHAHRABJP3 QUAKE\\challenge\\%s", 255, 255, 255, 255, challenge); NET_SendPacket (NS_CLIENT, strlen(data), data, adr); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 3a261c531..0073f9c7b 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -268,7 +268,7 @@ char *svc_nqstrings[] = "NEW PROTOCOL(81)", //81 "NEW PROTOCOL(82)", //82 "nqsvcfte_cgamepacket(83)", //83 - "NEW PROTOCOL(84)", //84 + "nqsvcfte_voicechat", //84 "NEW PROTOCOL(85)", //85 "nqsvcfte_updateentities", //86 "NEW PROTOCOL(87)", //87 @@ -3659,6 +3659,10 @@ void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caution. if (CPNQ_IS_DP) //DP's protocol requires client+server to have exactly the same data files. this is shit, but in the interests of compatibility... COM_Effectinfo_Enumerate(CL_Darkplaces_Particle_Precache); +#ifdef VOICECHAT + S_Voip_MapChange(); +#endif + #ifdef PEXT_CSQC CSQC_Shutdown(); CSQC_Init(cls.demoplayback, false, 0); @@ -7823,6 +7827,12 @@ void CLNQ_ParseServerMessage (void) S_StopSound(i>>3, i&7); break; +#ifdef PEXT2_VOICECHAT + case svcfte_voicechat: + S_Voip_Parse(); + break; +#endif + case svc_temp_entity: CL_ParseTEnt (true); break; diff --git a/engine/client/m_options.c b/engine/client/m_options.c index cb9db792b..76927a358 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -552,19 +552,23 @@ void M_Menu_Audio_f (void) }; #ifdef VOICECHAT static const char *voipcodecoptions[] = { + "Auto", "Speex (ez-compat)", -// "Raw (11025)", - "Opus (external)", +// "Raw16 (11025)", + "Opus", "Speex (Narrow)", "Speex (Wide)", +// "Speex (UltraWide)", NULL }; static const char *voipcodecvalue[] = { + "", "0", // "1", "2", "3", "4", +// "5", NULL }; diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 138e7bc39..d27fb22c1 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -2684,7 +2684,7 @@ static void Sbar_Voice(int y) int s, i; float range = loudness/100.0f; w = 0; - Font_BeginString(font_default, sbar_rect.x + sbar_rect.width/2, sbar_rect.y + y + sbar_rect.height-SBAR_HEIGHT, &x, &y); + Font_BeginString(font_default, sbar_rect.x + min(320,sbar_rect.width)/2, sbar_rect.y + y + sbar_rect.height-SBAR_HEIGHT, &x, &y); w += Font_CharWidth(CON_WHITEMASK, 0xe080); w += Font_CharWidth(CON_WHITEMASK, 0xe081)*16; w += Font_CharWidth(CON_WHITEMASK, 0xe082); diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 2cdd92748..82bda41a3 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -150,10 +150,10 @@ cvar_t snd_voip_showmeter = CVARAFD("cl_voip_showmeter", "1", NULL, CVAR_ARCHIV cvar_t snd_voip_play = CVARAFDC("cl_voip_play", "1", NULL, CVAR_ARCHIVE, "Enables voip playback. Value is a volume scaler.", S_Voip_Play_Callback); cvar_t snd_voip_ducking = CVARAFD("cl_voip_ducking", "0.5", NULL, CVAR_ARCHIVE, "Scales game audio by this much when someone is talking to you. Does not affect your speaker volume when you speak (minimum of cl_voip_capturingvol and cl_voip_ducking is used)."); cvar_t snd_voip_micamp = CVARAFDC("cl_voip_micamp", "2", NULL, CVAR_ARCHIVE, "Amplifies your microphone when using voip.", 0); -cvar_t snd_voip_codec = CVARAFDC("cl_voip_codec", "0", NULL, CVAR_ARCHIVE, "0: speex(@11khz). 1: raw. 2: opus. 3: speex(@8khz). 4: speex(@16). 5:speex(@32).", 0); +cvar_t snd_voip_codec = CVARAFDC("cl_voip_codec", "", NULL, CVAR_ARCHIVE, "0: speex(@11khz). 1: raw. 2: opus. 3: speex(@8khz). 4: speex(@16). 5:speex(@32).", 0); cvar_t snd_voip_noisefilter = CVARAFDC("cl_voip_noisefilter", "1", NULL, CVAR_ARCHIVE, "Enable the use of the noise cancelation filter.", 0); cvar_t snd_voip_autogain = CVARAFDC("cl_voip_autogain", "0", NULL, CVAR_ARCHIVE, "Attempts to normalize your voice levels to a standard level. Useful for lazy people, but interferes with voice activation levels.", 0); -cvar_t snd_voip_bitrate = CVARAFDC("cl_voip_bitrate", "0", NULL, CVAR_ARCHIVE, "For codecs with non-specific bitrates, this specifies the target bitrate to use (in kb).", 0); +cvar_t snd_voip_opus_bitrate = CVARAFDC("cl_voip_opus_bitrate", "3000", NULL, CVAR_ARCHIVE, "For codecs with non-specific bitrates, this specifies the target bitrate to use.", 0); #endif extern vfsfile_t *rawwritefile; @@ -248,7 +248,7 @@ void S_SoundInfo_f(void) enum { VOIP_SPEEX_OLD = 0, //original supported codec (with needless padding and at the wrong rate to keep quake implementations easy) - VOIP_RAW = 1, //support is not recommended. + VOIP_RAW16 = 1, //support is not recommended. VOIP_OPUS = 2, //supposed to be better than speex. VOIP_SPEEX_NARROW = 3, //narrowband speex. packed data. VOIP_SPEEX_WIDE = 4, //wideband speex. packed data. @@ -256,6 +256,7 @@ enum VOIP_INVALID = 16 //not currently generating audio. }; +#define VOIP_DEFAULT_CODEC (cls.protocol==CP_QUAKEWORLD?VOIP_SPEEX_OLD:VOIP_OPUS) //opus is preferred, but ezquake is still common and only supports my first attempt at voice compression so favour that for quakeworld. static struct { struct @@ -301,7 +302,7 @@ static struct unsigned char decgen[MAX_CLIENTS]; /*last generation. if it changes, we flush speex to reset packet loss*/ unsigned int decsamplerate[MAX_CLIENTS]; unsigned int decframesize[MAX_CLIENTS]; - float lastspoke[MAX_CLIENTS]; /*time when they're no longer considered talking. if future, they're talking*/ + float lastspoke[MAX_CLIENTS]; /*time when they're no longer considered talking. if future, they're talking (timeout avoids flickering, and harder to troll with fake-tourettes when noone is looking)*/ float lastspoke_any; unsigned char capturebuf[32768]; /*pending data*/ @@ -511,8 +512,6 @@ static qboolean S_Opus_Init(void) } #endif - Con_Printf("OPUS support is experimental and should not be used\n"); //need to remove the packet length prefix. - s_voip.opus.loaded = true; return s_voip.opus.loaded; } @@ -551,7 +550,7 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un case VOIP_SPEEX_ULTRAWIDE: qspeex_decoder_destroy(s_voip.decoder[sender]); break; - case VOIP_RAW: + case VOIP_RAW16: break; case VOIP_OPUS: qopus_decoder_destroy(s_voip.decoder[sender]); @@ -565,7 +564,7 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un { default: //codec not supported. return; - case VOIP_RAW: + case VOIP_RAW16: s_voip.decsamplerate[sender] = 11025; break; case VOIP_SPEEX_OLD: @@ -634,7 +633,7 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un if (!s_voip.decoder[sender]) return; - s_voip.decframesize[sender] = (sizeof(decodebuf) / sizeof(decodebuf[0])) / 2; //this is the maximum size in a single frame. + s_voip.decframesize[sender] = s_voip.decsamplerate[sender]/400; //this is the maximum size in a single frame. } else qopus_decoder_ctl(s_voip.decoder[sender], OPUS_RESET_STATE); @@ -715,7 +714,7 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un } } break; - case VOIP_RAW: + case VOIP_RAW16: len = min(bytes, sizeof(decodebuf)-(sizeof(decodebuf[0])*decodesamps)); memcpy(decodebuf+decodesamps, start, len); decodesamps += len / sizeof(decodebuf[0]); @@ -734,9 +733,10 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un // Con_Printf("Decoded %i frames from %i bytes\n", r, len); if (r > 0) { + int frames = r / s_voip.decframesize[sender]; decodesamps += r; - s_voip.decseq[sender] = (s_voip.decseq[sender] + 1) & 0xff;//r / s_voip.decframesize[sender]; - seq = (seq+1)&0xff;//r / s_voip.decframesize[sender]; + s_voip.decseq[sender] = (s_voip.decseq[sender] + frames) & 0xff; + seq = (seq+frames)&0xff; } else if (r < 0) Con_Printf("Opus decoding error %i\n", r); @@ -909,7 +909,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) int len; float micamp = snd_voip_micamp.value; qboolean voipsendenable = true; - int voipcodec = snd_voip_codec.ival; + int voipcodec = *snd_voip_codec.string?snd_voip_codec.ival:VOIP_DEFAULT_CODEC; qboolean rtpstream = NET_RTP_Active(); if (buf) @@ -1023,7 +1023,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) qspeex_encoder_ctl(s_voip.encoder, SPEEX_SET_SAMPLING_RATE, &s_voip.encsamplerate); } break; - case VOIP_RAW: + case VOIP_RAW16: s_voip.encsamplerate = 11025; s_voip.encframesize = 256; break; @@ -1037,7 +1037,6 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) //use whatever is convienient. s_voip.encsamplerate = 48000; s_voip.encframesize = s_voip.encsamplerate / 400; //2.5ms frames, at a minimum. - s_voip.encframesize *= 4; //go for 10ms s_voip.encoder = qopus_encoder_create(s_voip.encsamplerate, 1, OPUS_APPLICATION_VOIP, NULL); if (!s_voip.encoder) return; @@ -1100,7 +1099,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) case VOIP_SPEEX_ULTRAWIDE: qspeex_bits_reset(&s_voip.speex.encbits); break; - case VOIP_RAW: + case VOIP_RAW16: break; case VOIP_OPUS: qopus_encoder_ctl(s_voip.encoder, OPUS_RESET_STATE); @@ -1196,7 +1195,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) len = qspeex_bits_write(&s_voip.speex.encbits, outbuf+outpos, sizeof(outbuf) - outpos); outpos += len; break; - case VOIP_RAW: + case VOIP_RAW16: len = s_voip.capturepos-encpos; //amount of data to be eaten in this frame len = min(len, sizeof(outbuf)-outpos); len &= ~((s_voip.encframesize*2)-1); @@ -1216,38 +1215,36 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) //densely pack the frames. start = (short*)(s_voip.capturebuf + encpos); frames = (s_voip.capturepos-encpos)/2; - frames = s_voip.encframesize; - if (frames >= 2880) - frames = 2880; - else if (frames >= 1920) - frames = 1920; - else if (frames >= 960) - frames = 960; - else if (frames >= 480) - frames = 480; - else if (frames >= 240) - frames = 240; - else if (frames >= 120) - frames = 120; - else - { - Con_Printf("invalid Opus frame size\n"); - frames = 0; - } - nrate = snd_voip_bitrate.value * 1000; + nrate = snd_voip_opus_bitrate.value; if (nrate != s_voip.curbitrate) { s_voip.curbitrate = nrate; if (nrate == 0) nrate = -1000; qopus_encoder_ctl(s_voip.encoder, OPUS_SET_BITRATE_REQUEST, (int)nrate); + nrate = 10000; } -// Con_Printf("Encoding %i frames", frames); + if (frames >= 2880) + frames = 2880; + else if (frames >= 1920 && nrate > 100) + frames = 1920; + else if (frames >= 960 && nrate > 500) + frames = 960; + else if (frames >= 480 && nrate > 1000) + frames = 480; + else if (snd_voip_send.ival & 4) + break; //don't send small rtp packets, its abusive. + else if (frames >= 240 && nrate > 2000) + frames = 240; + else if (frames >= 120 && nrate > 4000) + frames = 120; + else + break; //invalid size, wait for more. + level += S_Voip_Preprocess(start, frames, micamp); len = qopus_encode(s_voip.encoder, start, frames, outbuf+outpos, sizeof(outbuf) - outpos); -// Con_Printf(" (%i bytes)\n", len); if (len >= 0) { s_voip.encsequence += frames / s_voip.encframesize; @@ -1301,15 +1298,20 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) } } - if (outpos && (!buf || buf->maxsize - buf->cursize >= outpos+4)) + if (outpos) { - if (buf && (snd_voip_send.ival != 4)) + if (buf && !(snd_voip_send.ival & 4)) { - MSG_WriteByte(buf, clc); - MSG_WriteByte(buf, (s_voip.enccodec<<4) | (s_voip.generation & 0x0f)); /*gonna leave that nibble clear here... in this version, the client will ignore packets with those bits set. can use them for codec or something*/ - MSG_WriteByte(buf, initseq&0xff); - MSG_WriteShort(buf, outpos); - SZ_Write(buf, outbuf, outpos); + if (buf->maxsize - buf->cursize >= 5+outpos) + { + MSG_WriteByte(buf, clc); + MSG_WriteByte(buf, (s_voip.enccodec<<4) | (s_voip.generation & 0x0f)); /*gonna leave that nibble clear here... in this version, the client will ignore packets with those bits set. can use them for codec or something*/ + MSG_WriteByte(buf, initseq&0xff); + MSG_WriteShort(buf, outpos); + SZ_Write(buf, outbuf, outpos); + } + else + Con_Printf("Audio frame too small %i vs %i\n", outpos+4, buf->maxsize - buf->cursize); } #ifdef SUPPORT_ICE @@ -1379,6 +1381,7 @@ static void QDECL S_Voip_Play_Callback(cvar_t *var, char *oldval) } void S_Voip_MapChange(void) { + voipbutton = false; Cvar_ForceCallback(&snd_voip_play); } int S_Voip_Loudness(qboolean ignorevad) @@ -1417,6 +1420,7 @@ void S_Voip_Init(void) Cvar_Register(&snd_voip_codec, "Voice Chat"); Cvar_Register(&snd_voip_noisefilter, "Voice Chat"); Cvar_Register(&snd_voip_autogain, "Voice Chat"); + Cvar_Register(&snd_voip_opus_bitrate, "Voice Chat"); Cmd_AddCommand("+voip", S_Voip_Enable_f); Cmd_AddCommand("-voip", S_Voip_Disable_f); Cmd_AddCommand("voip", S_Voip_f); diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 83684eca3..7be78b2ea 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -7217,7 +7217,6 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, size_t fsi oevent->code = fteevents->evcode; oevent->data = ZG_Malloc(&mod->memgroup, strlen(strings+fteevents->evdata_str)+1); strcpy(oevent->data, strings+fteevents->evdata_str); - oevent->timestamp /= fgroup[fteevents->anim].rate; link = &fgroup[fteevents->anim].events; while (*link && (*link)->timestamp <= oevent->timestamp) link = &(*link)->next;