src/multimedia/audio/qaudioinput_alsa_p.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
--- a/src/multimedia/audio/qaudioinput_alsa_p.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/src/multimedia/audio/qaudioinput_alsa_p.cpp	Wed Mar 31 11:06:36 2010 +0300
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
@@ -121,6 +121,11 @@
         err = snd_pcm_prepare(handle);
         if(err < 0)
             reset = true;
+        else {
+            bytesAvailable = bytesReady();
+            if (bytesAvailable <= 0)
+                reset = true;
+        }
 
     } else if((err == -ESTRPIPE)||(err == -EIO)) {
         errorState = QAudio::IOError;
@@ -217,9 +222,11 @@
         //set to pull mode
         pullMode = true;
         audioSource = device;
+        deviceState = QAudio::ActiveState;
     } else {
         //set to push mode
         pullMode = false;
+        deviceState = QAudio::IdleState;
         audioSource = new InputPrivate(this);
         audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
     }
@@ -413,7 +420,6 @@
     timer->start(period_time*chunks/2000);
 
     errorState  = QAudio::NoError;
-    deviceState = QAudio::ActiveState;
 
     totalTimeValue = 0;
 
@@ -439,9 +445,10 @@
     if(resuming)
         return period_size;
 
-    if(deviceState != QAudio::ActiveState)
+    if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
         return 0;
     int frames = snd_pcm_avail_update(handle);
+    if (frames < 0) return frames;
     if((int)frames > (int)buffer_frames)
         frames = buffer_frames;
 
