Commit message: None
CVE: CVE-2017-6903
CWE: CWE-269
Vulnerability description: In ioquake3 before 2017-03-14, the auto-downloading feature has insufficient content restrictions. This also affects Quake III Arena, OpenArena, OpenJK, iortcw, and other id Tech 3 (aka Quake 3 engine) forks. A malicious auto-downloaded file can trigger loading of crafted auto-downloaded files as native code DLLs. A malicious auto-downloaded file can contain configuration defaults that override the user's. Executable bytecode in a malicious auto-downloaded file can set configuration variables to values that will result in unwanted native code DLLs being loaded, resulting in sandbox escape.

Project: OpenJK
File: snd_openal.c

static void S_AL_AddLoopingSound(int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx)
{
	S_AL_SrcLoop(SRCPRI_ENTITY, sfx, origin, velocity, entityNum);
}

Project: OpenJK

static void S_AL_AllocateStreamChannel(int stream, int entityNum)
{
        srcHandle_t cursrc;
        ALuint alsrc;
        
	if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
		return;

        if(entityNum >= 0)
        {
        	cursrc = S_AL_SrcAlloc(SRCPRI_ENTITY, entityNum, 0);
        	if(cursrc < 0)
	        	return;

        	S_AL_SrcSetup(cursrc, -1, SRCPRI_ENTITY, entityNum, 0, qfalse);
        	alsrc = S_AL_SrcGet(cursrc);
        	srcList[cursrc].isTracking = qtrue;
        	srcList[cursrc].isStream = qtrue;
        }
        else
        {

        	cursrc = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
        	if(cursrc < 0)
	        	return;

        	alsrc = S_AL_SrcGet(cursrc);

        	S_AL_SrcLock(cursrc);
        
        	srcList[cursrc].scaleGain = 0.0f;

        	qalSourcei (alsrc, AL_BUFFER,          0            );
        	qalSourcei (alsrc, AL_LOOPING,         AL_FALSE     );
        	qalSource3f(alsrc, AL_POSITION,        0.0, 0.0, 0.0);
        	qalSource3f(alsrc, AL_VELOCITY,        0.0, 0.0, 0.0);
        	qalSource3f(alsrc, AL_DIRECTION,       0.0, 0.0, 0.0);
        	qalSourcef (alsrc, AL_ROLLOFF_FACTOR,  0.0          );
        	qalSourcei (alsrc, AL_SOURCE_RELATIVE, AL_TRUE      );
        }

        streamSourceHandles[stream] = cursrc;
       	streamSources[stream] = alsrc;

	streamNumBuffers[stream] = 0;
	streamBufIndex[stream] = 0;
}

Project: OpenJK
File: snd_openal.c

int S_AL_AvailableCaptureSamples( void )
{
	int retval = 0;
	if (alCaptureDevice != NULL)
	{
		ALint samples = 0;
		qalcGetIntegerv(alCaptureDevice, ALC_CAPTURE_SAMPLES, sizeof (samples), &samples);
		retval = (int) samples;
	}
	return retval;
}

Project: OpenJK
File: snd_openal.c

void S_AL_BeginRegistration( void )
{
	if(!numSfx)
		S_AL_BufferInit();
}

Project: OpenJK
File: snd_openal.c

static qboolean S_AL_BufferEvict( void )
{
	int	i, oldestBuffer = -1;
	int	oldestTime = Sys_Milliseconds( );

	for( i = 0; i < numSfx; i++ )
	{
		if( !knownSfx[ i ].filename[ 0 ] )
			continue;

		if( !knownSfx[ i ].inMemory )
			continue;

		if( knownSfx[ i ].lastUsedTime < oldestTime )
		{
			oldestTime = knownSfx[ i ].lastUsedTime;
			oldestBuffer = i;
		}
	}

	if( oldestBuffer >= 0 )
	{
		S_AL_BufferUnload( oldestBuffer );
		return qtrue;
	}
	else
		return qfalse;
}

Project: OpenJK

static sfxHandle_t S_AL_BufferFind(const char *filename)
{
	sfxHandle_t sfx = -1;
	int i;

	if ( !filename ) {
		Com_Error( ERR_FATAL, "Sound name is NULL" );
	}

	if ( !filename[0] ) {
		Com_Printf( S_COLOR_YELLOW "WARNING: Sound name is empty\n" );
		return 0;
	}

	if ( strlen( filename ) >= MAX_QPATH ) {
		Com_Printf( S_COLOR_YELLOW "WARNING: Sound name is too long: %s\n", filename );
		return 0;
	}

	if ( filename[0] == '*' ) {
		Com_Printf( S_COLOR_YELLOW "WARNING: Tried to load player sound directly: %s\n", filename );
		return 0;
	}

	for(i = 0; i < numSfx; i++)
	{
		if(!Q_stricmp(knownSfx[i].filename, filename))
		{
			sfx = i;
			break;
		}
	}

	if(sfx == -1)
	{
		alSfx_t *ptr;

		sfx = S_AL_BufferFindFree();

		ptr = &knownSfx[sfx];
		memset(ptr, 0, sizeof(*ptr));
		ptr->masterLoopSrc = -1;
		strcpy(ptr->filename, filename);
	}

	return sfx;
}

Project: OpenJK

static sfxHandle_t S_AL_BufferFindFree( void )
{
	int i;

	for(i = 0; i < MAX_SFX; i++)
	{
		if(knownSfx[i].filename[0] == '\0')
		{
			if(i >= numSfx)
				numSfx = i + 1;
			return i;
		}
	}

	Com_Error(ERR_FATAL, "S_AL_BufferFindFree: No free sound handles");
	return -1;
}

Project: OpenJK
File: snd_openal.c

ALuint S_AL_BufferGet(sfxHandle_t sfx)
{
	return knownSfx[sfx].buffer;
}

Project: OpenJK

qboolean S_AL_BufferInit( void )
{
	if(alBuffersInitialised)
		return qtrue;

	memset(knownSfx, 0, sizeof(knownSfx));
	numSfx = 0;

	default_sfx = S_AL_BufferFind("sound/feedback/hit.wav");
	S_AL_BufferUse(default_sfx);
	knownSfx[default_sfx].isLocked = qtrue;

	alBuffersInitialised = qtrue;
	return qtrue;
}

