00001
00012 #include "WinBaseLib.h"
00013 #include "WinAudioStream.h"
00014
00015 #include <strsafe.h>
00016 #include <limits.h>
00017
00018
00019 #ifndef _USE_MATH_DEFINES
00020 #define _USE_MATH_DEFINES
00021 #endif
00022 #include <math.h>
00023
00024
00025 using namespace jbxl;
00026 using namespace jbxwl;
00027
00028
00029 CWinAudioStream::CWinAudioStream(IMediaObject* pObj)
00030 {
00031 m_cRef = 1;
00032 m_pMediaObj = pObj;
00033
00034 m_writeBuffer = NULL;
00035 m_readBuffer = NULL;
00036 m_readBufferSize = 0;
00037 m_readBufferCount = 0;
00038 m_readBufferIndex = 0;
00039
00040 m_hStopEvent = NULL;
00041 m_hDataReady = NULL;
00042
00043 m_captureThread = NULL;
00044
00045 m_hWave = NULL;
00046 m_waveHeaders = NULL;
00047 m_outputBufferNum = 0;
00048 m_outputBufferIndex = 0;
00049
00050 m_streamData = init_Buffer();
00051
00052 if (m_pMediaObj!=NULL) m_pMediaObj->AddRef();
00053
00054 InitializeCriticalSection(&m_lock);
00055 }
00056
00057
00058
00059 CWinAudioStream::~CWinAudioStream()
00060 {
00061 DEBUG_INFO("DESTRUCTOR: CWinAudioStream: START\n");
00062
00063 closeOutput();
00064 stopCapture();
00065
00066 DeleteCriticalSection(&m_lock);
00067
00068 DEBUG_INFO("DESTRUCTOR: CWinAudioStream: END\n");
00069 }
00070
00071
00072
00073 BOOL CWinAudioStream::startCapture(WAVEFORMATEX* fmt)
00074 {
00075 if (m_pMediaObj==NULL && fmt==NULL) return FALSE;
00076
00077 m_hStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
00078 m_hDataReady = CreateEvent(NULL, FALSE, FALSE, NULL);
00079 m_writeBuffer = NULL;
00080 m_readBufferCount = 0;
00081
00082
00083 WAVEFORMATEX format;
00084 if (fmt!=NULL) {
00085 format = *fmt;
00086 }
00087 else {
00088 DMO_MEDIA_TYPE media;
00089 m_pMediaObj->GetOutputCurrentType(0, &media);
00090 format = *(WAVEFORMATEX*)media.pbFormat;
00091 }
00092
00093
00094 m_readBufferSize = format.nSamplesPerSec*format.nBlockAlign;
00095 for (UINT i=0; i<MaxReadBuffers; i++) {
00096 CWinMediaBuffer* pMediaBuf = new CWinMediaBuffer(m_readBufferSize);
00097 m_bufferStack.push(pMediaBuf);
00098 }
00099 m_streamData = make_Buffer(m_readBufferSize);
00100
00101
00102 m_captureThread = AfxBeginThread(CaptureThread, (LPVOID)this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
00103 m_captureThread->m_bAutoDelete = FALSE;
00104 m_captureThread->ResumeThread();
00105 ::Sleep(10);
00106
00107 return TRUE;
00108 }
00109
00110
00111
00112 void CWinAudioStream::stopCapture(void)
00113 {
00114 if (m_hStopEvent!=NULL) {
00115 SetEvent(m_hStopEvent);
00116
00117 if (m_captureThread!=NULL) {
00118
00119 WaitForSingleObject(m_captureThread->m_hThread, INFINITE);
00120 CloseHandle(m_captureThread->m_hThread);
00121 delete m_captureThread;
00122 m_captureThread = NULL;
00123 }
00124 CloseHandle(m_hStopEvent);
00125 m_hStopEvent = NULL;
00126 }
00127
00128
00129 if (m_hDataReady!=NULL) {
00130 SetEvent(m_hDataReady);
00131 CloseHandle(m_hDataReady);
00132 m_hDataReady = NULL;
00133 }
00134
00135
00136 Back2BufferStackAll();
00137
00138
00139 while(!m_bufferStack.empty()) {
00140 CWinMediaBuffer* pMediaBuf = m_bufferStack.top();
00141 delete pMediaBuf;
00142 m_bufferStack.pop();
00143 }
00144
00145
00146 free_Buffer(&m_streamData);
00147
00148 return;
00149 }
00150
00151
00152
00153 BOOL CWinAudioStream::openOutput(ULONG bufcount, WAVEFORMATEX* fmt)
00154 {
00155 if (m_pMediaObj==NULL && fmt==NULL) return FALSE;
00156
00157
00158 WAVEFORMATEX format;
00159 if (fmt!=NULL) {
00160 format = *fmt;
00161 }
00162 else {
00163 DMO_MEDIA_TYPE media;
00164 m_pMediaObj->GetOutputCurrentType(0, &media);
00165 format = *(WAVEFORMATEX*)media.pbFormat;
00166 }
00167
00168
00169 MMRESULT ret = ::waveOutOpen(&m_hWave, WAVE_MAPPER, &format, NULL, NULL, 0);
00170 if (ret!=MMSYSERR_NOERROR) return FALSE;
00171
00172 m_outputBufferNum = bufcount;
00173 ULONG bufsz = sizeof(WAVEHDR)*m_outputBufferNum;
00174 m_waveHeaders = (WAVEHDR*)malloc(bufsz);
00175 memset(m_waveHeaders, 0, bufsz);
00176
00177 for (ULONG i=0; i<m_outputBufferNum; i++) {
00178 m_waveHeaders[i].lpData = (LPSTR)malloc(MaxOutputBuffers);
00179 m_waveHeaders[i].dwUser = i;
00180 m_waveHeaders[i].dwFlags = WHDR_DONE;
00181 }
00182
00183 return TRUE;
00184 }
00185
00186
00187
00188 void CWinAudioStream::closeOutput(void)
00189 {
00190 freeOutputHeaders();
00191
00192 if (m_hWave!=NULL) {
00193 ::waveOutPause(m_hWave);
00194 ::waveOutClose(m_hWave);
00195 m_hWave = NULL;
00196 }
00197 }
00198
00199
00200
00201 Buffer CWinAudioStream::input(void)
00202 {
00203 if (m_streamData.buf!=NULL) {
00204 ULONG len = 0;
00205 Read((void*)m_streamData.buf, (ULONG)m_streamData.bufsz, &len);
00206 m_streamData.vldsz = (int)len;
00207 }
00208 return m_streamData;
00209 }
00210
00211
00212
00213 void CWinAudioStream::output(Buffer buf)
00214 {
00215 if (buf.buf==NULL || buf.vldsz<=0) return;
00216
00217 Write((const void*)buf.buf, (ULONG)buf.vldsz, NULL);
00218 return;
00219 }
00220
00221
00222
00223 void CWinAudioStream::freeOutputHeaders(void)
00224 {
00225 if (m_waveHeaders==NULL) return;
00226
00227 for (ULONG i=0; i<m_outputBufferNum; i++) {
00228 if (m_waveHeaders[i].lpData!=NULL) {
00229 ::free(m_waveHeaders[i].lpData);
00230 m_waveHeaders[i].lpData = NULL;
00231 }
00232 }
00233 freeNull(m_waveHeaders);
00234 }
00235
00236
00237
00238
00240
00241
00242 STDMETHODIMP CWinAudioStream::Read(void* pData, ULONG cbBuffer, ULONG *pcbRead)
00243 {
00244 if (pcbRead==NULL) return E_INVALIDARG;
00245
00246 ULONG bytesPendingToRead = cbBuffer;
00247
00248 while (bytesPendingToRead>0 && IsCapturing()) {
00249 ReadOneBuffer((BYTE**)&pData, &bytesPendingToRead);
00250 if (m_readBuffer==NULL) WaitForSingleObject(m_hDataReady, INFINITE);
00251 }
00252
00253 ULONG bytesRead = cbBuffer - bytesPendingToRead;
00254 m_readBufferCount += bytesRead;
00255
00256 *pcbRead = bytesRead;
00257
00258 return S_OK;
00259 }
00260
00261
00262
00263 STDMETHODIMP CWinAudioStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition )
00264 {
00265 if (plibNewPosition!=NULL) plibNewPosition->QuadPart = m_readBufferCount + dlibMove.QuadPart;
00266
00267 return S_OK;
00268 }
00269
00270
00271
00272 STDMETHODIMP CWinAudioStream::Write(const void* pbuf, ULONG bufsz, ULONG* dummy)
00273 {
00274 if (pbuf==NULL || bufsz==0 || bufsz>MaxOutputBuffers) return E_INVALIDARG;
00275
00276 WAVEHDR* header = &m_waveHeaders[m_outputBufferIndex];
00277 if (!(header->dwFlags & WHDR_DONE)) return E_FAIL ;
00278
00279 MMRESULT ret = ::waveOutUnprepareHeader(m_hWave, header, sizeof(WAVEHDR));
00280 if (ret!=MMSYSERR_NOERROR) return E_FAIL;
00281
00282 header->dwBufferLength = (DWORD)bufsz;
00283 header->dwFlags = 0;
00284 memcpy(header->lpData, pbuf, bufsz);
00285
00286 ret = ::waveOutPrepareHeader(m_hWave, header, sizeof(WAVEHDR));
00287 if (ret!=MMSYSERR_NOERROR) {
00288 header->dwFlags = WHDR_DONE;
00289 return E_FAIL;
00290 }
00291
00292 ret = ::waveOutWrite(m_hWave, header, sizeof(WAVEHDR));
00293 if (ret!=MMSYSERR_NOERROR) {
00294 header->dwFlags = WHDR_DONE;
00295 return E_FAIL;
00296 }
00297
00298 m_outputBufferIndex = (m_outputBufferIndex + 1) % m_outputBufferNum;
00299
00300 return S_OK;
00301 }
00302
00303
00304
00305
00307
00308
00309 CWinMediaBuffer* CWinAudioStream::GetWriteBuffer()
00310 {
00311 CWinMediaBuffer* pMediaBuf = NULL;
00312
00313 EnterCriticalSection(&m_lock);
00314
00315 if (m_bufferStack.size()>0) {
00316 pMediaBuf = m_bufferStack.top();
00317 m_bufferStack.pop();
00318 pMediaBuf->SetLength(0);
00319 }
00320 else if (m_bufferQueue.size()>0) {
00321 pMediaBuf = m_bufferQueue.front();
00322 m_bufferQueue.pop();
00323 pMediaBuf->SetLength(0);
00324 }
00325
00326 LeaveCriticalSection(&m_lock);
00327
00328 return pMediaBuf;
00329 }
00330
00331
00332
00333 void CWinAudioStream::Back2BufferStack(CWinMediaBuffer* pMediaBuf)
00334 {
00335 if (pMediaBuf!=NULL) {
00336 EnterCriticalSection(&m_lock);
00337
00338 pMediaBuf->SetLength(0);
00339 m_bufferStack.push(pMediaBuf);
00340
00341 LeaveCriticalSection(&m_lock);
00342 }
00343 }
00344
00345
00346
00347 void CWinAudioStream::Back2BufferStackAll()
00348 {
00349 EnterCriticalSection(&m_lock);
00350
00351 while (m_bufferQueue.size()>0) {
00352 CWinMediaBuffer* pMediaBuf = m_bufferQueue.front();
00353 m_bufferQueue.pop();
00354 Back2BufferStack(pMediaBuf);
00355 }
00356
00357 if (m_readBuffer!=NULL) Back2BufferStack(m_readBuffer);
00358
00359 m_readBufferIndex = 0;
00360 m_readBuffer = NULL;
00361
00362 LeaveCriticalSection(&m_lock);
00363 }
00364
00365
00366
00367 void CWinAudioStream::QueueCapturedData(BYTE* pData, UINT cbData)
00368 {
00369 if (cbData<=0) return;
00370
00371 if (m_writeBuffer==NULL) m_writeBuffer = GetWriteBuffer();
00372 if (m_writeBuffer==NULL) return;
00373
00374
00375 BYTE* pWriteData = NULL;
00376 DWORD cbWriteData = 0;
00377 DWORD cbMaxLength = 0;
00378
00379
00380 m_writeBuffer->GetBufferAndLength(&pWriteData, &cbWriteData);
00381 m_writeBuffer->GetMaxLength(&cbMaxLength);
00382
00383 if (cbWriteData+cbData<cbMaxLength) {
00384 memcpy(pWriteData+cbWriteData, pData, cbData);
00385 m_writeBuffer->SetLength(cbWriteData + cbData);
00386 }
00387 else {
00388 QueueCapturedBuffer(m_writeBuffer);
00389
00390 m_writeBuffer = GetWriteBuffer();
00391 m_writeBuffer->GetBufferAndLength(&pWriteData, &cbWriteData);
00392
00393 memcpy(pWriteData, pData, cbData);
00394 m_writeBuffer->SetLength(cbData);
00395 }
00396 }
00397
00398
00399
00400 void CWinAudioStream::QueueCapturedBuffer(CWinMediaBuffer* pMediaBuf)
00401 {
00402 EnterCriticalSection(&m_lock);
00403
00404 m_bufferQueue.push(pMediaBuf);
00405 SetEvent(m_hDataReady);
00406
00407 LeaveCriticalSection(&m_lock);
00408 }
00409
00410
00411
00412 void CWinAudioStream::ReadOneBuffer(BYTE** ppbData, ULONG* pcbData)
00413 {
00414 EnterCriticalSection(&m_lock);
00415
00416
00417 if (m_readBuffer==NULL) {
00418 if(m_bufferQueue.size()!=0) {
00419 m_readBuffer = m_bufferQueue.front();
00420 m_bufferQueue.pop();
00421 }
00422 }
00423
00424
00425 if (m_readBuffer!=NULL) {
00426
00427 BYTE* pData = NULL;
00428 DWORD dwDataLength = 0;
00429 m_readBuffer->GetBufferAndLength(&pData, &dwDataLength);
00430
00431 ULONG cbToCopy = min(dwDataLength-m_readBufferIndex, *pcbData);
00432 memcpy(*ppbData, pData+m_readBufferIndex, cbToCopy);
00433 *ppbData = (*ppbData) + cbToCopy;
00434 *pcbData = (*pcbData) - cbToCopy;
00435 m_readBufferIndex += cbToCopy;
00436
00437
00438 if (m_readBufferIndex>=dwDataLength) {
00439 Back2BufferStack(m_readBuffer);
00440 m_readBuffer = NULL;
00441 m_readBufferIndex = 0;
00442
00443 if (m_bufferQueue.size()!=0) {
00444 m_readBuffer = m_bufferQueue.front();
00445 m_bufferQueue.pop();
00446 }
00447 }
00448 }
00449
00450 LeaveCriticalSection(&m_lock);
00451 }
00452
00453
00454
00455 UINT CWinAudioStream::CaptureThread(LPVOID pParam)
00456 {
00457 CWinAudioStream* pthis = (CWinAudioStream*)pParam;
00458 return pthis->CaptureThread();
00459 }
00460
00461
00462
00463 UINT CWinAudioStream::CaptureThread(void)
00464 {
00465 HANDLE mmHandle = NULL;
00466 DWORD mmTaskIndex = 0;
00467
00468 HRESULT hr = S_OK;
00469 bool bContinue = true;
00470
00471 BYTE* pbOutputBuffer = NULL;
00472 CWinMediaBuffer outputBuffer(m_readBufferSize);
00473
00474 DMO_OUTPUT_DATA_BUFFER OutputBufferStruct = {0};
00475 OutputBufferStruct.pBuffer = (IMediaBuffer*)&outputBuffer;
00476
00477 DWORD dwStatus = 0;
00478 ULONG cbProduced = 0;
00479
00480
00481 mmHandle = AvSetMmThreadCharacteristics(_T("Audio"), &mmTaskIndex);
00482
00483 while(bContinue) {
00484
00485 if (WaitForSingleObject(m_hStopEvent, 0)==WAIT_OBJECT_0) {
00486 bContinue = false;
00487 continue;
00488 }
00489
00490 do {
00491 outputBuffer.clear();
00492 OutputBufferStruct.dwStatus = 0;
00493
00494 hr = m_pMediaObj->ProcessOutput(0, 1, &OutputBufferStruct, &dwStatus);
00495 if (FAILED(hr)) {
00496 bContinue = false;
00497 break;
00498 }
00499 else if (hr==S_FALSE) {
00500 cbProduced = 0;
00501 }
00502 else {
00503 outputBuffer.GetBufferAndLength(&pbOutputBuffer, &cbProduced);
00504 }
00505
00506
00507 if (cbProduced>0) {
00508 QueueCapturedData(pbOutputBuffer, cbProduced);
00509
00510 }
00511
00512 } while (OutputBufferStruct.dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE);
00513
00514
00515 Sleep(10);
00516 }
00517
00518
00519 SetEvent(m_hDataReady);
00520 AvRevertMmThreadCharacteristics(mmHandle);
00521
00522
00523 if (FAILED(hr)) return FALSE;
00524 return TRUE;
00525 }
00526
00527