aboutsummaryrefslogtreecommitdiffstats
path: root/code/server/sv_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'code/server/sv_client.c')
-rw-r--r--code/server/sv_client.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/code/server/sv_client.c b/code/server/sv_client.c
index c9915b9..6f932d1 100644
--- a/code/server/sv_client.c
+++ b/code/server/sv_client.c
@@ -1083,6 +1083,50 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
}
}
+#if USE_VOIP
+/*
+==================
+SV_WriteVoipToClient
+
+Check to see if there is any VoIP queued for a client, and send if there is.
+==================
+*/
+void SV_WriteVoipToClient( client_t *cl, msg_t *msg )
+{
+ voipServerPacket_t *packet = &cl->voipPacket[0];
+ int totalbytes = 0;
+ int i;
+
+ if (*cl->downloadName) {
+ cl->queuedVoipPackets = 0;
+ return; // no VoIP allowed if download is going, to save bandwidth.
+ }
+
+ // Write as many VoIP packets as we reasonably can...
+ for (i = 0; i < cl->queuedVoipPackets; i++, packet++) {
+ totalbytes += packet->len;
+ if (totalbytes > MAX_DOWNLOAD_BLKSIZE)
+ break;
+
+ MSG_WriteByte( msg, svc_voip );
+ MSG_WriteShort( msg, packet->sender );
+ MSG_WriteByte( msg, (byte) packet->generation );
+ MSG_WriteLong( msg, packet->sequence );
+ MSG_WriteByte( msg, packet->frames );
+ MSG_WriteShort( msg, packet->len );
+ MSG_WriteData( msg, packet->data, packet->len );
+ }
+
+ // !!! FIXME: I hate this queue system.
+ cl->queuedVoipPackets -= i;
+ if (cl->queuedVoipPackets > 0) {
+ memmove( &cl->voipPacket[0], &cl->voipPacket[i],
+ sizeof (voipServerPacket_t) * i);
+ }
+}
+#endif
+
+
/*
=================
SV_Disconnect_f
@@ -1326,6 +1370,11 @@ void SV_UserinfoChanged( client_t *cl ) {
cl->snapshotMsec = 50;
}
+#if USE_VOIP
+ val = Info_ValueForKey (cl->userinfo, "voip");
+ cl->hasVoip = (strlen(val) && atoi(val)) ? qtrue : qfalse;
+#endif
+
// TTimo
// maintain the IP information
// the banning code relies on this being consistently present
@@ -1361,6 +1410,39 @@ static void SV_UpdateUserinfo_f( client_t *cl ) {
VM_Call( gvm, GAME_CLIENT_USERINFO_CHANGED, cl - svs.clients );
}
+
+#if USE_VOIP
+static
+void SV_UpdateVoipIgnore(client_t *cl, const char *idstr, qboolean ignore)
+{
+ if ((*idstr >= '0') && (*idstr <= '9')) {
+ const int id = atoi(idstr);
+ if ((id >= 0) && (id < MAX_CLIENTS)) {
+ cl->ignoreVoipFromClient[id] = ignore;
+ }
+ }
+}
+
+/*
+==================
+SV_UpdateUserinfo_f
+==================
+*/
+static void SV_Voip_f( client_t *cl ) {
+ const char *cmd = Cmd_Argv(1);
+ if (strcmp(cmd, "ignore") == 0) {
+ SV_UpdateVoipIgnore(cl, Cmd_Argv(2), qtrue);
+ } else if (strcmp(cmd, "unignore") == 0) {
+ SV_UpdateVoipIgnore(cl, Cmd_Argv(2), qfalse);
+ } else if (strcmp(cmd, "muteall") == 0) {
+ cl->muteAllVoip = qtrue;
+ } else if (strcmp(cmd, "unmuteall") == 0) {
+ cl->muteAllVoip = qfalse;
+ }
+}
+#endif
+
+
typedef struct {
char *name;
void (*func)( client_t *cl );
@@ -1376,6 +1458,10 @@ static ucmd_t ucmds[] = {
{"stopdl", SV_StopDownload_f},
{"donedl", SV_DoneDownload_f},
+#if USE_VOIP
+ {"voip", SV_Voip_f},
+#endif
+
{NULL, NULL}
};
@@ -1596,6 +1682,118 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) {
}
+#if USE_VOIP
+static
+qboolean SV_ShouldIgnoreVoipSender(const client_t *cl)
+{
+ if (!sv_voip->integer)
+ return qtrue; // VoIP disabled on this server.
+ else if (!cl->hasVoip) // client doesn't have VoIP support?!
+ return qtrue;
+
+ // !!! FIXME: implement player blacklist.
+
+ return qfalse; // don't ignore.
+}
+
+static
+void SV_UserVoip( client_t *cl, msg_t *msg ) {
+ const int sender = (int) (cl - svs.clients);
+ const int generation = MSG_ReadByte(msg);
+ const int sequence = MSG_ReadLong(msg);
+ const int frames = MSG_ReadByte(msg);
+ const int recip1 = MSG_ReadLong(msg);
+ const int recip2 = MSG_ReadLong(msg);
+ const int recip3 = MSG_ReadLong(msg);
+ const int packetsize = MSG_ReadShort(msg);
+ byte encoded[sizeof (cl->voipPacket[0].data)];
+ client_t *client = NULL;
+ voipServerPacket_t *packet = NULL;
+ int i;
+
+ if (generation < 0)
+ return; // short/invalid packet, bail.
+ else if (sequence < 0)
+ return; // short/invalid packet, bail.
+ else if (frames < 0)
+ return; // short/invalid packet, bail.
+ else if (recip1 < 0)
+ return; // short/invalid packet, bail.
+ else if (recip2 < 0)
+ return; // short/invalid packet, bail.
+ else if (recip3 < 0)
+ return; // short/invalid packet, bail.
+ else if (packetsize < 0)
+ return; // short/invalid packet, bail.
+
+ if (packetsize > sizeof (encoded)) { // overlarge packet?
+ int bytesleft = packetsize;
+ while (bytesleft) {
+ int br = bytesleft;
+ if (br > sizeof (encoded))
+ br = sizeof (encoded);
+ MSG_ReadData(msg, encoded, br);
+ bytesleft -= br;
+ }
+ return; // overlarge packet, bail.
+ }
+
+ MSG_ReadData(msg, encoded, packetsize);
+
+ if (SV_ShouldIgnoreVoipSender(cl))
+ return; // Blacklisted, disabled, etc.
+
+ // !!! FIXME: see if we read past end of msg...
+
+ // !!! FIXME: reject if not speex narrowband codec.
+ // !!! FIXME: decide if this is bogus data?
+
+ // (the three recip* values are 31 bits each (ignores sign bit so we can
+ // get a -1 error from MSG_ReadLong() ... ), allowing for 93 clients.)
+ assert( sv_maxclients->integer < 93 );
+
+ // decide who needs this VoIP packet sent to them...
+ for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {
+ if (client->state != CS_ACTIVE)
+ continue; // not in the game yet, don't send to this guy.
+ else if (i == sender)
+ continue; // don't send voice packet back to original author.
+ else if (!client->hasVoip)
+ continue; // no VoIP support, or support disabled.
+ else if (client->muteAllVoip)
+ continue; // client is ignoring everyone.
+ else if (client->ignoreVoipFromClient[sender])
+ continue; // client is ignoring this talker.
+ else if (*cl->downloadName) // !!! FIXME: possible to DoS?
+ continue; // no VoIP allowed if downloading, to save bandwidth.
+ else if ( ((i >= 0) && (i < 31)) && ((recip1 & (1 << (i-0))) == 0) )
+ continue; // not addressed to this player.
+ else if ( ((i >= 31) && (i < 62)) && ((recip2 & (1 << (i-31))) == 0) )
+ continue; // not addressed to this player.
+ else if ( ((i >= 62) && (i < 93)) && ((recip3 & (1 << (i-62))) == 0) )
+ continue; // not addressed to this player.
+
+ // Transmit this packet to the client.
+ // !!! FIXME: I don't like this queueing system.
+ if (client->queuedVoipPackets >= (sizeof (client->voipPacket) / sizeof (client->voipPacket[0]))) {
+ Com_Printf("Too many VoIP packets queued for client #%d\n", i);
+ continue; // no room for another packet right now.
+ }
+
+ packet = &client->voipPacket[client->queuedVoipPackets];
+ packet->sender = sender;
+ packet->frames = frames;
+ packet->len = packetsize;
+ packet->generation = generation;
+ packet->sequence = sequence;
+ memcpy(packet->data, encoded, packetsize);
+ client->queuedVoipPackets++;
+ }
+}
+#endif
+
+
+
/*
===========================================================================
@@ -1699,6 +1897,10 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
SV_UserMove( cl, msg, qtrue );
} else if ( c == clc_moveNoDelta ) {
SV_UserMove( cl, msg, qfalse );
+#if USE_VOIP
+ } else if ( c == clc_voip ) {
+ SV_UserVoip( cl, msg );
+#endif
} else if ( c != clc_EOF ) {
Com_Printf( "WARNING: bad command byte for client %i\n", (int) (cl - svs.clients) );
}