summaryrefslogtreecommitdiff
path: root/engine/audio/private/voice_record_dsound.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/audio/private/voice_record_dsound.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'engine/audio/private/voice_record_dsound.cpp')
-rw-r--r--engine/audio/private/voice_record_dsound.cpp400
1 files changed, 400 insertions, 0 deletions
diff --git a/engine/audio/private/voice_record_dsound.cpp b/engine/audio/private/voice_record_dsound.cpp
new file mode 100644
index 0000000..70fc2b6
--- /dev/null
+++ b/engine/audio/private/voice_record_dsound.cpp
@@ -0,0 +1,400 @@
+//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+// This module implements the voice record and compression functions
+
+#include "audio_pch.h"
+#if !defined( _X360 )
+#include "dsound.h"
+#endif
+#include <assert.h>
+#include "voice.h"
+#include "tier0/vcrmode.h"
+#include "ivoicerecord.h"
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+// ------------------------------------------------------------------------------
+// Globals.
+// ------------------------------------------------------------------------------
+
+typedef HRESULT (WINAPI *DirectSoundCaptureCreateFn)(const GUID FAR *lpGUID, LPDIRECTSOUNDCAPTURE *pCapture, LPUNKNOWN pUnkOuter);
+
+
+
+// ------------------------------------------------------------------------------
+// Static helpers
+// ------------------------------------------------------------------------------
+
+
+
+// ------------------------------------------------------------------------------
+// VoiceRecord_DSound
+// ------------------------------------------------------------------------------
+
+class VoiceRecord_DSound : public IVoiceRecord
+{
+protected:
+
+ virtual ~VoiceRecord_DSound();
+
+
+// IVoiceRecord.
+public:
+
+ VoiceRecord_DSound();
+ virtual void Release();
+
+ virtual bool RecordStart();
+ virtual void RecordStop();
+
+ // Initialize. The format of the data we expect from the provider is
+ // 8-bit signed mono at the specified sample rate.
+ virtual bool Init(int sampleRate);
+
+ virtual void Idle();
+
+ // Get the most recent N samples.
+ virtual int GetRecordedData(short *pOut, int nSamplesWanted);
+
+private:
+ void Term(); // Delete members.
+ void Clear(); // Clear members.
+ void UpdateWrapping();
+
+ inline DWORD NumCaptureBufferBytes() {return m_nCaptureBufferBytes;}
+
+
+private:
+ HINSTANCE m_hInstDS;
+
+ LPDIRECTSOUNDCAPTURE m_pCapture;
+ LPDIRECTSOUNDCAPTUREBUFFER m_pCaptureBuffer;
+
+ // How many bytes our capture buffer has.
+ DWORD m_nCaptureBufferBytes;
+
+ // We need to know when the capture buffer loops, so we install an event and
+ // update this in the event.
+ DWORD m_WrapOffset;
+ HANDLE m_hWrapEvent;
+
+ // This is our (unwrapped) position that tells how much data we've given to the app.
+ DWORD m_LastReadPos;
+};
+
+
+
+VoiceRecord_DSound::VoiceRecord_DSound()
+{
+ Clear();
+}
+
+
+VoiceRecord_DSound::~VoiceRecord_DSound()
+{
+ Term();
+}
+
+
+void VoiceRecord_DSound::Release()
+{
+ delete this;
+}
+
+
+bool VoiceRecord_DSound::RecordStart()
+{
+ //When we start recording we want to make sure we don't provide any audio
+ //that occurred before now. So set m_LastReadPos to the current
+ //read position of the audio device
+ if (m_pCaptureBuffer == NULL)
+ {
+ return false;
+ }
+
+ Idle();
+
+ DWORD dwStatus;
+ HRESULT hr = m_pCaptureBuffer->GetStatus(&dwStatus);
+ if (FAILED(hr) || !(dwStatus & DSCBSTATUS_CAPTURING))
+ return false;
+
+ DWORD dwReadPos;
+ hr = m_pCaptureBuffer->GetCurrentPosition(NULL, &dwReadPos);
+ if (!FAILED(hr))
+ {
+ m_LastReadPos = dwReadPos + m_WrapOffset;
+ }
+
+ return true;
+}
+
+
+void VoiceRecord_DSound::RecordStop()
+{
+}
+
+static bool IsRunningWindows7()
+{
+ if ( IsPC() )
+ {
+ OSVERSIONINFOEX osvi;
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+ if ( GetVersionEx ((OSVERSIONINFO *)&osvi) )
+ {
+ if ( osvi.dwMajorVersion > 6 || (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion >= 1) )
+ return true;
+ }
+ }
+ return false;
+}
+
+bool VoiceRecord_DSound::Init(int sampleRate)
+{
+ HRESULT hr;
+ DSCBUFFERDESC dscDesc;
+ DirectSoundCaptureCreateFn createFn;
+
+
+ Term();
+
+
+ WAVEFORMATEX recordFormat =
+ {
+ WAVE_FORMAT_PCM, // wFormatTag
+ 1, // nChannels
+ (uint32)sampleRate, // nSamplesPerSec
+ (uint32)sampleRate*2, // nAvgBytesPerSec
+ 2, // nBlockAlign
+ 16, // wBitsPerSample
+ sizeof(WAVEFORMATEX) // cbSize
+ };
+
+
+
+ // Load the DSound DLL.
+ m_hInstDS = LoadLibrary("dsound.dll");
+ if(!m_hInstDS)
+ goto HandleError;
+
+ createFn = (DirectSoundCaptureCreateFn)GetProcAddress(m_hInstDS, "DirectSoundCaptureCreate");
+ if(!createFn)
+ goto HandleError;
+
+ const GUID FAR *pGuid = &DSDEVID_DefaultVoiceCapture;
+ if ( IsRunningWindows7() )
+ {
+ pGuid = NULL;
+ }
+ hr = createFn(pGuid, &m_pCapture, NULL);
+ if(FAILED(hr))
+ goto HandleError;
+
+ // Create the capture buffer.
+ memset(&dscDesc, 0, sizeof(dscDesc));
+ dscDesc.dwSize = sizeof(dscDesc);
+ dscDesc.dwFlags = 0;
+ dscDesc.dwBufferBytes = recordFormat.nAvgBytesPerSec;
+ dscDesc.lpwfxFormat = &recordFormat;
+
+ hr = m_pCapture->CreateCaptureBuffer(&dscDesc, &m_pCaptureBuffer, NULL);
+ if(FAILED(hr))
+ goto HandleError;
+
+
+ // Figure out how many bytes we got in our capture buffer.
+ DSCBCAPS caps;
+ memset(&caps, 0, sizeof(caps));
+ caps.dwSize = sizeof(caps);
+
+ hr = m_pCaptureBuffer->GetCaps(&caps);
+ if(FAILED(hr))
+ goto HandleError;
+
+ m_nCaptureBufferBytes = caps.dwBufferBytes;
+
+
+ // Set it up so we get notification when the buffer wraps.
+ m_hWrapEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if(!m_hWrapEvent)
+ goto HandleError;
+
+ DSBPOSITIONNOTIFY dsbNotify;
+ dsbNotify.dwOffset = dscDesc.dwBufferBytes - 1;
+ dsbNotify.hEventNotify = m_hWrapEvent;
+
+ // Get the IDirectSoundNotify interface.
+ LPDIRECTSOUNDNOTIFY pNotify;
+ hr = m_pCaptureBuffer->QueryInterface(IID_IDirectSoundNotify, (void**)&pNotify);
+ if(FAILED(hr))
+ goto HandleError;
+
+ hr = pNotify->SetNotificationPositions(1, &dsbNotify);
+ pNotify->Release();
+ if(FAILED(hr))
+ goto HandleError;
+
+ // Start capturing.
+ hr = m_pCaptureBuffer->Start(DSCBSTART_LOOPING);
+ if(FAILED(hr))
+ return false;
+
+ return true;
+
+
+HandleError:;
+ Term();
+ return false;
+}
+
+
+void VoiceRecord_DSound::Term()
+{
+ if(m_pCaptureBuffer)
+ m_pCaptureBuffer->Release();
+
+ if(m_pCapture)
+ m_pCapture->Release();
+
+ if(m_hWrapEvent)
+ DeleteObject(m_hWrapEvent);
+
+ if(m_hInstDS)
+ {
+ FreeLibrary(m_hInstDS);
+ m_hInstDS = NULL;
+ }
+
+ Clear();
+}
+
+
+void VoiceRecord_DSound::Clear()
+{
+ m_pCapture = NULL;
+ m_pCaptureBuffer = NULL;
+ m_WrapOffset = 0;
+ m_LastReadPos = 0;
+ m_hWrapEvent = NULL;
+ m_hInstDS = NULL;
+}
+
+
+void VoiceRecord_DSound::Idle()
+{
+ UpdateWrapping();
+}
+
+int VoiceRecord_DSound::GetRecordedData( short *pOut, int nSamples )
+{
+ if(!m_pCaptureBuffer)
+ {
+ assert(false);
+ return 0;
+ }
+
+ DWORD dwStatus;
+ HRESULT hr = m_pCaptureBuffer->GetStatus(&dwStatus);
+ if(FAILED(hr) || !(dwStatus & DSCBSTATUS_CAPTURING))
+ return 0;
+
+ Idle(); // Update wrapping..
+
+ DWORD nBytesWanted = (DWORD)( nSamples << 1 );
+
+ DWORD dwReadPos;
+ hr = m_pCaptureBuffer->GetCurrentPosition( NULL, &dwReadPos);
+ if(FAILED(hr))
+ return 0;
+
+ dwReadPos += m_WrapOffset;
+
+ // Read the range (dwReadPos-nSamplesWanted, dwReadPos), but don't re-read data we've already read.
+ DWORD readStart = Max( dwReadPos - nBytesWanted, (DWORD)0u );
+ if ( readStart < m_LastReadPos )
+ {
+ readStart = m_LastReadPos;
+ }
+
+ // Lock the buffer.
+ LPVOID pData[2];
+ DWORD dataLen[2];
+
+ hr = m_pCaptureBuffer->Lock(
+ readStart % NumCaptureBufferBytes(), // Offset.
+ dwReadPos - readStart, // Number of bytes to lock.
+ &pData[0], // Buffer 1.
+ &dataLen[0], // Buffer 1 length.
+ &pData[1], // Buffer 2.
+ &dataLen[1], // Buffer 2 length.
+ 0 // Flags.
+ );
+
+ if(FAILED(hr))
+ return 0;
+
+ // Hopefully we didn't get too much data back!
+ if((dataLen[0]+dataLen[1]) > nBytesWanted )
+ {
+ assert(false);
+ m_pCaptureBuffer->Unlock(pData[0], dataLen[0], pData[1], dataLen[1]);
+ return 0;
+ }
+
+ // Copy the data to the output.
+ memcpy(pOut, pData[0], dataLen[0]);
+ memcpy(&pOut[dataLen[0]/2], pData[1], dataLen[1]);
+
+ m_pCaptureBuffer->Unlock(pData[0], dataLen[0], pData[1], dataLen[1]);
+
+ // Last Read Position
+ m_LastReadPos = dwReadPos;
+ // Return sample count (not bytes)
+ return (dataLen[0] + dataLen[1]) >> 1;
+}
+
+
+void VoiceRecord_DSound::UpdateWrapping()
+{
+ if(!m_pCaptureBuffer)
+ return;
+
+ // Has the buffer wrapped?
+ if ( VCRHook_WaitForSingleObject(m_hWrapEvent, 0) == WAIT_OBJECT_0 )
+ {
+ m_WrapOffset += m_nCaptureBufferBytes;
+ }
+}
+
+
+
+IVoiceRecord* CreateVoiceRecord_DSound(int sampleRate)
+{
+ VoiceRecord_DSound *pRecord = new VoiceRecord_DSound;
+ if(pRecord && pRecord->Init(sampleRate))
+ {
+ return pRecord;
+ }
+ else
+ {
+ if(pRecord)
+ pRecord->Release();
+
+ return NULL;
+ }
+}
+