JunkBox_Win_Lib 1.5.3
Loading...
Searching...
No Matches
WinAudioStream.cpp
Go to the documentation of this file.
1
12#include "WinBaseLib.h"
13#include "WinAudioStream.h"
14
15#include <strsafe.h> // StringCch
16#include <limits.h> // INT_MAX
17
18
19#ifndef _USE_MATH_DEFINES
20#define _USE_MATH_DEFINES
21#endif
22#include <math.h>
23
24
25using namespace jbxl;
26using namespace jbxwl;
27
28
30{
31 m_cRef = 1;
32 m_pMediaObj = pObj;
33
34 m_writeBuffer = NULL;
35 m_readBuffer = NULL;
39 //
40 m_hStopEvent = NULL;
41 m_hDataReady = NULL;
42 //
43 m_captureThread = NULL;
44
45 m_hWave = NULL;
46 m_waveHeaders = NULL;
49
50 m_streamData = init_Buffer();
51
52 if (m_pMediaObj!=NULL) m_pMediaObj->AddRef();
53
54 InitializeCriticalSection(&m_lock);
55}
56
57
58
60{
61 DEBUG_INFO("DESTRUCTOR: CWinAudioStream: START\n");
62 //
65
66 DeleteCriticalSection(&m_lock);
67
68 DEBUG_INFO("DESTRUCTOR: CWinAudioStream: END\n");
69}
70
71
72
73BOOL CWinAudioStream::startCapture(WAVEFORMATEX* fmt)
74{
75 if (m_pMediaObj==NULL && fmt==NULL) return FALSE;
76
77 m_hStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
78 m_hDataReady = CreateEvent(NULL, FALSE, FALSE, NULL);
79 m_writeBuffer = NULL;
81
82 //
83 WAVEFORMATEX format;
84 if (fmt!=NULL) {
85 format = *fmt;
86 }
87 else {
88 DMO_MEDIA_TYPE media;
89 m_pMediaObj->GetOutputCurrentType(0, &media);
90 format = *(WAVEFORMATEX*)media.pbFormat;
91 }
92
93 // make Stack
94 m_readBufferSize = format.nSamplesPerSec*format.nBlockAlign;
95 for (UINT i=0; i<MaxReadBuffers; i++) {
97 m_bufferStack.push(pMediaBuf);
98 }
99 m_streamData = make_Buffer(m_readBufferSize);
100
101 // スレッドの起動
102 m_captureThread = AfxBeginThread(CaptureThread, (LPVOID)this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
103 m_captureThread->m_bAutoDelete = FALSE;
104 m_captureThread->ResumeThread();
105 ::Sleep(10);
106
107 return TRUE;
108}
109
110
111
113{
114 if (m_hStopEvent!=NULL) {
115 SetEvent(m_hStopEvent);
116 //
117 if (m_captureThread!=NULL) {
118 // スレッドが終了するまで待つ
119 WaitForSingleObject(m_captureThread->m_hThread, INFINITE);
120 CloseHandle(m_captureThread->m_hThread);
121 delete m_captureThread;
122 m_captureThread = NULL;
123 }
124 CloseHandle(m_hStopEvent);
125 m_hStopEvent = NULL;
126 }
127
128 //
129 if (m_hDataReady!=NULL) {
130 SetEvent(m_hDataReady);
131 CloseHandle(m_hDataReady);
132 m_hDataReady = NULL;
133 }
134
135 //
137
138 // delete Stack
139 while(!m_bufferStack.empty()) {
140 CWinMediaBuffer* pMediaBuf = m_bufferStack.top();
141 delete pMediaBuf;
142 m_bufferStack.pop();
143 }
144
145 //
146 free_Buffer(&m_streamData);
147
148 return;
149}
150
151
152
153BOOL CWinAudioStream::openOutput(ULONG bufcount, WAVEFORMATEX* fmt)
154{
155 if (m_pMediaObj==NULL && fmt==NULL) return FALSE;
156
157 //
158 WAVEFORMATEX format;
159 if (fmt!=NULL) {
160 format = *fmt;
161 }
162 else {
163 DMO_MEDIA_TYPE media;
164 m_pMediaObj->GetOutputCurrentType(0, &media);
165 format = *(WAVEFORMATEX*)media.pbFormat;
166 }
167
168 //
169 MMRESULT ret = ::waveOutOpen(&m_hWave, WAVE_MAPPER, &format, NULL, NULL, 0);
170 if (ret!=MMSYSERR_NOERROR) return FALSE;
171
172 m_outputBufferNum = bufcount;
173 ULONG bufsz = sizeof(WAVEHDR)*m_outputBufferNum;
174 m_waveHeaders = (WAVEHDR*)malloc(bufsz);
175 memset(m_waveHeaders, 0, bufsz);
176
177 for (ULONG i=0; i<m_outputBufferNum; i++) {
178 m_waveHeaders[i].lpData = (LPSTR)malloc(MaxOutputBuffers);
179 m_waveHeaders[i].dwUser = i;
180 m_waveHeaders[i].dwFlags = WHDR_DONE;
181 }
182
183 return TRUE;
184}
185
186
187
189{
191
192 if (m_hWave!=NULL) {
193 ::waveOutPause(m_hWave);
194 ::waveOutClose(m_hWave);
195 m_hWave = NULL;
196 }
197}
198
199
200
202{
203 if (m_streamData.buf!=NULL) {
204 ULONG len = 0;
205 Read((void*)m_streamData.buf, (ULONG)m_streamData.bufsz, &len);
206 m_streamData.vldsz = (int)len;
207 }
208 return m_streamData;
209}
210
211
212
214{
215 if (buf.buf==NULL || buf.vldsz<=0) return;
216
217 Write((const void*)buf.buf, (ULONG)buf.vldsz, NULL);
218 return;
219}
220
221
222
224{
225 if (m_waveHeaders==NULL) return;
226
227 for (ULONG i=0; i<m_outputBufferNum; i++) {
228 if (m_waveHeaders[i].lpData!=NULL) {
229 ::free(m_waveHeaders[i].lpData);
230 m_waveHeaders[i].lpData = NULL;
231 }
232 }
233 freeNull(m_waveHeaders);
234}
235
236
237
238
240// IStream methods
241
242STDMETHODIMP CWinAudioStream::Read(void* pData, ULONG cbBuffer, ULONG *pcbRead)
243{
244 if (pcbRead==NULL) return E_INVALIDARG;
245
246 ULONG bytesPendingToRead = cbBuffer; // バッファの残り
247
248 while (bytesPendingToRead>0 && IsCapturing()) {
249 ReadOneBuffer((BYTE**)&pData, &bytesPendingToRead);
250 if (m_readBuffer==NULL) WaitForSingleObject(m_hDataReady, INFINITE);
251 }
252
253 ULONG bytesRead = cbBuffer - bytesPendingToRead; // 読み込んだデータ長
254 m_readBufferCount += bytesRead;
255
256 *pcbRead = bytesRead;
257
258 return S_OK;
259}
260
261
262
263STDMETHODIMP CWinAudioStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition )
264{
265 if (plibNewPosition!=NULL) plibNewPosition->QuadPart = m_readBufferCount + dlibMove.QuadPart;
266
267 return S_OK;
268}
269
270
271
272STDMETHODIMP CWinAudioStream::Write(const void* pbuf, ULONG bufsz, ULONG* dummy)
273{
274 if (pbuf==NULL || bufsz==0 || bufsz>MaxOutputBuffers) return E_INVALIDARG;
275
276 WAVEHDR* header = &m_waveHeaders[m_outputBufferIndex];
277 if (!(header->dwFlags & WHDR_DONE)) return E_FAIL ;
278
279 MMRESULT ret = ::waveOutUnprepareHeader(m_hWave, header, sizeof(WAVEHDR));
280 if (ret!=MMSYSERR_NOERROR) return E_FAIL;
281
282 header->dwBufferLength = (DWORD)bufsz;
283 header->dwFlags = 0;
284 memcpy(header->lpData, pbuf, bufsz);
285
286 ret = ::waveOutPrepareHeader(m_hWave, header, sizeof(WAVEHDR));
287 if (ret!=MMSYSERR_NOERROR) {
288 header->dwFlags = WHDR_DONE;
289 return E_FAIL;
290 }
291
292 ret = ::waveOutWrite(m_hWave, header, sizeof(WAVEHDR));
293 if (ret!=MMSYSERR_NOERROR) {
294 header->dwFlags = WHDR_DONE;
295 return E_FAIL;
296 }
297
299
300 return S_OK;
301}
302
303
304
305
307// Private CWinAudioStream methods
308
310{
311 CWinMediaBuffer* pMediaBuf = NULL;
312
313 EnterCriticalSection(&m_lock);
314
315 if (m_bufferStack.size()>0) {
316 pMediaBuf = m_bufferStack.top();
317 m_bufferStack.pop();
318 pMediaBuf->SetLength(0);
319 }
320 else if (m_bufferQueue.size()>0) {
321 pMediaBuf = m_bufferQueue.front();
322 m_bufferQueue.pop();
323 pMediaBuf->SetLength(0);
324 }
325
326 LeaveCriticalSection(&m_lock);
327
328 return pMediaBuf;
329}
330
331
332
334{
335 if (pMediaBuf!=NULL) {
336 EnterCriticalSection(&m_lock);
337 //
338 pMediaBuf->SetLength(0);
339 m_bufferStack.push(pMediaBuf);
340 //
341 LeaveCriticalSection(&m_lock);
342 }
343}
344
345
346
348{
349 EnterCriticalSection(&m_lock);
350
351 while (m_bufferQueue.size()>0) {
352 CWinMediaBuffer* pMediaBuf = m_bufferQueue.front();
353 m_bufferQueue.pop();
354 Back2BufferStack(pMediaBuf);
355 }
356
358
360 m_readBuffer = NULL;
361 //
362 LeaveCriticalSection(&m_lock);
363}
364
365
366
367void CWinAudioStream::QueueCapturedData(BYTE* pData, UINT cbData)
368{
369 if (cbData<=0) return;
370
372 if (m_writeBuffer==NULL) return;
373
374 //
375 BYTE* pWriteData = NULL;
376 DWORD cbWriteData = 0;
377 DWORD cbMaxLength = 0;
378
379 //
380 m_writeBuffer->GetBufferAndLength(&pWriteData, &cbWriteData);
381 m_writeBuffer->GetMaxLength(&cbMaxLength);
382
383 if (cbWriteData+cbData<cbMaxLength) {
384 memcpy(pWriteData+cbWriteData, pData, cbData);
385 m_writeBuffer->SetLength(cbWriteData + cbData);
386 }
387 else {
389 //
391 m_writeBuffer->GetBufferAndLength(&pWriteData, &cbWriteData);
392 //
393 memcpy(pWriteData, pData, cbData);
394 m_writeBuffer->SetLength(cbData);
395 }
396}
397
398
399
401{
402 EnterCriticalSection(&m_lock);
403
404 m_bufferQueue.push(pMediaBuf);
405 SetEvent(m_hDataReady);
406
407 LeaveCriticalSection(&m_lock);
408}
409
410
411
412void CWinAudioStream::ReadOneBuffer(BYTE** ppbData, ULONG* pcbData)
413{
414 EnterCriticalSection(&m_lock);
415
416 //
417 if (m_readBuffer==NULL) {
418 if(m_bufferQueue.size()!=0) {
419 m_readBuffer = m_bufferQueue.front();
420 m_bufferQueue.pop();
421 }
422 }
423
424 //
425 if (m_readBuffer!=NULL) {
426 //Copy as much data as we can or need
427 BYTE* pData = NULL;
428 DWORD dwDataLength = 0;
429 m_readBuffer->GetBufferAndLength(&pData, &dwDataLength);
430
431 ULONG cbToCopy = min(dwDataLength-m_readBufferIndex, *pcbData);
432 memcpy(*ppbData, pData+m_readBufferIndex, cbToCopy);
433 *ppbData = (*ppbData) + cbToCopy;
434 *pcbData = (*pcbData) - cbToCopy;
435 m_readBufferIndex += cbToCopy;
436
437 //
438 if (m_readBufferIndex>=dwDataLength) {
440 m_readBuffer = NULL;
442
443 if (m_bufferQueue.size()!=0) {
444 m_readBuffer = m_bufferQueue.front();
445 m_bufferQueue.pop();
446 }
447 }
448 }
449
450 LeaveCriticalSection(&m_lock);
451}
452
453
454
456{
457 CWinAudioStream* pthis = (CWinAudioStream*)pParam;
458 return pthis->CaptureThread();
459}
460
461
462
464{
465 HANDLE mmHandle = NULL;
466 DWORD mmTaskIndex = 0;
467
468 HRESULT hr = S_OK;
469 bool bContinue = true;
470
471 BYTE* pbOutputBuffer = NULL;
472 CWinMediaBuffer outputBuffer(m_readBufferSize);
473
474 DMO_OUTPUT_DATA_BUFFER OutputBufferStruct = {0};
475 OutputBufferStruct.pBuffer = (IMediaBuffer*)&outputBuffer;
476
477 DWORD dwStatus = 0;
478 ULONG cbProduced = 0;
479
480 //
481 mmHandle = AvSetMmThreadCharacteristics(_T("Audio"), &mmTaskIndex);
482
483 while(bContinue) {
484 //
485 if (WaitForSingleObject(m_hStopEvent, 0)==WAIT_OBJECT_0) {
486 bContinue = false;
487 continue;
488 }
489
490 do {
491 outputBuffer.clear();
492 OutputBufferStruct.dwStatus = 0;
493
494 hr = m_pMediaObj->ProcessOutput(0, 1, &OutputBufferStruct, &dwStatus);
495 if (FAILED(hr)) {
496 bContinue = false;
497 break;
498 }
499 else if (hr==S_FALSE) {
500 cbProduced = 0;
501 }
502 else {
503 outputBuffer.GetBufferAndLength(&pbOutputBuffer, &cbProduced);
504 }
505
506 // Queue にデータを保存
507 if (cbProduced>0) {
508 QueueCapturedData(pbOutputBuffer, cbProduced);
509 //Write(pbOutputBuffer, cbProduced, NULL); // for TEST
510 }
511
512 } while (OutputBufferStruct.dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE);
513
514 //
515 Sleep(10);
516 }
517
518 //
519 SetEvent(m_hDataReady);
520 AvRevertMmThreadCharacteristics(mmHandle);
521
522 //
523 if (FAILED(hr)) return FALSE;
524 return TRUE;
525}
526
527
オーディオストリーム ヘッダ
STDMETHODIMP Read(void *, ULONG, ULONG *)
CWinMediaBuffer * m_readBuffer
void QueueCapturedBuffer(CWinMediaBuffer *pMediaBuf)
CRITICAL_SECTION m_lock
void Back2BufferStack(CWinMediaBuffer *pMediaBuf)
static UINT CaptureThread(LPVOID pParam)
CWinAudioStream(IMediaObject *pObj)
MediaBufferStack m_bufferStack
CWinMediaBuffer * GetWriteBuffer(void)
CWinMediaBuffer * m_writeBuffer
STDMETHODIMP Seek(LARGE_INTEGER, DWORD, ULARGE_INTEGER *)
virtual ~CWinAudioStream(void)
BOOL startCapture(WAVEFORMATEX *format=NULL)
IMediaObject * m_pMediaObj
STDMETHODIMP Write(const void *, ULONG, ULONG *)
void QueueCapturedData(BYTE *pData, UINT cbData)
static const UINT MaxOutputBuffers
void ReadOneBuffer(BYTE **ppbData, ULONG *pcbData)
BOOL openOutput(ULONG bufcount=100, WAVEFORMATEX *format=NULL)
static const UINT MaxReadBuffers
MediaBufferQueue m_bufferQueue
STDMETHODIMP GetMaxLength(DWORD *pMaxLength)
STDMETHODIMP SetLength(DWORD length)
STDMETHODIMP GetBufferAndLength(BYTE **ppData, DWORD *pLength)