00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #define STRICT
00023 #include "CLAM_windows.h"
00024 #undef GetClassName
00025 #include <basetsd.h>
00026 #include <mmsystem.h>
00027 #include <mmreg.h>
00028 #include <dxerr8.h>
00029 #include <dinput.h>
00030 #include <cstdlib>
00031 #include <iostream>
00032 #include <algorithm>
00033 using std::copy;
00034 using std::cout;
00035 using std::endl;
00036 #include "DXFullDuplex.hxx"
00037
00038 using namespace CLAM;
00039
00040 HWND DXFullDuplex::shMainWnd = 0;
00041
00042 DXFullDuplex::DXFullDuplex( TUInt32 irate, TByte ichannels, TSize latency, LPGUID pGUID )
00043 : mSampleRate ( irate ), mChannels ( ichannels ), mLatency ( latency ), mGUID( pGUID ),
00044 mDS( NULL ), mDSCapture( NULL ), mDSBPrimary( NULL ), mDSBOutput( NULL ), mDSBCapture( NULL ),
00045 mOutputBufferSize( 0 ), mCaptureBufferSize( 0 ), mNextCaptureOffset( 0 ), mNextOutputOffset( 0 ),
00046 mWritingToPrimary( false )
00047 {
00048 HRESULT hr;
00049
00050 hr = InitDSoundDevices();
00051
00052
00053 CheckResult( "At DXFullDuplex constructor - InitDSoundDevices", hr );
00054
00055 hr = CreateDXBuffers();
00056
00057 CheckResult( "At DXFullDuplex constructor - CreateDXBuffers", hr );
00058
00059 }
00060
00061 DXFullDuplex::~DXFullDuplex()
00062 {
00063
00064
00065 SafeRelease( mDSBPrimary );
00066 SafeRelease( mDSBOutput );
00067 SafeRelease( mDSBCapture );
00068
00069
00070 SafeRelease( mDSCapture );
00071 SafeRelease( mDS );
00072 }
00073
00074 HRESULT DXFullDuplex::InitDSoundDevices( void )
00075 {
00076 HRESULT hr;
00077
00078
00079
00080 hr = DirectSoundCreate( mGUID, &mDS, NULL );
00081 CheckResult( "Failed while obtaining a DirectSound interface", hr );
00082
00083 hr = mDS->SetCooperativeLevel( GetForegroundWindow(), DSSCL_WRITEPRIMARY );
00084
00085 if ( hr == DS_OK)
00086 {
00087 mWritingToPrimary = true;
00088
00089 }
00090 else
00091 {
00092 hr = mDS->SetCooperativeLevel( shMainWnd, DSSCL_PRIORITY );
00093 CheckResult( "Failed while setting up the cooperative level", hr );
00094 mWritingToPrimary = false;
00095
00096
00097
00098 }
00099
00100 mDS->Compact();
00101
00102
00103
00104 hr = DirectSoundCaptureCreate( mGUID, &mDSCapture, NULL );
00105 CheckResult( "Failed while obtaining a DirectSoundCapture interface", hr );
00106
00107 return S_OK;
00108 }
00109
00110 HRESULT DXFullDuplex::CreateDXBuffers( void )
00111 {
00112 HRESULT hr;
00113 DSBUFFERDESC buff_descriptor;
00114 DSCBUFFERDESC capt_buff_descriptor;
00115 DSBCAPS buff_caps;
00116
00117
00118
00119
00120 SetWaveFormat( &mOutputFormat );
00121
00122 memset(&buff_descriptor, 0, sizeof(DSBUFFERDESC));
00123 buff_descriptor.dwSize = sizeof(DSBUFFERDESC);
00124 buff_descriptor.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_LOCHARDWARE ;
00125
00126 buff_descriptor.dwBufferBytes = 0;
00127 buff_descriptor.lpwfxFormat = NULL;
00128
00129 hr = mDS->CreateSoundBuffer( &buff_descriptor, &mDSBPrimary, NULL );
00130 CheckResult( "Creating the Primary buffer", hr );
00131
00132 hr = mDSBPrimary->SetFormat( &mOutputFormat );
00133 CheckResult( "Setting up the Primary buffer format", hr );
00134
00135
00136 if ( mWritingToPrimary )
00137 {
00138 memset(&buff_caps, 0, sizeof(DSBUFFERDESC));
00139 buff_caps.dwSize = sizeof(DSBCAPS);
00140
00141
00142
00143 hr = mDSBPrimary->GetCaps( &buff_caps );
00144 CheckResult( "Getting the buffer capabilities", hr );
00145
00146 mOutputBufferSize = mCaptureBufferSize = buff_caps.dwBufferBytes;
00147
00148 mDSBOutput = mDSBPrimary;
00149
00150
00151 }
00152 else
00153 {
00154
00155
00156 DSCAPS dsound_caps;
00157
00158 memset( &dsound_caps, 0, sizeof(DSCAPS) );
00159 dsound_caps.dwSize = sizeof( DSCAPS );
00160
00161 hr = mDS->GetCaps( &dsound_caps );
00162
00163 mOutputBufferSize = mCaptureBufferSize = 32768;
00164
00165
00166
00167 memset( &buff_descriptor, 0, sizeof( DSBUFFERDESC ) );
00168 buff_descriptor.dwSize = sizeof( DSBUFFERDESC );
00169 buff_descriptor.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCHARDWARE;
00170 buff_descriptor.dwBufferBytes = mOutputBufferSize;
00171 buff_descriptor.guid3DAlgorithm = GUID_NULL;
00172 buff_descriptor.lpwfxFormat = &mOutputFormat;
00173
00174 hr = mDS->CreateSoundBuffer( &buff_descriptor, &mDSBOutput, NULL );
00175 CheckResult( "Creating the Secondary buffer", hr );
00176
00177 }
00178
00179
00180
00181 SetWaveFormat( &mCaptureWaveFormat );
00182
00183 memset( &capt_buff_descriptor, 0, sizeof( DSCBUFFERDESC ) );
00184 capt_buff_descriptor.dwSize = sizeof( DSCBUFFERDESC );
00185 capt_buff_descriptor.dwBufferBytes = mCaptureBufferSize;
00186 capt_buff_descriptor.lpwfxFormat = &mCaptureWaveFormat;
00187
00188 hr = mDSCapture->CreateCaptureBuffer( &capt_buff_descriptor, &mDSBCapture, NULL );
00189 CheckResult( "Creating the Capture (Input) buffer", hr );
00190
00191 return S_OK;
00192 }
00193
00194 void DXFullDuplex::CheckResult ( const char* msg, HRESULT hr )
00195 {
00196 if (FAILED(hr))
00197 {
00198 throw ErrDXFullDuplex( msg, hr);
00199 }
00200 }
00201
00202 HRESULT DXFullDuplex::Read( short* buf, TSize size)
00203 {
00204 HRESULT hr;
00205 VOID* pDSLockedBuffer1 = NULL;
00206 DWORD dwDSLockedBufferSize1;
00207 VOID* pDSLockedBuffer2 = NULL;
00208 DWORD dwDSLockedBufferSize2;
00209
00210 DWORD blocksize = size*mChannels*2;
00211 DWORD tmpPos = (mNextCaptureOffset - mLatency + mCaptureBufferSize)%mCaptureBufferSize;
00212
00213
00214
00215
00216
00217
00218 hr = mDSBCapture->Lock( tmpPos, blocksize,
00219 &pDSLockedBuffer1,
00220 &dwDSLockedBufferSize1,
00221 &pDSLockedBuffer2,
00222 &dwDSLockedBufferSize2,
00223 0L );
00224
00225 CheckResult("DirectSoundBuffer::Lock", hr );
00226
00227 TSize midpoint = dwDSLockedBufferSize1 >> 1;
00228 TSize endpoint = dwDSLockedBufferSize2 >> 1;
00229
00230 buf = copy( (short*)pDSLockedBuffer1, (short*)pDSLockedBuffer1 + midpoint, buf);
00231
00232 copy( (short*)pDSLockedBuffer2, (short*)pDSLockedBuffer2+endpoint, buf );
00233
00234 mDSBCapture->Unlock(
00235 pDSLockedBuffer1, dwDSLockedBufferSize1,
00236 pDSLockedBuffer2, dwDSLockedBufferSize2
00237 );
00238
00239 mNextCaptureOffset += blocksize;
00240 mNextCaptureOffset %= mCaptureBufferSize;
00241
00242 return S_OK;
00243 }
00244
00245 HRESULT DXFullDuplex::Write(short* buf,TSize size)
00246 {
00247 HRESULT hr;
00248 VOID* pDSLockedBuffer1 = NULL;
00249 DWORD dwDSLockedBufferSize1;
00250 VOID* pDSLockedBuffer2 = NULL;
00251 DWORD dwDSLockedBufferSize2;
00252
00253 DWORD blocksize = size*mChannels*2;
00254 bool were_restored;
00255
00256 hr = RestoreBuffer( mDSBOutput, were_restored );
00257 CheckResult("Restoring Output Buffer",hr);
00258
00259 hr = mDSBOutput->Lock( mNextOutputOffset, blocksize,
00260 &pDSLockedBuffer1,
00261 &dwDSLockedBufferSize1,
00262 &pDSLockedBuffer2,
00263 &dwDSLockedBufferSize2,
00264 0L );
00265
00266 CheckResult("DirectSoundBuffer::Lock", hr );
00267
00268 TSize midpoint = dwDSLockedBufferSize1 >> 1;
00269 TSize endpoint = dwDSLockedBufferSize2 >> 1;
00270
00271 copy( buf, buf + midpoint, (short*)pDSLockedBuffer1 );
00272
00273 copy( buf+midpoint, buf+midpoint+endpoint, (short*)pDSLockedBuffer2 );
00274
00275
00276
00277 mDSBOutput->Unlock(
00278 pDSLockedBuffer1, dwDSLockedBufferSize1,
00279 pDSLockedBuffer2, dwDSLockedBufferSize2
00280 );
00281
00282 mNextOutputOffset += blocksize;
00283 mNextOutputOffset %= mOutputBufferSize;
00284
00285 return S_OK;
00286 }
00287
00288
00289 void DXFullDuplex::SetWaveFormat( WAVEFORMATEX* pwfx )
00290 {
00291 memset( pwfx, 0, sizeof( WAVEFORMATEX ) );
00292
00293 pwfx->wFormatTag = WAVE_FORMAT_PCM;
00294 pwfx->nChannels = mChannels;
00295 pwfx->nSamplesPerSec = mSampleRate;
00296 pwfx->wBitsPerSample = 16;
00297 pwfx->nBlockAlign = pwfx->nChannels * ( pwfx->wBitsPerSample / 8 );
00298 pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
00299 }
00300
00301 HRESULT DXFullDuplex::Poll( void )
00302 {
00303
00304
00305 DWORD dist;
00306
00307 do
00308 {
00309
00310 DWORD pos;
00311 mDSBCapture->GetCurrentPosition(&pos,0);
00312 dist = pos >= mNextCaptureOffset ? pos - mNextCaptureOffset : pos + mCaptureBufferSize- mNextCaptureOffset;
00313
00314
00315
00316
00317 if ( dist < mLatency )
00318 {
00319 Sleep( 1 );
00320 }
00321
00322 } while (dist<mLatency);
00323
00324 return S_OK;
00325 }
00326
00327 HRESULT DXFullDuplex::Start( void )
00328 {
00329 HRESULT hr;
00330
00331 mNextCaptureOffset = 0;
00332 mNextOutputOffset = mLatency*3;
00333
00334
00335
00336
00337 bool were_restored;
00338
00339 hr = RestoreBuffer( mDSBOutput, were_restored );
00340 CheckResult("Restoring Output Buffer",hr);
00341
00342 mDSBOutput->SetCurrentPosition(0);
00343 mDSBCapture->GetCurrentPosition(&mNextCaptureOffset,0);
00344
00345 hr = mDSBCapture->Start( DSCBSTART_LOOPING );
00346 CheckResult("Start Capture",hr);
00347
00348 hr = mDSBOutput->Play( 0, 0, DSBPLAY_LOOPING );
00349 CheckResult("Start Output",hr);
00350
00351 return S_OK;
00352 }
00353
00354 HRESULT DXFullDuplex::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSBuffer, bool& pbRestored )
00355 {
00356 HRESULT hr;
00357
00358 pbRestored = false;
00359
00360 if( !pDSBuffer )
00361 return S_FALSE;
00362
00363 DWORD dwStatus;
00364 hr = pDSBuffer->GetStatus( &dwStatus );
00365 CheckResult("At DXFullDuplex::RestoreBuffer GetStatus", hr );
00366
00367 if( dwStatus & DSBSTATUS_BUFFERLOST )
00368 {
00369
00370
00371
00372
00373 hr = pDSBuffer->Restore();
00374 while ( hr != DS_OK )
00375 {
00376 Sleep( 10 );
00377 hr = pDSBuffer->Restore();
00378 }
00379
00380
00381 pbRestored = true;
00382
00383 return S_OK;
00384 }
00385 else
00386 {
00387 return S_FALSE;
00388 }
00389 }
00390