summaryrefslogtreecommitdiff
path: root/src/client/cl_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/cl_main.c')
-rw-r--r--src/client/cl_main.c234
1 files changed, 152 insertions, 82 deletions
diff --git a/src/client/cl_main.c b/src/client/cl_main.c
index 34eb95af..dc177cf7 100644
--- a/src/client/cl_main.c
+++ b/src/client/cl_main.c
@@ -45,6 +45,7 @@ cvar_t *cl_voipSendTarget;
cvar_t *cl_voipGainDuringCapture;
cvar_t *cl_voipCaptureMult;
cvar_t *cl_voipShowMeter;
+cvar_t *cl_voipProtocol;
cvar_t *cl_voip;
#endif
@@ -149,7 +150,6 @@ typedef struct serverStatus_s
} serverStatus_t;
serverStatus_t cl_serverStatusList[MAX_SERVERSTATUSREQUESTS];
-int serverStatusCount;
#if defined __USEA3D && defined __A3D_GEOM
void hA3Dg_ExportRenderGeom (refexport_t *incoming_re);
@@ -251,8 +251,8 @@ void CL_Voip_f( void )
if (clc.state != CA_ACTIVE)
reason = "Not connected to a server";
- else if (!clc.speexInitialized)
- reason = "Speex not initialized";
+ else if (!clc.voipCodecInitialized)
+ reason = "Voip codec not initialized";
else if (!clc.voipEnabled)
reason = "Server doesn't support VoIP";
@@ -305,6 +305,8 @@ void CL_VoipNewGeneration(void)
clc.voipOutgoingGeneration = 1;
clc.voipPower = 0.0f;
clc.voipOutgoingSequence = 0;
+
+ opus_encoder_ctl(clc.opusEncoder, OPUS_RESET_STATE);
}
/*
@@ -393,7 +395,7 @@ void CL_VoipParseTargets(void)
===============
CL_CaptureVoip
-Record more audio from the hardware if required and encode it into Speex
+Record more audio from the hardware if required and encode it into Opus
data for later transmission.
===============
*/
@@ -423,11 +425,12 @@ void CL_CaptureVoip(void)
Com_Printf("Until then, VoIP is disabled.\n");
Cvar_Set("cl_voip", "0");
}
+ Cvar_Set("cl_voipProtocol", cl_voip->integer ? "opus" : "");
cl_voip->modified = qfalse;
cl_rate->modified = qfalse;
}
- if (!clc.speexInitialized)
+ if (!clc.voipCodecInitialized)
return; // just in case this gets called at a bad time.
if (clc.voipOutgoingDataSize > 0)
@@ -480,80 +483,67 @@ void CL_CaptureVoip(void)
if ((cl_voipSend->integer) || (finalFrame)) { // user wants to capture audio?
int samples = S_AvailableCaptureSamples();
- const int mult = (finalFrame) ? 1 : 4; // 4 == 80ms of audio.
+ const int packetSamples = (finalFrame) ? VOIP_MAX_FRAME_SAMPLES : VOIP_MAX_PACKET_SAMPLES;
// enough data buffered in audio hardware to process yet?
- if (samples >= (clc.speexFrameSize * mult)) {
- // audio capture is always MONO16 (and that's what speex wants!).
- // 2048 will cover 12 uncompressed frames in narrowband mode.
- static int16_t sampbuffer[2048];
+ if (samples >= packetSamples) {
+ // audio capture is always MONO16.
+ static int16_t sampbuffer[VOIP_MAX_PACKET_SAMPLES];
float voipPower = 0.0f;
- int speexFrames = 0;
- int wpos = 0;
- int pos = 0;
+ int voipFrames;
+ int i, bytes;
- if (samples > (clc.speexFrameSize * 4))
- samples = (clc.speexFrameSize * 4);
+ if (samples > VOIP_MAX_PACKET_SAMPLES)
+ samples = VOIP_MAX_PACKET_SAMPLES;
// !!! FIXME: maybe separate recording from encoding, so voipPower
// !!! FIXME: updates faster than 4Hz?
- samples -= samples % clc.speexFrameSize;
- S_Capture(samples, (byte *) sampbuffer); // grab from audio card.
-
- // this will probably generate multiple speex packets each time.
- while (samples > 0) {
- int16_t *sampptr = &sampbuffer[pos];
- int i, bytes;
+ samples -= samples % VOIP_MAX_FRAME_SAMPLES;
+ if (samples != 120 && samples != 240 && samples != 480 && samples != 960 && samples != 1920 && samples != 2880 ) {
+ Com_Printf("Voip: bad number of samples %d\n", samples);
+ return;
+ }
+ voipFrames = samples / VOIP_MAX_FRAME_SAMPLES;
- // preprocess samples to remove noise...
- speex_preprocess_run(clc.speexPreprocessor, sampptr);
+ S_Capture(samples, (byte *) sampbuffer); // grab from audio card.
- // check the "power" of this packet...
- for (i = 0; i < clc.speexFrameSize; i++) {
- const float flsamp = (float) sampptr[i];
- const float s = fabs(flsamp);
- voipPower += s * s;
- sampptr[i] = (int16_t) ((flsamp) * audioMult);
- }
+ // check the "power" of this packet...
+ for (i = 0; i < samples; i++) {
+ const float flsamp = (float) sampbuffer[i];
+ const float s = fabs(flsamp);
+ voipPower += s * s;
+ sampbuffer[i] = (int16_t) ((flsamp) * audioMult);
+ }
- // encode raw audio samples into Speex data...
- speex_bits_reset(&clc.speexEncoderBits);
- speex_encode_int(clc.speexEncoder, sampptr,
- &clc.speexEncoderBits);
- bytes = speex_bits_write(&clc.speexEncoderBits,
- (char *) &clc.voipOutgoingData[wpos+1],
- sizeof (clc.voipOutgoingData) - (wpos+1));
- assert((bytes > 0) && (bytes < 256));
- clc.voipOutgoingData[wpos] = (byte) bytes;
- wpos += bytes + 1;
-
- // look at the data for the next packet...
- pos += clc.speexFrameSize;
- samples -= clc.speexFrameSize;
- speexFrames++;
+ // encode raw audio samples into Opus data...
+ bytes = opus_encode(clc.opusEncoder, sampbuffer, samples,
+ (unsigned char *) clc.voipOutgoingData,
+ sizeof (clc.voipOutgoingData));
+ if ( bytes <= 0 ) {
+ Com_DPrintf("VoIP: Error encoding %d samples\n", samples);
+ bytes = 0;
}
clc.voipPower = (voipPower / (32768.0f * 32768.0f *
- ((float) (clc.speexFrameSize * speexFrames)))) *
- 100.0f;
+ ((float) samples))) * 100.0f;
if ((useVad) && (clc.voipPower < cl_voipVADThreshold->value)) {
CL_VoipNewGeneration(); // no "talk" for at least 1/4 second.
} else {
- clc.voipOutgoingDataSize = wpos;
- clc.voipOutgoingDataFrames = speexFrames;
+ clc.voipOutgoingDataSize = bytes;
+ clc.voipOutgoingDataFrames = voipFrames;
Com_DPrintf("VoIP: Send %d frames, %d bytes, %f power\n",
- speexFrames, wpos, clc.voipPower);
+ voipFrames, bytes, clc.voipPower);
#if 0
static FILE *encio = NULL;
if (encio == NULL) encio = fopen("voip-outgoing-encoded.bin", "wb");
- if (encio != NULL) { fwrite(clc.voipOutgoingData, wpos, 1, encio); fflush(encio); }
+ if (encio != NULL) { fwrite(clc.voipOutgoingData, bytes, 1, encio); fflush(encio); }
static FILE *decio = NULL;
if (decio == NULL) decio = fopen("voip-outgoing-decoded.bin", "wb");
- if (decio != NULL) { fwrite(sampbuffer, speexFrames * clc.speexFrameSize * 2, 1, decio); fflush(decio); }
+ if (decio != NULL) { fwrite(sampbuffer, voipFrames * VOIP_MAX_FRAME_SAMPLES * 2, 1, decio); fflush(decio); }
#endif
}
}
@@ -1420,14 +1410,11 @@ void CL_Disconnect( qboolean showMainMenu ) {
cl_voipUseVAD->integer = tmp;
}
- if (clc.speexInitialized) {
+ if (clc.voipCodecInitialized) {
int i;
- speex_bits_destroy(&clc.speexEncoderBits);
- speex_encoder_destroy(clc.speexEncoder);
- speex_preprocess_state_destroy(clc.speexPreprocessor);
+ opus_encoder_destroy(clc.opusEncoder);
for (i = 0; i < MAX_CLIENTS; i++) {
- speex_bits_destroy(&clc.speexDecoderBits[i]);
- speex_decoder_destroy(clc.speexDecoder[i]);
+ opus_decoder_destroy(clc.opusDecoder[i]);
}
}
Cmd_RemoveCommand ("voip");
@@ -1732,6 +1719,50 @@ static void CL_CompleteRcon( char *args, int argNum )
}
/*
+==================
+CL_CompletePlayerName
+==================
+*/
+static void CL_CompletePlayerName( char *args, int argNum )
+{
+ if( argNum == 2 )
+ {
+ char names[MAX_CLIENTS][MAX_NAME_LENGTH];
+ char *namesPtr[MAX_CLIENTS];
+ int i;
+ int clientCount;
+ int nameCount;
+ const char *info;
+ const char *name;
+
+ //configstring
+ info = cl.gameState.stringData + cl.gameState.stringOffsets[CS_SERVERINFO];
+ clientCount = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
+
+ nameCount = 0;
+
+ for( i = 0; i < clientCount; i++ ) {
+ if( i == clc.clientNum )
+ continue;
+
+ info = cl.gameState.stringData + cl.gameState.stringOffsets[CS_PLAYERS+i];
+
+ name = Info_ValueForKey( info, "n" );
+ if( name[0] == '\0' )
+ continue;
+ Q_strncpyz( names[nameCount], name, sizeof(names[nameCount]) );
+ Q_CleanStr( names[nameCount] );
+
+ namesPtr[nameCount] = names[nameCount];
+ nameCount++;
+ }
+ qsort( (void*)namesPtr, nameCount, sizeof( namesPtr[0] ), Com_strCompare );
+
+ Field_CompletePlayerName( namesPtr, nameCount );
+ }
+}
+
+/*
=====================
CL_Rcon_f
@@ -1743,7 +1774,7 @@ void CL_Rcon_f( void ) {
char message[MAX_RCON_MESSAGE];
netadr_t to;
- if ( !rcon_client_password->string ) {
+ if ( !rcon_client_password->string[0] ) {
Com_Printf ("You must set 'rconpassword' before\n"
"issuing an rcon command.\n");
return;
@@ -2312,9 +2343,9 @@ Resend a connect message if the last one has timed out
=================
*/
void CL_CheckForResend( void ) {
- int port, i;
+ int port;
char info[MAX_INFO_STRING];
- char data[MAX_INFO_STRING];
+ char data[MAX_INFO_STRING + 10];
// don't send anything if playing back a demo
if ( clc.demoplaying ) {
@@ -2355,19 +2386,8 @@ void CL_CheckForResend( void ) {
Info_SetValueForKey( info, "qport", va("%i", port ) );
Info_SetValueForKey( info, "challenge", va("%i", clc.challenge ) );
- strcpy(data, "connect ");
- // TTimo adding " " around the userinfo string to avoid truncated userinfo on the server
- // (Com_TokenizeString tokenizes around spaces)
- data[8] = '"';
-
- for(i=0;i<strlen(info);i++) {
- data[9+i] = info[i]; // + (clc.challenge)&0x3;
- }
- data[9+i] = '"';
- data[10+i] = 0;
-
- // NOTE TTimo don't forget to set the right data length!
- NET_OutOfBandData( NS_CLIENT, clc.serverAddress, (byte *) &data[0], i+10 );
+ Com_sprintf( data, sizeof(data), "connect \"%s\"", info );
+ NET_OutOfBandData( NS_CLIENT, clc.serverAddress, (byte *) data, strlen ( data ) );
// the most current userinfo has been sent, so watch for any
// newer changes to userinfo variables
cvar_modifiedFlags &= ~CVAR_USERINFO;
@@ -3474,6 +3494,56 @@ static void CL_GenerateQKey(void)
}
}
+void CL_Sayto_f( void ) {
+ char *rawname;
+ char name[MAX_NAME_LENGTH];
+ char cleanName[MAX_NAME_LENGTH];
+ const char *info;
+ int count;
+ int i;
+ int clientNum;
+ char *p;
+
+ if ( Cmd_Argc() < 3 ) {
+ Com_Printf ("sayto <player name> <text>\n");
+ return;
+ }
+
+ rawname = Cmd_Argv(1);
+
+ Com_FieldStringToPlayerName( name, MAX_NAME_LENGTH, rawname );
+
+ info = cl.gameState.stringData + cl.gameState.stringOffsets[CS_SERVERINFO];
+ count = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
+
+ clientNum = -1;
+ for( i = 0; i < count; i++ ) {
+
+ info = cl.gameState.stringData + cl.gameState.stringOffsets[CS_PLAYERS+i];
+ Q_strncpyz( cleanName, Info_ValueForKey( info, "n" ), sizeof(cleanName) );
+ Q_CleanStr( cleanName );
+
+ if ( !Q_stricmp( cleanName, name ) ) {
+ clientNum = i;
+ break;
+ }
+ }
+ if( clientNum <= -1 )
+ {
+ Com_Printf ("No such player name: %s.\n", name);
+ return;
+ }
+
+ p = Cmd_ArgsFrom(2);
+
+ if ( *p == '"' ) {
+ p++;
+ p[strlen(p)-1] = 0;
+ }
+
+ CL_AddReliableCommand(va("tell %i \"%s\"", clientNum, p ), qfalse);
+}
+
/*
====================
CL_Init
@@ -3624,9 +3694,9 @@ void CL_Init( void ) {
cl_voipVADThreshold = Cvar_Get ("cl_voipVADThreshold", "0.25", CVAR_ARCHIVE);
cl_voipShowMeter = Cvar_Get ("cl_voipShowMeter", "1", CVAR_ARCHIVE);
- // This is a protocol version number.
- cl_voip = Cvar_Get ("cl_voip", "1", CVAR_USERINFO | CVAR_ARCHIVE);
+ cl_voip = Cvar_Get ("cl_voip", "1", CVAR_ARCHIVE);
Cvar_CheckRange( cl_voip, 0, 1, qtrue );
+ cl_voipProtocol = Cvar_Get ("cl_voipProtocol", cl_voip->integer ? "opus" : "", CVAR_USERINFO | CVAR_ROM);
#endif
@@ -3663,6 +3733,10 @@ void CL_Init( void ) {
Cmd_AddCommand ("model", CL_SetModel_f );
Cmd_AddCommand ("video", CL_Video_f );
Cmd_AddCommand ("stopvideo", CL_StopVideo_f );
+ if( !com_dedicated->integer ) {
+ Cmd_AddCommand ("sayto", CL_Sayto_f );
+ Cmd_SetCommandCompletionFunc( "sayto", CL_CompletePlayerName );
+ }
CL_InitRef();
SCR_Init ();
@@ -3918,11 +3992,7 @@ serverStatus_t *CL_GetServerStatus( netadr_t from ) {
oldestTime = cl_serverStatusList[i].startTime;
}
}
- if (oldest != -1) {
- return &cl_serverStatusList[oldest];
- }
- serverStatusCount++;
- return &cl_serverStatusList[serverStatusCount & (MAX_SERVERSTATUSREQUESTS-1)];
+ return &cl_serverStatusList[oldest];
}
/*