mirror of
https://github.com/UberGames/lilium-voyager.git
synced 2024-12-13 13:40:56 +00:00
VoIP: initial shot at voice activation.
This commit is contained in:
parent
8028fc042c
commit
fec2cc2f05
4 changed files with 70 additions and 33 deletions
|
@ -937,6 +937,10 @@ void CL_FirstSnapshot( void ) {
|
||||||
speex_preprocess_ctl(clc.speexPreprocessor,
|
speex_preprocess_ctl(clc.speexPreprocessor,
|
||||||
SPEEX_PREPROCESS_SET_DENOISE, &i);
|
SPEEX_PREPROCESS_SET_DENOISE, &i);
|
||||||
|
|
||||||
|
i = (cl_voipUseVAD->integer != 0);
|
||||||
|
speex_preprocess_ctl(clc.speexPreprocessor,
|
||||||
|
SPEEX_PREPROCESS_SET_VAD, &i);
|
||||||
|
|
||||||
for (i = 0; i < MAX_CLIENTS; i++) {
|
for (i = 0; i < MAX_CLIENTS; i++) {
|
||||||
speex_bits_init(&clc.speexDecoderBits[i]);
|
speex_bits_init(&clc.speexDecoderBits[i]);
|
||||||
speex_bits_reset(&clc.speexDecoderBits[i]);
|
speex_bits_reset(&clc.speexDecoderBits[i]);
|
||||||
|
|
|
@ -221,8 +221,17 @@ void IN_StrafeDown(void) {IN_KeyDown(&in_strafe);}
|
||||||
void IN_StrafeUp(void) {IN_KeyUp(&in_strafe);}
|
void IN_StrafeUp(void) {IN_KeyUp(&in_strafe);}
|
||||||
|
|
||||||
#if USE_VOIP
|
#if USE_VOIP
|
||||||
void IN_VoipRecordDown(void) {IN_KeyDown(&in_voiprecord);}
|
void IN_VoipRecordDown(void)
|
||||||
void IN_VoipRecordUp(void) {IN_KeyUp(&in_voiprecord);}
|
{
|
||||||
|
IN_KeyDown(&in_voiprecord);
|
||||||
|
Cvar_Set("cl_voipSend", "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
void IN_VoipRecordUp(void)
|
||||||
|
{
|
||||||
|
IN_KeyUp(&in_voiprecord);
|
||||||
|
Cvar_Set("cl_voipSend", "0");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);}
|
void IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);}
|
||||||
|
@ -556,14 +565,6 @@ usercmd_t CL_CreateCmd( void ) {
|
||||||
// get basic movement from joystick
|
// get basic movement from joystick
|
||||||
CL_JoystickMove( &cmd );
|
CL_JoystickMove( &cmd );
|
||||||
|
|
||||||
#if USE_VOIP
|
|
||||||
if ( ( in_voiprecord.active ) && ( !cl_voipSend->integer ) ) {
|
|
||||||
Cvar_Set("cl_voipSend", "1");
|
|
||||||
} else if ( ( !in_voiprecord.active ) && ( cl_voipSend->integer ) ) {
|
|
||||||
Cvar_Set("cl_voipSend", "0");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// check to make sure the angles haven't wrapped
|
// check to make sure the angles haven't wrapped
|
||||||
if ( cl.viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
|
if ( cl.viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
|
||||||
cl.viewangles[PITCH] = oldAngles[PITCH] + 90;
|
cl.viewangles[PITCH] = oldAngles[PITCH] + 90;
|
||||||
|
|
|
@ -34,6 +34,7 @@ cvar_t *cl_mumbleScale;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if USE_VOIP
|
#if USE_VOIP
|
||||||
|
cvar_t *cl_voipUseVAD;
|
||||||
cvar_t *cl_voipSend;
|
cvar_t *cl_voipSend;
|
||||||
cvar_t *cl_voipSendTarget;
|
cvar_t *cl_voipSendTarget;
|
||||||
cvar_t *cl_voipGainDuringCapture;
|
cvar_t *cl_voipGainDuringCapture;
|
||||||
|
@ -242,6 +243,18 @@ void CL_Voip_f( void )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
void CL_VoipNewGeneration(void)
|
||||||
|
{
|
||||||
|
// don't have a zero generation so new clients won't match, and don't
|
||||||
|
// wrap to negative so MSG_ReadLong() doesn't "fail."
|
||||||
|
clc.voipOutgoingGeneration++;
|
||||||
|
if (clc.voipOutgoingGeneration <= 0)
|
||||||
|
clc.voipOutgoingGeneration = 1;
|
||||||
|
clc.voipPower = 0.0f;
|
||||||
|
clc.voipOutgoingSequence = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
CL_CaptureVoip
|
CL_CaptureVoip
|
||||||
|
@ -253,6 +266,7 @@ Record more audio from the hardware if required and encode it into Speex
|
||||||
static
|
static
|
||||||
void CL_CaptureVoip(void)
|
void CL_CaptureVoip(void)
|
||||||
{
|
{
|
||||||
|
const qboolean useVad = (cl_voipUseVAD->integer != 0);
|
||||||
qboolean initialFrame = qfalse;
|
qboolean initialFrame = qfalse;
|
||||||
qboolean finalFrame = qfalse;
|
qboolean finalFrame = qfalse;
|
||||||
|
|
||||||
|
@ -268,6 +282,17 @@ void CL_CaptureVoip(void)
|
||||||
if (clc.voipOutgoingDataSize > 0)
|
if (clc.voipOutgoingDataSize > 0)
|
||||||
return; // packet is pending transmission, don't record more yet.
|
return; // packet is pending transmission, don't record more yet.
|
||||||
|
|
||||||
|
if (cl_voipUseVAD->modified) {
|
||||||
|
int useVadi = (int) useVad;
|
||||||
|
speex_preprocess_ctl(clc.speexPreprocessor,
|
||||||
|
SPEEX_PREPROCESS_SET_VAD, &useVadi);
|
||||||
|
cl_voipUseVAD->modified = qfalse;
|
||||||
|
Cvar_Set("cl_voipSend", (useVad) ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((useVad) && (!cl_voipSend->integer))
|
||||||
|
Cvar_Set("cl_voipSend", "1"); // lots of things reset this.
|
||||||
|
|
||||||
if (cl_voipSend->modified) {
|
if (cl_voipSend->modified) {
|
||||||
qboolean dontCapture = qfalse;
|
qboolean dontCapture = qfalse;
|
||||||
if (cls.state != CA_ACTIVE)
|
if (cls.state != CA_ACTIVE)
|
||||||
|
@ -302,11 +327,7 @@ void CL_CaptureVoip(void)
|
||||||
if (gain < 0.0f) gain = 0.0f; else if (gain >= 1.0f) gain = 1.0f;
|
if (gain < 0.0f) gain = 0.0f; else if (gain >= 1.0f) gain = 1.0f;
|
||||||
S_MasterGain(cl_voipGainDuringCapture->value);
|
S_MasterGain(cl_voipGainDuringCapture->value);
|
||||||
S_StartCapture();
|
S_StartCapture();
|
||||||
clc.voipPower = 0.0f;
|
CL_VoipNewGeneration();
|
||||||
clc.voipOutgoingSequence = 0;
|
|
||||||
clc.voipOutgoingGeneration++;
|
|
||||||
if (clc.voipOutgoingGeneration == 0) // don't have a zero generation...
|
|
||||||
clc.voipOutgoingGeneration = 1; // ...so new clients won't match.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cl_voipSend->integer) || (finalFrame)) { // user wants to capture audio?
|
if ((cl_voipSend->integer) || (finalFrame)) { // user wants to capture audio?
|
||||||
|
@ -318,6 +339,7 @@ void CL_CaptureVoip(void)
|
||||||
// audio capture is always MONO16 (and that's what speex wants!).
|
// audio capture is always MONO16 (and that's what speex wants!).
|
||||||
// 2048 will cover 12 uncompressed frames in narrowband mode.
|
// 2048 will cover 12 uncompressed frames in narrowband mode.
|
||||||
static int16_t sampbuffer[2048];
|
static int16_t sampbuffer[2048];
|
||||||
|
qboolean isVoice = qfalse;
|
||||||
int16_t voipPower = 0;
|
int16_t voipPower = 0;
|
||||||
int speexFrames = 0;
|
int speexFrames = 0;
|
||||||
int wpos = 0;
|
int wpos = 0;
|
||||||
|
@ -334,22 +356,25 @@ void CL_CaptureVoip(void)
|
||||||
|
|
||||||
// this will probably generate multiple speex packets each time.
|
// this will probably generate multiple speex packets each time.
|
||||||
while (samples > 0) {
|
while (samples > 0) {
|
||||||
|
int16_t *sampptr = &sampbuffer[pos];
|
||||||
int i, bytes;
|
int i, bytes;
|
||||||
|
|
||||||
// Check the "power" of this packet...
|
// check the "power" of this packet...
|
||||||
for (i = 0; i < clc.speexFrameSize; i++) {
|
for (i = 0; i < clc.speexFrameSize; i++) {
|
||||||
int16_t s = sampbuffer[i+pos];
|
int16_t s = sampptr[i];
|
||||||
if (s < 0)
|
if (s < 0)
|
||||||
s = -s;
|
s = -s;
|
||||||
if (s > voipPower)
|
if (s > voipPower)
|
||||||
voipPower = s; // !!! FIXME: this isn't very clever.
|
voipPower = s; // !!! FIXME: this isn't very clever.
|
||||||
}
|
}
|
||||||
|
|
||||||
speex_preprocess_run(clc.speexPreprocessor, &sampbuffer[pos]);
|
// preprocess samples to remove noise, check for voice...
|
||||||
|
if (speex_preprocess_run(clc.speexPreprocessor, sampptr))
|
||||||
|
isVoice = qtrue; // player is probably speaking.
|
||||||
|
|
||||||
// Encode raw audio samples into Speex data...
|
// encode raw audio samples into Speex data...
|
||||||
speex_bits_reset(&clc.speexEncoderBits);
|
speex_bits_reset(&clc.speexEncoderBits);
|
||||||
speex_encode_int(clc.speexEncoder, &sampbuffer[pos],
|
speex_encode_int(clc.speexEncoder, sampptr,
|
||||||
&clc.speexEncoderBits);
|
&clc.speexEncoderBits);
|
||||||
bytes = speex_bits_write(&clc.speexEncoderBits,
|
bytes = speex_bits_write(&clc.speexEncoderBits,
|
||||||
(char *) &clc.voipOutgoingData[wpos+1],
|
(char *) &clc.voipOutgoingData[wpos+1],
|
||||||
|
@ -363,21 +388,26 @@ void CL_CaptureVoip(void)
|
||||||
samples -= clc.speexFrameSize;
|
samples -= clc.speexFrameSize;
|
||||||
speexFrames++;
|
speexFrames++;
|
||||||
}
|
}
|
||||||
clc.voipPower = ((float) voipPower) / 32767.0f;
|
|
||||||
clc.voipOutgoingDataSize = wpos;
|
|
||||||
clc.voipOutgoingDataFrames = speexFrames;
|
|
||||||
|
|
||||||
Com_DPrintf("Outgoing VoIP data: %d frames, %d bytes, %f power\n",
|
if ((useVad) && (!isVoice)) {
|
||||||
speexFrames, wpos, clc.voipPower);
|
CL_VoipNewGeneration(); // no talk for at least 1/4 second.
|
||||||
|
} else {
|
||||||
|
clc.voipPower = ((float) voipPower) / 32767.0f;
|
||||||
|
clc.voipOutgoingDataSize = wpos;
|
||||||
|
clc.voipOutgoingDataFrames = speexFrames;
|
||||||
|
|
||||||
#if 0
|
Com_DPrintf("VoIP: Send %d frames, %d bytes, %f power\n",
|
||||||
static FILE *encio = NULL;
|
speexFrames, wpos, clc.voipPower);
|
||||||
if (encio == NULL) encio = fopen("outgoing-encoded.bin", "wb");
|
|
||||||
if (encio != NULL) { fwrite(clc.voipOutgoingData, wpos, 1, encio); fflush(encio); }
|
#if 0
|
||||||
static FILE *decio = NULL;
|
static FILE *encio = NULL;
|
||||||
if (decio == NULL) decio = fopen("outgoing-decoded.bin", "wb");
|
if (encio == NULL) encio = fopen("voip-outgoing-encoded.bin", "wb");
|
||||||
if (decio != NULL) { fwrite(sampbuffer, speexFrames * clc.speexFrameSize * 2, 1, decio); fflush(decio); }
|
if (encio != NULL) { fwrite(clc.voipOutgoingData, wpos, 1, encio); fflush(encio); }
|
||||||
#endif
|
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); }
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3057,6 +3087,7 @@ void CL_Init( void ) {
|
||||||
cl_voipSend = Cvar_Get ("cl_voipSend", "0", 0);
|
cl_voipSend = Cvar_Get ("cl_voipSend", "0", 0);
|
||||||
cl_voipSendTarget = Cvar_Get ("cl_voipSendTarget", "all", 0);
|
cl_voipSendTarget = Cvar_Get ("cl_voipSendTarget", "all", 0);
|
||||||
cl_voipGainDuringCapture = Cvar_Get ("cl_voipGainDuringCapture", "0.2", CVAR_ARCHIVE);
|
cl_voipGainDuringCapture = Cvar_Get ("cl_voipGainDuringCapture", "0.2", CVAR_ARCHIVE);
|
||||||
|
cl_voipUseVAD = Cvar_Get ("cl_voipUseVAD", "0", CVAR_ARCHIVE);
|
||||||
voip = Cvar_Get ("voip", "1", CVAR_USERINFO | CVAR_ARCHIVE | CVAR_LATCH);
|
voip = Cvar_Get ("voip", "1", CVAR_USERINFO | CVAR_ARCHIVE | CVAR_LATCH);
|
||||||
|
|
||||||
// This is a protocol version number.
|
// This is a protocol version number.
|
||||||
|
|
|
@ -411,6 +411,7 @@ extern cvar_t *cl_mumbleScale;
|
||||||
// cl_voipSendTarget is a string: "all" to broadcast to everyone, "none" to
|
// cl_voipSendTarget is a string: "all" to broadcast to everyone, "none" to
|
||||||
// send to no one, or a comma-separated list of client numbers:
|
// send to no one, or a comma-separated list of client numbers:
|
||||||
// "0,7,2,23" ... an empty string is treated like "all".
|
// "0,7,2,23" ... an empty string is treated like "all".
|
||||||
|
extern cvar_t *cl_voipUseVAD;
|
||||||
extern cvar_t *cl_voipSend;
|
extern cvar_t *cl_voipSend;
|
||||||
extern cvar_t *cl_voipSendTarget;
|
extern cvar_t *cl_voipSendTarget;
|
||||||
extern cvar_t *cl_voipGainDuringCapture;
|
extern cvar_t *cl_voipGainDuringCapture;
|
||||||
|
|
Loading…
Reference in a new issue