Project: OpenJK

static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache)
{
	ALenum error;
	ALuint format;

	void *data;
	snd_info_t info;
	alSfx_t *curSfx = &knownSfx[sfx];

	if(curSfx->filename[0] == '\0')
		return;

	if((curSfx->inMemory) || (curSfx->isDefault) || (!cache && curSfx->isDefaultChecked))
		return;

	data = S_CodecLoad(curSfx->filename, &info);
	if(!data)
	{
		S_AL_BufferUseDefault(sfx);
		return;
	}

	curSfx->isDefaultChecked = qtrue;

	if (!cache)
	{
		Hunk_FreeTempMemory(data);
		return;
	}

	format = S_AL_Format(info.width, info.channels);

	if (!S_AL_GenBuffers(1, &curSfx->buffer, curSfx->filename))
	{
		S_AL_BufferUseDefault(sfx);
		Hunk_FreeTempMemory(data);
		return;
	}

	if( info.size == 0 )
	{
		byte dummyData[ 2 ] = { 0 };

		qalBufferData(curSfx->buffer, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050);
	}
	else
		qalBufferData(curSfx->buffer, format, data, info.size, info.rate);

	error = qalGetError();

	while(error == AL_OUT_OF_MEMORY)
	{
		if( !S_AL_BufferEvict( ) )
		{
			qalDeleteBuffers(1, &curSfx->buffer);
			S_AL_BufferUseDefault(sfx);
			Hunk_FreeTempMemory(data);
			Com_Printf( S_COLOR_RED "ERROR: Out of memory loading %s\n", curSfx->filename);
			return;
		}

		qalBufferData(curSfx->buffer, format, data, info.size, info.rate);
		error = qalGetError();
	}

	if(error != AL_NO_ERROR)
	{
		qalDeleteBuffers(1, &curSfx->buffer);
		S_AL_BufferUseDefault(sfx);
		Hunk_FreeTempMemory(data);
		Com_Printf( S_COLOR_RED "ERROR: Can't fill sound buffer for %s - %s\n",
				curSfx->filename, S_AL_ErrorMsg(error));
		return;
	}

	curSfx->info = info;
	
	Hunk_FreeTempMemory(data);

	curSfx->inMemory = qtrue;
}

Project: OpenJK

void S_AL_BufferShutdown( void )
{
	int i;

	if(!alBuffersInitialised)
		return;

	knownSfx[default_sfx].isLocked = qfalse;

	for(i = 0; i < numSfx; i++)
		S_AL_BufferUnload(i);

	numSfx = 0;

	alBuffersInitialised = qfalse;
}

Project: OpenJK

static void S_AL_BufferUnload(sfxHandle_t sfx)
{
	if(knownSfx[sfx].filename[0] == '\0')
		return;

	if(!knownSfx[sfx].inMemory)
		return;

	S_AL_ClearError( qfalse );
	qalDeleteBuffers(1, &knownSfx[sfx].buffer);
	if(qalGetError() != AL_NO_ERROR)
		Com_Printf( S_COLOR_RED "ERROR: Can't delete sound buffer for %s\n",
				knownSfx[sfx].filename);

	knownSfx[sfx].inMemory = qfalse;
}

Project: OpenJK
File: snd_openal.c

void S_AL_BufferUse(sfxHandle_t sfx)
{
	if(knownSfx[sfx].filename[0] == '\0')
		return;

	if((!knownSfx[sfx].inMemory) && (!knownSfx[sfx].isDefault))
		S_AL_BufferLoad(sfx, qtrue);
	knownSfx[sfx].lastUsedTime = Sys_Milliseconds();
}

Project: OpenJK
File: snd_openal.c

static void S_AL_BufferUseDefault(sfxHandle_t sfx)
{
	if(sfx == default_sfx)
		Com_Error(ERR_FATAL, "Can't load default sound effect %s", knownSfx[sfx].filename);

	Com_Printf( S_COLOR_YELLOW "WARNING: Using default sound for %s\n", knownSfx[sfx].filename);
	knownSfx[sfx].isDefault = qtrue;
	knownSfx[sfx].buffer = knownSfx[default_sfx].buffer;
}

Project: OpenJK
File: snd_openal.c

static qboolean S_AL_CheckInput(int entityNum, sfxHandle_t sfx)
{
	if (entityNum < 0 || entityNum >= MAX_GENTITIES)
		Com_Error(ERR_DROP, "ERROR: S_AL_CheckInput: bad entitynum %i", entityNum);

	if (sfx < 0 || sfx >= numSfx)
	{
		Com_Printf(S_COLOR_RED "ERROR: S_AL_CheckInput: handle %i out of range\n", sfx);
		return qtrue;
	}

	return qfalse;
}

Project: OpenJK
File: snd_openal.c

static void S_AL_ClearError( qboolean quiet )
{
	int error = qalGetError();

	if( quiet )
		return;
	if(error != AL_NO_ERROR)
	{
		Com_Printf(S_COLOR_YELLOW "WARNING: unhandled AL error: %s\n",
			S_AL_ErrorMsg(error));
	}
}

Project: OpenJK
File: snd_openal.c

void S_AL_ClearLoopingSounds( qboolean killall )
{
	int i;
	for(i = 0; i < srcCount; i++)
	{
		if((srcList[i].isLooping) && (srcList[i].entity != -1))
			entityList[srcList[i].entity].loopAddedThisFrame = qfalse;
	}
}

Project: OpenJK
File: snd_openal.c

void S_AL_ClearSoundBuffer( void )
{
}

Project: OpenJK
File: snd_openal.c

static void S_AL_CloseMusicFiles(void)
{
	if(intro_stream)
	{
		S_CodecCloseStream(intro_stream);
		intro_stream = NULL;
	}
	
	if(mus_stream)
	{
		S_CodecCloseStream(mus_stream);
		mus_stream = NULL;
	}
}

Project: OpenJK
File: snd_openal.c

void S_AL_DisableSounds( void )
{
	S_AL_StopAllSounds();
}

Project: OpenJK
File: snd_openal.c

