src/multimedia/audio/qaudiooutput_alsa_p.cpp
branchRCL_3
changeset 8 3f74d0d4af4c
parent 4 3b1da2848fc7
child 14 c0432d11811c
equal deleted inserted replaced
6:dee5afe5301f 8:3f74d0d4af4c
   257 
   257 
   258 void QAudioOutputPrivate::stop()
   258 void QAudioOutputPrivate::stop()
   259 {
   259 {
   260     if(deviceState == QAudio::StoppedState)
   260     if(deviceState == QAudio::StoppedState)
   261         return;
   261         return;
       
   262     errorState = QAudio::NoError;
   262     deviceState = QAudio::StoppedState;
   263     deviceState = QAudio::StoppedState;
   263     close();
   264     close();
   264     emit stateChanged(deviceState);
   265     emit stateChanged(deviceState);
   265 }
   266 }
   266 
   267 
   366             fatal = true;
   367             fatal = true;
   367             errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err);
   368             errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err);
   368         }
   369         }
   369     }
   370     }
   370     if ( !fatal ) {
   371     if ( !fatal ) {
       
   372         unsigned int maxBufferTime = 0;
       
   373         unsigned int minBufferTime = 0;
       
   374         unsigned int maxPeriodTime = 0;
       
   375         unsigned int minPeriodTime = 0;
       
   376 
       
   377         err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &maxBufferTime, &dir);
       
   378         if ( err >= 0)
       
   379             err = snd_pcm_hw_params_get_buffer_time_min(hwparams, &minBufferTime, &dir);
       
   380         if ( err >= 0)
       
   381             err = snd_pcm_hw_params_get_period_time_max(hwparams, &maxPeriodTime, &dir);
       
   382         if ( err >= 0)
       
   383             err = snd_pcm_hw_params_get_period_time_min(hwparams, &minPeriodTime, &dir);
       
   384 
       
   385         if ( err < 0 ) {
       
   386             fatal = true;
       
   387             errMessage = QString::fromLatin1("QAudioOutput: buffer/period min and max: err = %1").arg(err);
       
   388         } else {
       
   389             if (maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time) {
       
   390 #ifdef DEBUG_AUDIO
       
   391                 qDebug()<<"defaults out of range";
       
   392                 qDebug()<<"pmin="<<minPeriodTime<<", pmax="<<maxPeriodTime<<", bmin="<<minBufferTime<<", bmax="<<maxBufferTime;
       
   393 #endif
       
   394                 period_time = minPeriodTime;
       
   395                 if (period_time*4 <= maxBufferTime) {
       
   396                     // Use 4 periods if possible
       
   397                     buffer_time = period_time*4;
       
   398                     chunks = 4;
       
   399                 } else if (period_time*2 <= maxBufferTime) {
       
   400                     // Use 2 periods if possible
       
   401                     buffer_time = period_time*2;
       
   402                     chunks = 2;
       
   403                 } else {
       
   404                     qWarning()<<"QAudioOutput: alsa only supports single period!";
       
   405                     fatal = true;
       
   406                 }
       
   407 #ifdef DEBUG_AUDIO
       
   408                 qDebug()<<"used: buffer_time="<<buffer_time<<", period_time="<<period_time;
       
   409 #endif
       
   410             }
       
   411         }
       
   412     }
       
   413     if ( !fatal ) {
   371         err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
   414         err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
   372         if ( err < 0 ) {
   415         if ( err < 0 ) {
   373             fatal = true;
   416             fatal = true;
   374                 errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err);
   417             errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err);
   375         }
   418         }
   376     }
   419     }
   377     if ( !fatal ) {
   420     if ( !fatal ) {
   378         err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
   421         err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
   379         if ( err < 0 ) {
   422         if ( err < 0 ) {
   492         // Only write space worth
   535         // Only write space worth
   493         frames = snd_pcm_bytes_to_frames( handle, (int)space );
   536         frames = snd_pcm_bytes_to_frames( handle, (int)space );
   494         err = snd_pcm_writei( handle, data, frames );
   537         err = snd_pcm_writei( handle, data, frames );
   495     }
   538     }
   496     if(err > 0) {
   539     if(err > 0) {
   497         totalTimeValue += err*1000000/settings.frequency();
   540         totalTimeValue += err;
   498         resuming = false;
   541         resuming = false;
   499         errorState = QAudio::NoError;
   542         errorState = QAudio::NoError;
   500         deviceState = QAudio::ActiveState;
   543         if (deviceState != QAudio::ActiveState) {
       
   544             deviceState = QAudio::ActiveState;
       
   545             emit stateChanged(deviceState);
       
   546         }
   501         return snd_pcm_frames_to_bytes( handle, err );
   547         return snd_pcm_frames_to_bytes( handle, err );
   502     } else
   548     } else
   503         err = xrun_recovery(err);
   549         err = xrun_recovery(err);
   504 
   550 
   505     if(err < 0) {
   551     if(err < 0) {
   540     return intervalTime;
   586     return intervalTime;
   541 }
   587 }
   542 
   588 
   543 qint64 QAudioOutputPrivate::processedUSecs() const
   589 qint64 QAudioOutputPrivate::processedUSecs() const
   544 {
   590 {
   545     return totalTimeValue;
   591     return qint64(1000000) * totalTimeValue / settings.frequency();
   546 }
   592 }
   547 
   593 
   548 void QAudioOutputPrivate::resume()
   594 void QAudioOutputPrivate::resume()
   549 {
   595 {
   550     if(deviceState == QAudio::SuspendedState) {
   596     if(deviceState == QAudio::SuspendedState) {
   560                 xrun_recovery(err);
   606                 xrun_recovery(err);
   561 
   607 
   562             bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames);
   608             bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames);
   563         }
   609         }
   564         resuming = true;
   610         resuming = true;
   565         if(pullMode)
   611 
   566             deviceState = QAudio::ActiveState;
   612         deviceState = QAudio::ActiveState;
   567         else
       
   568             deviceState = QAudio::IdleState;
       
   569 
   613 
   570         errorState = QAudio::NoError;
   614         errorState = QAudio::NoError;
   571         timer->start(period_time/1000);
   615         timer->start(period_time/1000);
   572         emit stateChanged(deviceState);
   616         emit stateChanged(deviceState);
   573     }
   617     }
   602     deviceReady();
   646     deviceReady();
   603 }
   647 }
   604 
   648 
   605 void QAudioOutputPrivate::feedback()
   649 void QAudioOutputPrivate::feedback()
   606 {
   650 {
   607     QMetaObject::invokeMethod(this, SLOT(updateAvailable()), Qt::QueuedConnection);
   651     updateAvailable();
   608 }
   652 }
       
   653 
   609 
   654 
   610 void QAudioOutputPrivate::updateAvailable()
   655 void QAudioOutputPrivate::updateAvailable()
   611 {
   656 {
   612 #ifdef DEBUG_AUDIO
   657 #ifdef DEBUG_AUDIO
   613     QTime now(QTime::currentTime());
   658     QTime now(QTime::currentTime());
   635         l = audioSource->read(audioBuffer,snd_pcm_frames_to_bytes(handle, input));
   680         l = audioSource->read(audioBuffer,snd_pcm_frames_to_bytes(handle, input));
   636         if(l > 0) {
   681         if(l > 0) {
   637             // Got some data to output
   682             // Got some data to output
   638             if(deviceState != QAudio::ActiveState)
   683             if(deviceState != QAudio::ActiveState)
   639                 return true;
   684                 return true;
   640             write(audioBuffer,l);
   685             qint64 bytesWritten = write(audioBuffer,l);
       
   686             if (bytesWritten != l)
       
   687                 audioSource->seek(audioSource->pos()-(l-bytesWritten));
   641             bytesAvailable = bytesFree();
   688             bytesAvailable = bytesFree();
   642 
   689 
   643         } else if(l == 0) {
   690         } else if(l == 0) {
   644             // Did not get any data to output
   691             // Did not get any data to output
   645             bytesAvailable = bytesFree();
   692             bytesAvailable = bytesFree();
   646             if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) {
   693             if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) {
   647                 // Underrun
   694                 // Underrun
       
   695                 if (deviceState != QAudio::IdleState) {
       
   696                     errorState = QAudio::UnderrunError;
       
   697                     deviceState = QAudio::IdleState;
       
   698                     emit stateChanged(deviceState);
       
   699                 }
       
   700             }
       
   701 
       
   702         } else if(l < 0) {
       
   703             close();
       
   704             errorState = QAudio::IOError;
       
   705             emit stateChanged(deviceState);
       
   706         }
       
   707     } else {
       
   708         bytesAvailable = bytesFree();
       
   709         if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) {
       
   710             // Underrun
       
   711             if (deviceState != QAudio::IdleState) {
   648                 errorState = QAudio::UnderrunError;
   712                 errorState = QAudio::UnderrunError;
   649                 deviceState = QAudio::IdleState;
   713                 deviceState = QAudio::IdleState;
   650                 emit stateChanged(deviceState);
   714                 emit stateChanged(deviceState);
   651             }
   715             }
   652 
   716         }
   653         } else if(l < 0) {
   717     }
   654             close();
       
   655             errorState = QAudio::IOError;
       
   656             emit stateChanged(deviceState);
       
   657         }
       
   658     } else
       
   659         bytesAvailable = bytesFree();
       
   660 
   718 
   661     if(deviceState != QAudio::ActiveState)
   719     if(deviceState != QAudio::ActiveState)
   662         return true;
   720         return true;
   663 
   721 
   664     if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) {
   722     if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) {
   669     return true;
   727     return true;
   670 }
   728 }
   671 
   729 
   672 qint64 QAudioOutputPrivate::elapsedUSecs() const
   730 qint64 QAudioOutputPrivate::elapsedUSecs() const
   673 {
   731 {
   674     if(!handle)
       
   675         return 0;
       
   676 
       
   677     if (deviceState == QAudio::StoppedState)
   732     if (deviceState == QAudio::StoppedState)
   678         return 0;
   733         return 0;
   679 
   734 
   680 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   681     snd_pcm_status_t* status;
       
   682     snd_pcm_status_alloca(&status);
       
   683 
       
   684     snd_timestamp_t t1,t2;
       
   685     if( snd_pcm_status(handle, status) >= 0) {
       
   686         snd_pcm_status_get_tstamp(status,&t1);
       
   687         snd_pcm_status_get_trigger_tstamp(status,&t2);
       
   688         t1.tv_sec-=t2.tv_sec;
       
   689 
       
   690         signed long l = (signed long)t1.tv_usec - (signed long)t2.tv_usec;
       
   691         if(l < 0) {
       
   692             t1.tv_sec--;
       
   693             l = -l;
       
   694             l %= 1000000;
       
   695         }
       
   696         return ((t1.tv_sec * 1000000)+l);
       
   697     } else
       
   698         return 0;
       
   699 #else
       
   700     return clockStamp.elapsed()*1000;
   735     return clockStamp.elapsed()*1000;
   701 #endif
       
   702     return 0;
       
   703 }
   736 }
   704 
   737 
   705 void QAudioOutputPrivate::reset()
   738 void QAudioOutputPrivate::reset()
   706 {
   739 {
   707     if(handle)
   740     if(handle)