src/multimedia/audio/qaudiooutput_win32_p.cpp
branchGCC_SURGE
changeset 31 5daf16870df6
parent 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
27:93b982ccede2 31:5daf16870df6
    53 #include "qaudiooutput_win32_p.h"
    53 #include "qaudiooutput_win32_p.h"
    54 
    54 
    55 //#define DEBUG_AUDIO 1
    55 //#define DEBUG_AUDIO 1
    56 
    56 
    57 QT_BEGIN_NAMESPACE
    57 QT_BEGIN_NAMESPACE
    58 
       
    59 static const int minimumIntervalTime = 50;
       
    60 
    58 
    61 QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
    59 QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
    62     settings(audioFormat)
    60     settings(audioFormat)
    63 {
    61 {
    64     bytesAvailable = 0;
    62     bytesAvailable = 0;
    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 	}
   331     return buffer_size;
   326     return buffer_size;
   332 }
   327 }
   333 
   328 
   334 void QAudioOutputPrivate::setNotifyInterval(int ms)
   329 void QAudioOutputPrivate::setNotifyInterval(int ms)
   335 {
   330 {
   336     if(ms >= minimumIntervalTime)
   331     intervalTime = qMax(0, ms);
   337         intervalTime = ms;
       
   338     else
       
   339         intervalTime = minimumIntervalTime;
       
   340 }
   332 }
   341 
   333 
   342 int QAudioOutputPrivate::notifyInterval() const
   334 int QAudioOutputPrivate::notifyInterval() const
   343 {
   335 {
   344     return intervalTime;
   336     return intervalTime;
   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;
   451     }
   441     }
   452 }
   442 }
   453 
   443 
   454 bool QAudioOutputPrivate::deviceReady()
   444 bool QAudioOutputPrivate::deviceReady()
   455 {
   445 {
   456     if(deviceState == QAudio::StoppedState)
   446     if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState)
   457         return false;
   447         return false;
   458 
   448 
   459     if(pullMode) {
   449     if(pullMode) {
   460         int chunks = bytesAvailable/period_size;
   450         int chunks = bytesAvailable/period_size;
   461 #ifdef DEBUG_AUDIO
   451 #ifdef DEBUG_AUDIO
   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