Skip to content

Commit

Permalink
Allow multiple clients (up to 4) to transmit audio at once
Browse files Browse the repository at this point in the history
Assign the 4 VOIP audio streams dynamically to transmitting
clients via snis_server, decode and mix the VOIP audio streams
on the clients.

Signed-off-by: Stephen M. Cameron <stephenmcameron@gmail.com>
  • Loading branch information
smcameron committed Apr 2, 2020
1 parent 22c3da8 commit 47d3010
Show file tree
Hide file tree
Showing 12 changed files with 324 additions and 65 deletions.
5 changes: 4 additions & 1 deletion Makefile
Expand Up @@ -505,7 +505,7 @@ _SERVEROBJS=snis_server.o starbase-comms.o \
snis_server_tracker.o snis_bridge_update_packet.o solarsystem_config.o a_star.o \
key_value_parser.o nonuniform_random_sampler.o oriented_bounding_box.o shape_collision.o \
graph_dev_mesh_stub.o turret_aimer.o snis_hash.o snis_server_debug.o \
ship_registration.o
ship_registration.o talking_stick.o
SERVEROBJS=${COMMONOBJS} $(patsubst %,$(OD)/%,${_SERVEROBJS})

_MULTIVERSEOBJS=snis_multiverse.o snis_marshal.o snis_socket_io.o mathutils.o mtwist.o stacktrace.o \
Expand Down Expand Up @@ -1106,6 +1106,9 @@ $(OD)/mtwist.o: mtwist.c Makefile ${ODT}
$(OD)/elastic_collision.o: elastic_collision.c elastic_collision.h Makefile ${ODT}
$(Q)$(COMPILE)

$(OD)/talking_stick.o: talking_stick.c talking_stick.h Makefile ${ODT}
$(Q)$(COMPILE)

$(OD)/fleet.o: fleet.c Makefile ${ODT}
$(Q)$(COMPILE)

Expand Down
2 changes: 1 addition & 1 deletion snis.h
Expand Up @@ -41,7 +41,7 @@
#include "shape_collision.h"

#define DEFAULT_SOLAR_SYSTEM "default"
#define SNIS_PROTOCOL_VERSION "SNIS051"
#define SNIS_PROTOCOL_VERSION "SNIS052"
#define COMMON_MTWIST_SEED 97872
/* dimensions of the "known" universe */
#define XKNOWN_DIM 600000.0
Expand Down
65 changes: 61 additions & 4 deletions snis_client.c
Expand Up @@ -196,6 +196,8 @@ static float current_altitude = 1e20;
static int idiot_light_threshold = 10; /* tweakable */
static int dejitter_science_details = 1; /* Tweakable. 1 means de-jitter science details, 0 means don't */
static int monitor_voice_chat = 0;
static int have_talking_stick = 0;
static pthread_mutex_t voip_mutex = PTHREAD_MUTEX_INITIALIZER;

/* I can switch out the line drawing function with these macros */
/* in case I come across something faster than gdk_draw_line */
Expand Down Expand Up @@ -4380,6 +4382,19 @@ static void deal_with_keyboard()
}
}

static void request_talking_stick(void)
{
queue_to_server(snis_opcode_subcode_pkt("bb", OPCODE_TALKING_STICK, OPCODE_TALKING_STICK_REQUEST));
}

static void release_talking_stick(void)
{
queue_to_server(snis_opcode_subcode_pkt("bb", OPCODE_TALKING_STICK, OPCODE_TALKING_STICK_RELEASE));
pthread_mutex_lock(&voip_mutex);
have_talking_stick = 0;
pthread_mutex_unlock(&voip_mutex);
}

static gint key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data)
{
enum keyaction ka;
Expand All @@ -4399,6 +4414,15 @@ static gint key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data)
}

