71 errorState = QAudio::NoError; |
69 errorState = QAudio::NoError; |
72 deviceState = QAudio::StoppedState; |
70 deviceState = QAudio::StoppedState; |
73 audioSource = 0; |
71 audioSource = 0; |
74 pullMode = true; |
72 pullMode = true; |
75 finished = false; |
73 finished = false; |
76 InitializeCriticalSection(&waveOutCriticalSection); |
|
77 } |
74 } |
78 |
75 |
79 QAudioOutputPrivate::~QAudioOutputPrivate() |
76 QAudioOutputPrivate::~QAudioOutputPrivate() |
80 { |
77 { |
81 EnterCriticalSection(&waveOutCriticalSection); |
78 mutex.lock(); |
82 finished = true; |
79 finished = true; |
83 LeaveCriticalSection(&waveOutCriticalSection); |
80 mutex.unlock(); |
84 |
81 |
85 close(); |
82 close(); |
86 DeleteCriticalSection(&waveOutCriticalSection); |
|
87 } |
83 } |
88 |
84 |
89 void CALLBACK QAudioOutputPrivate::waveOutProc( HWAVEOUT hWaveOut, UINT uMsg, |
85 void CALLBACK QAudioOutputPrivate::waveOutProc( HWAVEOUT hWaveOut, UINT uMsg, |
90 DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) |
86 DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) |
91 { |
87 { |
95 |
91 |
96 QAudioOutputPrivate* qAudio; |
92 QAudioOutputPrivate* qAudio; |
97 qAudio = (QAudioOutputPrivate*)(dwInstance); |
93 qAudio = (QAudioOutputPrivate*)(dwInstance); |
98 if(!qAudio) |
94 if(!qAudio) |
99 return; |
95 return; |
|
96 |
|
97 QMutexLocker(&qAudio->mutex); |
100 |
98 |
101 switch(uMsg) { |
99 switch(uMsg) { |
102 case WOM_OPEN: |
100 case WOM_OPEN: |
103 qAudio->feedback(); |
101 qAudio->feedback(); |
104 break; |
102 break; |
105 case WOM_CLOSE: |
103 case WOM_CLOSE: |
106 return; |
104 return; |
107 case WOM_DONE: |
105 case WOM_DONE: |
108 EnterCriticalSection(&qAudio->waveOutCriticalSection); |
|
109 if(qAudio->finished || qAudio->buffer_size == 0 || qAudio->period_size == 0) { |
106 if(qAudio->finished || qAudio->buffer_size == 0 || qAudio->period_size == 0) { |
110 LeaveCriticalSection(&qAudio->waveOutCriticalSection); |
|
111 return; |
107 return; |
112 } |
108 } |
113 qAudio->waveFreeBlockCount++; |
109 qAudio->waveFreeBlockCount++; |
114 if(qAudio->waveFreeBlockCount >= qAudio->buffer_size/qAudio->period_size) |
110 if(qAudio->waveFreeBlockCount >= qAudio->buffer_size/qAudio->period_size) |
115 qAudio->waveFreeBlockCount = qAudio->buffer_size/qAudio->period_size; |
111 qAudio->waveFreeBlockCount = qAudio->buffer_size/qAudio->period_size; |
116 qAudio->feedback(); |
112 qAudio->feedback(); |
117 LeaveCriticalSection(&qAudio->waveOutCriticalSection); |
|
118 break; |
113 break; |
119 default: |
114 default: |
120 return; |
115 return; |
121 } |
116 } |
122 } |
117 } |
148 WAVEHDR* blocks = blockArray; |
143 WAVEHDR* blocks = blockArray; |
149 |
144 |
150 int count = buffer_size/period_size; |
145 int count = buffer_size/period_size; |
151 |
146 |
152 for(int i = 0; i < count; i++) { |
147 for(int i = 0; i < count; i++) { |
153 waveOutUnprepareHeader(hWaveOut,&blocks[i], sizeof(WAVEHDR)); |
148 waveOutUnprepareHeader(hWaveOut,blocks, sizeof(WAVEHDR)); |
154 blocks+=sizeof(WAVEHDR); |
149 blocks+=sizeof(WAVEHDR); |
155 } |
150 } |
156 HeapFree(GetProcessHeap(), 0, blockArray); |
151 HeapFree(GetProcessHeap(), 0, blockArray); |
157 } |
152 } |
158 |
153 |
223 } else { |
218 } else { |
224 period_size = buffer_size/5; |
219 period_size = buffer_size/5; |
225 } |
220 } |
226 waveBlocks = allocateBlocks(period_size, buffer_size/period_size); |
221 waveBlocks = allocateBlocks(period_size, buffer_size/period_size); |
227 |
222 |
228 EnterCriticalSection(&waveOutCriticalSection); |
223 mutex.lock(); |
229 waveFreeBlockCount = buffer_size/period_size; |
224 waveFreeBlockCount = buffer_size/period_size; |
230 LeaveCriticalSection(&waveOutCriticalSection); |
225 mutex.unlock(); |
231 |
226 |
232 waveCurrentBlock = 0; |
227 waveCurrentBlock = 0; |
233 |
228 |
234 if(audioBuffer == 0) |
229 if(audioBuffer == 0) |
235 audioBuffer = new char[buffer_size]; |
230 audioBuffer = new char[buffer_size]; |
253 iNumDevs = waveOutGetNumDevs(); |
248 iNumDevs = waveOutGetNumDevs(); |
254 for(ii=0;ii<iNumDevs;ii++) { |
249 for(ii=0;ii<iNumDevs;ii++) { |
255 if(waveOutGetDevCaps(ii, &woc, sizeof(WAVEOUTCAPS)) |
250 if(waveOutGetDevCaps(ii, &woc, sizeof(WAVEOUTCAPS)) |
256 == MMSYSERR_NOERROR) { |
251 == MMSYSERR_NOERROR) { |
257 QString tmp; |
252 QString tmp; |
258 tmp = QString::fromUtf16((const unsigned short*)woc.szPname); |
253 tmp = QString((const QChar *)woc.szPname); |
259 if(tmp.compare(QLatin1String(m_device)) == 0) { |
254 if(tmp.compare(QLatin1String(m_device)) == 0) { |
260 devId = ii; |
255 devId = ii; |
261 break; |
256 break; |
262 } |
257 } |
263 } |
258 } |
366 |
358 |
367 WAVEHDR* current; |
359 WAVEHDR* current; |
368 int remain; |
360 int remain; |
369 current = &waveBlocks[waveCurrentBlock]; |
361 current = &waveBlocks[waveCurrentBlock]; |
370 while(l > 0) { |
362 while(l > 0) { |
371 EnterCriticalSection(&waveOutCriticalSection); |
363 mutex.lock(); |
372 if(waveFreeBlockCount==0) { |
364 if(waveFreeBlockCount==0) { |
373 LeaveCriticalSection(&waveOutCriticalSection); |
365 mutex.unlock(); |
374 break; |
366 break; |
375 } |
367 } |
376 LeaveCriticalSection(&waveOutCriticalSection); |
368 mutex.unlock(); |
377 |
369 |
378 if(current->dwFlags & WHDR_PREPARED) |
370 if(current->dwFlags & WHDR_PREPARED) |
379 waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR)); |
371 waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR)); |
380 |
372 |
381 if(l < period_size) |
373 if(l < period_size) |
388 p += remain; |
380 p += remain; |
389 current->dwBufferLength = remain; |
381 current->dwBufferLength = remain; |
390 waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR)); |
382 waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR)); |
391 waveOutWrite(hWaveOut, current, sizeof(WAVEHDR)); |
383 waveOutWrite(hWaveOut, current, sizeof(WAVEHDR)); |
392 |
384 |
393 EnterCriticalSection(&waveOutCriticalSection); |
385 mutex.lock(); |
394 waveFreeBlockCount--; |
386 waveFreeBlockCount--; |
395 LeaveCriticalSection(&waveOutCriticalSection); |
|
396 #ifdef DEBUG_AUDIO |
387 #ifdef DEBUG_AUDIO |
397 EnterCriticalSection(&waveOutCriticalSection); |
|
398 qDebug("write out l=%d, waveFreeBlockCount=%d", |
388 qDebug("write out l=%d, waveFreeBlockCount=%d", |
399 current->dwBufferLength,waveFreeBlockCount); |
389 current->dwBufferLength,waveFreeBlockCount); |
400 LeaveCriticalSection(&waveOutCriticalSection); |
|
401 #endif |
390 #endif |
|
391 mutex.unlock(); |
402 totalTimeValue += current->dwBufferLength; |
392 totalTimeValue += current->dwBufferLength; |
403 waveCurrentBlock++; |
393 waveCurrentBlock++; |
404 waveCurrentBlock %= buffer_size/period_size; |
394 waveCurrentBlock %= buffer_size/period_size; |
405 current = &waveBlocks[waveCurrentBlock]; |
395 current = &waveBlocks[waveCurrentBlock]; |
406 current->dwUser = 0; |
396 current->dwUser = 0; |
465 bool startup = false; |
455 bool startup = false; |
466 if(totalTimeValue == 0) |
456 if(totalTimeValue == 0) |
467 startup = true; |
457 startup = true; |
468 |
458 |
469 bool full=false; |
459 bool full=false; |
470 EnterCriticalSection(&waveOutCriticalSection); |
460 |
|
461 mutex.lock(); |
471 if(waveFreeBlockCount==0) full = true; |
462 if(waveFreeBlockCount==0) full = true; |
472 LeaveCriticalSection(&waveOutCriticalSection); |
463 mutex.unlock(); |
|
464 |
473 if (full){ |
465 if (full){ |
474 #ifdef DEBUG_AUDIO |
466 #ifdef DEBUG_AUDIO |
475 qDebug() << "Skipping data as unable to write"; |
467 qDebug() << "Skipping data as unable to write"; |
476 #endif |
468 #endif |
477 if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime ) { |
469 if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime ) { |
478 emit notify(); |
470 emit notify(); |
479 elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; |
471 elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; |
480 timeStamp.restart(); |
472 timeStamp.restart(); |
481 } |
473 } |
482 return true; |
474 return true; |
502 waveOutRestart(hWaveOut); |
494 waveOutRestart(hWaveOut); |
503 } else if(l == 0) { |
495 } else if(l == 0) { |
504 bytesAvailable = bytesFree(); |
496 bytesAvailable = bytesFree(); |
505 |
497 |
506 int check = 0; |
498 int check = 0; |
507 EnterCriticalSection(&waveOutCriticalSection); |
499 |
|
500 mutex.lock(); |
508 check = waveFreeBlockCount; |
501 check = waveFreeBlockCount; |
509 LeaveCriticalSection(&waveOutCriticalSection); |
502 mutex.unlock(); |
|
503 |
510 if(check == buffer_size/period_size) { |
504 if(check == buffer_size/period_size) { |
511 errorState = QAudio::UnderrunError; |
|
512 if (deviceState != QAudio::IdleState) { |
505 if (deviceState != QAudio::IdleState) { |
|
506 errorState = QAudio::UnderrunError; |
513 deviceState = QAudio::IdleState; |
507 deviceState = QAudio::IdleState; |
514 emit stateChanged(deviceState); |
508 emit stateChanged(deviceState); |
515 } |
509 } |
516 } |
510 } |
517 |
511 |
519 bytesAvailable = bytesFree(); |
513 bytesAvailable = bytesFree(); |
520 errorState = QAudio::IOError; |
514 errorState = QAudio::IOError; |
521 } |
515 } |
522 } else { |
516 } else { |
523 int buffered; |
517 int buffered; |
524 EnterCriticalSection(&waveOutCriticalSection); |
518 |
|
519 mutex.lock(); |
525 buffered = waveFreeBlockCount; |
520 buffered = waveFreeBlockCount; |
526 LeaveCriticalSection(&waveOutCriticalSection); |
521 mutex.unlock(); |
527 errorState = QAudio::UnderrunError; |
522 |
528 if (buffered >= buffer_size/period_size && deviceState == QAudio::ActiveState) { |
523 if (buffered >= buffer_size/period_size && deviceState == QAudio::ActiveState) { |
529 deviceState = QAudio::IdleState; |
524 if (deviceState != QAudio::IdleState) { |
530 emit stateChanged(deviceState); |
525 errorState = QAudio::UnderrunError; |
|
526 deviceState = QAudio::IdleState; |
|
527 emit stateChanged(deviceState); |
|
528 } |
531 } |
529 } |
532 } |
530 } |
533 if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) |
531 if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) |
534 return true; |
532 return true; |
535 |
533 |
536 if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { |
534 if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { |
537 emit notify(); |
535 emit notify(); |
538 elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; |
536 elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; |
539 timeStamp.restart(); |
537 timeStamp.restart(); |
540 } |
538 } |
541 |
539 |