From b4fa369428493692d1f72085641364eeeef79218 Mon Sep 17 00:00:00 2001 From: Martin Johansson Date: Mon, 26 Nov 2012 23:02:36 +0100 Subject: [PATCH] Add initial support for Opus --- src/client.c | 92 ++++++++++++++++++++++++++++++++------------ src/client.h | 4 +- src/messagehandler.c | 8 +++- src/messages.h | 1 + 4 files changed, 76 insertions(+), 29 deletions(-) diff --git a/src/client.c b/src/client.c index 189836c..c3831f7 100644 --- a/src/client.c +++ b/src/client.c @@ -57,6 +57,7 @@ void Client_free(client_t *client); declare_list(clients); static int clientcount; /* = 0 */ static int maxBandwidth; +static bool_t bOpus = true; int iCodecAlpha, iCodecBeta; bool_t bPreferAlpha; @@ -194,21 +195,25 @@ void Client_token_free(client_t *client) client->tokencount = 0; } -void recheckCodecVersions() + +#define OPUS_WARN "WARNING: Your client doesn't support the Opus codec the server is using, you won't be able to talk or hear anyone. Please upgrade" +void recheckCodecVersions(client_t *connectingClient) { client_t *client_itr = NULL; int max = 0, version, current_version; + int users = 0, opus = 0; message_t *sendmsg; struct dlist codec_list, *itr, *save; codec_t *codec_itr, *cd; bool_t found; - + bool_t enableOpus; + init_list_entry(&codec_list); while (Client_iterate(&client_itr) != NULL) { codec_itr = NULL; while (Client_codec_iterate(client_itr, &codec_itr) != NULL) { - found = false; + found = false; list_iterate(itr, &codec_list) { cd = list_get_entry(itr, codec_t, node); if (cd->codec == codec_itr->codec) { @@ -226,9 +231,14 @@ void recheckCodecVersions() cd->count = 1; list_add_tail(&cd->node, &codec_list); } + users++; + if (client_itr->bOpus) + opus++; } } + enableOpus = ((opus * 100 / users) >= getIntConf(OPUS_THRESHOLD)); + list_iterate(itr, &codec_list) { cd = list_get_entry(itr, codec_t, node); if (cd->count > max) { @@ -240,24 +250,48 @@ void recheckCodecVersions() list_del(&list_get_entry(itr, codec_t, node)->node); free(list_get_entry(itr, codec_t, node)); } - + current_version = bPreferAlpha ? iCodecAlpha : iCodecBeta; - if (current_version == version) + if (current_version != version) { + // If we don't already use the compat bitstream version set + // it as alpha and announce it. If another codec now got the + // majority set it as the opposite of the currently valid bPreferAlpha + // and announce it. + if (version == (uint32_t)0x8000000b) + bPreferAlpha = true; + else + bPreferAlpha = !bPreferAlpha; + + if (bPreferAlpha) + iCodecAlpha = version; + else + iCodecBeta = version; + } else if (bOpus == enableOpus) { + if (connectingClient && !connectingClient->bOpus) { + char *message; + uint32_t *tree_id; + message_t *sendmsg = NULL; + + message = malloc(strlen(OPUS_WARN)); + if (!message) + Log_fatal("Out of memory"); + tree_id = malloc(sizeof(uint32_t)); + if (!tree_id) + Log_fatal("Out of memory"); + *tree_id = 0; + sendmsg = Msg_create(TextMessage); + sendmsg->payload.textMessage->message = message; + sendmsg->payload.textMessage->n_tree_id = 1; + sendmsg->payload.textMessage->tree_id = tree_id; + sprintf(message, OPUS_WARN); + Client_send_message(connectingClient, sendmsg); + sendmsg = NULL; + } return; - // If we don't already use the compat bitstream version set - // it as alpha and announce it. If another codec now got the - // majority set it as the opposite of the currently valid bPreferAlpha - // and announce it. - if (version == (uint32_t)0x8000000b) - bPreferAlpha = true; - else - bPreferAlpha = ! bPreferAlpha; - - if (bPreferAlpha) - iCodecAlpha = version; - else - iCodecBeta = version; + } + bOpus = enableOpus; + sendmsg = Msg_create(CodecVersion); sendmsg->payload.codecVersion->alpha = iCodecAlpha; sendmsg->payload.codecVersion->beta = iCodecBeta; @@ -766,6 +800,9 @@ int Client_read_udp() case UDPVoiceSpeex: case UDPVoiceCELTAlpha: case UDPVoiceCELTBeta: + if (bOpus) + break; + case UDPVoiceOpus: Client_voiceMsg(itr, buffer, len); break; case UDPPing: @@ -801,7 +838,7 @@ int Client_voiceMsg(client_t *client, uint8_t *data, int len) pds_t *pds = Pds_create(buffer + 1, UDP_PACKET_SIZE - 1); unsigned int type = data[0] & 0xe0; unsigned int target = data[0] & 0x1f; - unsigned int poslen, counter; + unsigned int poslen, counter, size; int offset, packetsize; voicetarget_t *vt; @@ -819,12 +856,17 @@ int Client_voiceMsg(client_t *client, uint8_t *data, int len) Timer_restart(&client->idleTime); Timer_restart(&client->lastActivity); - counter = Pds_get_numval(pdi); /* step past session id */ - do { - counter = Pds_next8(pdi); - offset = Pds_skip(pdi, counter & 0x7f); - } while ((counter & 0x80) && offset > 0); - + if ((type >> 5) != UDPVoiceOpus) { + counter = Pds_get_numval(pdi); /* step past session id */ + do { + counter = Pds_next8(pdi); + offset = Pds_skip(pdi, counter & 0x7f); + } while ((counter & 0x80) && offset > 0); + } else { + size = Pds_get_numval(pdi); + Pds_skip(pdi, size & 0x1fff); + } + poslen = pdi->maxsize - pdi->offset; /* For stripping of positional info */ Pds_add_numval(pds, client->sessionId); diff --git a/src/client.h b/src/client.h index a3ce2c2..a0f42d5 100644 --- a/src/client.h +++ b/src/client.h @@ -73,7 +73,7 @@ typedef struct { int sessionId; uint64_t key; char *username; - bool_t bUDP, authenticated, deaf, mute, self_deaf, self_mute, recording; + bool_t bUDP, authenticated, deaf, mute, self_deaf, self_mute, recording, bOpus; char *os, *release, *os_version; uint32_t version; int codec_count; @@ -121,7 +121,7 @@ int Client_send_message_except(client_t *client, message_t *msg); int Client_read_udp(void); void Client_disconnect_all(); int Client_voiceMsg(client_t *client, uint8_t *data, int len); -void recheckCodecVersions(); +void recheckCodecVersions(client_t *connectingClient); void Client_codec_add(client_t *client, int codec); void Client_codec_free(client_t *client); codec_t *Client_codec_iterate(client_t *client, codec_t **codec_itr); diff --git a/src/messagehandler.c b/src/messagehandler.c index 2dea858..504c66b 100644 --- a/src/messagehandler.c +++ b/src/messagehandler.c @@ -47,7 +47,7 @@ extern channel_t *defaultChan; extern int iCodecAlpha, iCodecBeta; -extern bool_t bPreferAlpha; +extern bool_t bPreferAlpha, bOpus; static void sendServerReject(client_t *client, const char *reason, MumbleProto__Reject__RejectType type) { @@ -227,8 +227,10 @@ void Mh_handle_message(client_t *client, message_t *msg) Client_codec_add(client, (int32_t)0x8000000a); client->codec_count = 1; } + if (msg->payload.authenticate->opus) + client->bOpus = true; - recheckCodecVersions(); + recheckCodecVersions(client); sendmsg = Msg_create(CodecVersion); sendmsg->payload.codecVersion->alpha = iCodecAlpha; @@ -815,6 +817,8 @@ void Mh_handle_message(client_t *client, message_t *msg) while (Client_codec_iterate(target, &codec_itr) != NULL) sendmsg->payload.userStats->celt_versions[i++] = codec_itr->codec; + sendmsg->payload.userStats->opus = target->bOpus; + /* Address */ sendmsg->payload.userStats->has_address = true; sendmsg->payload.userStats->address.data = malloc(sizeof(uint8_t) * 16); diff --git a/src/messages.h b/src/messages.h index 8acab9d..72b51da 100644 --- a/src/messages.h +++ b/src/messages.h @@ -98,6 +98,7 @@ typedef enum { UDPPing, UDPVoiceSpeex, UDPVoiceCELTBeta, + UDPVoiceOpus, } UDPMessageType_t; -- 2.30.2