if (event->keyval == GDK_F12) {
pthread_mutex_lock(&voip_mutex);
if (!have_talking_stick) {
pthread_mutex_unlock(&voip_mutex);
request_talking_stick();
} else {
pthread_mutex_unlock(&voip_mutex);
}
/* We transmit regardless of whether we have a talking stick.
* If we do not have it, snis_server will drop our messages */
if (control_key_pressed)
voice_chat_start_recording(VOICE_CHAT_DESTINATION_ALL, 0);
else
Expand Down Expand Up @@ -4648,8 +4672,11 @@ static gint key_release_cb(GtkWidget* widget, GdkEventKey* event, gpointer data)
if (ka > 0 && ka < NKEYSTATES)
kbstate.pressed[ka] = 0;

if (event->keyval == GDK_F12)
if (event->keyval == GDK_F12) {
voice_chat_stop_recording();
/* We release even if we don't have, snis_server will know the real deal. */
release_talking_stick();
}

return FALSE;
}
Expand Down Expand Up @@ -7701,12 +7728,13 @@ static int process_opus_audio_data(void)
{
int rc;
uint8_t buffer[4008];
uint16_t audio_chain;
uint8_t destination;
uint32_t radio_channel;
uint16_t datalen;

rc = read_and_unpack_buffer(buffer, "bwh",
&destination, &radio_channel, &datalen);
rc = read_and_unpack_buffer(buffer, "bhwh",
&audio_chain, &destination, &radio_channel, &datalen);
if (rc)
return rc;
if (datalen > 4000) {
Expand All @@ -7717,7 +7745,31 @@ static int process_opus_audio_data(void)
rc = snis_readsocket(gameserver_sock, buffer, datalen);
if (rc)
return rc;
voice_chat_play_opus_packet(buffer, datalen);
if (audio_chain < WWVIAUDIO_CHAIN_COUNT)
voice_chat_play_opus_packet(buffer, datalen, audio_chain);
return 0;
}

static int process_talking_stick(void)
{
uint8_t buffer[10];
uint8_t subcode;
int rc;

rc = read_and_unpack_buffer(buffer, "b", &subcode);
if (rc)
return rc;
switch (subcode) {
case OPCODE_TALKING_STICK_GRANT:
pthread_mutex_lock(&voip_mutex);
have_talking_stick = 1;
pthread_mutex_unlock(&voip_mutex);
break;
default:
fprintf(stderr, "%s: Unexpected OPCODE_TALKING_STICK subcode %hhu\n",
"snis_client", subcode);
return -1;
}
return 0;
}

Expand Down Expand Up @@ -8036,6 +8088,11 @@ static void *gameserver_reader(__attribute__((unused)) void *arg)
if (rc)
goto protocol_error;
break;
case OPCODE_TALKING_STICK:
rc = process_talking_stick();
if (rc)
goto protocol_error;
break;
default:
goto protocol_error;
}
Expand Down
7 changes: 5 additions & 2 deletions snis_opcode_def.c
Expand Up @@ -78,6 +78,9 @@ int snis_opcode_def_init(void)
rc |= init_opcode_def(OPCODE_ID_CLIENT_SHIP, "bw");
rc |= init_opcode_def(OPCODE_UPDATE_ASTEROID, "bwwSSS");
rc |= init_opcode_def(OPCODE_UPDATE_ASTEROID_MINERALS, "bwbbbb");
rc |= init_opcode_subcode_def(OPCODE_TALKING_STICK, OPCODE_TALKING_STICK_REQUEST, "bb");
rc |= init_opcode_subcode_def(OPCODE_TALKING_STICK, OPCODE_TALKING_STICK_GRANT, "bb");
rc |= init_opcode_subcode_def(OPCODE_TALKING_STICK, OPCODE_TALKING_STICK_RELEASE, "bb");
rc |= init_opcode_def(OPCODE_UPDATE_WARP_CORE, "bwwSSS");
rc |= init_opcode_def(OPCODE_DEMON_RTSMODE, "bb");
rc |= init_opcode_subcode_def(OPCODE_RTS_FUNC, OPCODE_RTS_FUNC_COMMS_BUTTON, "bbb");
Expand Down Expand Up @@ -222,8 +225,8 @@ int snis_opcode_def_init(void)
rc |= init_opcode_def(OPCODE_LOAD_SKYBOX, "n/a");
rc |= init_opcode_def(OPCODE_ROBOT_AUTO_MANUAL, "bb");
rc |= init_opcode_def(OPCODE_ADD_WARP_EFFECT, "bwSSSSSS");
/* rc |= init_opcode_def(OPCODE_OPUS_AUDIO_DATA, "bbwhr"); */
/* ^^^ opcode, destination, channel, bytecount, audio data */
/* rc |= init_opcode_def(OPCODE_OPUS_AUDIO_DATA, "bhbwhr"); */
/* ^^^ opcode, audio chain, destination, channel, bytecount, audio data */
rc |= init_opcode_def(OPCODE_REQUEST_PITCH, "bb");
rc |= init_opcode_def(OPCODE_REQUEST_ROLL, "bb");
rc |= init_opcode_def(OPCODE_REQUEST_SCIBALL_YAW, "bb");
Expand Down
5 changes: 4 additions & 1 deletion snis_packet.h
Expand Up @@ -182,7 +182,10 @@
#define OPCODE_REQUEST_WEAPONS_YAW_PITCH 198
#define OPCODE_UPDATE_COOLANT_DATA 199
#define OPCODE_UPDATE_ASTEROID_MINERALS 200
/* UNUSED OPCODE 201 */
#define OPCODE_TALKING_STICK 201
#define OPCODE_TALKING_STICK_REQUEST 1
#define OPCODE_TALKING_STICK_GRANT 2
#define OPCODE_TALKING_STICK_RELEASE 3
/* UNUSED OPCODE 202 */
/* UNUSED OPCODE 203 */
/* UNUSED OPCODE 204 */
Expand Down
79 changes: 74 additions & 5 deletions snis_server.c
Expand Up @@ -122,9 +122,12 @@
#include "planetary_ring_data.h"
#include "scipher.h"
#include "snis_voice_chat.h"
#include "talking_stick.h"
#include "wwviaudio.h" /* Just for WWVIAUDIO_CHAIN_COUNT */

