diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/audio/private/snd_dev_xaudio.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'engine/audio/private/snd_dev_xaudio.cpp')
| -rw-r--r-- | engine/audio/private/snd_dev_xaudio.cpp | 872 |
1 files changed, 872 insertions, 0 deletions
diff --git a/engine/audio/private/snd_dev_xaudio.cpp b/engine/audio/private/snd_dev_xaudio.cpp new file mode 100644 index 0000000..1601701 --- /dev/null +++ b/engine/audio/private/snd_dev_xaudio.cpp @@ -0,0 +1,872 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: X360 XAudio Version +// +//=====================================================================================// + + +#include "audio_pch.h" +#include "snd_dev_xaudio.h" +#include "UtlLinkedList.h" +#include "session.h" +#include "server.h" +#include "client.h" +#include "matchmaking.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// The outer code mixes in PAINTBUFFER_SIZE (# of samples) chunks (see MIX_PaintChannels), we will never need more than +// that many samples in a buffer. This ends up being about 20ms per buffer +#define XAUDIO2_BUFFER_SAMPLES 8192 +// buffer return has a latency, so need a decent pool +#define MAX_XAUDIO2_BUFFERS 32 + + +#define SURROUND_HEADPHONES 0 +#define SURROUND_STEREO 2 +#define SURROUND_DIGITAL5DOT1 5 + +// 5.1 means there are a max of 6 channels +#define MAX_DEVICE_CHANNELS 6 + +ConVar snd_xaudio_spew_packets( "snd_xaudio_spew_packets", "0", 0, "Spew XAudio packet delivery" ); + + + +//----------------------------------------------------------------------------- +// Implementation of XAudio +//----------------------------------------------------------------------------- +class CAudioXAudio : public CAudioDeviceBase +{ +public: + ~CAudioXAudio( void ); + + bool IsActive( void ) { return true; } + bool Init( void ); + void Shutdown( void ); + + void Pause( void ); + void UnPause( void ); + int PaintBegin( float mixAheadTime, int soundtime, int paintedtime ); + int GetOutputPosition( void ); + void ClearBuffer( void ); + void TransferSamples( int end ); + + const char *DeviceName( void ); + int DeviceChannels( void ) { return m_deviceChannels; } + int DeviceSampleBits( void ) { return m_deviceSampleBits; } + int DeviceSampleBytes( void ) { return m_deviceSampleBits/8; } + int DeviceDmaSpeed( void ) { return m_deviceDmaSpeed; } + int DeviceSampleCount( void ) { return m_deviceSampleCount; } + + + + void XAudioPacketCallback( int hCompletedBuffer ); + + static CAudioXAudio *m_pSingleton; + + CXboxVoice *GetVoiceData( void ) { return &m_VoiceData; } + IXAudio2 *GetXAudio2( void ) { return m_pXAudio2; } + +private: + int TransferStereo( const portable_samplepair_t *pFront, int paintedTime, int endTime, char *pOutptuBuffer ); + int TransferSurroundInterleaved( const portable_samplepair_t *pFront, const portable_samplepair_t *pRear, const portable_samplepair_t *pCenter, int paintedTime, int endTime, char *pOutputBuffer ); + + int m_deviceChannels; // channels per hardware output buffer (1 for quad/5.1, 2 for stereo) + int m_deviceSampleBits; // bits per sample (16) + int m_deviceSampleCount; // count of mono samples in output buffer + int m_deviceDmaSpeed; // samples per second per output buffer + int m_clockDivider; + + IXAudio2 *m_pXAudio2; + IXAudio2MasteringVoice *m_pMasteringVoice; + IXAudio2SourceVoice *m_pSourceVoice; + + XAUDIO2_BUFFER m_Buffers[MAX_XAUDIO2_BUFFERS]; + BYTE *m_pOutputBuffer; + int m_bufferSizeBytes; // size of a single hardware output buffer, in bytes + CInterlockedUInt m_BufferTail; + CInterlockedUInt m_BufferHead; + + CXboxVoice m_VoiceData; +}; + +CAudioXAudio *CAudioXAudio::m_pSingleton = NULL; + +//----------------------------------------------------------------------------- +// XAudio packet completion callback +//----------------------------------------------------------------------------- +class XAudio2VoiceCallback : public IXAudio2VoiceCallback +{ +public: + XAudio2VoiceCallback() {} + ~XAudio2VoiceCallback() {} + + void OnStreamEnd() {} + + void OnVoiceProcessingPassEnd() {} + + void OnVoiceProcessingPassStart( UINT32 SamplesRequired ) {} + + void OnBufferEnd( void *pBufferContext ) + { + CAudioXAudio::m_pSingleton->XAudioPacketCallback( (int)pBufferContext ); + } + + void OnBufferStart( void *pBufferContext ) {} + + void OnLoopEnd( void *pBufferContext ) {} + + void OnVoiceError( void *pBufferContext, HRESULT Error ) {} +}; +XAudio2VoiceCallback s_XAudio2VoiceCallback; + + + +//----------------------------------------------------------------------------- +// Create XAudio Device +//----------------------------------------------------------------------------- +IAudioDevice *Audio_CreateXAudioDevice( void ) +{ + MEM_ALLOC_CREDIT(); + + if ( !CAudioXAudio::m_pSingleton ) + { + CAudioXAudio::m_pSingleton = new CAudioXAudio; + } + + if ( !CAudioXAudio::m_pSingleton->Init() ) + { + delete CAudioXAudio::m_pSingleton; + CAudioXAudio::m_pSingleton = NULL; + } + + return CAudioXAudio::m_pSingleton; +} + +CXboxVoice *Audio_GetXVoice( void ) +{ + if ( CAudioXAudio::m_pSingleton ) + { + return CAudioXAudio::m_pSingleton->GetVoiceData(); + } + + return NULL; +} + +IXAudio2 *Audio_GetXAudio2( void ) +{ + if ( CAudioXAudio::m_pSingleton ) + { + return CAudioXAudio::m_pSingleton->GetXAudio2(); + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +CAudioXAudio::~CAudioXAudio( void ) +{ + m_pSingleton = NULL; +} + +//----------------------------------------------------------------------------- +// Initialize XAudio +//----------------------------------------------------------------------------- +bool CAudioXAudio::Init( void ) +{ + XAUDIOSPEAKERCONFIG xAudioConfig = 0; + XAudioGetSpeakerConfig( &xAudioConfig ); + snd_surround.SetValue( ( xAudioConfig & XAUDIOSPEAKERCONFIG_DIGITAL_DOLBYDIGITAL ) ? SURROUND_DIGITAL5DOT1 : SURROUND_STEREO ); + + m_bHeadphone = false; + m_bSurround = false; + m_bSurroundCenter = false; + + switch ( snd_surround.GetInt() ) + { + case SURROUND_HEADPHONES: + m_bHeadphone = true; + m_deviceChannels = 2; + break; + + default: + case SURROUND_STEREO: + m_deviceChannels = 2; + break; + + case SURROUND_DIGITAL5DOT1: + m_bSurround = true; + m_bSurroundCenter = true; + m_deviceChannels = 6; + break; + } + + m_deviceSampleBits = 16; + m_deviceDmaSpeed = SOUND_DMA_SPEED; + + // initialize the XAudio Engine + // Both threads on core 2 + m_pXAudio2 = NULL; + HRESULT hr = XAudio2Create( &m_pXAudio2, 0, XboxThread5 ); + if ( FAILED( hr ) ) + return false; + + // create the mastering voice, this will upsample to the devices target hw output rate + m_pMasteringVoice = NULL; + hr = m_pXAudio2->CreateMasteringVoice( &m_pMasteringVoice ); + if ( FAILED( hr ) ) + return false; + + // 16 bit PCM + WAVEFORMATEX waveFormatEx = { 0 }; + waveFormatEx.wFormatTag = WAVE_FORMAT_PCM; + waveFormatEx.nChannels = m_deviceChannels; + waveFormatEx.nSamplesPerSec = m_deviceDmaSpeed; + waveFormatEx.wBitsPerSample = 16; + waveFormatEx.nBlockAlign = ( waveFormatEx.nChannels * waveFormatEx.wBitsPerSample ) / 8; + waveFormatEx.nAvgBytesPerSec = waveFormatEx.nSamplesPerSec * waveFormatEx.nBlockAlign; + waveFormatEx.cbSize = 0; + + m_pSourceVoice = NULL; + hr = m_pXAudio2->CreateSourceVoice( + &m_pSourceVoice, + &waveFormatEx, + 0, + XAUDIO2_DEFAULT_FREQ_RATIO, + &s_XAudio2VoiceCallback, + NULL, + NULL ); + if ( FAILED( hr ) ) + return false; + + float volumes[MAX_DEVICE_CHANNELS]; + for ( int i = 0; i < MAX_DEVICE_CHANNELS; i++ ) + { + if ( !m_bSurround && i >= 2 ) + { + volumes[i] = 0; + } + else + { + volumes[i] = 1.0; + } + } + m_pSourceVoice->SetChannelVolumes( m_deviceChannels, volumes ); + + m_bufferSizeBytes = XAUDIO2_BUFFER_SAMPLES * (m_deviceSampleBits/8) * m_deviceChannels; + m_pOutputBuffer = new BYTE[MAX_XAUDIO2_BUFFERS * m_bufferSizeBytes]; + ClearBuffer(); + + V_memset( m_Buffers, 0, MAX_XAUDIO2_BUFFERS * sizeof( XAUDIO2_BUFFER ) ); + for ( int i = 0; i < MAX_XAUDIO2_BUFFERS; i++ ) + { + m_Buffers[i].pAudioData = m_pOutputBuffer + i*m_bufferSizeBytes; + m_Buffers[i].pContext = (LPVOID)i; + } + m_BufferHead = 0; + m_BufferTail = 0; + + // number of mono samples output buffer may hold + m_deviceSampleCount = MAX_XAUDIO2_BUFFERS * (m_bufferSizeBytes/(DeviceSampleBytes())); + + // NOTE: This really shouldn't be tied to the # of bufferable samples. + // This just needs to be large enough so that it doesn't fake out the sampling in + // GetSoundTime(). Basically GetSoundTime() assumes a cyclical time stamp and finds wraparound cases + // but that means it needs to get called much more often than once per cycle. So this number should be + // much larger than the framerate in terms of output time + m_clockDivider = m_deviceSampleCount / DeviceChannels(); + + // not really part of XAudio2, but mixer xma lacks one-time init, so doing it here + XMAPlaybackInitialize(); + + hr = m_pSourceVoice->Start( 0 ); + if ( FAILED( hr ) ) + return false; + + DevMsg( "XAudio Device Initialized:\n" ); + DevMsg( " %s\n" + " %d channel(s)\n" + " %d bits/sample\n" + " %d samples/sec\n", DeviceName(), DeviceChannels(), DeviceSampleBits(), DeviceDmaSpeed() ); + + m_VoiceData.VoiceInit(); + + // success + return true; +} + +//----------------------------------------------------------------------------- +// Shutdown XAudio +//----------------------------------------------------------------------------- +void CAudioXAudio::Shutdown( void ) +{ + if ( m_pSourceVoice ) + { + m_pSourceVoice->Stop( 0 ); + m_pSourceVoice->DestroyVoice(); + m_pSourceVoice = NULL; + delete[] m_pOutputBuffer; + } + + if ( m_pMasteringVoice ) + { + m_pMasteringVoice->DestroyVoice(); + m_pMasteringVoice = NULL; + } + + // need to release ref to XAudio2 + m_VoiceData.VoiceShutdown(); + + if ( m_pXAudio2 ) + { + m_pXAudio2->Release(); + m_pXAudio2 = NULL; + } + + if ( this == CAudioXAudio::m_pSingleton ) + { + CAudioXAudio::m_pSingleton = NULL; + } +} + +//----------------------------------------------------------------------------- +// XAudio has completed a packet. Assuming these are sequential +//----------------------------------------------------------------------------- +void CAudioXAudio::XAudioPacketCallback( int hCompletedBuffer ) +{ + // packet completion expected to be sequential + Assert( hCompletedBuffer == (int)( m_PacketTail % MAX_XAUDIO2_BUFFERS ) ); + + m_BufferTail++; + + if ( snd_xaudio_spew_packets.GetBool() ) + { + if ( m_BufferTail == m_BufferHead ) + { + Warning( "XAudio: Starved\n" ); + } + else + { + Msg( "XAudio: Packet Callback, Submit: %2d, Free: %2d\n", m_BufferHead - m_BufferTail, MAX_XAUDIO2_BUFFERS - ( m_BufferHead - m_BufferTail ) ); + } + } + + if ( m_BufferTail == m_BufferHead ) + { + // very bad, out of packets, xaudio is starving + // mix thread didn't keep up with audio clock and submit packets + // submit a silent buffer to keep stream playing and audio clock running + int head = m_BufferHead++; + XAUDIO2_BUFFER *pBuffer = &m_Buffers[head % MAX_XAUDIO2_BUFFERS]; + V_memset( pBuffer->pAudioData, 0, m_bufferSizeBytes ); + pBuffer->AudioBytes = m_bufferSizeBytes; + m_pSourceVoice->SubmitSourceBuffer( pBuffer ); + } +} + +//----------------------------------------------------------------------------- +// Return the "write" cursor. Used to clock the audio mixing. +// The actual hw write cursor and the number of samples it fetches is unknown. +//----------------------------------------------------------------------------- +int CAudioXAudio::GetOutputPosition( void ) +{ + XAUDIO2_VOICE_STATE state; + + state.SamplesPlayed = 0; + m_pSourceVoice->GetState( &state ); + + return ( state.SamplesPlayed % m_clockDivider ); +} + +//----------------------------------------------------------------------------- +// Pause playback +//----------------------------------------------------------------------------- +void CAudioXAudio::Pause( void ) +{ + if ( m_pSourceVoice ) + { + m_pSourceVoice->Stop( 0 ); + } +} + +//----------------------------------------------------------------------------- +// Resume playback +//----------------------------------------------------------------------------- +void CAudioXAudio::UnPause( void ) +{ + if ( m_pSourceVoice ) + { + m_pSourceVoice->Start( 0 ); + } +} + +//----------------------------------------------------------------------------- +// Calc the paint position +//----------------------------------------------------------------------------- +int CAudioXAudio::PaintBegin( float mixAheadTime, int soundtime, int paintedtime ) +{ + // soundtime = total full samples that have been played out to hardware at dmaspeed + // paintedtime = total full samples that have been mixed at speed + + // endtime = target for full samples in mixahead buffer at speed + int mixaheadtime = mixAheadTime * DeviceDmaSpeed(); + int endtime = soundtime + mixaheadtime; + if ( endtime <= paintedtime ) + { + return endtime; + } + + int fullsamps = DeviceSampleCount() / DeviceChannels(); + + if ( ( endtime - soundtime ) > fullsamps ) + { + endtime = soundtime + fullsamps; + } + if ( ( endtime - paintedtime ) & 0x03 ) + { + // The difference between endtime and painted time should align on + // boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz. + endtime -= ( endtime - paintedtime ) & 0x03; + } + + return endtime; +} + +//----------------------------------------------------------------------------- +// Fill the output buffers with silence +//----------------------------------------------------------------------------- +void CAudioXAudio::ClearBuffer( void ) +{ + V_memset( m_pOutputBuffer, 0, MAX_XAUDIO2_BUFFERS * m_bufferSizeBytes ); +} + +//----------------------------------------------------------------------------- +// Fill the output buffer with L/R samples +//----------------------------------------------------------------------------- +int CAudioXAudio::TransferStereo( const portable_samplepair_t *pFrontBuffer, int paintedTime, int endTime, char *pOutputBuffer ) +{ + int linearCount; + int i; + int val; + + int volumeFactor = S_GetMasterVolume() * 256; + + int *pFront = (int *)pFrontBuffer; + short *pOutput = (short *)pOutputBuffer; + + // get size of output buffer in full samples (LR pairs) + // number of sequential sample pairs that can be wrriten + linearCount = g_AudioDevice->DeviceSampleCount() >> 1; + + // clamp output count to requested number of samples + if ( linearCount > endTime - paintedTime ) + { + linearCount = endTime - paintedTime; + } + + // linearCount is now number of mono 16 bit samples (L and R) to xfer. + linearCount <<= 1; + + // transfer mono 16bit samples multiplying each sample by volume. + for ( i=0; i<linearCount; i+=2 ) + { + // L Channel + val = ( pFront[i] * volumeFactor ) >> 8; + *pOutput++ = CLIP( val ); + + // R Channel + val = ( pFront[i+1] * volumeFactor ) >> 8; + *pOutput++ = CLIP( val ); + } + + return linearCount * DeviceSampleBytes(); +} + +//----------------------------------------------------------------------------- +// Fill the output buffer with interleaved surround samples +//----------------------------------------------------------------------------- +int CAudioXAudio::TransferSurroundInterleaved( const portable_samplepair_t *pFrontBuffer, const portable_samplepair_t *pRearBuffer, const portable_samplepair_t *pCenterBuffer, int paintedTime, int endTime, char *pOutputBuffer ) +{ + int linearCount; + int i, j; + int val; + + int volumeFactor = S_GetMasterVolume() * 256; + + int *pFront = (int *)pFrontBuffer; + int *pRear = (int *)pRearBuffer; + int *pCenter = (int *)pCenterBuffer; + short *pOutput = (short *)pOutputBuffer; + + // number of mono samples per channel + // number of sequential samples that can be wrriten + linearCount = m_bufferSizeBytes/( DeviceSampleBytes() * DeviceChannels() ); + + // clamp output count to requested number of samples + if ( linearCount > endTime - paintedTime ) + { + linearCount = endTime - paintedTime; + } + + for ( i = 0, j = 0; i < linearCount; i++, j += 2 ) + { + // FL + val = ( pFront[j] * volumeFactor ) >> 8; + *pOutput++ = CLIP( val ); + + // FR + val = ( pFront[j+1] * volumeFactor ) >> 8; + *pOutput++ = CLIP( val ); + + // Center + val = ( pCenter[j] * volumeFactor) >> 8; + *pOutput++ = CLIP( val ); + + // Let the hardware mix the sub from the main channels since + // we don't have any sub-specific sounds, or direct sub-addressing + *pOutput++ = 0; + + // RL + val = ( pRear[j] * volumeFactor ) >> 8; + *pOutput++ = CLIP( val ); + + // RR + val = ( pRear[j+1] * volumeFactor ) >> 8; + *pOutput++ = CLIP( val ); + } + + return linearCount * DeviceSampleBytes() * DeviceChannels(); +} + +//----------------------------------------------------------------------------- +// Transfer up to a full paintbuffer (PAINTBUFFER_SIZE) of samples out to the xaudio buffer(s). +//----------------------------------------------------------------------------- +void CAudioXAudio::TransferSamples( int endTime ) +{ + XAUDIO2_BUFFER *pBuffer; + + if ( m_BufferHead - m_BufferTail >= MAX_XAUDIO2_BUFFERS ) + { + DevWarning( "XAudio: No Free Buffers!\n" ); + return; + } + + int sampleCount = endTime - g_paintedtime; + if ( sampleCount > XAUDIO2_BUFFER_SAMPLES ) + { + DevWarning( "XAudio: Overflowed mix buffer!\n" ); + endTime = g_paintedtime + XAUDIO2_BUFFER_SAMPLES; + } + + unsigned int nBuffer = m_BufferHead++; + pBuffer = &m_Buffers[nBuffer % MAX_XAUDIO2_BUFFERS]; + + if ( !m_bSurround ) + { + pBuffer->AudioBytes = TransferStereo( PAINTBUFFER, g_paintedtime, endTime, (char *)pBuffer->pAudioData ); + } + else + { + pBuffer->AudioBytes = TransferSurroundInterleaved( PAINTBUFFER, REARPAINTBUFFER, CENTERPAINTBUFFER, g_paintedtime, endTime, (char *)pBuffer->pAudioData ); + } + + // submit buffer + m_pSourceVoice->SubmitSourceBuffer( pBuffer ); +} + +//----------------------------------------------------------------------------- +// Get our device name +//----------------------------------------------------------------------------- +const char *CAudioXAudio::DeviceName( void ) +{ + if ( m_bSurround ) + { + return "XAudio: 5.1 Channel Surround"; + } + + return "XAudio: Stereo"; +} + +CXboxVoice::CXboxVoice() +{ + m_pXHVEngine = NULL; +} + +//----------------------------------------------------------------------------- +// Initialize Voice +//----------------------------------------------------------------------------- +void CXboxVoice::VoiceInit( void ) +{ + if ( !m_pXHVEngine ) + { + // Set the processing modes + XHV_PROCESSING_MODE rgMode = XHV_VOICECHAT_MODE; + + // Set up parameters for the voice chat engine + XHV_INIT_PARAMS xhvParams = {0}; + xhvParams.dwMaxRemoteTalkers = MAX_PLAYERS; + xhvParams.dwMaxLocalTalkers = XUSER_MAX_COUNT; + xhvParams.localTalkerEnabledModes = &rgMode; + xhvParams.remoteTalkerEnabledModes = &rgMode; + xhvParams.dwNumLocalTalkerEnabledModes = 1; + xhvParams.dwNumRemoteTalkerEnabledModes = 1; + xhvParams.pXAudio2 = CAudioXAudio::m_pSingleton->GetXAudio2(); + + // Create the engine + HRESULT hr = XHV2CreateEngine( &xhvParams, NULL, &m_pXHVEngine ); + if ( hr != S_OK ) + { + Warning( "Couldn't load XHV engine!\n" ); + } + } + + VoiceResetLocalData( ); +} + +void CXboxVoice::VoiceShutdown( void ) +{ + if ( !m_pXHVEngine ) + return; + + m_pXHVEngine->Release(); + m_pXHVEngine = NULL; +} + +void CXboxVoice::AddPlayerToVoiceList( CClientInfo *pClient, bool bLocal ) +{ + XHV_PROCESSING_MODE local_proc_mode = XHV_VOICECHAT_MODE; + + for ( int i = 0; i < pClient->m_cPlayers; ++i ) + { + if ( pClient->m_xuids[i] == 0 ) + continue; + + if ( bLocal == true ) + { + if ( m_pXHVEngine->RegisterLocalTalker( pClient->m_iControllers[i] ) == S_OK ) + { + m_pXHVEngine->StartLocalProcessingModes( pClient->m_iControllers[i], &local_proc_mode, 1 ); + } + } + else + { + if ( m_pXHVEngine->RegisterRemoteTalker( pClient->m_xuids[i], NULL, NULL, NULL ) == S_OK ) + { + m_pXHVEngine->StartRemoteProcessingModes( pClient->m_xuids[i], &local_proc_mode, 1 ); + } + } + } +} + +void CXboxVoice::RemovePlayerFromVoiceList( CClientInfo *pClient, bool bLocal ) +{ + for ( int i = 0; i < pClient->m_cPlayers; ++i ) + { + if ( pClient->m_xuids[i] == 0 ) + continue; + + if ( bLocal == true ) + { + m_pXHVEngine->UnregisterLocalTalker( pClient->m_iControllers[i] ); + } + else + { + m_pXHVEngine->UnregisterRemoteTalker( pClient->m_xuids[i] ); + } + } +} + +void CXboxVoice::PlayIncomingVoiceData( XUID xuid, const byte *pbData, DWORD pdwSize ) +{ + XUID localXUID; + + XUserGetXUID( XBX_GetPrimaryUserId(), &localXUID ); + + //Hack: Don't play stuff that comes from ourselves. + if ( localXUID == xuid ) + return; + + m_pXHVEngine->SubmitIncomingChatData( xuid, pbData, &pdwSize ); +} + + +void CXboxVoice::UpdateHUDVoiceStatus( void ) +{ + for ( int iClient = 0; iClient < cl.m_nMaxClients; iClient++ ) + { + bool bSelf = (cl.m_nPlayerSlot == iClient); + + int iIndex = iClient + 1; + XUID id = g_pMatchmaking->PlayerIdToXuid( iIndex ); + + if ( id != 0 ) + { + bool bTalking = false; + + if ( bSelf == true ) + { + //Make sure the player's own label is not on. + g_pSoundServices->OnChangeVoiceStatus( iIndex, false ); + + iIndex = -1; + + if ( IsPlayerTalking( XBX_GetPrimaryUserId(), true ) ) + { + bTalking = true; + } + } + else + { + if ( IsPlayerTalking( id, false ) ) + { + bTalking = true; + } + } + + g_pSoundServices->OnChangeVoiceStatus( iIndex, bTalking ); + } + else + { + g_pSoundServices->OnChangeVoiceStatus( iIndex, false ); + } + } +} + +bool CXboxVoice::VoiceUpdateData( void ) +{ + DWORD dwNumPackets = 0; + DWORD dwBytes = 0; + WORD wVoiceBytes = 0; + bool bShouldSend = false; + DWORD dwVoiceFlags = m_pXHVEngine->GetDataReadyFlags(); + + //Update UI stuff. + UpdateHUDVoiceStatus(); + + for ( uint i = 0; i < XUSER_MAX_COUNT; ++i ) + { + // We currently only allow one player per console + if ( i != XBX_GetPrimaryUserId() ) + { + continue; + } + + if ( IsHeadsetPresent( i ) == false ) + continue; + + if ( !(dwVoiceFlags & ( 1 << i )) ) + continue; + + dwBytes = m_ChatBufferSize - m_wLocalDataSize; + + if( dwBytes < XHV_VOICECHAT_MODE_PACKET_SIZE ) + { + bShouldSend = true; + } + else + { + m_pXHVEngine->GetLocalChatData( i, m_ChatBuffer + m_wLocalDataSize, &dwBytes, &dwNumPackets ); + m_wLocalDataSize += ((WORD)dwBytes) & MAXWORD; + + if( m_wLocalDataSize > ( ( m_ChatBufferSize * 7 ) / 10 ) ) + { + bShouldSend = true; + } + } + + wVoiceBytes += m_wLocalDataSize & MAXWORD; + break; + } + + return bShouldSend || + ( wVoiceBytes && + ( GetTickCount() - m_dwLastVoiceSend ) > MAX_VOICE_BUFFER_TIME ); +} + +void CXboxVoice::SetPlaybackPriority( XUID remoteTalker, DWORD dwUserIndex, XHV_PLAYBACK_PRIORITY playbackPriority ) +{ + m_pXHVEngine->SetPlaybackPriority( remoteTalker, dwUserIndex, playbackPriority ); +} + +void CXboxVoice::GetRemoteTalkers( int *pNumTalkers, XUID *pRemoteTalkers ) +{ + m_pXHVEngine->GetRemoteTalkers( (DWORD*)pNumTalkers, pRemoteTalkers ); +} + +void CXboxVoice::GetVoiceData( CLC_VoiceData *pMessage ) +{ + byte *puchVoiceData = NULL; + pMessage->m_nLength = m_wLocalDataSize; + XUserGetXUID( XBX_GetPrimaryUserId(), &pMessage->m_xuid ); + + puchVoiceData = m_ChatBuffer; + + pMessage->m_DataOut.StartWriting( puchVoiceData, pMessage->m_nLength ); + pMessage->m_nLength *= 8; + pMessage->m_DataOut.SeekToBit( pMessage->m_nLength ); // set correct writing position +} + +void CXboxVoice::VoiceSendData( INetChannel *pChannel ) +{ + CLC_VoiceData voiceMsg; + GetVoiceData( &voiceMsg ); + + if ( pChannel ) + { + pChannel->SendNetMsg( voiceMsg, false, true ); + VoiceResetLocalData(); + } +} + +void CXboxVoice::VoiceResetLocalData( void ) +{ + m_wLocalDataSize = 0; + m_dwLastVoiceSend = GetTickCount(); + Q_memset( m_ChatBuffer, 0, m_ChatBufferSize ); +} + +bool CXboxVoice::IsPlayerTalking( XUID uid, bool bLocal ) +{ + if ( bLocal == true ) + { + return m_pXHVEngine->IsLocalTalking( XBX_GetPrimaryUserId() ); + } + else + { + return !g_pMatchmaking->IsPlayerMuted( XBX_GetPrimaryUserId(), uid ) && m_pXHVEngine->IsRemoteTalking( uid ); + } + + return false; +} + +bool CXboxVoice::IsHeadsetPresent( int id ) +{ + return m_pXHVEngine->IsHeadsetPresent( id ); +} + +void CXboxVoice::RemoveAllTalkers( CClientInfo *pLocal ) +{ + int numRemoteTalkers; + XUID remoteTalkers[MAX_PLAYERS]; + GetRemoteTalkers( &numRemoteTalkers, remoteTalkers ); + + for ( int iRemote = 0; iRemote < numRemoteTalkers; iRemote++ ) + { + m_pXHVEngine->UnregisterRemoteTalker( remoteTalkers[iRemote] ); + } + + if ( pLocal ) + { + for ( int i = 0; i < pLocal->m_cPlayers; ++i ) + { + if ( pLocal->m_xuids[i] == 0 ) + continue; + + m_pXHVEngine->UnregisterLocalTalker( pLocal->m_iControllers[i] ); + } + } +}
\ No newline at end of file |