static const char *S_AL_ErrorMsg(ALenum error)
{
	switch(error)
	{
		case AL_NO_ERROR:
			return "No error";
		case AL_INVALID_NAME:
			return "Invalid name";
		case AL_INVALID_ENUM:
			return "Invalid enumerator";
		case AL_INVALID_VALUE:
			return "Invalid value";
		case AL_INVALID_OPERATION:
			return "Invalid operation";
		case AL_OUT_OF_MEMORY:
			return "Out of memory";
		default:
			return "Unknown error";
	}
}

Project: OpenJK

ALuint S_AL_Format(int width, int channels)
{
	ALuint format = AL_FORMAT_MONO16;

	if(width == 1)
	{
		if(channels == 1)
			format = AL_FORMAT_MONO8;
		else if(channels == 2)
			format = AL_FORMAT_STEREO8;
	}
	else if(width == 2)
	{
		if(channels == 1)
			format = AL_FORMAT_MONO16;
		else if(channels == 2)
			format = AL_FORMAT_STEREO16;
	}

	return format;
}

Project: OpenJK

static void S_AL_FreeStreamChannel( int stream )
{
	if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
		return;

	qalSourcei(streamSources[stream], AL_BUFFER, 0);

	if (streamNumBuffers[stream] > 0) {
		qalDeleteBuffers(streamNumBuffers[stream], streamBuffers[stream]);
		streamNumBuffers[stream] = 0;
	}

	S_AL_SrcUnlock(streamSourceHandles[stream]);
	S_AL_SrcKill(streamSourceHandles[stream]);
	streamSources[stream] = 0;
	streamSourceHandles[stream] = -1;
}

Project: OpenJK
File: snd_openal.c

static void S_AL_Gain(ALuint source, float gainval)
{
	if(s_muted->integer)
		qalSourcef(source, AL_GAIN, 0.0f);
	else
		qalSourcef(source, AL_GAIN, gainval);
}

Project: OpenJK

static qboolean S_AL_GenBuffers(ALsizei numBuffers, ALuint *buffers, const char *name)
{
	ALenum error;

	S_AL_ClearError( qfalse );
	qalGenBuffers( numBuffers, buffers );
	error = qalGetError();

	while( error == AL_INVALID_VALUE )
	{
		if( !S_AL_BufferEvict( ) )
		{
			Com_Printf( S_COLOR_RED "ERROR: Out of audio buffers\n");
			return qfalse;
		}

		S_AL_ClearError( qfalse );
		qalGenBuffers( numBuffers, buffers );
		error = qalGetError();
	}

	if( error != AL_NO_ERROR )
	{
		Com_Printf( S_COLOR_RED "ERROR: Can't create a sound buffer for %s - %s\n",
				    name, S_AL_ErrorMsg(error));
		return qfalse;
	}

	return qtrue;
}

Project: OpenJK

static qboolean S_AL_HearingThroughEntity( int entityNum )
{
	float	distanceSq;

	if( lastListenerNumber == entityNum )
	{
		distanceSq = DistanceSquared(
				entityList[ entityNum ].origin,
				lastListenerOrigin );

		if( distanceSq > THIRD_PERSON_THRESHOLD_SQ )
			return qfalse; //we're the player, but third person
		else
			return qtrue;  //we're the player
	}
	else
		return qfalse; //not the player
}

Project: OpenJK
File: snd_openal.c

void S_AL_MasterGain( float gain )
{
	qalListenerf(AL_GAIN, gain);
}

Project: OpenJK

void S_AL_MusicProcess(ALuint b)
{
	ALenum error;
	int l;
	ALuint format;
	snd_stream_t *curstream;

	S_AL_ClearError( qfalse );

	if(intro_stream)
		curstream = intro_stream;
	else
		curstream = mus_stream;

	if(!curstream)
		return;

	l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer);

	if(l == 0)
	{
		S_CodecCloseStream(curstream);

		if(intro_stream)
			intro_stream = NULL;
		else
			mus_stream = S_CodecOpenStream(s_backgroundLoop);
		
		curstream = mus_stream;

		if(!curstream)
		{
			S_AL_StopBackgroundTrack();
			return;
		}

		l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer);
	}

	format = S_AL_Format(curstream->info.width, curstream->info.channels);

	if( l == 0 )
	{
		byte dummyData[ 2 ] = { 0 };

		qalBufferData( b, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050 );
	}
	else
		qalBufferData(b, format, decode_buffer, l, curstream->info.rate);

	if( ( error = qalGetError( ) ) != AL_NO_ERROR )
	{
		S_AL_StopBackgroundTrack( );
		Com_Printf( S_COLOR_RED "ERROR: while buffering data for music stream - %s\n",
				S_AL_ErrorMsg( error ) );
		return;
	}
}

Project: OpenJK

static void S_AL_MusicSourceFree( void )
{
	S_AL_SrcUnlock(musicSourceHandle);
	S_AL_SrcKill(musicSourceHandle);
	musicSource = 0;
	musicSourceHandle = -1;
}

Project: OpenJK

static void S_AL_MusicSourceGet( void )
{
	musicSourceHandle = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
	if(musicSourceHandle == -1)
		return;

	S_AL_SrcLock(musicSourceHandle);
	musicSource = S_AL_SrcGet(musicSourceHandle);

	srcList[musicSourceHandle].scaleGain = 0.0f;

	qalSource3f(musicSource, AL_POSITION,        0.0, 0.0, 0.0);
	qalSource3f(musicSource, AL_VELOCITY,        0.0, 0.0, 0.0);
	qalSource3f(musicSource, AL_DIRECTION,       0.0, 0.0, 0.0);
	qalSourcef (musicSource, AL_ROLLOFF_FACTOR,  0.0          );
	qalSourcei (musicSource, AL_SOURCE_RELATIVE, AL_TRUE      );
}

Project: OpenJK