#define CLIENT_UPDATE_PERIOD_NSECS 500000000
#define MAXCLIENTS 100
#define NTALKING_STICKS (WWVIAUDIO_CHAIN_COUNT)

/*
* The following globals are adjustable at runtime via the demon console.
Expand Down Expand Up @@ -427,6 +430,8 @@ static struct game_client {
uint8_t current_station; /* what station (displaymode) client is currently on. Mostly the server doesn't */
/* need to know this, but uses it for demon serverside builtin commands "clients" */
/* "lockroles", and "rotateroles" */
int16_t talking_stick; /* Which audio chain VOIP transmissions from this client should use. */
/* -1 if none assigned */
#define COMPUTE_AVERAGE_TO_CLIENT_BUFFER_SIZE 0
#if COMPUTE_AVERAGE_TO_CLIENT_BUFFER_SIZE
uint64_t write_sum; /* Statistics about data written to client */
Expand Down Expand Up @@ -706,6 +711,8 @@ static void put_client(struct game_client *c)
c->refcount--;
fprintf(stderr, "snis_server: client refcount = %d\n", c->refcount);
if (c->refcount == 0) {
if (c->talking_stick != NO_TALKING_STICK)
talking_stick_release(c->talking_stick);
if (c->bridge >= 0 && c->bridge < nbridges) {
bridgelist[c->bridge].nclients--;
fprintf(stderr, "snis_server: client count of bridge %d = %d\n", c->bridge, bridgelist[c->bridge].nclients);
Expand Down Expand Up @@ -20050,14 +20057,16 @@ static int process_opus_audio_data(struct game_client *c)
{
int rc;
uint8_t buffer[4008];
uint16_t ignored;
int16_t audio_chain;
uint8_t destination;
uint32_t radio_channel;
uint16_t datalen;
struct packed_buffer *pb;
struct except_clients except;

rc = read_and_unpack_buffer(c, buffer, "bwh",
&destination, &radio_channel, &datalen);
rc = read_and_unpack_buffer(c, buffer, "hbwh",
&ignored, &destination, &radio_channel, &datalen);
if (rc)
return rc;
if (datalen > 4000) {
Expand All @@ -20068,9 +20077,22 @@ static int process_opus_audio_data(struct game_client *c)
rc = snis_readsocket(c->socket, buffer, datalen);
if (rc)
return rc;
pb = packed_buffer_allocate(8 + datalen);
packed_buffer_append(pb, "bbwhr", OPCODE_OPUS_AUDIO_DATA,
destination, radio_channel, datalen, buffer, datalen);

pthread_mutex_lock(&universe_mutex);
client_lock();
if (c->talking_stick == NO_TALKING_STICK) {
/* Client does not have talking stick. */
client_unlock();
pthread_mutex_unlock(&universe_mutex);
return 0;
}
/* Ignore audio chain from client, it put 255 there anyway 'cause it doesn't know */
audio_chain = c->talking_stick;
client_unlock();
pthread_mutex_unlock(&universe_mutex);
pb = packed_buffer_allocate(10 + datalen);
packed_buffer_append(pb, "bhbwhr", OPCODE_OPUS_AUDIO_DATA,
(uint16_t) audio_chain, destination, radio_channel, datalen, buffer, datalen);

/* Don't send a client's own audio back at him. */
except.nclients = 1;
Expand All @@ -20092,6 +20114,46 @@ static int process_opus_audio_data(struct game_client *c)
return 0;
}

static int process_talking_stick(struct game_client *c)
{
int rc;
uint8_t subcode;
unsigned char buffer[20];
int16_t ts;

rc = read_and_unpack_buffer(c, buffer, "b", &subcode);
if (rc)
return rc;
switch (subcode) {
case OPCODE_TALKING_STICK_REQUEST:
pthread_mutex_lock(&universe_mutex);
client_lock();
if (c->talking_stick == NO_TALKING_STICK)
c->talking_stick = talking_stick_get();
ts = c->talking_stick;
client_unlock();
pthread_mutex_unlock(&universe_mutex);
if (ts > 0)
pb_queue_to_client(c, snis_opcode_subcode_pkt("bb",
OPCODE_TALKING_STICK, OPCODE_TALKING_STICK_GRANT));
break;
case OPCODE_TALKING_STICK_RELEASE:
pthread_mutex_lock(&universe_mutex);
client_lock();
if (c->talking_stick != NO_TALKING_STICK)
talking_stick_release(c->talking_stick);
c->talking_stick = NO_TALKING_STICK;
client_unlock();
pthread_mutex_unlock(&universe_mutex);
break;
default:
fprintf(stderr, "%s: bad OPCODE_TALKING_STICK subcode %hhu in request from client\n",
logprefix(), subcode);
return -1;
}
return 0;
}

static int process_toggle_demon_ai_debug_mode(struct game_client *c)
{
c->debug_ai = !c->debug_ai;
Expand Down Expand Up @@ -22831,6 +22893,11 @@ static void process_instructions_from_client(struct game_client *c)
if (rc)
goto protocol_error;
break;
case OPCODE_TALKING_STICK:
rc = process_talking_stick(c);
if (rc)
goto protocol_error;
break;
default:
goto protocol_error;
}
Expand Down Expand Up @@ -24491,6 +24558,7 @@ static void service_connection(int connection)
client[i].socket = connection;
client[i].timestamp = 0; /* newborn client, needs everything */
client[i].current_station = 255; /* unknown */
client[i].talking_stick = NO_TALKING_STICK; /* No VOIP channel assigned */

log_client_info(SNIS_INFO, connection, "add new player\n");

Expand Down Expand Up @@ -29844,6 +29912,7 @@ int main(int argc, char *argv[])
snis_protocol_debugging(1);
snis_debug_dump_set_label("SERVER");
snis_opcode_def_init();
talking_stick_setup(NTALKING_STICKS);

memset(&thirtieth_second, 0, sizeof(thirtieth_second));
thirtieth_second.tv_nsec = 33333333; /* 1/30th second */
Expand Down

0 comments on commit 47d3010

Please sign in to comment.