summaryrefslogtreecommitdiffstats
path: root/src/multimedia/audio
diff options
context:
space:
mode:
authorAndrew den Exter <andrew.den-exter@nokia.com>2010-09-22 05:41:34 (GMT)
committerAndrew den Exter <andrew.den-exter@nokia.com>2010-09-22 08:03:38 (GMT)
commit5b7d75a57e0ec8ee78f843ab0eb6485b8e3b4a22 (patch)
tree7a474601e5daa4cc6cfb823c0af870f6bd7eb155 /src/multimedia/audio
parent2836c2806e3bdfb6d29d99f74f1b15950fa39e35 (diff)
downloadQt-5b7d75a57e0ec8ee78f843ab0eb6485b8e3b4a22.zip
Qt-5b7d75a57e0ec8ee78f843ab0eb6485b8e3b4a22.tar.gz
Qt-5b7d75a57e0ec8ee78f843ab0eb6485b8e3b4a22.tar.bz2
Verify the audio format before trying to open an audio device.
This was causing a crash on windows because the buffer and period sizes were worked out to 0 with an invalid sample size and dividing one by the other is division by 0. Task-number: QTMOBILITY-438 Reviewed-by: Justin McPherson
Diffstat (limited to 'src/multimedia/audio')
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp23
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp8
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp11
-rw-r--r--src/multimedia/audio/qaudioinput_alsa_p.cpp24
-rw-r--r--src/multimedia/audio/qaudioinput_mac_p.cpp2
-rw-r--r--src/multimedia/audio/qaudioinput_win32_p.cpp41
-rw-r--r--src/multimedia/audio/qaudiooutput_alsa_p.cpp23
-rw-r--r--src/multimedia/audio/qaudiooutput_mac_p.cpp6
-rw-r--r--src/multimedia/audio/qaudiooutput_mac_p.h2
-rw-r--r--src/multimedia/audio/qaudiooutput_win32_p.cpp36
10 files changed, 141 insertions, 35 deletions
diff --git a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp
index 633b309..25622a4 100644
--- a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp
+++ b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp
@@ -257,37 +257,40 @@ bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
// set the values!
snd_pcm_hw_params_set_channels(handle,params,format.channels());
snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
+
+ err = -1;
+
switch(format.sampleSize()) {
case 8:
if(format.sampleType() == QAudioFormat::SignedInt)
- snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
else if(format.sampleType() == QAudioFormat::UnSignedInt)
- snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
break;
case 16:
if(format.sampleType() == QAudioFormat::SignedInt) {
if(format.byteOrder() == QAudioFormat::LittleEndian)
- snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
else if(format.byteOrder() == QAudioFormat::BigEndian)
- snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
} else if(format.sampleType() == QAudioFormat::UnSignedInt) {
if(format.byteOrder() == QAudioFormat::LittleEndian)
- snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
else if(format.byteOrder() == QAudioFormat::BigEndian)
- snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
}
break;
case 32:
if(format.sampleType() == QAudioFormat::SignedInt) {
if(format.byteOrder() == QAudioFormat::LittleEndian)
- snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
else if(format.byteOrder() == QAudioFormat::BigEndian)
- snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
} else if(format.sampleType() == QAudioFormat::UnSignedInt) {
if(format.byteOrder() == QAudioFormat::LittleEndian)
- snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
else if(format.byteOrder() == QAudioFormat::BigEndian)
- snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
}
}
diff --git a/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp
index ecd03e5..1909009 100644
--- a/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp
+++ b/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp
@@ -78,7 +78,13 @@ QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray const& handle, QAu
bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const
{
- return format.codec() == QString::fromLatin1("audio/pcm");
+ QAudioDeviceInfoInternal *self = const_cast<QAudioDeviceInfoInternal*>(this);
+
+ return format.isValid()
+ && format.codec() == QString::fromLatin1("audio/pcm")
+ && self->supportedSampleRates().contains(format.sampleRate())
+ && self->supportedChannelCounts().contains(format.channelCount())
+ && self->supportedSampleSizes().contains(format.sampleSize());
}
QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const
diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp
index 4e6b2df..a4b28d4 100644
--- a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp
+++ b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp
@@ -196,8 +196,9 @@ bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
break;
}
}
+ if (!match)
+ failed = true;
}
- if (!match) failed = true;
// check frequency
match = false;
@@ -208,6 +209,8 @@ bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
break;
}
}
+ if (!match)
+ failed = true;
}
// check sample size
@@ -219,6 +222,8 @@ bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
break;
}
}
+ if (!match)
+ failed = true;
}
// check byte order
@@ -230,6 +235,8 @@ bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
break;
}
}
+ if (!match)
+ failed = true;
}
// check sample type
@@ -241,6 +248,8 @@ bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
break;
}
}
+ if (!match)
+ failed = true;
}
if(!failed) {
diff --git a/src/multimedia/audio/qaudioinput_alsa_p.cpp b/src/multimedia/audio/qaudioinput_alsa_p.cpp
index 58669b3..ddafa3d 100644
--- a/src/multimedia/audio/qaudioinput_alsa_p.cpp
+++ b/src/multimedia/audio/qaudioinput_alsa_p.cpp
@@ -152,7 +152,7 @@ int QAudioInputPrivate::xrun_recovery(int err)
int QAudioInputPrivate::setFormat()
{
- snd_pcm_format_t format = SND_PCM_FORMAT_S16;
+ snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
if(settings.sampleSize() == 8) {
format = SND_PCM_FORMAT_U8;
@@ -204,7 +204,9 @@ int QAudioInputPrivate::setFormat()
format = SND_PCM_FORMAT_FLOAT64_BE;
}
- return snd_pcm_hw_params_set_format( handle, hwparams, format);
+ return format != SND_PCM_FORMAT_UNKNOWN
+ ? snd_pcm_hw_params_set_format( handle, hwparams, format)
+ : -1;
}
QIODevice* QAudioInputPrivate::start(QIODevice* device)
@@ -259,10 +261,26 @@ bool QAudioInputPrivate::open()
elapsedTimeOffset = 0;
int dir;
- int err=-1;
+ int err = 0;
int count=0;
unsigned int freakuency=settings.frequency();
+ if (!settings.isValid()) {
+ qWarning("QAudioOutput: open error, invalid format.");
+ } else if (settings.frequency() <= 0) {
+ qWarning("QAudioOutput: open error, invalid sample rate (%d).",
+ settings.frequency());
+ } else {
+ err = -1;
+ }
+
+ if (err == 0) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StoppedState;
+ return false;
+ }
+
+
QString dev = QString(QLatin1String(m_device.constData()));
QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioInput);
if(dev.compare(QLatin1String("default")) == 0) {
diff --git a/src/multimedia/audio/qaudioinput_mac_p.cpp b/src/multimedia/audio/qaudioinput_mac_p.cpp
index 5897e75..c3d2ae2 100644
--- a/src/multimedia/audio/qaudioinput_mac_p.cpp
+++ b/src/multimedia/audio/qaudioinput_mac_p.cpp
@@ -717,7 +717,7 @@ QIODevice* QAudioInputPrivate::start(QIODevice* device)
{
QIODevice* op = device;
- if (!audioFormat.isValid() || !open()) {
+ if (!audioDeviceInfo->isFormatSupported(audioFormat) || !open()) {
stateCode = QAudio::StoppedState;
errorCode = QAudio::OpenError;
return audioIO;
diff --git a/src/multimedia/audio/qaudioinput_win32_p.cpp b/src/multimedia/audio/qaudioinput_win32_p.cpp
index 3f6e778..225d2f1 100644
--- a/src/multimedia/audio/qaudioinput_win32_p.cpp
+++ b/src/multimedia/audio/qaudioinput_win32_p.cpp
@@ -214,13 +214,44 @@ bool QAudioInputPrivate::open()
qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
#endif
header = 0;
- if(buffer_size == 0) {
- // Default buffer size, 200ms, default period size is 40ms
- buffer_size = settings.frequency()*settings.channels()*(settings.sampleSize()/8)*0.2;
- period_size = buffer_size/5;
+ period_size = 0;
+
+ if (!settings.isValid()) {
+ qWarning("QAudioInput: open error, invalid format.");
+ } else if (settings.channels() <= 0) {
+ qWarning("QAudioInput: open error, invalid number of channels (%d).",
+ settings.channels());
+ } else if (settings.sampleSize() <= 0) {
+ qWarning("QAudioInput: open error, invalid sample size (%d).",
+ settings.sampleSize());
+ } else if (settings.frequency() < 8000 || settings.frequency() > 48000) {
+ qWarning("QAudioInput: open error, frequency out of range (%d).", settings.frequency());
+ } else if (buffer_size == 0) {
+
+ buffer_size
+ = (settings.frequency()
+ * settings.channels()
+ * settings.sampleSize()
+#ifndef Q_OS_WINCE // Default buffer size, 200ms, default period size is 40ms
+ + 39) / 40;
+ period_size = buffer_size / 5;
+ } else {
+ period_size = buffer_size / 5;
+#else // For wince reduce size to 40ms for buffer size and 20ms period
+ + 199) / 200;
+ period_size = buffer_size / 2;
} else {
- period_size = buffer_size/5;
+ period_size = buffer_size / 2;
+#endif
}
+
+ if (period_size == 0) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StoppedState;
+ emit stateChanged(deviceState);
+ return false;
+ }
+
timeStamp.restart();
elapsedTimeOffset = 0;
wfx.nSamplesPerSec = settings.frequency();
diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.cpp b/src/multimedia/audio/qaudiooutput_alsa_p.cpp
index 49b32c0..ecf3215 100644
--- a/src/multimedia/audio/qaudiooutput_alsa_p.cpp
+++ b/src/multimedia/audio/qaudiooutput_alsa_p.cpp
@@ -155,7 +155,7 @@ int QAudioOutputPrivate::xrun_recovery(int err)
int QAudioOutputPrivate::setFormat()
{
- snd_pcm_format_t pcmformat = SND_PCM_FORMAT_S16;
+ snd_pcm_format_t pcmformat = SND_PCM_FORMAT_UNKNOWN;
if(settings.sampleSize() == 8) {
pcmformat = SND_PCM_FORMAT_U8;
@@ -208,7 +208,9 @@ int QAudioOutputPrivate::setFormat()
pcmformat = SND_PCM_FORMAT_FLOAT64_BE;
}
- return snd_pcm_hw_params_set_format( handle, hwparams, pcmformat);
+ return pcmformat != SND_PCM_FORMAT_UNKNOWN
+ ? snd_pcm_hw_params_set_format( handle, hwparams, pcmformat)
+ : -1;
}
QIODevice* QAudioOutputPrivate::start(QIODevice* device)
@@ -275,10 +277,25 @@ bool QAudioOutputPrivate::open()
elapsedTimeOffset = 0;
int dir;
- int err=-1;
+ int err = 0;
int count=0;
unsigned int freakuency=settings.frequency();
+ if (!settings.isValid()) {
+ qWarning("QAudioOutput: open error, invalid format.");
+ } else if (settings.frequency() <= 0) {
+ qWarning("QAudioOutput: open error, invalid sample rate (%d).",
+ settings.frequency());
+ } else {
+ err = -1;
+ }
+
+ if (err == 0) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StoppedState;
+ return false;
+ }
+
QString dev = QString(QLatin1String(m_device.constData()));
QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput);
if(dev.compare(QLatin1String("default")) == 0) {
diff --git a/src/multimedia/audio/qaudiooutput_mac_p.cpp b/src/multimedia/audio/qaudiooutput_mac_p.cpp
index cc52d90..86a2e31 100644
--- a/src/multimedia/audio/qaudiooutput_mac_p.cpp
+++ b/src/multimedia/audio/qaudiooutput_mac_p.cpp
@@ -60,11 +60,11 @@
#include <QtCore/qtimer.h>
#include <QtCore/qdebug.h>
-#include <QtMultimedia/qaudiodeviceinfo.h>
#include <QtMultimedia/qaudiooutput.h>
#include "qaudio_mac_p.h"
#include "qaudiooutput_mac_p.h"
+#include "qaudiodeviceinfo_mac_p.h"
QT_BEGIN_NAMESPACE
@@ -278,6 +278,7 @@ QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray& device, const QAudioF
if (QAudio::Mode(mode) == QAudio::AudioInput)
errorCode = QAudio::OpenError;
else {
+ audioDeviceInfo = new QAudioDeviceInfoInternal(device, QAudio::AudioOutput);
isOpen = false;
audioDeviceId = AudioDeviceID(did);
audioUnit = 0;
@@ -299,6 +300,7 @@ QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray& device, const QAudioF
QAudioOutputPrivate::~QAudioOutputPrivate()
{
+ delete audioDeviceInfo;
close();
}
@@ -424,7 +426,7 @@ QIODevice* QAudioOutputPrivate::start(QIODevice* device)
{
QIODevice* op = device;
- if (!audioFormat.isValid() || !open()) {
+ if (!audioDeviceInfo->isFormatSupported(audioFormat) || !open()) {
stateCode = QAudio::StoppedState;
errorCode = QAudio::OpenError;
return audioIO;
diff --git a/src/multimedia/audio/qaudiooutput_mac_p.h b/src/multimedia/audio/qaudiooutput_mac_p.h
index 752905c..7013961 100644
--- a/src/multimedia/audio/qaudiooutput_mac_p.h
+++ b/src/multimedia/audio/qaudiooutput_mac_p.h
@@ -73,6 +73,7 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QIODevice;
+class QAbstractAudioDeviceInfo;
namespace QtMultimediaInternal
{
@@ -101,6 +102,7 @@ public:
QWaitCondition threadFinished;
QMutex mutex;
QTimer* intervalTimer;
+ QAbstractAudioDeviceInfo *audioDeviceInfo;
QAudio::Error errorCode;
QAudio::State stateCode;
diff --git a/src/multimedia/audio/qaudiooutput_win32_p.cpp b/src/multimedia/audio/qaudiooutput_win32_p.cpp
index 09771b3..f038e51 100644
--- a/src/multimedia/audio/qaudiooutput_win32_p.cpp
+++ b/src/multimedia/audio/qaudiooutput_win32_p.cpp
@@ -251,20 +251,38 @@ bool QAudioOutputPrivate::open()
QTime now(QTime::currentTime());
qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
#endif
- if (!(settings.frequency() >= 8000 && settings.frequency() <= 48000)) {
+
+ period_size = 0;
+
+ if (!settings.isValid()) {
+ qWarning("QAudioOutput: open error, invalid format.");
+ } else if (settings.channels() <= 0) {
+ qWarning("QAudioOutput: open error, invalid number of channels (%d).",
+ settings.channels());
+ } else if (settings.sampleSize() <= 0) {
+ qWarning("QAudioOutput: open error, invalid sample size (%d).",
+ settings.sampleSize());
+ } else if (settings.frequency() < 8000 || settings.frequency() > 48000) {
+ qWarning("QAudioOutput: open error, frequency out of range (%d).", settings.frequency());
+ } else if (buffer_size == 0) {
+ // Default buffer size, 200ms, default period size is 40ms
+ buffer_size
+ = (settings.frequency()
+ * settings.channels()
+ * settings.sampleSize()
+ + 39) / 40;
+ period_size = buffer_size / 5;
+ } else {
+ period_size = buffer_size / 5;
+ }
+
+ if (period_size == 0) {
errorState = QAudio::OpenError;
deviceState = QAudio::StoppedState;
emit stateChanged(deviceState);
- qWarning("QAudioOutput: open error, frequency out of range.");
return false;
}
- if(buffer_size == 0) {
- // Default buffer size, 200ms, default period size is 40ms
- buffer_size = settings.frequency()*settings.channels()*(settings.sampleSize()/8)*0.2;
- period_size = buffer_size/5;
- } else {
- period_size = buffer_size/5;
- }
+
waveBlocks = allocateBlocks(period_size, buffer_size/period_size);
mutex.lock();