void S_AL_MusicUpdate( void )
{
	int		numBuffers;
	ALint	state;

	if(!musicPlaying)
		return;

	qalGetSourcei( musicSource, AL_BUFFERS_PROCESSED, &numBuffers );
	while( numBuffers-- )
	{
		ALuint b;
		qalSourceUnqueueBuffers(musicSource, 1, &b);
		S_AL_MusicProcess(b);
		qalSourceQueueBuffers(musicSource, 1, &b);
	}

	qalGetSourcei( musicSource, AL_SOURCE_STATE, &state );
	qalGetSourcei( musicSource, AL_BUFFERS_QUEUED, &numBuffers );
	if( state == AL_STOPPED && numBuffers )
	{
		Com_DPrintf( S_COLOR_YELLOW "Restarted OpenAL music\n" );
		qalSourcePlay(musicSource);
	}

	S_AL_Gain(musicSource, s_alGain->value * s_musicVolume->value);
}

Project: OpenJK

static void S_AL_NewLoopMaster(src_t *rmSource, qboolean iskilled)
{
	int index;
	src_t *curSource = NULL;
	alSfx_t *curSfx;
	
	curSfx = &knownSfx[rmSource->sfx];

	if(rmSource->isPlaying)
		curSfx->loopActiveCnt--;
	if(iskilled)
		curSfx->loopCnt--;
	
	if(curSfx->loopCnt)
	{
		if(rmSource->priority == SRCPRI_ENTITY)
		{
			if(!iskilled && rmSource->isPlaying)
			{
				S_AL_SaveLoopPos(rmSource, rmSource->alSource);
			}
		}
		else if(rmSource == &srcList[curSfx->masterLoopSrc])
		{
			int firstInactive = -1;

	
			if(iskilled || curSfx->loopActiveCnt)
			{
				for(index = 0; index < srcCount; index++)
				{
					curSource = &srcList[index];
	
					if(curSource->sfx == rmSource->sfx && curSource != rmSource &&
					   curSource->isActive && curSource->isLooping && curSource->priority == SRCPRI_AMBIENT)
					{
						if(curSource->isPlaying)
						{
							curSfx->masterLoopSrc = index;
							break;
						}
						else if(firstInactive < 0)
							firstInactive = index;
					}
				}
			}
		
			if(!curSfx->loopActiveCnt)
			{
				if(firstInactive < 0)
				{
					if(iskilled)
					{
						curSfx->masterLoopSrc = -1;
						return;
					}
					else
						curSource = rmSource;
				}
				else
					curSource = &srcList[firstInactive];

				if(rmSource->isPlaying)
				{
					S_AL_SaveLoopPos(curSource, rmSource->alSource);
				}
				else
				{
					curSource->lastTimePos = rmSource->lastTimePos;
					curSource->lastSampleTime = rmSource->lastSampleTime;
				}
			}
		}
	}
	else
		curSfx->masterLoopSrc = -1;
}

Project: OpenJK

void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum)
{
	int numBuffers;
	ALuint buffer;
	ALuint format;

	if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
		return;

	format = S_AL_Format( width, channels );

	if(streamSourceHandles[stream] == -1)
	{
		S_AL_AllocateStreamChannel(stream, entityNum);
	
		if(streamSourceHandles[stream] == -1)
		{
			Com_Printf( S_COLOR_RED "ERROR: Can't allocate streaming streamSource\n");
			return;
		}
	}

	qalGetSourcei(streamSources[stream], AL_BUFFERS_QUEUED, &numBuffers);

	if (numBuffers == MAX_STREAM_BUFFERS)
	{
		Com_DPrintf(S_COLOR_RED"WARNING: Steam dropping raw samples, reached MAX_STREAM_BUFFERS\n");
		return;
	}

	if (numBuffers == streamNumBuffers[stream])
	{
		ALuint oldBuffers[MAX_STREAM_BUFFERS];
		int	i;

		if (!S_AL_GenBuffers(1, &buffer, "stream"))
			return;

		Com_Memcpy(oldBuffers, &streamBuffers[stream], sizeof (oldBuffers));

		for ( i = 0; i < streamNumBuffers[stream]; ++i )
			streamBuffers[stream][i] = oldBuffers[(streamBufIndex[stream] + i) % streamNumBuffers[stream]];

		streamBuffers[stream][streamNumBuffers[stream]] = buffer;
		streamBufIndex[stream] = streamNumBuffers[stream];
		streamNumBuffers[stream]++;
	}

	buffer = streamBuffers[stream][ streamBufIndex[stream] ];
	streamBufIndex[stream] = (streamBufIndex[stream] + 1) % streamNumBuffers[stream];

	qalBufferData(buffer, format, (ALvoid *)data, (samples * width * channels), rate);

	qalSourceQueueBuffers(streamSources[stream], 1, &buffer);

	if(entityNum < 0)
	{
        	S_AL_Gain (streamSources[stream], volume * s_volume->value * s_alGain->value);
        }

	if(!streamPlaying[stream])
	{
		qalSourcePlay( streamSources[stream] );
		streamPlaying[stream] = qtrue;
	}
}

Project: OpenJK
File: snd_openal.c

sfxHandle_t S_AL_RegisterSound( const char *sample, qboolean compressed )
{
	sfxHandle_t sfx = S_AL_BufferFind(sample);

	if((!knownSfx[sfx].inMemory) && (!knownSfx[sfx].isDefault))
		S_AL_BufferLoad(sfx, s_alPrecache->integer);
	knownSfx[sfx].lastUsedTime = Com_Milliseconds();

	if (knownSfx[sfx].isDefault) {
		return 0;
	}

	return sfx;
}

Project: OpenJK

void S_AL_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater )
{
	float		orientation[6];
	vec3_t	sorigin;

	VectorCopy( origin, sorigin );
	S_AL_SanitiseVector( sorigin );

	S_AL_SanitiseVector( axis[ 0 ] );
	S_AL_SanitiseVector( axis[ 1 ] );
	S_AL_SanitiseVector( axis[ 2 ] );

	orientation[0] = axis[0][0]; orientation[1] = axis[0][1]; orientation[2] = axis[0][2];
	orientation[3] = axis[2][0]; orientation[4] = axis[2][1]; orientation[5] = axis[2][2];

	lastListenerNumber = entityNum;
	VectorCopy( sorigin, lastListenerOrigin );

	qalListenerfv(AL_POSITION, (ALfloat *)sorigin);
	qalListenerfv(AL_VELOCITY, vec3_origin);
	qalListenerfv(AL_ORIENTATION, orientation);
}