@@ -450,14 +457,28 @@
 
 qint64 QAudioInputPrivate::read(char* data, qint64 len)
 {
-    Q_UNUSED(data)
     Q_UNUSED(len)
+
     // Read in some audio data and write it to QIODevice, pull mode
     if ( !handle )
         return 0;
 
     bytesAvailable = bytesReady();
 
+    if (bytesAvailable < 0) {
+        // bytesAvailable as negative is error code, try to recover from it.
+        xrun_recovery(bytesAvailable);
+        bytesAvailable = bytesReady();
+        if (bytesAvailable < 0) {
+            // recovery failed must stop and set error.
+            close();
+            errorState = QAudio::IOError;
+            deviceState = QAudio::StoppedState;
+            emit stateChanged(deviceState);
+            return 0;
+        }
+    }
+
     int count=0, err = 0;
     while(count < 5) {
         int chunks = bytesAvailable/period_size;
@@ -468,7 +489,7 @@
         if (readFrames >= 0) {
             err = snd_pcm_frames_to_bytes(handle, readFrames);
 #ifdef DEBUG_AUDIO
-            qDebug()<<QString::fromLatin1("PULL: read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData();
+            qDebug()<<QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData();
 #endif
             break;
         } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
@@ -489,28 +510,46 @@
     if(err > 0) {
         // got some send it onward
 #ifdef DEBUG_AUDIO
-        qDebug()<<"PULL: frames to write to QIODevice = "<<
+        qDebug()<<"frames to write to QIODevice = "<<
             snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes";
 #endif
-        if(deviceState != QAudio::ActiveState)
+        if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
             return 0;
+        if (pullMode) {
+            qint64 l = audioSource->write(audioBuffer,err);
+            if(l < 0) {
+                close();
+                errorState = QAudio::IOError;
+                deviceState = QAudio::StoppedState;
+                emit stateChanged(deviceState);
+            } else if(l == 0) {
+                if (deviceState != QAudio::IdleState) {
+                    errorState = QAudio::NoError;
+                    deviceState = QAudio::IdleState;
+                    emit stateChanged(deviceState);
+                }
+            } else {
+                totalTimeValue += err;
+                resuming = false;
+                if (deviceState != QAudio::ActiveState) {
+                    errorState = QAudio::NoError;
+                    deviceState = QAudio::ActiveState;
+                    emit stateChanged(deviceState);
+                }
+            }
+            return l;
 
-        qint64 l = audioSource->write(audioBuffer,err);
-        if(l < 0) {
-            close();
-            errorState = QAudio::IOError;
-            deviceState = QAudio::StoppedState;
-            emit stateChanged(deviceState);
-        } else if(l == 0) {
-            errorState = QAudio::NoError;
-            deviceState = QAudio::IdleState;
         } else {
-            totalTimeValue += snd_pcm_bytes_to_frames(handle, err)*1000000/settings.frequency();
+            memcpy(data,audioBuffer,err);
+            totalTimeValue += err;
             resuming = false;
-            errorState = QAudio::NoError;
-            deviceState = QAudio::ActiveState;
+            if (deviceState != QAudio::ActiveState) {
+                errorState = QAudio::NoError;
+                deviceState = QAudio::ActiveState;
+                emit stateChanged(deviceState);
+            }
+            return err;
         }
-        return l;
     }
     return 0;
 }
@@ -534,7 +573,7 @@
         resuming = true;
         deviceState = QAudio::ActiveState;
         int chunks = buffer_size/period_size;
-        timer->start(buffer_time*chunks/2000);
+        timer->start(period_time*chunks/2000);
         emit stateChanged(deviceState);
     }
 }
@@ -569,7 +608,11 @@
 
 qint64 QAudioInputPrivate::processedUSecs() const
 {
-    return totalTimeValue;
+    qint64 result = qint64(1000000) * totalTimeValue /
+        (settings.channels()*(settings.sampleSize()/8)) /
+        settings.frequency();
+
+    return result;
 }
 
 void QAudioInputPrivate::suspend()
@@ -617,34 +660,10 @@
 
 qint64 QAudioInputPrivate::elapsedUSecs() const
 {
-    if(!handle)
-        return 0;
-
     if (deviceState == QAudio::StoppedState)
         return 0;
 
-#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
-    snd_pcm_status_t* status;
-    snd_pcm_status_alloca(&status);
-
-    snd_timestamp_t t1,t2;
-    if( snd_pcm_status(handle, status) >= 0) {
-        snd_pcm_status_get_tstamp(status,&t1);
-        snd_pcm_status_get_trigger_tstamp(status,&t2);
-        t1.tv_sec-=t2.tv_sec;
-
-        signed long l = (signed long)t1.tv_usec - (signed long)t2.tv_usec;
-        if(l < 0) {
-            t1.tv_sec--;
-            l = -l;
-            l %= 1000000;
-        }
-        return ((t1.tv_sec * 1000000)+l);
-    } else
-        return 0;
-#else
     return clockStamp.elapsed()*1000;
-#endif
 }
 
 void QAudioInputPrivate::reset()
@@ -670,43 +689,7 @@
 
 qint64 InputPrivate::readData( char* data, qint64 len)
 {
-    // push mode, user read() called
-    if((audioDevice->state() != QAudio::ActiveState) && !audioDevice->resuming)
-        return 0;
-
-    int readFrames;
-    int count=0, err = 0;
-
-    while(count < 5) {
-        int frames = snd_pcm_bytes_to_frames(audioDevice->handle, len);
-        readFrames = snd_pcm_readi(audioDevice->handle, data, frames);
-        if (readFrames >= 0) {
-            err = snd_pcm_frames_to_bytes(audioDevice->handle, readFrames);
-#ifdef DEBUG_AUDIO
-            qDebug()<<QString::fromLatin1("PUSH: read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData();
-#endif
-            break;
-        } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
-            audioDevice->errorState = QAudio::IOError;
-            err = 0;
-            break;
-        } else {
-            if(readFrames == -EPIPE) {
-                audioDevice->errorState = QAudio::UnderrunError;
-                err = snd_pcm_prepare(audioDevice->handle);
-            } else if(readFrames == -ESTRPIPE) {
-                err = snd_pcm_prepare(audioDevice->handle);
-            }
-            if(err != 0) break;
-        }
-        count++;
-    }
-    if(err > 0 && readFrames > 0) {
-        audioDevice->totalTimeValue += readFrames*1000/audioDevice->settings.frequency()*1000;
-        audioDevice->deviceState = QAudio::ActiveState;
-        return err;
-    }
-    return 0;
+    return audioDevice->read(data,len);
 }
 
 qint64 InputPrivate::writeData(const char* data, qint64 len)