summaryrefslogtreecommitdiffstats
path: root/src/multimedia/audio
diff options
context:
space:
mode:
authorKurt Korbatits <kurt.korbatits@nokia.com>2010-02-23 03:40:03 (GMT)
committerKurt Korbatits <kurt.korbatits@nokia.com>2010-02-23 03:40:03 (GMT)
commit04532ba052559b265b1bc85dc143d8aeeb02149f (patch)
tree73284772620b9714819141ac815e257da9bf9824 /src/multimedia/audio
parentf91f64ee2d0caa86b004bf3653f286116681fa3d (diff)
downloadQt-04532ba052559b265b1bc85dc143d8aeeb02149f.zip
Qt-04532ba052559b265b1bc85dc143d8aeeb02149f.tar.gz
Qt-04532ba052559b265b1bc85dc143d8aeeb02149f.tar.bz2
alsa backend for low-level audio doesn't pass new unit tests
New unit tests have identified issues with alsa backend. These issues need to be resolved before new unit tests are added. * stateChanged() signal should only be emitted on change of state currently signals can be emitted multiple times. * elapsedUSecs() currently uses alsa to provide this value but this is not reliable enough and this time is reset when suspend/resuming. This is not correct operation. * for output data is being lost when input cant be read from QIODevice but cannot be written to audio sub system. Task-number:QTBUG-8440 Reviewed-by:Dmytro Poplavskiy
Diffstat (limited to 'src/multimedia/audio')
-rw-r--r--src/multimedia/audio/qaudioinput_alsa_p.cpp121
-rw-r--r--src/multimedia/audio/qaudiooutput_alsa_p.cpp64
2 files changed, 67 insertions, 118 deletions
diff --git a/src/multimedia/audio/qaudioinput_alsa_p.cpp b/src/multimedia/audio/qaudioinput_alsa_p.cpp
index 26e46b3..6010f3c 100644
--- a/src/multimedia/audio/qaudioinput_alsa_p.cpp
+++ b/src/multimedia/audio/qaudioinput_alsa_p.cpp
@@ -217,9 +217,11 @@ QIODevice* QAudioInputPrivate::start(QIODevice* device)
//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 +415,6 @@ bool QAudioInputPrivate::open()
timer->start(period_time*chunks/2000);
errorState = QAudio::NoError;
- deviceState = QAudio::ActiveState;
totalTimeValue = 0;
@@ -439,7 +440,7 @@ int QAudioInputPrivate::bytesReady() const
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((int)frames > (int)buffer_frames)
@@ -450,8 +451,8 @@ int QAudioInputPrivate::bytesReady() const
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;
@@ -468,7 +469,7 @@ qint64 QAudioInputPrivate::read(char* data, qint64 len)
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 +490,46 @@ qint64 QAudioInputPrivate::read(char* data, qint64 len)
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;
}
@@ -569,7 +588,7 @@ int QAudioInputPrivate::notifyInterval() const
qint64 QAudioInputPrivate::processedUSecs() const
{
- return totalTimeValue;
+ return qint64(1000000) * totalTimeValue / settings.frequency();
}
void QAudioInputPrivate::suspend()
@@ -617,34 +636,10 @@ bool QAudioInputPrivate::deviceReady()
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 +665,7 @@ InputPrivate::~InputPrivate()
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)
diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.cpp b/src/multimedia/audio/qaudiooutput_alsa_p.cpp
index 7b89cef..b127103 100644
--- a/src/multimedia/audio/qaudiooutput_alsa_p.cpp
+++ b/src/multimedia/audio/qaudiooutput_alsa_p.cpp
@@ -259,6 +259,7 @@ void QAudioOutputPrivate::stop()
{
if(deviceState == QAudio::StoppedState)
return;
+ errorState = QAudio::NoError;
deviceState = QAudio::StoppedState;
close();
emit stateChanged(deviceState);
@@ -494,10 +495,13 @@ qint64 QAudioOutputPrivate::write( const char *data, qint64 len )
err = snd_pcm_writei( handle, data, frames );
}
if(err > 0) {
- totalTimeValue += err*1000000/settings.frequency();
+ totalTimeValue += err;
resuming = false;
errorState = QAudio::NoError;
- deviceState = QAudio::ActiveState;
+ if (deviceState != QAudio::ActiveState) {
+ deviceState = QAudio::ActiveState;
+ emit stateChanged(deviceState);
+ }
return snd_pcm_frames_to_bytes( handle, err );
} else
err = xrun_recovery(err);
@@ -542,7 +546,7 @@ int QAudioOutputPrivate::notifyInterval() const
qint64 QAudioOutputPrivate::processedUSecs() const
{
- return totalTimeValue;
+ return qint64(1000000) * totalTimeValue / settings.frequency();
}
void QAudioOutputPrivate::resume()
@@ -562,10 +566,8 @@ void QAudioOutputPrivate::resume()
bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames);
}
resuming = true;
- if(pullMode)
- deviceState = QAudio::ActiveState;
- else
- deviceState = QAudio::IdleState;
+
+ deviceState = QAudio::ActiveState;
errorState = QAudio::NoError;
timer->start(period_time/1000);
@@ -637,7 +639,9 @@ bool QAudioOutputPrivate::deviceReady()
// Got some data to output
if(deviceState != QAudio::ActiveState)
return true;
- write(audioBuffer,l);
+ qint64 bytesWritten = write(audioBuffer,l);
+ if (bytesWritten != l)
+ audioSource->seek(audioSource->pos()-(l-bytesWritten));
bytesAvailable = bytesFree();
} else if(l == 0) {
@@ -645,9 +649,11 @@ bool QAudioOutputPrivate::deviceReady()
bytesAvailable = bytesFree();
if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) {
// Underrun
- errorState = QAudio::UnderrunError;
- deviceState = QAudio::IdleState;
- emit stateChanged(deviceState);
+ if (deviceState != QAudio::IdleState) {
+ errorState = QAudio::UnderrunError;
+ deviceState = QAudio::IdleState;
+ emit stateChanged(deviceState);
+ }
}
} else if(l < 0) {
@@ -655,8 +661,17 @@ bool QAudioOutputPrivate::deviceReady()
errorState = QAudio::IOError;
emit stateChanged(deviceState);
}
- } else
+ } else {
bytesAvailable = bytesFree();
+ if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) {
+ // Underrun
+ if (deviceState != QAudio::IdleState) {
+ errorState = QAudio::UnderrunError;
+ deviceState = QAudio::IdleState;
+ emit stateChanged(deviceState);
+ }
+ }
+ }
if(deviceState != QAudio::ActiveState)
return true;
@@ -671,35 +686,10 @@ bool QAudioOutputPrivate::deviceReady()
qint64 QAudioOutputPrivate::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
- return 0;
}
void QAudioOutputPrivate::reset()