Project: OpenJK

static void S_AL_SaveLoopPos(src_t *dest, ALuint alSource)
{
	int error;
	
	S_AL_ClearError(qfalse);
	
	qalGetSourcef(alSource, AL_SEC_OFFSET, &dest->lastTimePos);
	if((error = qalGetError()) != AL_NO_ERROR)
	{

		if(error != AL_INVALID_ENUM)
		{
			Com_Printf(S_COLOR_YELLOW "WARNING: Could not get time offset for alSource %d: %s\n",
				   alSource, S_AL_ErrorMsg(error));
		}
		
		dest->lastTimePos = -1;
	}
	else
		dest->lastSampleTime = Sys_Milliseconds();
}

Project: OpenJK

static void S_AL_ScaleGain(src_t *chksrc, vec3_t origin)
{
	float distance;
	
	if(!chksrc->local)
		distance = Distance(origin, lastListenerOrigin);
		
	if(!chksrc->local && (distance -= s_alMaxDistance->value) > 0)
	{
		float scaleFactor;

		if(distance >= s_alGraceDistance->value)
			scaleFactor = 0.0f;
		else
			scaleFactor = 1.0f - distance / s_alGraceDistance->value;
		
		scaleFactor *= chksrc->curGain;
		
		if(chksrc->scaleGain != scaleFactor)
		{
			chksrc->scaleGain = scaleFactor;
			S_AL_Gain(chksrc->alSource, chksrc->scaleGain);
		}
	}
	else if(chksrc->scaleGain != chksrc->curGain)
	{
		chksrc->scaleGain = chksrc->curGain;
		S_AL_Gain(chksrc->alSource, chksrc->scaleGain);
	}
}

Project: OpenJK

void S_AL_Shutdown( void )
{
	int i;
	for (i = 0; i < MAX_RAW_STREAMS; i++)
		S_AL_StreamDie(i);
	S_AL_StopBackgroundTrack( );
	S_AL_SrcShutdown( );
	S_AL_BufferShutdown( );

	qalcDestroyContext(alContext);
	qalcCloseDevice(alDevice);

#ifdef USE_VOIP
	if (alCaptureDevice != NULL) {
		qalcCaptureStop(alCaptureDevice);
		qalcCaptureCloseDevice(alCaptureDevice);
		alCaptureDevice = NULL;
		Com_Printf( "OpenAL capture device closed.\n" );
	}
#endif

	for (i = 0; i < MAX_RAW_STREAMS; i++) {
		streamSourceHandles[i] = -1;
		streamPlaying[i] = qfalse;
		streamSources[i] = 0;
	}

	QAL_Shutdown();
}

Project: OpenJK
File: snd_openal.c

static void S_AL_SoundInfo(void)
{
	Com_Printf( "OpenAL info:\n" );
	Com_Printf( "  Vendor:         %s\n", qalGetString( AL_VENDOR ) );
	Com_Printf( "  Version:        %s\n", qalGetString( AL_VERSION ) );
	Com_Printf( "  Renderer:       %s\n", qalGetString( AL_RENDERER ) );
	Com_Printf( "  AL Extensions:  %s\n", qalGetString( AL_EXTENSIONS ) );
	Com_Printf( "  ALC Extensions: %s\n", qalcGetString( alDevice, ALC_EXTENSIONS ) );

	if(enumeration_all_ext)
		Com_Printf("  Device:         %s\n", qalcGetString(alDevice, ALC_ALL_DEVICES_SPECIFIER));
	else if(enumeration_ext)
		Com_Printf("  Device:         %s\n", qalcGetString(alDevice, ALC_DEVICE_SPECIFIER));

	if(enumeration_all_ext || enumeration_ext)
		Com_Printf("  Available Devices:\n%s", s_alAvailableDevices->string);

#ifdef USE_VOIP
	if(capture_ext)
	{
		Com_Printf("  Input Device:   %s\n", qalcGetString(alCaptureDevice, ALC_CAPTURE_DEVICE_SPECIFIER));
		Com_Printf("  Available Input Devices:\n%s", s_alAvailableInputDevices->string);
	}
#endif
}

Project: OpenJK
File: snd_openal.c

void S_AL_SoundList( void )
{
}

Project: OpenJK

srcHandle_t S_AL_SrcAlloc( alSrcPriority_t priority, int entnum, int channel )
{
	int i;
	int empty = -1;
	int weakest = -1;
	int weakest_time = Sys_Milliseconds();
	int weakest_pri = 999;
	float weakest_gain = 1000.0;
	qboolean weakest_isplaying = qtrue;
	int weakest_numloops = 0;
	src_t *curSource;

	for(i = 0; i < srcCount; i++)
	{
		curSource = &srcList[i];
		
		if(curSource->isLocked)
			continue;

		if(!curSource->isActive)
		{
			empty = i;
			break;
		}

		if(curSource->isPlaying)
		{
			if(weakest_isplaying && curSource->priority < priority &&
			   (curSource->priority < weakest_pri ||
			   (!curSource->isLooping && (curSource->scaleGain < weakest_gain || curSource->lastUsedTime < weakest_time))))
			{
				weakest_pri = curSource->priority;
				weakest_time = curSource->lastUsedTime;
				weakest_gain = curSource->scaleGain;
				weakest = i;
			}
		}
		else
		{
			weakest_isplaying = qfalse;
			
			if(weakest < 0 ||
			   knownSfx[curSource->sfx].loopCnt > weakest_numloops ||
			   curSource->priority < weakest_pri ||
			   curSource->lastUsedTime < weakest_time)
			{
				weakest_pri = curSource->priority;
				weakest_time = curSource->lastUsedTime;
				weakest_numloops = knownSfx[curSource->sfx].loopCnt;
				weakest = i;
			}
		}

#if 0
		if((curSource->entity == entnum) && (curSource->channel == channel) && (channel != 0))
		{
			S_AL_SrcKill(i);
			return i;
		}
#endif
	}

	if(empty == -1)
		empty = weakest;
	
	if(empty >= 0)
	{
		S_AL_SrcKill(empty);
		srcList[empty].isActive = qtrue;
		srcActiveCnt++;
	}

	return empty;
}

