src/multimedia/audio/qaudioinput_alsa_p.cpp
branchRCL_3
changeset 8 3f74d0d4af4c
parent 4 3b1da2848fc7
child 14 c0432d11811c
equal deleted inserted replaced
6:dee5afe5301f 8:3f74d0d4af4c
   119     if(err == -EPIPE) {
   119     if(err == -EPIPE) {
   120         errorState = QAudio::UnderrunError;
   120         errorState = QAudio::UnderrunError;
   121         err = snd_pcm_prepare(handle);
   121         err = snd_pcm_prepare(handle);
   122         if(err < 0)
   122         if(err < 0)
   123             reset = true;
   123             reset = true;
       
   124         else {
       
   125             bytesAvailable = bytesReady();
       
   126             if (bytesAvailable <= 0)
       
   127                 reset = true;
       
   128         }
   124 
   129 
   125     } else if((err == -ESTRPIPE)||(err == -EIO)) {
   130     } else if((err == -ESTRPIPE)||(err == -EIO)) {
   126         errorState = QAudio::IOError;
   131         errorState = QAudio::IOError;
   127         while((err = snd_pcm_resume(handle)) == -EAGAIN){
   132         while((err = snd_pcm_resume(handle)) == -EAGAIN){
   128             usleep(100);
   133             usleep(100);
   215 
   220 
   216     if(device) {
   221     if(device) {
   217         //set to pull mode
   222         //set to pull mode
   218         pullMode = true;
   223         pullMode = true;
   219         audioSource = device;
   224         audioSource = device;
       
   225         deviceState = QAudio::ActiveState;
   220     } else {
   226     } else {
   221         //set to push mode
   227         //set to push mode
   222         pullMode = false;
   228         pullMode = false;
       
   229         deviceState = QAudio::IdleState;
   223         audioSource = new InputPrivate(this);
   230         audioSource = new InputPrivate(this);
   224         audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
   231         audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
   225     }
   232     }
   226 
   233 
   227     if( !open() )
   234     if( !open() )
   411     // Step 6: Start audio processing
   418     // Step 6: Start audio processing
   412     chunks = buffer_size/period_size;
   419     chunks = buffer_size/period_size;
   413     timer->start(period_time*chunks/2000);
   420     timer->start(period_time*chunks/2000);
   414 
   421 
   415     errorState  = QAudio::NoError;
   422     errorState  = QAudio::NoError;
   416     deviceState = QAudio::ActiveState;
       
   417 
   423 
   418     totalTimeValue = 0;
   424     totalTimeValue = 0;
   419 
   425 
   420     return true;
   426     return true;
   421 }
   427 }
   437 int QAudioInputPrivate::bytesReady() const
   443 int QAudioInputPrivate::bytesReady() const
   438 {
   444 {
   439     if(resuming)
   445     if(resuming)
   440         return period_size;
   446         return period_size;
   441 
   447 
   442     if(deviceState != QAudio::ActiveState)
   448     if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
   443         return 0;
   449         return 0;
   444     int frames = snd_pcm_avail_update(handle);
   450     int frames = snd_pcm_avail_update(handle);
       
   451     if (frames < 0) return frames;
   445     if((int)frames > (int)buffer_frames)
   452     if((int)frames > (int)buffer_frames)
   446         frames = buffer_frames;
   453         frames = buffer_frames;
   447 
   454 
   448     return snd_pcm_frames_to_bytes(handle, frames);
   455     return snd_pcm_frames_to_bytes(handle, frames);
   449 }
   456 }
   450 
   457 
   451 qint64 QAudioInputPrivate::read(char* data, qint64 len)
   458 qint64 QAudioInputPrivate::read(char* data, qint64 len)
   452 {
   459 {
   453     Q_UNUSED(data)
       
   454     Q_UNUSED(len)
   460     Q_UNUSED(len)
       
   461 
   455     // Read in some audio data and write it to QIODevice, pull mode
   462     // Read in some audio data and write it to QIODevice, pull mode
   456     if ( !handle )
   463     if ( !handle )
   457         return 0;
   464         return 0;
   458 
   465 
   459     bytesAvailable = bytesReady();
   466     bytesAvailable = bytesReady();
       
   467 
       
   468     if (bytesAvailable < 0) {
       
   469         // bytesAvailable as negative is error code, try to recover from it.
       
   470         xrun_recovery(bytesAvailable);
       
   471         bytesAvailable = bytesReady();
       
   472         if (bytesAvailable < 0) {
       
   473             // recovery failed must stop and set error.
       
   474             close();
       
   475             errorState = QAudio::IOError;
       
   476             deviceState = QAudio::StoppedState;
       
   477             emit stateChanged(deviceState);
       
   478             return 0;
       
   479         }
       
   480     }
   460 
   481 
   461     int count=0, err = 0;
   482     int count=0, err = 0;
   462     while(count < 5) {
   483     while(count < 5) {
   463         int chunks = bytesAvailable/period_size;
   484         int chunks = bytesAvailable/period_size;
   464         int frames = chunks*period_frames;
   485         int frames = chunks*period_frames;
   466             frames = buffer_frames;
   487             frames = buffer_frames;
   467         int readFrames = snd_pcm_readi(handle, audioBuffer, frames);
   488         int readFrames = snd_pcm_readi(handle, audioBuffer, frames);
   468         if (readFrames >= 0) {
   489         if (readFrames >= 0) {
   469             err = snd_pcm_frames_to_bytes(handle, readFrames);
   490             err = snd_pcm_frames_to_bytes(handle, readFrames);
   470 #ifdef DEBUG_AUDIO
   491 #ifdef DEBUG_AUDIO
   471             qDebug()<<QString::fromLatin1("PULL: read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData();
   492             qDebug()<<QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData();
   472 #endif
   493 #endif
   473             break;
   494             break;
   474         } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
   495         } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
   475             errorState = QAudio::IOError;
   496             errorState = QAudio::IOError;
   476             err = 0;
   497             err = 0;
   487         count++;
   508         count++;
   488     }
   509     }
   489     if(err > 0) {
   510     if(err > 0) {
   490         // got some send it onward
   511         // got some send it onward
   491 #ifdef DEBUG_AUDIO
   512 #ifdef DEBUG_AUDIO
   492         qDebug()<<"PULL: frames to write to QIODevice = "<<
   513         qDebug()<<"frames to write to QIODevice = "<<
   493             snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes";
   514             snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes";
   494 #endif
   515 #endif
   495         if(deviceState != QAudio::ActiveState)
   516         if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
   496             return 0;
   517             return 0;
   497 
   518         if (pullMode) {
   498         qint64 l = audioSource->write(audioBuffer,err);
   519             qint64 l = audioSource->write(audioBuffer,err);
   499         if(l < 0) {
   520             if(l < 0) {
   500             close();
   521                 close();
   501             errorState = QAudio::IOError;
   522                 errorState = QAudio::IOError;
   502             deviceState = QAudio::StoppedState;
   523                 deviceState = QAudio::StoppedState;
   503             emit stateChanged(deviceState);
   524                 emit stateChanged(deviceState);
   504         } else if(l == 0) {
   525             } else if(l == 0) {
   505             errorState = QAudio::NoError;
   526                 if (deviceState != QAudio::IdleState) {
   506             deviceState = QAudio::IdleState;
   527                     errorState = QAudio::NoError;
       
   528                     deviceState = QAudio::IdleState;
       
   529                     emit stateChanged(deviceState);
       
   530                 }
       
   531             } else {
       
   532                 totalTimeValue += err;
       
   533                 resuming = false;
       
   534                 if (deviceState != QAudio::ActiveState) {
       
   535                     errorState = QAudio::NoError;
       
   536                     deviceState = QAudio::ActiveState;
       
   537                     emit stateChanged(deviceState);
       
   538                 }
       
   539             }
       
   540             return l;
       
   541 
   507         } else {
   542         } else {
   508             totalTimeValue += snd_pcm_bytes_to_frames(handle, err)*1000000/settings.frequency();
   543             memcpy(data,audioBuffer,err);
       
   544             totalTimeValue += err;
   509             resuming = false;
   545             resuming = false;
   510             errorState = QAudio::NoError;
   546             if (deviceState != QAudio::ActiveState) {
   511             deviceState = QAudio::ActiveState;
   547                 errorState = QAudio::NoError;
   512         }
   548                 deviceState = QAudio::ActiveState;
   513         return l;
   549                 emit stateChanged(deviceState);
       
   550             }
       
   551             return err;
       
   552         }
   514     }
   553     }
   515     return 0;
   554     return 0;
   516 }
   555 }
   517 
   556 
   518 void QAudioInputPrivate::resume()
   557 void QAudioInputPrivate::resume()
   567     return intervalTime;
   606     return intervalTime;
   568 }
   607 }
   569 
   608 
   570 qint64 QAudioInputPrivate::processedUSecs() const
   609 qint64 QAudioInputPrivate::processedUSecs() const
   571 {
   610 {
   572     return totalTimeValue;
   611     qint64 result = qint64(1000000) * totalTimeValue /
       
   612         (settings.channels()*(settings.sampleSize()/8)) /
       
   613         settings.frequency();
       
   614 
       
   615     return result;
   573 }
   616 }
   574 
   617 
   575 void QAudioInputPrivate::suspend()
   618 void QAudioInputPrivate::suspend()
   576 {
   619 {
   577     if(deviceState == QAudio::ActiveState||resuming) {
   620     if(deviceState == QAudio::ActiveState||resuming) {
   615     return true;
   658     return true;
   616 }
   659 }
   617 
   660 
   618 qint64 QAudioInputPrivate::elapsedUSecs() const
   661 qint64 QAudioInputPrivate::elapsedUSecs() const
   619 {
   662 {
   620     if(!handle)
       
   621         return 0;
       
   622 
       
   623     if (deviceState == QAudio::StoppedState)
   663     if (deviceState == QAudio::StoppedState)
   624         return 0;
   664         return 0;
   625 
   665 
   626 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   627     snd_pcm_status_t* status;
       
   628     snd_pcm_status_alloca(&status);
       
   629 
       
   630     snd_timestamp_t t1,t2;
       
   631     if( snd_pcm_status(handle, status) >= 0) {
       
   632         snd_pcm_status_get_tstamp(status,&t1);
       
   633         snd_pcm_status_get_trigger_tstamp(status,&t2);
       
   634         t1.tv_sec-=t2.tv_sec;
       
   635 
       
   636         signed long l = (signed long)t1.tv_usec - (signed long)t2.tv_usec;
       
   637         if(l < 0) {
       
   638             t1.tv_sec--;
       
   639             l = -l;
       
   640             l %= 1000000;
       
   641         }
       
   642         return ((t1.tv_sec * 1000000)+l);
       
   643     } else
       
   644         return 0;
       
   645 #else
       
   646     return clockStamp.elapsed()*1000;
   666     return clockStamp.elapsed()*1000;
   647 #endif
       
   648 }
   667 }
   649 
   668 
   650 void QAudioInputPrivate::reset()
   669 void QAudioInputPrivate::reset()
   651 {
   670 {
   652     if(handle)
   671     if(handle)
   668 {
   687 {
   669 }
   688 }
   670 
   689 
   671 qint64 InputPrivate::readData( char* data, qint64 len)
   690 qint64 InputPrivate::readData( char* data, qint64 len)
   672 {
   691 {
   673     // push mode, user read() called
   692     return audioDevice->read(data,len);
   674     if((audioDevice->state() != QAudio::ActiveState) && !audioDevice->resuming)
       
   675         return 0;
       
   676 
       
   677     int readFrames;
       
   678     int count=0, err = 0;
       
   679 
       
   680     while(count < 5) {
       
   681         int frames = snd_pcm_bytes_to_frames(audioDevice->handle, len);
       
   682         readFrames = snd_pcm_readi(audioDevice->handle, data, frames);
       
   683         if (readFrames >= 0) {
       
   684             err = snd_pcm_frames_to_bytes(audioDevice->handle, readFrames);
       
   685 #ifdef DEBUG_AUDIO
       
   686             qDebug()<<QString::fromLatin1("PUSH: read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData();
       
   687 #endif
       
   688             break;
       
   689         } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
       
   690             audioDevice->errorState = QAudio::IOError;
       
   691             err = 0;
       
   692             break;
       
   693         } else {
       
   694             if(readFrames == -EPIPE) {
       
   695                 audioDevice->errorState = QAudio::UnderrunError;
       
   696                 err = snd_pcm_prepare(audioDevice->handle);
       
   697             } else if(readFrames == -ESTRPIPE) {
       
   698                 err = snd_pcm_prepare(audioDevice->handle);
       
   699             }
       
   700             if(err != 0) break;
       
   701         }
       
   702         count++;
       
   703     }
       
   704     if(err > 0 && readFrames > 0) {
       
   705         audioDevice->totalTimeValue += readFrames*1000/audioDevice->settings.frequency()*1000;
       
   706         audioDevice->deviceState = QAudio::ActiveState;
       
   707         return err;
       
   708     }
       
   709     return 0;
       
   710 }
   693 }
   711 
   694 
   712 qint64 InputPrivate::writeData(const char* data, qint64 len)
   695 qint64 InputPrivate::writeData(const char* data, qint64 len)
   713 {
   696 {
   714     Q_UNUSED(data)
   697     Q_UNUSED(data)