src/multimedia/audio/qaudioinput_alsa_p.cpp
changeset 18 2f34d5167611
parent 3 41300fa6a67c
child 19 fcece45ef507
equal deleted inserted replaced
3:41300fa6a67c 18:2f34d5167611
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtMultimedia module of the Qt Toolkit.
     7 ** This file is part of the QtMultimedia module of the Qt Toolkit.
     8 **
     8 **
   215 
   215 
   216     if(device) {
   216     if(device) {
   217         //set to pull mode
   217         //set to pull mode
   218         pullMode = true;
   218         pullMode = true;
   219         audioSource = device;
   219         audioSource = device;
       
   220         deviceState = QAudio::ActiveState;
   220     } else {
   221     } else {
   221         //set to push mode
   222         //set to push mode
   222         pullMode = false;
   223         pullMode = false;
       
   224         deviceState = QAudio::IdleState;
   223         audioSource = new InputPrivate(this);
   225         audioSource = new InputPrivate(this);
   224         audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
   226         audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
   225     }
   227     }
   226 
   228 
   227     if( !open() )
   229     if( !open() )
   411     // Step 6: Start audio processing
   413     // Step 6: Start audio processing
   412     chunks = buffer_size/period_size;
   414     chunks = buffer_size/period_size;
   413     timer->start(period_time*chunks/2000);
   415     timer->start(period_time*chunks/2000);
   414 
   416 
   415     errorState  = QAudio::NoError;
   417     errorState  = QAudio::NoError;
   416     deviceState = QAudio::ActiveState;
       
   417 
   418 
   418     totalTimeValue = 0;
   419     totalTimeValue = 0;
   419 
   420 
   420     return true;
   421     return true;
   421 }
   422 }
   437 int QAudioInputPrivate::bytesReady() const
   438 int QAudioInputPrivate::bytesReady() const
   438 {
   439 {
   439     if(resuming)
   440     if(resuming)
   440         return period_size;
   441         return period_size;
   441 
   442 
   442     if(deviceState != QAudio::ActiveState)
   443     if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
   443         return 0;
   444         return 0;
   444     int frames = snd_pcm_avail_update(handle);
   445     int frames = snd_pcm_avail_update(handle);
   445     if((int)frames > (int)buffer_frames)
   446     if((int)frames > (int)buffer_frames)
   446         frames = buffer_frames;
   447         frames = buffer_frames;
   447 
   448 
   448     return snd_pcm_frames_to_bytes(handle, frames);
   449     return snd_pcm_frames_to_bytes(handle, frames);
   449 }
   450 }
   450 
   451 
   451 qint64 QAudioInputPrivate::read(char* data, qint64 len)
   452 qint64 QAudioInputPrivate::read(char* data, qint64 len)
   452 {
   453 {
   453     Q_UNUSED(data)
       
   454     Q_UNUSED(len)
   454     Q_UNUSED(len)
       
   455 
   455     // Read in some audio data and write it to QIODevice, pull mode
   456     // Read in some audio data and write it to QIODevice, pull mode
   456     if ( !handle )
   457     if ( !handle )
   457         return 0;
   458         return 0;
   458 
   459 
   459     bytesAvailable = bytesReady();
   460     bytesAvailable = bytesReady();
   466             frames = buffer_frames;
   467             frames = buffer_frames;
   467         int readFrames = snd_pcm_readi(handle, audioBuffer, frames);
   468         int readFrames = snd_pcm_readi(handle, audioBuffer, frames);
   468         if (readFrames >= 0) {
   469         if (readFrames >= 0) {
   469             err = snd_pcm_frames_to_bytes(handle, readFrames);
   470             err = snd_pcm_frames_to_bytes(handle, readFrames);
   470 #ifdef DEBUG_AUDIO
   471 #ifdef DEBUG_AUDIO
   471             qDebug()<<QString::fromLatin1("PULL: read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData();
   472             qDebug()<<QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData();
   472 #endif
   473 #endif
   473             break;
   474             break;
   474         } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
   475         } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
   475             errorState = QAudio::IOError;
   476             errorState = QAudio::IOError;
   476             err = 0;
   477             err = 0;
   487         count++;
   488         count++;
   488     }
   489     }
   489     if(err > 0) {
   490     if(err > 0) {
   490         // got some send it onward
   491         // got some send it onward
   491 #ifdef DEBUG_AUDIO
   492 #ifdef DEBUG_AUDIO
   492         qDebug()<<"PULL: frames to write to QIODevice = "<<
   493         qDebug()<<"frames to write to QIODevice = "<<
   493             snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes";
   494             snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes";
   494 #endif
   495 #endif
   495         if(deviceState != QAudio::ActiveState)
   496         if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
   496             return 0;
   497             return 0;
   497 
   498         if (pullMode) {
   498         qint64 l = audioSource->write(audioBuffer,err);
   499             qint64 l = audioSource->write(audioBuffer,err);
   499         if(l < 0) {
   500             if(l < 0) {
   500             close();
   501                 close();
   501             errorState = QAudio::IOError;
   502                 errorState = QAudio::IOError;
   502             deviceState = QAudio::StoppedState;
   503                 deviceState = QAudio::StoppedState;
   503             emit stateChanged(deviceState);
   504                 emit stateChanged(deviceState);
   504         } else if(l == 0) {
   505             } else if(l == 0) {
   505             errorState = QAudio::NoError;
   506                 if (deviceState != QAudio::IdleState) {
   506             deviceState = QAudio::IdleState;
   507                     errorState = QAudio::NoError;
       
   508                     deviceState = QAudio::IdleState;
       
   509                     emit stateChanged(deviceState);
       
   510                 }
       
   511             } else {
       
   512                 totalTimeValue += err;
       
   513                 resuming = false;
       
   514                 if (deviceState != QAudio::ActiveState) {
       
   515                     errorState = QAudio::NoError;
       
   516                     deviceState = QAudio::ActiveState;
       
   517                     emit stateChanged(deviceState);
       
   518                 }
       
   519             }
       
   520             return l;
       
   521 
   507         } else {
   522         } else {
   508             totalTimeValue += snd_pcm_bytes_to_frames(handle, err)*1000000/settings.frequency();
   523             memcpy(data,audioBuffer,err);
       
   524             totalTimeValue += err;
   509             resuming = false;
   525             resuming = false;
   510             errorState = QAudio::NoError;
   526             if (deviceState != QAudio::ActiveState) {
   511             deviceState = QAudio::ActiveState;
   527                 errorState = QAudio::NoError;
   512         }
   528                 deviceState = QAudio::ActiveState;
   513         return l;
   529                 emit stateChanged(deviceState);
       
   530             }
       
   531             return err;
       
   532         }
   514     }
   533     }
   515     return 0;
   534     return 0;
   516 }
   535 }
   517 
   536 
   518 void QAudioInputPrivate::resume()
   537 void QAudioInputPrivate::resume()
   532             bytesAvailable = buffer_size;
   551             bytesAvailable = buffer_size;
   533         }
   552         }
   534         resuming = true;
   553         resuming = true;
   535         deviceState = QAudio::ActiveState;
   554         deviceState = QAudio::ActiveState;
   536         int chunks = buffer_size/period_size;
   555         int chunks = buffer_size/period_size;
   537         timer->start(buffer_time*chunks/2000);
   556         timer->start(period_time*chunks/2000);
   538         emit stateChanged(deviceState);
   557         emit stateChanged(deviceState);
   539     }
   558     }
   540 }
   559 }
   541 
   560 
   542 void QAudioInputPrivate::setBufferSize(int value)
   561 void QAudioInputPrivate::setBufferSize(int value)
   567     return intervalTime;
   586     return intervalTime;
   568 }
   587 }
   569 
   588 
   570 qint64 QAudioInputPrivate::processedUSecs() const
   589 qint64 QAudioInputPrivate::processedUSecs() const
   571 {
   590 {
   572     return totalTimeValue;
   591     return qint64(1000000) * totalTimeValue / settings.frequency();
   573 }
   592 }
   574 
   593 
   575 void QAudioInputPrivate::suspend()
   594 void QAudioInputPrivate::suspend()
   576 {
   595 {
   577     if(deviceState == QAudio::ActiveState||resuming) {
   596     if(deviceState == QAudio::ActiveState||resuming) {
   615     return true;
   634     return true;
   616 }
   635 }
   617 
   636 
   618 qint64 QAudioInputPrivate::elapsedUSecs() const
   637 qint64 QAudioInputPrivate::elapsedUSecs() const
   619 {
   638 {
   620     if(!handle)
       
   621         return 0;
       
   622 
       
   623     if (deviceState == QAudio::StoppedState)
   639     if (deviceState == QAudio::StoppedState)
   624         return 0;
   640         return 0;
   625 
   641 
   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;
   642     return clockStamp.elapsed()*1000;
   647 #endif
       
   648 }
   643 }
   649 
   644 
   650 void QAudioInputPrivate::reset()
   645 void QAudioInputPrivate::reset()
   651 {
   646 {
   652     if(handle)
   647     if(handle)
   668 {
   663 {
   669 }
   664 }
   670 
   665 
   671 qint64 InputPrivate::readData( char* data, qint64 len)
   666 qint64 InputPrivate::readData( char* data, qint64 len)
   672 {
   667 {
   673     // push mode, user read() called
   668     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 }
   669 }
   711 
   670 
   712 qint64 InputPrivate::writeData(const char* data, qint64 len)
   671 qint64 InputPrivate::writeData(const char* data, qint64 len)
   713 {
   672 {
   714     Q_UNUSED(data)
   673     Q_UNUSED(data)