Project: OpenJK
File: snd_openal.c

ALuint S_AL_SrcGet(srcHandle_t src)
{
	return srcList[src].alSource;
}

Project: OpenJK

qboolean S_AL_SrcInit( void )
{
	int i;
	int limit;

	memset(srcList, 0, sizeof(srcList));
	srcCount = 0;
	srcActiveCnt = 0;

	limit = s_alSources->integer;
	if(limit > MAX_SRC)
		limit = MAX_SRC;
	else if(limit < 16)
		limit = 16;
 
	S_AL_ClearError( qfalse );
	for(i = 0; i < limit; i++)
	{
		qalGenSources(1, &srcList[i].alSource);
		if(qalGetError() != AL_NO_ERROR)
			break;
		srcCount++;
	}

	Com_Printf( "Allocated %d sources.\n", srcCount);
	alSourcesInitialised = qtrue;
	return qtrue;
}

Project: OpenJK
File: snd_openal.c

void S_AL_SrcLock(srcHandle_t src)
{
	srcList[src].isLocked = qtrue;
}

Project: OpenJK

static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx,
		const vec3_t origin, const vec3_t velocity, int entityNum )
{
	int				src;
	sentity_t	*sent = &entityList[ entityNum ];
	src_t		*curSource;
	vec3_t		sorigin, svelocity;

	if(S_AL_CheckInput(entityNum, sfx))
		return;

	if( !sent->srcAllocated )
	{
		src = S_AL_SrcAlloc( priority, entityNum, -1 );
		if( src == -1 )
		{
			Com_DPrintf( S_COLOR_YELLOW "WARNING: Failed to allocate source "
					"for loop sfx %d on entity %d\n", sfx, entityNum );
			return;
		}

		curSource = &srcList[src];

		sent->startLoopingSound = qtrue;

		curSource->lastTimePos = -1.0;
		curSource->lastSampleTime = Sys_Milliseconds();
	}
	else
	{
		src = sent->srcIndex;
		curSource = &srcList[src];
	}

	sent->srcAllocated = qtrue;
	sent->srcIndex = src;

	sent->loopPriority = priority;
	sent->loopSfx = sfx;

	sent->loopAddedThisFrame = qtrue;

	curSource->entity = entityNum;
	curSource->isLooping = qtrue;

	if( S_AL_HearingThroughEntity( entityNum ) )
	{
		curSource->local = qtrue;

		VectorClear(sorigin);

		qalSourcefv(curSource->alSource, AL_POSITION, sorigin);
		qalSourcefv(curSource->alSource, AL_VELOCITY, vec3_origin);
	}
	else
	{
		curSource->local = qfalse;

		if(origin)
			VectorCopy(origin, sorigin);
		else
			VectorCopy(sent->origin, sorigin);

		S_AL_SanitiseVector(sorigin);
		
		VectorCopy(sorigin, curSource->loopSpeakerPos);
		
		if(velocity)
		{
			VectorCopy(velocity, svelocity);
			S_AL_SanitiseVector(svelocity);
		}
		else
			VectorClear(svelocity);

		qalSourcefv(curSource->alSource, AL_POSITION, (ALfloat *) sorigin);
		qalSourcefv(curSource->alSource, AL_VELOCITY, (ALfloat *) svelocity);
	}
}

Project: OpenJK

static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t priority,
		int entity, int channel, qboolean local)
{
	src_t *curSource;

	curSource = &srcList[src];
	
	curSource->lastUsedTime = Sys_Milliseconds();
	curSource->sfx = sfx;
	curSource->priority = priority;
	curSource->entity = entity;
	curSource->channel = channel;
	curSource->isPlaying = qfalse;
	curSource->isLocked = qfalse;
	curSource->isLooping = qfalse;
	curSource->isTracking = qfalse;
	curSource->isStream = qfalse;
	curSource->curGain = s_alGain->value * s_volume->value;
	curSource->scaleGain = curSource->curGain;
	curSource->local = local;

	if(sfx >= 0)
	{
        	S_AL_BufferUse(sfx);
        	qalSourcei(curSource->alSource, AL_BUFFER, S_AL_BufferGet(sfx));
	}

	qalSourcef(curSource->alSource, AL_PITCH, 1.0f);
	S_AL_Gain(curSource->alSource, curSource->curGain);
	qalSourcefv(curSource->alSource, AL_POSITION, vec3_origin);
	qalSourcefv(curSource->alSource, AL_VELOCITY, vec3_origin);
	qalSourcei(curSource->alSource, AL_LOOPING, AL_FALSE);
	qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);

	if(local)
	{
		qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE);
		qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f);
	}
	else
	{
		qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE);
		qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
	}
}

Project: OpenJK

void S_AL_SrcShutdown( void )
{
	int i;
	src_t *curSource;

	if(!alSourcesInitialised)
		return;

	for(i = 0; i < srcCount; i++)
	{
		curSource = &srcList[i];
		
		if(curSource->isLocked)
			Com_DPrintf( S_COLOR_YELLOW "WARNING: Source %d is locked\n", i);

		if(curSource->entity > 0)
			entityList[curSource->entity].srcAllocated = qfalse;

		qalSourceStop(srcList[i].alSource);
		qalDeleteSources(1, &srcList[i].alSource);
	}

	memset(srcList, 0, sizeof(srcList));

	alSourcesInitialised = qfalse;
}

Project: OpenJK
File: snd_openal.c

void S_AL_SrcShutup( void )
{
	int i;
	for(i = 0; i < srcCount; i++)
		S_AL_SrcKill(i);
}

Project: OpenJK
File: snd_openal.c

void S_AL_SrcUnlock(srcHandle_t src)
{
	srcList[src].isLocked = qfalse;
}

Project: OpenJK

