src/multimedia/audio/qaudioinput_win32_p.cpp
changeset 23 89e065397ea6
parent 22 79de32ba3296
child 30 5dc02b23752f
equal deleted inserted replaced
22:79de32ba3296 23:89e065397ea6
    54 #include "qaudioinput_win32_p.h"
    54 #include "qaudioinput_win32_p.h"
    55 
    55 
    56 QT_BEGIN_NAMESPACE
    56 QT_BEGIN_NAMESPACE
    57 
    57 
    58 //#define DEBUG_AUDIO 1
    58 //#define DEBUG_AUDIO 1
    59 
       
    60 static const int minimumIntervalTime = 50;
       
    61 
    59 
    62 QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
    60 QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
    63     settings(audioFormat)
    61     settings(audioFormat)
    64 {
    62 {
    65     bytesAvailable = 0;
    63     bytesAvailable = 0;
    72     deviceState = QAudio::StoppedState;
    70     deviceState = QAudio::StoppedState;
    73     audioSource = 0;
    71     audioSource = 0;
    74     pullMode = true;
    72     pullMode = true;
    75     resuming = false;
    73     resuming = false;
    76     finished = false;
    74     finished = false;
    77 
       
    78     connect(this,SIGNAL(processMore()),SLOT(deviceReady()));
       
    79 
       
    80     InitializeCriticalSection(&waveInCriticalSection);
       
    81 }
    75 }
    82 
    76 
    83 QAudioInputPrivate::~QAudioInputPrivate()
    77 QAudioInputPrivate::~QAudioInputPrivate()
    84 {
    78 {
    85     stop();
    79     stop();
    86     DeleteCriticalSection(&waveInCriticalSection);
       
    87 }
    80 }
    88 
    81 
    89 void CALLBACK QAudioInputPrivate::waveInProc( HWAVEIN hWaveIn, UINT uMsg,
    82 void CALLBACK QAudioInputPrivate::waveInProc( HWAVEIN hWaveIn, UINT uMsg,
    90         DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
    83         DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
    91 {
    84 {
    96     QAudioInputPrivate* qAudio;
    89     QAudioInputPrivate* qAudio;
    97     qAudio = (QAudioInputPrivate*)(dwInstance);
    90     qAudio = (QAudioInputPrivate*)(dwInstance);
    98     if(!qAudio)
    91     if(!qAudio)
    99         return;
    92         return;
   100 
    93 
       
    94     QMutexLocker(&qAudio->mutex);
       
    95 
   101     switch(uMsg) {
    96     switch(uMsg) {
   102         case WIM_OPEN:
    97         case WIM_OPEN:
   103             break;
    98             break;
   104         case WIM_DATA:
    99         case WIM_DATA:
   105             EnterCriticalSection(&qAudio->waveInCriticalSection);
       
   106             if(qAudio->waveFreeBlockCount > 0)
   100             if(qAudio->waveFreeBlockCount > 0)
   107                 qAudio->waveFreeBlockCount--;
   101                 qAudio->waveFreeBlockCount--;
   108             qAudio->feedback();
   102             qAudio->feedback();
   109             LeaveCriticalSection(&qAudio->waveInCriticalSection);
       
   110             break;
   103             break;
   111         case WIM_CLOSE:
   104         case WIM_CLOSE:
   112             EnterCriticalSection(&qAudio->waveInCriticalSection);
       
   113             qAudio->finished = true;
   105             qAudio->finished = true;
   114             LeaveCriticalSection(&qAudio->waveInCriticalSection);
       
   115             break;
   106             break;
   116         default:
   107         default:
   117             return;
   108             return;
   118     }
   109     }
   119 }
   110 }
   154     WAVEHDR* blocks = blockArray;
   145     WAVEHDR* blocks = blockArray;
   155 
   146 
   156     int count = buffer_size/period_size;
   147     int count = buffer_size/period_size;
   157 
   148 
   158     for(int i = 0; i < count; i++) {
   149     for(int i = 0; i < count; i++) {
   159         waveInUnprepareHeader(hWaveIn,&blocks[i], sizeof(WAVEHDR));
   150         waveInUnprepareHeader(hWaveIn,blocks, sizeof(WAVEHDR));
   160         blocks+=sizeof(WAVEHDR);
   151         blocks+=sizeof(WAVEHDR);
   161     }
   152     }
   162     HeapFree(GetProcessHeap(), 0, blockArray);
   153     HeapFree(GetProcessHeap(), 0, blockArray);
   163 }
   154 }
   164 
   155 
   276         emit stateChanged(deviceState);
   267         emit stateChanged(deviceState);
   277         qWarning("QAudioInput: failed to allocate blocks. open failed");
   268         qWarning("QAudioInput: failed to allocate blocks. open failed");
   278         return false;
   269         return false;
   279     }
   270     }
   280 
   271 
   281     EnterCriticalSection(&waveInCriticalSection);
   272     mutex.lock();
   282     waveFreeBlockCount = buffer_size/period_size;
   273     waveFreeBlockCount = buffer_size/period_size;
   283     LeaveCriticalSection(&waveInCriticalSection);
   274     mutex.unlock();
   284 
   275 
   285     waveCurrentBlock = 0;
   276     waveCurrentBlock = 0;
   286 
   277 
   287     for(int i=0; i<buffer_size/period_size; i++) {
   278     for(int i=0; i<buffer_size/period_size; i++) {
   288         result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR));
   279         result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR));
   322     while(!finished && count < 500) {
   313     while(!finished && count < 500) {
   323         count++;
   314         count++;
   324         Sleep(10);
   315         Sleep(10);
   325     }
   316     }
   326 
   317 
   327     EnterCriticalSection(&waveInCriticalSection);
   318     mutex.lock();
   328     for(int i=0; i<waveFreeBlockCount; i++) {
   319     for(int i=0; i<waveFreeBlockCount; i++)
   329         if(waveBlocks[i].dwFlags & WHDR_PREPARED)
   320         waveInUnprepareHeader(hWaveIn,&waveBlocks[i],sizeof(WAVEHDR));
   330             waveInUnprepareHeader(hWaveIn,&waveBlocks[i],sizeof(WAVEHDR));
       
   331     }
       
   332     LeaveCriticalSection(&waveInCriticalSection);
       
   333     freeBlocks(waveBlocks);
   321     freeBlocks(waveBlocks);
       
   322     mutex.unlock();
   334 }
   323 }
   335 
   324 
   336 int QAudioInputPrivate::bytesReady() const
   325 int QAudioInputPrivate::bytesReady() const
   337 {
   326 {
   338     if(period_size == 0 || buffer_size == 0)
   327     if(period_size == 0 || buffer_size == 0)
   399             break;
   388             break;
   400         }
   389         }
   401 
   390 
   402         waveInUnprepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR));
   391         waveInUnprepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR));
   403 
   392 
   404         EnterCriticalSection(&waveInCriticalSection);
   393         mutex.lock();
   405         waveFreeBlockCount++;
   394         waveFreeBlockCount++;
   406         LeaveCriticalSection(&waveInCriticalSection);
   395         mutex.unlock();
       
   396 
   407         waveBlocks[header].dwBytesRecorded=0;
   397         waveBlocks[header].dwBytesRecorded=0;
   408         waveBlocks[header].dwFlags = 0L;
   398         waveBlocks[header].dwFlags = 0L;
   409         result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR));
   399         result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR));
   410         if(result != MMSYSERR_NOERROR) {
   400         if(result != MMSYSERR_NOERROR) {
   411             result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR));
   401             result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR));
   412             qWarning("QAudioInput: failed to prepare block %d,err=%d",header,result);
   402             qWarning("QAudioInput: failed to prepare block %d,err=%d",header,result);
   413             errorState = QAudio::IOError;
   403             errorState = QAudio::IOError;
   414             EnterCriticalSection(&waveInCriticalSection);
   404 
       
   405             mutex.lock();
   415             waveFreeBlockCount--;
   406             waveFreeBlockCount--;
   416             LeaveCriticalSection(&waveInCriticalSection);
   407             mutex.unlock();
       
   408 
   417             return 0;
   409             return 0;
   418         }
   410         }
   419         result = waveInAddBuffer(hWaveIn, &waveBlocks[header], sizeof(WAVEHDR));
   411         result = waveInAddBuffer(hWaveIn, &waveBlocks[header], sizeof(WAVEHDR));
   420         if(result != MMSYSERR_NOERROR) {
   412         if(result != MMSYSERR_NOERROR) {
   421             qWarning("QAudioInput: failed to setup block %d,err=%d",header,result);
   413             qWarning("QAudioInput: failed to setup block %d,err=%d",header,result);
   422             errorState = QAudio::IOError;
   414             errorState = QAudio::IOError;
   423             EnterCriticalSection(&waveInCriticalSection);
   415 
       
   416             mutex.lock();
   424             waveFreeBlockCount--;
   417             waveFreeBlockCount--;
   425             LeaveCriticalSection(&waveInCriticalSection);
   418             mutex.unlock();
       
   419 
   426             return 0;
   420             return 0;
   427         }
   421         }
   428         header++;
   422         header++;
   429         if(header >= buffer_size/period_size)
   423         if(header >= buffer_size/period_size)
   430             header = 0;
   424             header = 0;
   431         p+=l;
   425         p+=l;
   432 
   426 
   433         EnterCriticalSection(&waveInCriticalSection);
   427         mutex.lock();
   434         if(!pullMode) {
   428         if(!pullMode) {
   435 	    if(l+period_size > len && waveFreeBlockCount == buffer_size/period_size)
   429 	    if(l+period_size > len && waveFreeBlockCount == buffer_size/period_size)
   436 	        done = true;
   430 	        done = true;
   437 	} else {
   431 	} else {
   438 	    if(waveFreeBlockCount == buffer_size/period_size)
   432 	    if(waveFreeBlockCount == buffer_size/period_size)
   439 	        done = true;
   433 	        done = true;
   440 	}
   434 	}
   441         LeaveCriticalSection(&waveInCriticalSection);
   435         mutex.unlock();
   442 
   436 
   443 	written+=l;
   437 	written+=l;
   444     }
   438     }
   445 #ifdef DEBUG_AUDIO
   439 #ifdef DEBUG_AUDIO
   446     qDebug()<<"read in len="<<written;
   440     qDebug()<<"read in len="<<written;
   460                 deviceState = QAudio::StoppedState;
   454                 deviceState = QAudio::StoppedState;
   461                 emit stateChanged(deviceState);
   455                 emit stateChanged(deviceState);
   462                 return;
   456                 return;
   463             }
   457             }
   464         }
   458         }
   465         EnterCriticalSection(&waveInCriticalSection);
   459 
       
   460         mutex.lock();
   466         waveFreeBlockCount = buffer_size/period_size;
   461         waveFreeBlockCount = buffer_size/period_size;
   467         LeaveCriticalSection(&waveInCriticalSection);
   462         mutex.unlock();
   468 
   463 
   469         waveCurrentBlock = 0;
   464         waveCurrentBlock = 0;
   470         header = 0;
   465         header = 0;
   471 	resuming = true;
   466 	resuming = true;
   472         waveInStart(hWaveIn);
   467         waveInStart(hWaveIn);
   490     return period_size;
   485     return period_size;
   491 }
   486 }
   492 
   487 
   493 void QAudioInputPrivate::setNotifyInterval(int ms)
   488 void QAudioInputPrivate::setNotifyInterval(int ms)
   494 {
   489 {
   495     if(ms >= minimumIntervalTime)
   490     intervalTime = qMax(0, ms);
   496         intervalTime = ms;
       
   497     else
       
   498         intervalTime = minimumIntervalTime;
       
   499 }
   491 }
   500 
   492 
   501 int QAudioInputPrivate::notifyInterval() const
   493 int QAudioInputPrivate::notifyInterval() const
   502 {
   494 {
   503     return intervalTime;
   495     return intervalTime;
   527 {
   519 {
   528 #ifdef DEBUG_AUDIO
   520 #ifdef DEBUG_AUDIO
   529     QTime now(QTime::currentTime());
   521     QTime now(QTime::currentTime());
   530     qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback() INPUT "<<this;
   522     qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback() INPUT "<<this;
   531 #endif
   523 #endif
       
   524     if(!(deviceState==QAudio::StoppedState||deviceState==QAudio::SuspendedState))
       
   525         QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection);
       
   526 }
       
   527 
       
   528 bool QAudioInputPrivate::deviceReady()
       
   529 {
   532     bytesAvailable = bytesReady();
   530     bytesAvailable = bytesReady();
   533 
       
   534     if(!(deviceState==QAudio::StoppedState||deviceState==QAudio::SuspendedState))
       
   535         emit processMore();
       
   536 }
       
   537 
       
   538 bool QAudioInputPrivate::deviceReady()
       
   539 {
       
   540 #ifdef DEBUG_AUDIO
   531 #ifdef DEBUG_AUDIO
   541     QTime now(QTime::currentTime());
   532     QTime now(QTime::currentTime());
   542     qDebug()<<now.second()<<"s "<<now.msec()<<"ms :deviceReady() INPUT";
   533     qDebug()<<now.second()<<"s "<<now.msec()<<"ms :deviceReady() INPUT";
   543 #endif
   534 #endif
   544     if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
   535     if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
   551         // emits readyRead() so user will call read() on QIODevice to get some audio data
   542         // emits readyRead() so user will call read() on QIODevice to get some audio data
   552 	InputPrivate* a = qobject_cast<InputPrivate*>(audioSource);
   543 	InputPrivate* a = qobject_cast<InputPrivate*>(audioSource);
   553 	a->trigger();
   544 	a->trigger();
   554     }
   545     }
   555 
   546 
   556     if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) {
   547     if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) {
   557         emit notify();
   548         emit notify();
   558         elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime;
   549         elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime;
   559         timeStamp.restart();
   550         timeStamp.restart();
   560     }
   551     }
   561     return true;
   552     return true;