From 69f92daf084b5545f223ec000e62306b5a6d9700 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 13 Apr 2018 22:38:17 -0400 Subject: [PATCH] Added audio capture support to SDL backend. This lets you speak through VoIP when not using OpenAL. Previously you could listen but not speak. --- code/client/snd_dma.c | 11 ++-- code/client/snd_local.h | 9 +++ code/null/null_snddma.c | 24 ++++++++ code/sdl/sdl_snd.c | 128 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 165 insertions(+), 7 deletions(-) diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index 382031b6..28de908e 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -119,32 +119,31 @@ void S_Base_SoundInfo(void) { static void S_Base_StartCapture( void ) { - // !!! FIXME: write me. + SNDDMA_StartCapture(); } static int S_Base_AvailableCaptureSamples( void ) { - // !!! FIXME: write me. - return 0; + return SNDDMA_AvailableCaptureSamples(); } static void S_Base_Capture( int samples, byte *data ) { - // !!! FIXME: write me. + SNDDMA_Capture(samples, data); } static void S_Base_StopCapture( void ) { - // !!! FIXME: write me. + SNDDMA_StopCapture(); } static void S_Base_MasterGain( float val ) { - // !!! FIXME: write me. + SNDDMA_MasterGain(val); } #endif diff --git a/code/client/snd_local.h b/code/client/snd_local.h index 053325cf..dc56f1bc 100644 --- a/code/client/snd_local.h +++ b/code/client/snd_local.h @@ -176,6 +176,15 @@ void SNDDMA_BeginPainting (void); void SNDDMA_Submit(void); +#ifdef USE_VOIP +void SNDDMA_StartCapture(void); +int SNDDMA_AvailableCaptureSamples(void); +void SNDDMA_Capture(int samples, byte *data); +void SNDDMA_StopCapture(void); +void SNDDMA_MasterGain(float val); +#endif + + //==================================================================== #define MAX_CHANNELS 96 diff --git a/code/null/null_snddma.c b/code/null/null_snddma.c index 448a4dc9..7f3cfe29 100644 --- a/code/null/null_snddma.c +++ b/code/null/null_snddma.c @@ -48,6 +48,30 @@ void SNDDMA_Submit(void) { } +#ifdef USE_VOIP +void SNDDMA_StartCapture(void) +{ +} + +int SNDDMA_AvailableCaptureSamples(void) +{ + return 0; +} + +void SNDDMA_Capture(int samples, byte *data) +{ +} + +void SNDDMA_StopCapture(void) +{ +} + +void SNDDMA_MasterGain( float val ) +{ +} +#endif + + sfxHandle_t S_RegisterSound( const char *name, qboolean compressed ) { return 0; diff --git a/code/sdl/sdl_snd.c b/code/sdl/sdl_snd.c index e921f55c..a3e5b724 100644 --- a/code/sdl/sdl_snd.c +++ b/code/sdl/sdl_snd.c @@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/q_shared.h" #include "../client/snd_local.h" +#include "../client/client.h" qboolean snd_inited = qfalse; @@ -44,6 +45,13 @@ cvar_t *s_sdlMixSamps; static int dmapos = 0; static int dmasize = 0; +#ifdef USE_VOIP +static SDL_AudioDeviceID sdlCaptureDevice; +static cvar_t *s_sdlCapture; +static float sdlMasterGain = 1.0f; +#endif + + /* =============== SNDDMA_AudioCallback @@ -83,6 +91,40 @@ static void SNDDMA_AudioCallback(void *userdata, Uint8 *stream, int len) if (dmapos >= dmasize) dmapos = 0; + +#ifdef USE_VOIP + if (sdlMasterGain != 1.0f) + { + int i; + if (dma.isfloat && (dma.samplebits == 32)) + { + float *ptr = (float *) stream; + len /= sizeof (*ptr); + for (i = 0; i < len; i++, ptr++) + { + *ptr *= sdlMasterGain; + } + } + else if (dma.samplebits == 16) + { + Sint16 *ptr = (Sint16 *) stream; + len /= sizeof (*ptr); + for (i = 0; i < len; i++, ptr++) + { + *ptr = (Sint16) (((float) *ptr) * sdlMasterGain); + } + } + else if (dma.samplebits == 8) + { + Uint8 *ptr = (Uint8 *) stream; + len /= sizeof (*ptr); + for (i = 0; i < len; i++, ptr++) + { + *ptr = (Uint8) (((float) *ptr) * sdlMasterGain); + } + } + } +#endif } static struct @@ -236,8 +278,39 @@ qboolean SNDDMA_Init(void) dmasize = (dma.samples * (dma.samplebits/8)); dma.buffer = calloc(1, dmasize); +#ifdef USE_VOIP + // !!! FIXME: some of these SDL_OpenAudioDevice() values should be cvars. + s_sdlCapture = Cvar_Get( "s_sdlCapture", "1", CVAR_ARCHIVE | CVAR_LATCH ); + if (!s_sdlCapture->integer) + { + Com_Printf("SDL audio capture support disabled by user ('+set s_sdlCapture 1' to enable)\n"); + } +#if USE_MUMBLE + else if (cl_useMumble->integer) + { + Com_Printf("SDL audio capture support disabled for Mumble support\n"); + } +#endif + else + { + /* !!! FIXME: list available devices and let cvar specify one, like OpenAL does */ + SDL_AudioSpec spec; + SDL_zero(spec); + spec.freq = 48000; + spec.format = AUDIO_S16SYS; + spec.channels = 1; + spec.samples = VOIP_MAX_PACKET_SAMPLES * 4; + sdlCaptureDevice = SDL_OpenAudioDevice(NULL, SDL_TRUE, &spec, NULL, 0); + Com_Printf( "SDL capture device %s.\n", + (sdlCaptureDevice == 0) ? "failed to open" : "opened"); + } +#endif + + sdlMasterGain = 1.0f; + Com_Printf("Starting SDL audio callback...\n"); SDL_PauseAudio(0); // start callback. + // don't unpause the capture device; we'll do that in StartCapture. Com_Printf("SDL audio initialized.\n"); snd_inited = qtrue; @@ -263,12 +336,20 @@ void SNDDMA_Shutdown(void) { Com_Printf("Closing SDL audio device...\n"); SDL_CloseAudio(); + + if (sdlCaptureDevice) + { + Com_Printf("Closing SDL audio capture device...\n"); + SDL_CloseAudioDevice(sdlCaptureDevice); + sdlCaptureDevice = 0; + } + SDL_QuitSubSystem(SDL_INIT_AUDIO); free(dma.buffer); dma.buffer = NULL; dmapos = dmasize = 0; snd_inited = qfalse; - Com_Printf("SDL audio device shut down.\n"); + Com_Printf("SDL audio shut down.\n"); } /* @@ -292,3 +373,48 @@ void SNDDMA_BeginPainting (void) { SDL_LockAudio(); } + + +#ifdef USE_VOIP +void SNDDMA_StartCapture(void) +{ + if (sdlCaptureDevice) + { + SDL_ClearQueuedAudio(sdlCaptureDevice); + SDL_PauseAudioDevice(sdlCaptureDevice, 0); + } +} + +int SNDDMA_AvailableCaptureSamples(void) +{ + // divided by 2 to convert from bytes to (mono16) samples. + return sdlCaptureDevice ? (SDL_GetQueuedAudioSize(sdlCaptureDevice) / 2) : 0; +} + +void SNDDMA_Capture(int samples, byte *data) +{ + // multiplied by 2 to convert from (mono16) samples to bytes. + if (sdlCaptureDevice) + { + SDL_DequeueAudio(sdlCaptureDevice, data, samples * 2); + } + else + { + SDL_memset(data, '\0', samples * 2); + } +} + +void SNDDMA_StopCapture(void) +{ + if (sdlCaptureDevice) + { + SDL_PauseAudioDevice(sdlCaptureDevice, 1); + } +} + +void SNDDMA_MasterGain( float val ) +{ + sdlMasterGain = val; +} +#endif +