void S_AL_SrcUpdate( void )
{
	int i;
	int entityNum;
	ALint state;
	src_t *curSource;
	
	for(i = 0; i < srcCount; i++)
	{
		entityNum = srcList[i].entity;
		curSource = &srcList[i];

		if(curSource->isLocked)
			continue;

		if(!curSource->isActive)
			continue;

		if((s_alGain->modified) || (s_volume->modified))
			curSource->curGain = s_alGain->value * s_volume->value;
		if((s_alRolloff->modified) && (!curSource->local))
			qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
		if(s_alMinDistance->modified)
			qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value);

		if(curSource->isLooping)
		{
			sentity_t *sent = &entityList[ entityNum ];

			if(sent->loopAddedThisFrame)
			{
				alSfx_t *curSfx;
			
				if(curSource->isActive && !sent->startLoopingSound &&
						curSource->sfx != sent->loopSfx)
				{
					S_AL_NewLoopMaster(curSource, qtrue);

					curSource->isPlaying = qfalse;
					qalSourceStop(curSource->alSource);
					qalSourcei(curSource->alSource, AL_BUFFER, 0);
					sent->startLoopingSound = qtrue;
				}

				if(sent->startLoopingSound)
				{
					S_AL_SrcSetup(i, sent->loopSfx, sent->loopPriority,
							entityNum, -1, curSource->local);
					curSource->isLooping = qtrue;
					
					knownSfx[curSource->sfx].loopCnt++;
					sent->startLoopingSound = qfalse;
				}
				
				curSfx = &knownSfx[curSource->sfx];

				S_AL_ScaleGain(curSource, curSource->loopSpeakerPos);
				if(!curSource->scaleGain)
				{
					if(curSource->isPlaying)
					{
						S_AL_NewLoopMaster(curSource, qfalse);
						qalSourceStop(curSource->alSource);
						curSource->isPlaying = qfalse;
					}
					else if(!curSfx->loopActiveCnt && curSfx->masterLoopSrc < 0)
						curSfx->masterLoopSrc = i;
					
					continue;
				}

				if(!curSource->isPlaying)
				{
					qalSourcei(curSource->alSource, AL_LOOPING, AL_TRUE);
					curSource->isPlaying = qtrue;
					qalSourcePlay(curSource->alSource);

					if(curSource->priority == SRCPRI_AMBIENT)
					{

						if(curSfx->loopActiveCnt)
						{
							int offset, error;
						
							S_AL_ClearError(qfalse);
							qalGetSourcei(srcList[curSfx->masterLoopSrc].alSource, AL_SAMPLE_OFFSET, &offset);
							if((error = qalGetError()) != AL_NO_ERROR)
							{
								if(error != AL_INVALID_ENUM)
								{
									Com_Printf(S_COLOR_YELLOW "WARNING: Cannot get sample offset from source %d: "
										   "%s\n", i, S_AL_ErrorMsg(error));
								}
							}
							else
								qalSourcei(curSource->alSource, AL_SAMPLE_OFFSET, offset);
						}
						else if(curSfx->loopCnt && curSfx->masterLoopSrc >= 0)
						{
							float secofs;
						
							src_t *master = &srcList[curSfx->masterLoopSrc];
						
							if(master->lastTimePos >= 0)
							{
								secofs = master->lastTimePos + (Sys_Milliseconds() - master->lastSampleTime) / 1000.0f;
								secofs = fmodf(secofs, (float) curSfx->info.samples / curSfx->info.rate);
						
								qalSourcef(curSource->alSource, AL_SEC_OFFSET, secofs);
							}

							curSfx->masterLoopSrc = i;
						}
						else
							curSfx->masterLoopSrc = i;
					}
					else if(curSource->lastTimePos >= 0)
					{
						float secofs;
						
						
						secofs = curSource->lastTimePos + (Sys_Milliseconds() - curSource->lastSampleTime) / 1000.0f;
						secofs = fmodf(secofs, (float) curSfx->info.samples / curSfx->info.rate);
						qalSourcef(curSource->alSource, AL_SEC_OFFSET, secofs);
					}
						
					curSfx->loopActiveCnt++;
				}

				if(curSource->local)
				{
					qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE);
					qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f);
				}
				else
				{
					qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE);
					qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value);
				}
				
			}
			else if(curSource->priority == SRCPRI_AMBIENT)
			{
				if(curSource->isPlaying)
				{
					S_AL_NewLoopMaster(curSource, qfalse);
					qalSourceStop(curSource->alSource);
					curSource->isPlaying = qfalse;
				}
			}
			else
				S_AL_SrcKill(i);

			continue;
		}

		if(!curSource->isStream)
		{
	        	qalGetSourcei(curSource->alSource, AL_SOURCE_STATE, &state);
	        	if(state == AL_STOPPED)
        		{
	        		curSource->isPlaying = qfalse;
		        	S_AL_SrcKill(i);
		        	continue;
        		}
                }

		qalGetSourcei(curSource->alSource, AL_SOURCE_RELATIVE, &state);

		if(curSource->isTracking && !state)
		{
			qalSourcefv(curSource->alSource, AL_POSITION, entityList[entityNum].origin);
 			S_AL_ScaleGain(curSource, entityList[entityNum].origin);
		}
	}
}

Project: OpenJK

void S_AL_StartBackgroundTrack( const char *intro, const char *loop )
{
	int i;
	qboolean issame;

	S_AL_StopBackgroundTrack();

	if((!intro || !*intro) && (!loop || !*loop))
		return;

	S_AL_MusicSourceGet();
	if(musicSourceHandle == -1)
		return;

	if (!loop || !*loop)
	{
		loop = intro;
		issame = qtrue;
	}
	else if(intro && *intro && !strcmp(intro, loop))
		issame = qtrue;
	else
		issame = qfalse;

	Q_strncpyz( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );

	if(!issame)
	{
		intro_stream = S_CodecOpenStream(intro);
	}
	else
		intro_stream = NULL;

	mus_stream = S_CodecOpenStream(s_backgroundLoop);
	if(!mus_stream)
	{
		S_AL_CloseMusicFiles();
		S_AL_MusicSourceFree();
		return;
	}

	if (!S_AL_GenBuffers(NUM_MUSIC_BUFFERS, musicBuffers, "music"))
		return;
	
	for(i = 0; i < NUM_MUSIC_BUFFERS; i++)
	{
		S_AL_MusicProcess(musicBuffers[i]);
	}

	qalSourceQueueBuffers(musicSource, NUM_MUSIC_BUFFERS, musicBuffers);

	S_AL_Gain(musicSource, s_alGain->value * s_musicVolume->value);
	
	qalSourcePlay(musicSource);

	musicPlaying = qtrue;
}

Project: OpenJK
File: snd_openal.c

void S_AL_StartCapture( void )
{
	if (alCaptureDevice != NULL)
		qalcCaptureStart(alCaptureDevice);
}

Project: OpenJK

void S_AL_StartLocalSound(sfxHandle_t sfx, int channel)
{
	srcHandle_t src;
	
	if(S_AL_CheckInput(0, sfx))
		return;

	src = S_AL_SrcAlloc(SRCPRI_LOCAL, -1, channel);
	
	if(src == -1)
		return;

	S_AL_SrcSetup(src, sfx, SRCPRI_LOCAL, -1, channel, qtrue);

	srcList[src].isPlaying = qtrue;
	qalSourcePlay(srcList[src].alSource);
}

Project: OpenJK

static void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx )
{
	vec3_t sorigin;
	srcHandle_t src;
	src_t *curSource;

	if(origin)
	{
		if(S_AL_CheckInput(0, sfx))
			return;
		
		VectorCopy(origin, sorigin);
	}
	else
	{
		if(S_AL_CheckInput(entnum, sfx))
			return;

		if(S_AL_HearingThroughEntity(entnum))
		{
			S_AL_StartLocalSound(sfx, entchannel);
			return;
		}
		
		VectorCopy(entityList[entnum].origin, sorigin);
	}
	
	S_AL_SanitiseVector(sorigin);
	
	if((srcActiveCnt > 5 * srcCount / 3) &&
		(DistanceSquared(sorigin, lastListenerOrigin) >=
		(s_alMaxDistance->value + s_alGraceDistance->value) * (s_alMaxDistance->value + s_alGraceDistance->value)))
	{
		return;
	}

	src = S_AL_SrcAlloc(SRCPRI_ONESHOT, entnum, entchannel);
	if(src == -1)
		return;

	S_AL_SrcSetup(src, sfx, SRCPRI_ONESHOT, entnum, entchannel, qfalse);
	
	curSource = &srcList[src];

	if(!origin)
		curSource->isTracking = qtrue;
		
	qalSourcefv(curSource->alSource, AL_POSITION, sorigin );
	S_AL_ScaleGain(curSource, sorigin);

	curSource->isPlaying = qtrue;
	qalSourcePlay(curSource->alSource);
}

Project: OpenJK
File: snd_openal.c

void S_AL_StopAllSounds( void )
{
	int i;
	S_AL_SrcShutup();
	S_AL_StopBackgroundTrack();
	for (i = 0; i < MAX_RAW_STREAMS; i++)
		S_AL_StreamDie(i);
}

Project: OpenJK

void S_AL_StopBackgroundTrack( void )
{
	if(!musicPlaying)
		return;

	qalSourceStop(musicSource);

	qalSourcei(musicSource, AL_BUFFER, 0);

	qalDeleteBuffers(NUM_MUSIC_BUFFERS, musicBuffers);

	S_AL_MusicSourceFree();

	S_AL_CloseMusicFiles();

	musicPlaying = qfalse;
}

Project: OpenJK
File: snd_openal.c

void S_AL_StopCapture( void )
{
	if (alCaptureDevice != NULL)
		qalcCaptureStop(alCaptureDevice);
}

Project: OpenJK
File: snd_openal.c

void S_AL_StopLoopingSound(int entityNum )
{
	if(entityList[entityNum].srcAllocated)
		S_AL_SrcKill(entityList[entityNum].srcIndex);
}

Project: OpenJK
File: snd_openal.c

void S_AL_StreamDie( int stream )
{
	if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
		return;

	if(streamSourceHandles[stream] == -1)
		return;

	streamPlaying[stream] = qfalse;
	qalSourceStop(streamSources[stream]);

	S_AL_FreeStreamChannel(stream);
}

Project: OpenJK

void S_AL_Update( void )
{
	int i;

	if(s_muted->modified)
	{
		for(i = 0; i < srcCount; i++)
		{
			if(srcList[i].isActive)
				S_AL_Gain(srcList[i].alSource, srcList[i].scaleGain);
		}
		
		s_muted->modified = qfalse;
	}

	S_AL_SrcUpdate();

	for (i = 0; i < MAX_RAW_STREAMS; i++)
		S_AL_StreamUpdate(i);
	S_AL_MusicUpdate();

	if(s_doppler->modified)
	{
		s_alDopplerFactor->modified = qtrue;
		s_doppler->modified = qfalse;
	}

	if(s_alDopplerFactor->modified)
	{
		if(s_doppler->integer)
			qalDopplerFactor(s_alDopplerFactor->value);
		else
			qalDopplerFactor(0.0f);
		s_alDopplerFactor->modified = qfalse;
	}
	if(s_alDopplerSpeed->modified)
	{
		qalSpeedOfSound(s_alDopplerSpeed->value);
		s_alDopplerSpeed->modified = qfalse;
	}

	s_alGain->modified = qfalse;
	s_volume->modified = qfalse;
	s_musicVolume->modified = qfalse;
	s_alMinDistance->modified = qfalse;
	s_alRolloff->modified = qfalse;
}

Project: OpenJK
File: snd_openal.c

void S_AL_UpdateEntityPosition( int entityNum, const vec3_t origin )
{
	vec3_t sanOrigin;

	VectorCopy( origin, sanOrigin );
	S_AL_SanitiseVector( sanOrigin );
	if ( entityNum < 0 || entityNum >= MAX_GENTITIES )
		Com_Error( ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum );
	VectorCopy( sanOrigin, entityList[entityNum].origin );
}

Project: OpenJK
File: snd_openal.c

static void _S_AL_SanitiseVector( vec3_t v, int line )
{
	if( Q_isnan( v[ 0 ] ) || Q_isnan( v[ 1 ] ) || Q_isnan( v[ 2 ] ) )
	{
		Com_DPrintf( S_COLOR_YELLOW "WARNING: vector with one or more NaN components "
				"being passed to OpenAL at %s:%d -- zeroing\n", __FILE__, line );
		VectorClear( v );
	}
}