summaryrefslogtreecommitdiffstats
path: root/src/multimedia
diff options
context:
space:
mode:
Diffstat (limited to 'src/multimedia')
-rw-r--r--src/multimedia/audio/audio.pri56
-rw-r--r--src/multimedia/audio/qaudio.cpp102
-rw-r--r--src/multimedia/audio/qaudio.h71
-rw-r--r--src/multimedia/audio/qaudio_mac.cpp142
-rw-r--r--src/multimedia/audio/qaudio_mac_p.h144
-rw-r--r--src/multimedia/audio/qaudiodevicefactory.cpp250
-rw-r--r--src/multimedia/audio/qaudiodevicefactory_p.h100
-rw-r--r--src/multimedia/audio/qaudiodeviceid.cpp168
-rw-r--r--src/multimedia/audio/qaudiodeviceid.h94
-rw-r--r--src/multimedia/audio/qaudiodeviceid_p.h82
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo.cpp270
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo.h102
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp394
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_alsa_p.h113
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp357
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_mac_p.h97
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp378
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_win32_p.h108
-rw-r--r--src/multimedia/audio/qaudioengine.cpp343
-rw-r--r--src/multimedia/audio/qaudioengine.h131
-rw-r--r--src/multimedia/audio/qaudioengineplugin.cpp54
-rw-r--r--src/multimedia/audio/qaudioengineplugin.h93
-rw-r--r--src/multimedia/audio/qaudioformat.cpp335
-rw-r--r--src/multimedia/audio/qaudioformat.h103
-rw-r--r--src/multimedia/audio/qaudioinput.cpp400
-rw-r--r--src/multimedia/audio/qaudioinput.h108
-rw-r--r--src/multimedia/audio/qaudioinput_alsa_p.cpp688
-rw-r--r--src/multimedia/audio/qaudioinput_alsa_p.h151
-rw-r--r--src/multimedia/audio/qaudioinput_mac_p.cpp930
-rw-r--r--src/multimedia/audio/qaudioinput_mac_p.h171
-rw-r--r--src/multimedia/audio/qaudioinput_win32_p.cpp540
-rw-r--r--src/multimedia/audio/qaudioinput_win32_p.h154
-rw-r--r--src/multimedia/audio/qaudiooutput.cpp403
-rw-r--r--src/multimedia/audio/qaudiooutput.h109
-rw-r--r--src/multimedia/audio/qaudiooutput_alsa_p.cpp706
-rw-r--r--src/multimedia/audio/qaudiooutput_alsa_p.h159
-rw-r--r--src/multimedia/audio/qaudiooutput_mac_p.cpp700
-rw-r--r--src/multimedia/audio/qaudiooutput_mac_p.h171
-rw-r--r--src/multimedia/audio/qaudiooutput_win32_p.cpp502
-rw-r--r--src/multimedia/audio/qaudiooutput_win32_p.h154
-rw-r--r--src/multimedia/multimedia.pro11
41 files changed, 10144 insertions, 0 deletions
diff --git a/src/multimedia/audio/audio.pri b/src/multimedia/audio/audio.pri
new file mode 100644
index 0000000..3ddb23b
--- /dev/null
+++ b/src/multimedia/audio/audio.pri
@@ -0,0 +1,56 @@
+HEADERS += $$PWD/qaudio.h \
+ $$PWD/qaudioformat.h \
+ $$PWD/qaudioinput.h \
+ $$PWD/qaudiooutput.h \
+ $$PWD/qaudiodeviceinfo.h \
+ $$PWD/qaudioengineplugin.h \
+ $$PWD/qaudioengine.h \
+ $$PWD/qaudiodevicefactory_p.h \
+ $$PWD/qaudiodeviceid.h \
+ $$PWD/qaudiodeviceid_p.h
+
+
+SOURCES += $$PWD/qaudio.cpp \
+ $$PWD/qaudioformat.cpp \
+ $$PWD/qaudiodeviceinfo.cpp \
+ $$PWD/qaudiooutput.cpp \
+ $$PWD/qaudioinput.cpp \
+ $$PWD/qaudioengineplugin.cpp \
+ $$PWD/qaudioengine.cpp \
+ $$PWD/qaudiodevicefactory.cpp \
+ $$PWD/qaudiodeviceid.cpp
+
+mac {
+ HEADERS += $$PWD/qaudioinput_mac_p.h \
+ $$PWD/qaudiooutput_mac_p.h \
+ $$PWD/qaudiodeviceinfo_mac_p.h \
+ $$PWD/qaudio_mac_p.h
+
+ SOURCES += $$PWD/qaudiodeviceinfo_mac_p.cpp \
+ $$PWD/qaudiooutput_mac_p.cpp \
+ $$PWD/qaudioinput_mac_p.cpp \
+ $$PWD/qaudio_mac.cpp
+
+ LIBS += -framework CoreAudio -framework AudioUnit -framework AudioToolbox
+
+} else:win32 {
+
+ HEADERS += $$PWD/qaudioinput_win32_p.h $$PWD/qaudiooutput_win32_p.h $$PWD/qaudiodeviceinfo_win32_p.h
+ SOURCES += $$PWD/qaudiodeviceinfo_win32_p.cpp \
+ $$PWD/qaudiooutput_win32_p.cpp \
+ $$PWD/qaudioinput_win32_p.cpp
+ !wince*:LIBS += -lwinmm
+ wince*:LIBS += -lcoredll
+
+} else:unix {
+ unix:contains(QT_CONFIG, alsa) {
+ linux-*|freebsd-*|openbsd-*:{
+ DEFINES += HAS_ALSA
+ HEADERS += $$PWD/qaudiooutput_alsa_p.h $$PWD/qaudioinput_alsa_p.h $$PWD/qaudiodeviceinfo_alsa_p.h
+ SOURCES += $$PWD/qaudiodeviceinfo_alsa_p.cpp \
+ $$PWD/qaudiooutput_alsa_p.cpp \
+ $$PWD/qaudioinput_alsa_p.cpp
+ LIBS += -lasound
+ }
+ }
+}
diff --git a/src/multimedia/audio/qaudio.cpp b/src/multimedia/audio/qaudio.cpp
new file mode 100644
index 0000000..5ba6493
--- /dev/null
+++ b/src/multimedia/audio/qaudio.cpp
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtMultimedia/qaudio.h>
+
+
+QT_BEGIN_NAMESPACE
+
+namespace QAudio
+{
+
+class RegisterMetaTypes
+{
+public:
+ RegisterMetaTypes()
+ {
+ qRegisterMetaType<QAudio::Error>();
+ qRegisterMetaType<QAudio::State>();
+ qRegisterMetaType<QAudio::Mode>();
+ }
+
+} _register;
+
+}
+
+/*!
+ \namespace QAudio
+ \brief The QAudio namespace contains enums used by the audio classes.
+ \since 4.6
+*/
+
+/*!
+ \enum QAudio::Error
+
+ \value NoError No errors have occurred
+ \value OpenError An error opening the audio device
+ \value IOError An error occurred during read/write of audio device
+ \value UnderrunError Audio data is not being fed to the audio device at a fast enough rate
+ \value FatalError A non-recoverable error has occurred, the audio device is not usable at this time.
+*/
+
+/*!
+ \enum QAudio::State
+
+ \value ActiveState Audio data is being processed, this state is set after start() is called
+ and while audio data is available to be processed.
+ \value SuspendState The audio device is in a suspended state, this state will only be entered
+ after suspend() is called.
+ \value StopState The audio device is closed, not processing any audio data
+ \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state
+ is set after start() is called and while no audio data is available to be processed.
+*/
+
+/*!
+ \enum QAudio::Mode
+
+ \value AudioOutput audio output device
+ \value AudioInput audio input device
+*/
+
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudio.h b/src/multimedia/audio/qaudio.h
new file mode 100644
index 0000000..b996cc6
--- /dev/null
+++ b/src/multimedia/audio/qaudio.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIO_H
+#define QAUDIO_H
+
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+namespace QAudio
+{
+ enum Error { NoError, OpenError, IOError, UnderrunError, FatalError };
+ enum State { ActiveState, SuspendState, StopState, IdleState };
+ enum Mode { AudioInput, AudioOutput };
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+Q_DECLARE_METATYPE(QAudio::Error);
+Q_DECLARE_METATYPE(QAudio::State);
+Q_DECLARE_METATYPE(QAudio::Mode);
+
+#endif // QAUDIO_H
diff --git a/src/multimedia/audio/qaudio_mac.cpp b/src/multimedia/audio/qaudio_mac.cpp
new file mode 100644
index 0000000..cfa7ca3
--- /dev/null
+++ b/src/multimedia/audio/qaudio_mac.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qaudio_mac_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// Debugging
+QDebug operator<<(QDebug dbg, const QAudioFormat& audioFormat)
+{
+ dbg.nospace() << "QAudioFormat(" <<
+ audioFormat.frequency() << "," <<
+ audioFormat.channels() << "," <<
+ audioFormat.sampleSize()<< "," <<
+ audioFormat.codec() << "," <<
+ audioFormat.byteOrder() << "," <<
+ audioFormat.sampleType() << ")";
+
+ return dbg.space();
+}
+
+
+// Conversion
+QAudioFormat toQAudioFormat(AudioStreamBasicDescription const& sf)
+{
+ QAudioFormat audioFormat;
+
+ audioFormat.setFrequency(sf.mSampleRate);
+ audioFormat.setChannels(sf.mChannelsPerFrame);
+ audioFormat.setSampleSize(sf.mBitsPerChannel);
+ audioFormat.setCodec(QString::fromLatin1("audio/pcm"));
+ audioFormat.setByteOrder(sf.mFormatFlags & kLinearPCMFormatFlagIsBigEndian != 0 ? QAudioFormat::BigEndian : QAudioFormat::LittleEndian);
+ QAudioFormat::SampleType type = QAudioFormat::UnSignedInt;
+ if ((sf.mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) != 0)
+ type = QAudioFormat::SignedInt;
+ else if ((sf.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0)
+ type = QAudioFormat::Float;
+ audioFormat.setSampleType(type);
+
+ return audioFormat;
+}
+
+AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat)
+{
+ AudioStreamBasicDescription sf;
+
+ sf.mFormatFlags = kAudioFormatFlagIsPacked;
+ sf.mSampleRate = audioFormat.frequency();
+ sf.mFramesPerPacket = 1;
+ sf.mChannelsPerFrame = audioFormat.channels();
+ sf.mBitsPerChannel = audioFormat.sampleSize();
+ sf.mBytesPerFrame = sf.mChannelsPerFrame * (sf.mBitsPerChannel / 8);
+ sf.mBytesPerPacket = sf.mFramesPerPacket * sf.mBytesPerFrame;
+ sf.mFormatID = kAudioFormatLinearPCM;
+
+ switch (audioFormat.sampleType()) {
+ case QAudioFormat::SignedInt: sf.mFormatFlags |= kAudioFormatFlagIsSignedInteger; break;
+ case QAudioFormat::UnSignedInt: /* default */ break;
+ case QAudioFormat::Float: sf.mFormatFlags |= kAudioFormatFlagIsFloat; break;
+ case QAudioFormat::Unknown: default: break;
+ }
+
+ return sf;
+}
+
+// QAudioRingBuffer
+QAudioRingBuffer::QAudioRingBuffer(int bufferSize):
+ m_bufferSize(bufferSize)
+{
+ m_buffer = new char[m_bufferSize];
+ reset();
+}
+
+QAudioRingBuffer::~QAudioRingBuffer()
+{
+ delete m_buffer;
+}
+
+int QAudioRingBuffer::used() const
+{
+ return m_bufferUsed;
+}
+
+int QAudioRingBuffer::free() const
+{
+ return m_bufferSize - m_bufferUsed;
+}
+
+int QAudioRingBuffer::size() const
+{
+ return m_bufferSize;
+}
+
+void QAudioRingBuffer::reset()
+{
+ m_readPos = 0;
+ m_writePos = 0;
+ m_bufferUsed = 0;
+}
+
+QT_END_NAMESPACE
+
+
diff --git a/src/multimedia/audio/qaudio_mac_p.h b/src/multimedia/audio/qaudio_mac_p.h
new file mode 100644
index 0000000..8e2d522
--- /dev/null
+++ b/src/multimedia/audio/qaudio_mac_p.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QAUDIO_MAC_P_H
+#define QAUDIO_MAC_P_H
+
+#include <CoreAudio/CoreAudio.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qatomic.h>
+
+#include <QtMultimedia/qaudioformat.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+extern QDebug operator<<(QDebug dbg, const QAudioFormat& audioFormat);
+
+extern QAudioFormat toQAudioFormat(const AudioStreamBasicDescription& streamFormat);
+extern AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat);
+
+class QAudioRingBuffer
+{
+public:
+ typedef QPair<char*, int> Region;
+
+ QAudioRingBuffer(int bufferSize);
+ ~QAudioRingBuffer();
+
+ Region acquireReadRegion(int size)
+ {
+ const int used = m_bufferUsed.fetchAndAddAcquire(0);
+
+ if (used > 0) {
+ const int readSize = qMin(size, qMin(m_bufferSize - m_readPos, used));
+
+ return readSize > 0 ? Region(m_buffer + m_readPos, readSize) : Region(0, 0);
+ }
+
+ return Region(0, 0);
+ }
+
+ void releaseReadRegion(Region const& region)
+ {
+ m_readPos = (m_readPos + region.second) % m_bufferSize;
+
+ m_bufferUsed.fetchAndAddRelease(-region.second);
+ }
+
+ Region acquireWriteRegion(int size)
+ {
+ const int free = m_bufferSize - m_bufferUsed.fetchAndAddAcquire(0);
+
+ if (free > 0) {
+ const int writeSize = qMin(size, qMin(m_bufferSize - m_writePos, free));
+
+ return writeSize > 0 ? Region(m_buffer + m_writePos, writeSize) : Region(0, 0);
+ }
+
+ return Region(0, 0);
+ }
+
+ void releaseWriteRegion(Region const& region)
+ {
+ m_writePos = (m_writePos + region.second) % m_bufferSize;
+
+ m_bufferUsed.fetchAndAddRelease(region.second);
+ }
+
+ int used() const;
+ int free() const;
+ int size() const;
+
+ void reset();
+
+private:
+ int m_bufferSize;
+ int m_readPos;
+ int m_writePos;
+ char* m_buffer;
+ QAtomicInt m_bufferUsed;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIO_MAC_P_H
+
+
diff --git a/src/multimedia/audio/qaudiodevicefactory.cpp b/src/multimedia/audio/qaudiodevicefactory.cpp
new file mode 100644
index 0000000..35e9c91
--- /dev/null
+++ b/src/multimedia/audio/qaudiodevicefactory.cpp
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qdebug.h>
+#include <QtMultimedia/qaudioengine.h>
+#include <QtMultimedia/qaudioengineplugin.h>
+#include <private/qfactoryloader_p.h>
+#include "qaudiodevicefactory_p.h"
+#include "qaudiodeviceid_p.h"
+
+#if defined(Q_OS_WIN)
+#include "qaudiodeviceinfo_win32_p.h"
+#include "qaudiooutput_win32_p.h"
+#include "qaudioinput_win32_p.h"
+#elif defined(Q_OS_MAC)
+#include "qaudiodeviceinfo_mac_p.h"
+#include "qaudiooutput_mac_p.h"
+#include "qaudioinput_mac_p.h"
+#elif defined(HAS_ALSA)
+#include "qaudiodeviceinfo_alsa_p.h"
+#include "qaudiooutput_alsa_p.h"
+#include "qaudioinput_alsa_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QAudioEngineFactoryInterface_iid, QLatin1String("/audio"), Qt::CaseInsensitive))
+
+
+class QNullDeviceInfo : public QAbstractAudioDeviceInfo
+{
+public:
+ QAudioFormat preferredFormat() const { qWarning()<<"using null deviceinfo, none available"; return QAudioFormat(); }
+ bool isFormatSupported(const QAudioFormat& ) const { return false; }
+ QAudioFormat nearestFormat(const QAudioFormat& ) const { return QAudioFormat(); }
+ QString deviceName() const { return QString(); }
+ QStringList codecList() { return QStringList(); }
+ QList<int> frequencyList() { return QList<int>(); }
+ QList<int> channelsList() { return QList<int>(); }
+ QList<int> sampleSizeList() { return QList<int>(); }
+ QList<QAudioFormat::Endian> byteOrderList() { return QList<QAudioFormat::Endian>(); }
+ QList<QAudioFormat::SampleType> sampleTypeList() { return QList<QAudioFormat::SampleType>(); }
+};
+
+class QNullInputDevice : public QAbstractAudioInput
+{
+public:
+ QIODevice* start(QIODevice* ) { qWarning()<<"using null input device, none available"; return 0; }
+ void stop() {}
+ void reset() {}
+ void suspend() {}
+ void resume() {}
+ int bytesReady() const { return 0; }
+ int periodSize() const { return 0; }
+ void setBufferSize(int ) {}
+ int bufferSize() const { return 0; }
+ void setNotifyInterval(int ) {}
+ int notifyInterval() const { return 0; }
+ qint64 totalTime() const { return 0; }
+ qint64 clock() const { return 0; }
+ QAudio::Error error() const { return QAudio::OpenError; }
+ QAudio::State state() const { return QAudio::StopState; }
+ QAudioFormat format() const { return QAudioFormat(); }
+};
+
+class QNullOutputDevice : public QAbstractAudioOutput
+{
+public:
+ QIODevice* start(QIODevice* ) { qWarning()<<"using null output device, none available"; return 0; }
+ void stop() {}
+ void reset() {}
+ void suspend() {}
+ void resume() {}
+ int bytesFree() const { return 0; }
+ int periodSize() const { return 0; }
+ void setBufferSize(int ) {}
+ int bufferSize() const { return 0; }
+ void setNotifyInterval(int ) {}
+ int notifyInterval() const { return 0; }
+ qint64 totalTime() const { return 0; }
+ qint64 clock() const { return 0; }
+ QAudio::Error error() const { return QAudio::OpenError; }
+ QAudio::State state() const { return QAudio::StopState; }
+ QAudioFormat format() const { return QAudioFormat(); }
+};
+
+QList<QAudioDeviceId> QAudioDeviceFactory::deviceList(QAudio::Mode mode)
+{
+ QList<QAudioDeviceId> devices;
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ foreach (const QByteArray &handle, QAudioDeviceInfoPrivate::deviceList(mode))
+ devices += createDeviceId(QLatin1String("builtin"), mode, handle);
+#endif
+ QFactoryLoader* l = loader();
+
+ foreach (QString const& key, l->keys()) {
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(l->instance(key));
+ if (plugin) {
+ foreach (QByteArray const& handle, plugin->deviceList(mode))
+ devices += createDeviceId(key, mode, handle);
+ }
+
+ delete plugin;
+ }
+
+ return devices;
+}
+
+QAudioDeviceId QAudioDeviceFactory::defaultInputDevice()
+{
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(QLatin1String("default")));
+
+ if (plugin) {
+ QList<QByteArray> list = plugin->deviceList(QAudio::AudioInput);
+ if (list.size() > 0)
+ return createDeviceId(QLatin1String("default"), QAudio::AudioInput, list.at(0));
+ }
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ return createDeviceId(QLatin1String("builtin"), QAudio::AudioInput, QAudioDeviceInfoPrivate::defaultInputDevice());
+#endif
+ return QAudioDeviceId();
+}
+
+QAudioDeviceId QAudioDeviceFactory::defaultOutputDevice()
+{
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(QLatin1String("default")));
+
+ if (plugin) {
+ QList<QByteArray> list = plugin->deviceList(QAudio::AudioOutput);
+ if (list.size() > 0)
+ return createDeviceId(QLatin1String("default"), QAudio::AudioOutput, list.at(0));
+ }
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ return createDeviceId(QLatin1String("builtin"), QAudio::AudioOutput, QAudioDeviceInfoPrivate::defaultOutputDevice());
+#endif
+ return QAudioDeviceId();
+}
+
+QAbstractAudioDeviceInfo* QAudioDeviceFactory::audioDeviceInfo(QAudioDeviceId const& id)
+{
+ if (id.isNull())
+ return new QNullDeviceInfo();
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ if (id.d->key == QLatin1String("builtin"))
+ return new QAudioDeviceInfoPrivate(id.d->handle, QAudio::Mode(id.d->mode));
+#endif
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(id.d->key));
+
+ if (plugin)
+ return plugin->createDeviceInfo(id.d->handle, QAudio::Mode(id.d->mode));
+
+ return new QNullDeviceInfo();
+}
+
+QAbstractAudioInput* QAudioDeviceFactory::createDefaultInputDevice(QAudioFormat const &format)
+{
+ return createInputDevice(defaultInputDevice(), format);
+}
+
+QAbstractAudioOutput* QAudioDeviceFactory::createDefaultOutputDevice(QAudioFormat const &format)
+{
+ return createOutputDevice(defaultOutputDevice(), format);
+}
+
+QAbstractAudioInput* QAudioDeviceFactory::createInputDevice(QAudioDeviceId const& id, QAudioFormat const &format)
+{
+ if (id.isNull())
+ return new QNullInputDevice();
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ if (id.d->key == QLatin1String("builtin")) {
+ if(!defaultInputDevice().isNull())
+ return new QAudioInputPrivate(id.d->handle, format);
+ else
+ return new QNullInputDevice();
+ }
+#endif
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance((id.d->key)));
+
+ if (plugin)
+ return plugin->createInput(id.d->handle, format);
+
+ return new QNullInputDevice();
+}
+
+QAbstractAudioOutput* QAudioDeviceFactory::createOutputDevice(QAudioDeviceId const& id, QAudioFormat const &format)
+{
+ if (id.isNull())
+ return new QNullOutputDevice();
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ if (id.d->key == QLatin1String("builtin")) {
+ if(!defaultOutputDevice().isNull())
+ return new QAudioOutputPrivate(id.d->handle, format);
+ else
+ return new QNullOutputDevice();
+ }
+#endif
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(id.d->key));
+
+ if (plugin)
+ return plugin->createOutput(id.d->handle, format);
+
+ return new QNullOutputDevice();
+}
+
+QAudioDeviceId QAudioDeviceFactory::createDeviceId(QString const& key, int mode, QByteArray const& handle)
+{
+ return QAudioDeviceId(new QAudioDeviceIdPrivate(key, mode, handle));
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudiodevicefactory_p.h b/src/multimedia/audio/qaudiodevicefactory_p.h
new file mode 100644
index 0000000..a8e2b28
--- /dev/null
+++ b/src/multimedia/audio/qaudiodevicefactory_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIODEVICEFACTORY_P_H
+#define QAUDIODEVICEFACTORY_P_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qlist.h>
+
+#include <QtMultimedia/qaudiodeviceid.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+class QAbstractAudioInput;
+class QAbstractAudioOutput;
+
+
+class QAudioDeviceFactory
+{
+public:
+ static QList<QAudioDeviceId> deviceList(QAudio::Mode mode);
+
+ static QAudioDeviceId defaultInputDevice();
+ static QAudioDeviceId defaultOutputDevice();
+
+ static QAbstractAudioDeviceInfo* audioDeviceInfo(QAudioDeviceId const &device);
+
+ static QAbstractAudioInput* createDefaultInputDevice(QAudioFormat const &format);
+ static QAbstractAudioOutput* createDefaultOutputDevice(QAudioFormat const &format);
+
+ static QAbstractAudioInput* createInputDevice(QAudioDeviceId const &device, QAudioFormat const &format);
+ static QAbstractAudioOutput* createOutputDevice(QAudioDeviceId const &device, QAudioFormat const &format);
+
+ static QAbstractAudioInput* createNullInput();
+ static QAbstractAudioOutput* createNullOutput();
+
+ static QAudioDeviceId createDeviceId(QString const& key, int mode, QByteArray const& handle);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIODEVICEFACTORY_P_H
+
diff --git a/src/multimedia/audio/qaudiodeviceid.cpp b/src/multimedia/audio/qaudiodeviceid.cpp
new file mode 100644
index 0000000..21a9cd8
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceid.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qstring.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdatastream.h>
+
+#include <QtMultimedia/qaudiodeviceid.h>
+#include "qaudiodeviceid_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioDeviceId
+ \brief The QAudioDeviceId class provides means for identifying a unique input or output device on a system.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \since 4.6
+
+ \sa QAudioDeviceInfo, QAudioOutput, QAudioInput
+*/
+
+/*!
+ Construct a new null QAudioDeviceId.
+*/
+
+QAudioDeviceId::QAudioDeviceId()
+{
+}
+
+/*!
+ Copy the QAudDeviceId referenced by \a other.
+*/
+
+QAudioDeviceId::QAudioDeviceId(const QAudioDeviceId &other):
+ d(other.d)
+{
+}
+
+/*!
+ Destroy the QAudioDeviceId.
+*/
+
+QAudioDeviceId::~QAudioDeviceId()
+{
+}
+
+/*!
+ Make a copy of the \a other QAudioDeviceId.
+*/
+
+QAudioDeviceId& QAudioDeviceId::operator=(const QAudioDeviceId &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Compare with the \a other QAudioDeviceId, return true if they are the same;
+ otherwise false.
+*/
+
+bool QAudioDeviceId::operator==(const QAudioDeviceId &other) const
+{
+ return (d.constData() == 0 && other.d.constData() == 0) ||
+ (d.constData() != 0 && other.d.constData() != 0 &&
+ d->key == other.d->key && d->mode == other.d->mode && d->handle == other.d->handle);
+}
+
+/*!
+ Compare with the \a other QAudioDeviceId, return false if they are the same;
+ otherwise true.
+*/
+
+bool QAudioDeviceId::operator!=(const QAudioDeviceId &other) const
+{
+ return !(*this == other);
+}
+
+/*!
+ Returns true if this is not a valid QAudioDeviceId; otherwise false.
+*/
+
+bool QAudioDeviceId::isNull() const
+{
+ return d.constData() == 0;
+}
+
+/*!
+ \internal
+*/
+
+QAudioDeviceId::QAudioDeviceId(QAudioDeviceIdPrivate* data):
+ d(data)
+{
+}
+
+/*!
+ \internal
+*/
+
+QAudioDeviceIdPrivate::QAudioDeviceIdPrivate(QString const& k, int m, QByteArray const& h):
+ key(k), mode(m), handle(h)
+{
+}
+
+#ifndef QT_NO_DATASTREAM
+Q_MULTIMEDIA_EXPORT QDataStream &operator<<(QDataStream &s, const QAudioDeviceId &id)
+{
+ s << id.d->key << id.d->mode << id.d->handle;
+ return s;
+}
+
+Q_MULTIMEDIA_EXPORT QDataStream &operator>>(QDataStream &s, QAudioDeviceId &id)
+{
+ QString key;
+ int mode;
+ QByteArray handle;
+
+ s >> key >> mode >> handle;
+ id = QAudioDeviceId(new QAudioDeviceIdPrivate(key, mode, handle));
+
+ return s;
+}
+#endif
+
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiodeviceid.h b/src/multimedia/audio/qaudiodeviceid.h
new file mode 100644
index 0000000..f9188d3
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceid.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QAUDIODEVICEID_H
+#define QAUDIODEVICEID_H
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qmetatype.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAudioDeviceFactory;
+class QAudioDeviceIdPrivate;
+
+class Q_MULTIMEDIA_EXPORT QAudioDeviceId
+{
+ friend class QAudioDeviceFactory;
+ friend Q_MULTIMEDIA_EXPORT QDataStream &operator<<(QDataStream&, const QAudioDeviceId&);
+ friend Q_MULTIMEDIA_EXPORT QDataStream &operator>>(QDataStream&, QAudioDeviceId&);
+
+public:
+ QAudioDeviceId();
+ QAudioDeviceId(const QAudioDeviceId &other);
+ ~QAudioDeviceId();
+
+ QAudioDeviceId& operator=(const QAudioDeviceId &other);
+ bool operator==(const QAudioDeviceId &id) const;
+ bool operator!=(const QAudioDeviceId &id) const;
+
+ bool isNull() const;
+
+private:
+ QAudioDeviceId(QAudioDeviceIdPrivate *data);
+
+ QSharedDataPointer<QAudioDeviceIdPrivate> d;
+};
+
+#ifndef QT_NO_DATASTREAM
+Q_MULTIMEDIA_EXPORT QDataStream &operator<<(QDataStream&, const QAudioDeviceId&);
+Q_MULTIMEDIA_EXPORT QDataStream &operator>>(QDataStream&, QAudioDeviceId&);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+Q_DECLARE_METATYPE(QAudioDeviceId);
+
+
+#endif // QAUDIODEVICEID_H
diff --git a/src/multimedia/audio/qaudiodeviceid_p.h b/src/multimedia/audio/qaudiodeviceid_p.h
new file mode 100644
index 0000000..3034574
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceid_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIODEVICEIDPRIVATE_H
+#define QAUDIODEVICEIDPRIVATE_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAudioDeviceIdPrivate : public QSharedData
+{
+public:
+ QAudioDeviceIdPrivate(QString const& k, int m, QByteArray const& h);
+
+ QString key;
+ int mode;
+ QByteArray handle;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIODEVICEIDPRIVATE_H
diff --git a/src/multimedia/audio/qaudiodeviceinfo.cpp b/src/multimedia/audio/qaudiodeviceinfo.cpp
new file mode 100644
index 0000000..c1895d7
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo.cpp
@@ -0,0 +1,270 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaudiodevicefactory_p.h"
+#include <QtMultimedia/qaudioengine.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioDeviceInfo
+ \brief The QAudioDeviceInfo class provides an interface to query audio devices and their functionality.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \since 4.6
+
+ QAudioDeviceInfo lets you query for audio devices--such as sound
+ cards and USB headsets--that are currently available on the system.
+ The audio devices available are dependent on the platform or audio plugins installed.
+
+ You can also query each device for the formats it supports. A
+ format in this context is a set consisting of a specific byte
+ order, channel, codec, frequency, sample rate, and sample type. A
+ format is represented by the QAudioFormat class.
+
+ The values supported by the the device for each of these
+ parameters can be fetched with
+ supportedByteOrders(), supportedChannels(), supportedCodecs(),
+ supportedFrequencies(), supportedSampleSizes(), and
+ supportedSampleTypes(). The combinations supported are dependent on the platform,
+ audio plugins installed and the audio device capabilities. If you need a specific format, you can check if
+ the device supports it with isFormatSupported(), or fetch a
+ supported format that is as close as possible to the format with
+ nearestFormat().
+
+ A QAudioDeviceInfo is constructed with a QAudioDeviceId, which is
+ an identifier for a physical device. It is used by Qt to construct
+ classes that communicate with the device--such as
+ QAudioDeviceInfo, QAudioInput, and QAudioOutput. The static
+ functions defaultInputDevice(), defaultOutputDevice(), and
+ deviceList() let you get a hold of the ids for all available
+ devices. You fetch ids based on whether you will use the device
+ for input or output; this is specified by the QAudio::Mode enum.
+ The QAudioDeviceId returned are only valid for the QAudio::Mode.
+
+ For instance:
+
+ \code
+ foreach(QAudioDeviceId audioId, QAudioDeviceInfo::deviceList(QAudio::AudioOutput)) {
+ QAudioDeviceInfo info(audioId);
+ qDebug() << "Device name: " << info.deviceName();
+ }
+ \endcode
+
+ In this code sample, we loop through all devices that are able to output
+ sound, i.e., play an audio stream in a supported format. For each device we
+ find, we simply print the deviceName().
+
+ \sa QAudioOutput, QAudioInput, QAudioDeviceId
+*/
+
+/*!
+ Construct a new audio device info and attach it to \a parent.
+ Using the audio device with the specified \a id.
+*/
+
+QAudioDeviceInfo::QAudioDeviceInfo(const QAudioDeviceId &id, QObject *parent):
+ QObject(parent)
+{
+ d = QAudioDeviceFactory::audioDeviceInfo(id);
+}
+
+/*!
+ Destroy this audio device info.
+*/
+
+QAudioDeviceInfo::~QAudioDeviceInfo()
+{
+ delete d;
+}
+
+/*!
+ Returns human readable name of audio device.
+
+ Device names vary depending on platform/audio plugin being used.
+
+ They are a unique string identifiers for the audio device.
+
+ eg. default, Intel, U0x46d0x9a4
+*/
+
+QString QAudioDeviceInfo::deviceName() const
+{
+ return d->deviceName();
+}
+
+/*!
+ Returns true if \a settings are supported by the audio device of this QAudioDeviceInfo.
+*/
+
+bool QAudioDeviceInfo::isFormatSupported(const QAudioFormat &settings) const
+{
+ return d->isFormatSupported(settings);
+}
+
+/*!
+ Returns QAudioFormat of default settings.
+
+ These settings are provided by the platform/audio plugin being used.
+
+ They also are dependent on the QAudio::Mode being used.
+
+ A typical audio system would provide something like:
+ \list
+ \o Input settings: 8000Hz mono 8 bit.
+ \o Output settings: 44100Hz stereo 16 bit little endian.
+ \endlist
+*/
+
+QAudioFormat QAudioDeviceInfo::preferredFormat() const
+{
+ return d->preferredFormat();
+}
+
+/*!
+ Returns closest QAudioFormat to \a settings that system audio supports.
+
+ These settings are provided by the platform/audio plugin being used.
+
+ They also are dependent on the QAudio::Mode being used.
+*/
+
+QAudioFormat QAudioDeviceInfo::nearestFormat(const QAudioFormat &settings) const
+{
+ return d->nearestFormat(settings);
+}
+
+/*!
+ Returns a list of supported codecs.
+
+ All platform and plugin implementations should provide support for:
+
+ "audio/pcm" - Linear PCM
+
+ For writing plugins to support additional codecs refer to:
+
+ http://www.iana.org/assignments/media-types/audio/
+*/
+
+QStringList QAudioDeviceInfo::supportedCodecs() const
+{
+ return d->codecList();
+}
+
+/*!
+ Returns a list of supported frequencies.
+*/
+
+QList<int> QAudioDeviceInfo::supportedFrequencies() const
+{
+ return d->frequencyList();
+}
+
+/*!
+ Returns a list of supported channels.
+*/
+
+QList<int> QAudioDeviceInfo::supportedChannels() const
+{
+ return d->channelsList();
+}
+
+/*!
+ Returns a list of supported sample sizes.
+*/
+
+QList<int> QAudioDeviceInfo::supportedSampleSizes() const
+{
+ return d->sampleSizeList();
+}
+
+/*!
+ Returns a list of supported byte orders.
+*/
+
+QList<QAudioFormat::Endian> QAudioDeviceInfo::supportedByteOrders() const
+{
+ return d->byteOrderList();
+}
+
+/*!
+ Returns a list of supported sample types.
+*/
+
+QList<QAudioFormat::SampleType> QAudioDeviceInfo::supportedSampleTypes() const
+{
+ return d->sampleTypeList();
+}
+
+/*!
+ Returns the name of the default input audio device.
+ All platform and audio plugin implementations provide a default audio device to use.
+*/
+
+QAudioDeviceId QAudioDeviceInfo::defaultInputDevice()
+{
+ return QAudioDeviceFactory::defaultInputDevice();
+}
+
+/*!
+ Returns the name of the default output audio device.
+ All platform and audio plugin implementations provide a default audio device to use.
+*/
+
+QAudioDeviceId QAudioDeviceInfo::defaultOutputDevice()
+{
+ return QAudioDeviceFactory::defaultOutputDevice();
+}
+
+/*!
+ Returns a list of audio devices that support \a mode.
+*/
+
+QList<QAudioDeviceId> QAudioDeviceInfo::deviceList(QAudio::Mode mode)
+{
+ return QAudioDeviceFactory::deviceList(mode);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudiodeviceinfo.h b/src/multimedia/audio/qaudiodeviceinfo.h
new file mode 100644
index 0000000..444a00a
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIODEVICEINFO_H
+#define QAUDIODEVICEINFO_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodeviceid.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAbstractAudioDeviceInfo;
+
+class Q_MULTIMEDIA_EXPORT QAudioDeviceInfo : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QAudioDeviceInfo(const QAudioDeviceId &id, QObject *parent = 0);
+ ~QAudioDeviceInfo();
+
+ QString deviceName() const;
+
+ bool isFormatSupported(const QAudioFormat &format) const;
+ QAudioFormat preferredFormat() const;
+ QAudioFormat nearestFormat(const QAudioFormat &format) const;
+
+ QStringList supportedCodecs() const;
+ QList<int> supportedFrequencies() const;
+ QList<int> supportedChannels() const;
+ QList<int> supportedSampleSizes() const;
+ QList<QAudioFormat::Endian> supportedByteOrders() const;
+ QList<QAudioFormat::SampleType> supportedSampleTypes() const;
+
+ static QAudioDeviceId defaultInputDevice();
+ static QAudioDeviceId defaultOutputDevice();
+
+ static QList<QAudioDeviceId> deviceList(QAudio::Mode mode);
+
+private:
+ Q_DISABLE_COPY(QAudioDeviceInfo)
+
+ QAbstractAudioDeviceInfo* d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIODEVICEINFO_H
diff --git a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp
new file mode 100644
index 0000000..fe45f82
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp
@@ -0,0 +1,394 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qaudiodeviceinfo_alsa_p.h"
+
+QAudioDeviceInfoPrivate::QAudioDeviceInfoPrivate(QByteArray dev, QAudio::Mode mode)
+{
+ handle = 0;
+
+ device = QLatin1String(dev);
+ this->mode = mode;
+}
+
+QAudioDeviceInfoPrivate::~QAudioDeviceInfoPrivate()
+{
+ close();
+}
+
+bool QAudioDeviceInfoPrivate::isFormatSupported(const QAudioFormat& format) const
+{
+ return testSettings(format);
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::preferredFormat() const
+{
+ QAudioFormat nearest;
+ if(mode == QAudio::AudioOutput) {
+ nearest.setFrequency(44100);
+ nearest.setChannels(2);
+ nearest.setByteOrder(QAudioFormat::LittleEndian);
+ nearest.setSampleType(QAudioFormat::SignedInt);
+ nearest.setSampleSize(16);
+ nearest.setCodec(tr("audio/pcm"));
+ } else {
+ nearest.setFrequency(8000);
+ nearest.setChannels(1);
+ nearest.setSampleType(QAudioFormat::SignedInt);
+ nearest.setSampleSize(8);
+ nearest.setCodec(tr("audio/pcm"));
+ }
+ return nearest;
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::nearestFormat(const QAudioFormat& format) const
+{
+ if(testSettings(format))
+ return format;
+ else
+ return preferredFormat();
+}
+
+QString QAudioDeviceInfoPrivate::deviceName() const
+{
+ return device;
+}
+
+QStringList QAudioDeviceInfoPrivate::codecList()
+{
+ updateLists();
+ return codecz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::frequencyList()
+{
+ updateLists();
+ return freqz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::channelsList()
+{
+ updateLists();
+ return channelz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::sampleSizeList()
+{
+ updateLists();
+ return sizez;
+}
+
+QList<QAudioFormat::Endian> QAudioDeviceInfoPrivate::byteOrderList()
+{
+ updateLists();
+ return byteOrderz;
+}
+
+QList<QAudioFormat::SampleType> QAudioDeviceInfoPrivate::sampleTypeList()
+{
+ updateLists();
+ return typez;
+}
+
+bool QAudioDeviceInfoPrivate::open()
+{
+ int err = 0;
+ QString dev = device;
+ if(!dev.contains(tr("default"))) {
+ int idx = snd_card_get_index(dev.toLocal8Bit().constData());
+ dev = QString(tr("hw:%1,0")).arg(idx);
+ }
+ if(mode == QAudio::AudioOutput) {
+ err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
+ } else {
+ err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
+ }
+ if(err < 0) {
+ handle = 0;
+ return false;
+ }
+ return true;
+}
+
+void QAudioDeviceInfoPrivate::close()
+{
+ if(handle)
+ snd_pcm_close(handle);
+ handle = 0;
+}
+
+bool QAudioDeviceInfoPrivate::testSettings(const QAudioFormat& format) const
+{
+ // Set nearest to closest settings that do work.
+ // See if what is in settings will work (return value).
+
+ int err = 0;
+ snd_pcm_t* handle;
+ snd_pcm_hw_params_t *params;
+ QString dev = device;
+
+ // open()
+ if(!dev.contains(tr("default"))) {
+ int idx = snd_card_get_index(dev.toLocal8Bit().constData());
+ dev = QString(tr("hw:%1,0")).arg(idx);
+ }
+ if(mode == QAudio::AudioOutput) {
+ err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
+ } else {
+ err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
+ }
+ if(err < 0) {
+ handle = 0;
+ return false;
+ }
+
+ bool testChannel = false;
+ bool testCodec = false;
+ bool testFreq = false;
+ bool testType = false;
+ bool testSize = false;
+
+ int dir = 0;
+
+ snd_pcm_nonblock( handle, 0 );
+ snd_pcm_hw_params_alloca( &params );
+ snd_pcm_hw_params_any( handle, params );
+
+ // For now, just accept only audio/pcm codec
+ if(!format.codec().startsWith(tr("audio/pcm"))) {
+ err=-1;
+ } else
+ testCodec = true;
+
+ if(err>=0 && format.channels() != -1) {
+ err = snd_pcm_hw_params_test_channels(handle,params,format.channels());
+ if(err>=0)
+ err = snd_pcm_hw_params_set_channels(handle,params,format.channels());
+ if(err>=0)
+ testChannel = true;
+ }
+
+ if(err>=0 && format.frequency() != -1) {
+ err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0);
+ if(err>=0)
+ err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
+ if(err>=0)
+ testFreq = true;
+ }
+
+ if((err>=0 && format.sampleSize() != -1) &&
+ (format.sampleType() != QAudioFormat::Unknown)) {
+ switch(format.sampleSize()) {
+ case 8:
+ if(format.sampleType() == QAudioFormat::SignedInt)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
+ else if(format.sampleType() == QAudioFormat::UnSignedInt)
+ 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)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
+ else if(format.byteOrder() == QAudioFormat::BigEndian)
+ 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)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
+ else if(format.byteOrder() == QAudioFormat::BigEndian)
+ 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)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
+ else if(format.byteOrder() == QAudioFormat::BigEndian)
+ 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)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
+ else if(format.byteOrder() == QAudioFormat::BigEndian)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
+ }
+ }
+ if(err>=0) {
+ testSize = true;
+ testType = true;
+ }
+ }
+ if(err>=0)
+ err = snd_pcm_hw_params(handle, params);
+
+ if(err == 0) {
+ // settings work
+ // close()
+ if(handle)
+ snd_pcm_close(handle);
+ return true;
+ }
+ if(handle)
+ snd_pcm_close(handle);
+
+ return false;
+}
+
+void QAudioDeviceInfoPrivate::updateLists()
+{
+ // redo all lists based on current settings
+ freqz.clear();
+ channelz.clear();
+ sizez.clear();
+ byteOrderz.clear();
+ typez.clear();
+ codecz.clear();
+
+ if(!handle)
+ open();
+
+ if(!handle)
+ return;
+
+ for(int i=0; i<(int)MAX_SAMPLE_RATES; i++) {
+ //if(snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0)
+ freqz.append(SAMPLE_RATES[i]);
+ }
+ channelz.append(1);
+ channelz.append(2);
+ sizez.append(8);
+ sizez.append(16);
+ sizez.append(32);
+ byteOrderz.append(QAudioFormat::LittleEndian);
+ byteOrderz.append(QAudioFormat::BigEndian);
+ typez.append(QAudioFormat::SignedInt);
+ typez.append(QAudioFormat::UnSignedInt);
+ typez.append(QAudioFormat::Float);
+ codecz.append(tr("audio/pcm"));
+ close();
+}
+
+QList<QByteArray> QAudioDeviceInfoPrivate::deviceList(QAudio::Mode mode)
+{
+ QAudio::Mode _m;
+ QList<QByteArray> devices;
+ QByteArray filter;
+ QString dir;
+
+ // Create a list of all current audio devices that support mode
+ void **hints, **n;
+ char *name, *descr, *io;
+
+ if(snd_device_name_hint(-1, "pcm", &hints) < 0) {
+ qWarning()<<"no alsa devices available";
+ return devices;
+ }
+ n = hints;
+
+ while (*n != NULL) {
+ _m = QAudio::AudioOutput;
+ name = snd_device_name_get_hint(*n, "NAME");
+ descr = snd_device_name_get_hint(*n, "DESC");
+ io = snd_device_name_get_hint(*n, "IOID");
+ dir = QString::fromUtf8(io);
+ if((name != NULL) && (descr != NULL) && ((io == NULL) || (dir.length() ==filter.length()))) {
+ if(dir.length() == 5)
+ _m = QAudio::AudioInput;
+ if(io == NULL)
+ _m = mode;
+
+ QString str = tr(name);
+
+ if(str.contains(tr("default"))) {
+ int pos = str.indexOf(tr("="),0);
+ devices.append(str.mid(pos+1).toLocal8Bit().constData());
+ }
+ }
+ if(name != NULL)
+ free(name);
+ if(descr != NULL)
+ free(descr);
+ if(io != NULL)
+ free(io);
+ n++;
+ }
+ snd_device_name_free_hint(hints);
+
+ if(devices.size() > 0) {
+ devices.append("default");
+ if(mode == QAudio::AudioInput) {
+ filter.append("Input");
+ } else {
+ filter.append("Output");
+ }
+ }
+
+ return devices;
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultInputDevice()
+{
+ QList<QByteArray> devices = deviceList(QAudio::AudioInput);
+ if(devices.size() == 0)
+ return QByteArray();
+
+ return QByteArray("default");
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultOutputDevice()
+{
+ QList<QByteArray> devices = deviceList(QAudio::AudioOutput);
+ if(devices.size() == 0)
+ return QByteArray();
+
+ return QByteArray("default");
+}
+
+
diff --git a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h
new file mode 100644
index 0000000..3ac9239
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QAUDIODEVICEINFOALSA_H
+#define QAUDIODEVICEINFOALSA_H
+
+#include <alsa/asoundlib.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+const unsigned int MAX_SAMPLE_RATES = 5;
+const unsigned int SAMPLE_RATES[] =
+ { 8000, 11025, 22050, 44100, 48000 };
+
+class QAudioDeviceInfoPrivate : public QAbstractAudioDeviceInfo
+{
+ Q_OBJECT
+public:
+ QAudioDeviceInfoPrivate(QByteArray dev,QAudio::Mode mode);
+ ~QAudioDeviceInfoPrivate();
+
+ bool testSettings(const QAudioFormat& format) const;
+ void updateLists();
+ QAudioFormat preferredFormat() const;
+ bool isFormatSupported(const QAudioFormat& format) const;
+ QAudioFormat nearestFormat(const QAudioFormat& format) const;
+ QString deviceName() const;
+ QStringList codecList();
+ QList<int> frequencyList();
+ QList<int> channelsList();
+ QList<int> sampleSizeList();
+ QList<QAudioFormat::Endian> byteOrderList();
+ QList<QAudioFormat::SampleType> sampleTypeList();
+ static QByteArray defaultInputDevice();
+ static QByteArray defaultOutputDevice();
+ static QList<QByteArray> deviceList(QAudio::Mode);
+
+private:
+ bool open();
+ void close();
+
+ QString device;
+ QAudio::Mode mode;
+ QAudioFormat nearest;
+ QList<int> freqz;
+ QList<int> channelz;
+ QList<int> sizez;
+ QList<QAudioFormat::Endian> byteOrderz;
+ QStringList codecz;
+ QList<QAudioFormat::SampleType> typez;
+ snd_pcm_t* handle;
+ snd_pcm_hw_params_t *params;
+};
+
+#endif
+
diff --git a/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp
new file mode 100644
index 0000000..c94e0c4
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp
@@ -0,0 +1,357 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qdebug.h>
+#include <private/qcore_mac_p.h>
+
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include "qaudio_mac_p.h"
+#include "qaudiodeviceinfo_mac_p.h"
+
+
+
+QT_BEGIN_NAMESPACE
+
+
+QAudioDeviceInfoPrivate::QAudioDeviceInfoPrivate(QByteArray const& handle, QAudio::Mode)
+{
+ QDataStream ds(handle);
+ quint32 did, tm;
+
+ ds >> did >> tm >> name;
+ deviceId = AudioDeviceID(did);
+ mode = QAudio::Mode(tm);
+}
+
+bool QAudioDeviceInfoPrivate::isFormatSupported(const QAudioFormat& format) const
+{
+ return format.codec() == QString::fromLatin1("audio/pcm");
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::preferredFormat() const
+{
+ QAudioFormat rc;
+
+ UInt32 propSize = 0;
+
+ if (AudioDeviceGetPropertyInfo(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyStreams,
+ &propSize,
+ 0) == noErr) {
+
+ const int sc = propSize / sizeof(AudioStreamID);
+
+ if (sc > 0) {
+ AudioStreamID* streams = new AudioStreamID[sc];
+
+ if (AudioDeviceGetProperty(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyStreams,
+ &propSize,
+ streams) == noErr) {
+
+ for (int i = 0; i < sc; ++i) {
+ if (AudioStreamGetPropertyInfo(streams[i],
+ 0,
+ kAudioStreamPropertyPhysicalFormat,
+ &propSize,
+ 0) == noErr) {
+
+ AudioStreamBasicDescription sf;
+
+ if (AudioStreamGetProperty(streams[i],
+ 0,
+ kAudioStreamPropertyPhysicalFormat,
+ &propSize,
+ &sf) == noErr) {
+ rc = toQAudioFormat(sf);
+ break;
+ }
+ }
+ }
+ }
+
+ delete streams;
+ }
+ }
+
+ return rc;
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::nearestFormat(const QAudioFormat& format) const
+{
+ QAudioFormat rc(format);
+ QAudioFormat target = preferredFormat();
+
+ if (!format.codec().isEmpty() && format.codec() != QString::fromLatin1("audio/pcm"))
+ return QAudioFormat();
+
+ rc.setCodec(QString::fromLatin1("audio/pcm"));
+
+ if (rc.frequency() != target.frequency())
+ rc.setFrequency(target.frequency());
+ if (rc.channels() != target.channels())
+ rc.setChannels(target.channels());
+ if (rc.sampleSize() != target.sampleSize())
+ rc.setSampleSize(target.sampleSize());
+ if (rc.byteOrder() != target.byteOrder())
+ rc.setByteOrder(target.byteOrder());
+ if (rc.sampleType() != target.sampleType())
+ rc.setSampleType(target.sampleType());
+
+ return rc;
+}
+
+QString QAudioDeviceInfoPrivate::deviceName() const
+{
+ return name;
+}
+
+QStringList QAudioDeviceInfoPrivate::codecList()
+{
+ return QStringList() << QString::fromLatin1("audio/pcm");
+}
+
+QList<int> QAudioDeviceInfoPrivate::frequencyList()
+{
+ QSet<int> rc;
+
+ // Add some common frequencies
+ rc << 8000 << 11025 << 22050 << 44100;
+
+ //
+ UInt32 propSize = 0;
+
+ if (AudioDeviceGetPropertyInfo(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyAvailableNominalSampleRates,
+ &propSize,
+ 0) == noErr) {
+
+ const int pc = propSize / sizeof(AudioValueRange);
+
+ if (pc > 0) {
+ AudioValueRange* vr = new AudioValueRange[pc];
+
+ if (AudioDeviceGetProperty(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyAvailableNominalSampleRates,
+ &propSize,
+ vr) == noErr) {
+
+ for (int i = 0; i < pc; ++i)
+ rc << vr[i].mMaximum;
+ }
+
+ delete vr;
+ }
+ }
+
+ return rc.toList();
+}
+
+QList<int> QAudioDeviceInfoPrivate::channelsList()
+{
+ QList<int> rc;
+
+ // Can mix down to 1 channel
+ rc << 1;
+
+ UInt32 propSize = 0;
+ int channels = 0;
+
+ if (AudioDeviceGetPropertyInfo(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyStreamConfiguration,
+ &propSize,
+ 0) == noErr) {
+
+ AudioBufferList* audioBufferList = static_cast<AudioBufferList*>(qMalloc(propSize));
+
+ if (audioBufferList != 0) {
+ if (AudioDeviceGetProperty(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyStreamConfiguration,
+ &propSize,
+ audioBufferList) == noErr) {
+
+ for (int i = 0; i < int(audioBufferList->mNumberBuffers); ++i) {
+ channels += audioBufferList->mBuffers[i].mNumberChannels;
+ rc << channels;
+ }
+ }
+
+ qFree(audioBufferList);
+ }
+ }
+
+ return rc;
+}
+
+QList<int> QAudioDeviceInfoPrivate::sampleSizeList()
+{
+ return QList<int>() << 8 << 16 << 24 << 32 << 64;
+}
+
+QList<QAudioFormat::Endian> QAudioDeviceInfoPrivate::byteOrderList()
+{
+ return QList<QAudioFormat::Endian>() << QAudioFormat::LittleEndian << QAudioFormat::BigEndian;
+}
+
+QList<QAudioFormat::SampleType> QAudioDeviceInfoPrivate::sampleTypeList()
+{
+ return QList<QAudioFormat::SampleType>() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float;
+}
+
+static QByteArray get_device_info(AudioDeviceID audioDevice, QAudio::Mode mode)
+{
+ UInt32 size;
+ QByteArray device;
+ QDataStream ds(&device, QIODevice::WriteOnly);
+ AudioStreamBasicDescription sf;
+ CFStringRef name;
+ Boolean isInput = mode == QAudio::AudioInput;
+
+ // Id
+ ds << quint32(audioDevice);
+
+ // Mode
+ size = sizeof(AudioStreamBasicDescription);
+ if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioDevicePropertyStreamFormat,
+ &size, &sf) != noErr) {
+ return QByteArray();
+ }
+ ds << quint32(mode);
+
+ // Name
+ size = sizeof(CFStringRef);
+ if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioObjectPropertyName,
+ &size, &name) != noErr) {
+ qWarning() << "QAudioDeviceInfo: Unable to find device name";
+ }
+ ds << QCFString::toQString(name);
+
+ CFRelease(name);
+
+ return device;
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultInputDevice()
+{
+ AudioDeviceID audioDevice;
+ UInt32 size = sizeof(audioDevice);
+
+ if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size,
+ &audioDevice) != noErr) {
+ qWarning() << "QAudioDeviceInfo: Unable to find default input device";
+ return QByteArray();
+ }
+
+ return get_device_info(audioDevice, QAudio::AudioInput);
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultOutputDevice()
+{
+ AudioDeviceID audioDevice;
+ UInt32 size = sizeof(audioDevice);
+
+ if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size,
+ &audioDevice) != noErr) {
+ qWarning() << "QAudioDeviceInfo: Unable to find default output device";
+ return QByteArray();
+ }
+
+ return get_device_info(audioDevice, QAudio::AudioOutput);
+}
+
+QList<QByteArray> QAudioDeviceInfoPrivate::deviceList(QAudio::Mode mode)
+{
+ QList<QByteArray> devices;
+
+ UInt32 propSize = 0;
+
+ if (AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propSize, 0) == noErr) {
+
+ const int dc = propSize / sizeof(AudioDeviceID);
+
+ if (dc > 0) {
+ AudioDeviceID* audioDevices = new AudioDeviceID[dc];
+
+ if (AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propSize, audioDevices) == noErr) {
+ for (int i = 0; i < dc; ++i) {
+ QByteArray info = get_device_info(audioDevices[i], mode);
+ if (!info.isNull())
+ devices << info;
+ }
+ }
+
+ delete audioDevices;
+ }
+ }
+
+ return devices;
+}
+
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudiodeviceinfo_mac_p.h b/src/multimedia/audio/qaudiodeviceinfo_mac_p.h
new file mode 100644
index 0000000..ee593de
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_mac_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QDEVICEINFO_MAC_P_H
+#define QDEVICEINFO_MAC_P_H
+
+#include <CoreAudio/CoreAudio.h>
+
+#include <QtMultimedia/qaudioengine.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QAudioDeviceInfoPrivate : public QAbstractAudioDeviceInfo
+{
+public:
+ AudioDeviceID deviceId;
+ QString name;
+ QAudio::Mode mode;
+
+ QAudioDeviceInfoPrivate(QByteArray const& handle, QAudio::Mode mode);
+
+ bool isFormatSupported(const QAudioFormat& format) const;
+ QAudioFormat preferredFormat() const;
+ QAudioFormat nearestFormat(const QAudioFormat& format) const;
+
+ QString deviceName() const;
+
+ QStringList codecList();
+ QList<int> frequencyList();
+ QList<int> channelsList();
+ QList<int> sampleSizeList();
+ QList<QAudioFormat::Endian> byteOrderList();
+ QList<QAudioFormat::SampleType> sampleTypeList();
+
+ static QByteArray defaultInputDevice();
+ static QByteArray defaultOutputDevice();
+
+ static QList<QByteArray> deviceList(QAudio::Mode mode);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDEVICEINFO_MAC_P_H
diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp
new file mode 100644
index 0000000..1a1995a
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <windows.h>
+#include <mmsystem.h>
+#include "qaudiodeviceinfo_win32_p.h"
+
+// For mingw toolchain mmsystem.h only defines half the defines, so add if needed.
+#ifndef WAVE_FORMAT_44M08
+#define WAVE_FORMAT_44M08 0x00000100
+#define WAVE_FORMAT_44S08 0x00000200
+#define WAVE_FORMAT_44M16 0x00000400
+#define WAVE_FORMAT_44S16 0x00000800
+#define WAVE_FORMAT_48M08 0x00001000
+#define WAVE_FORMAT_48S08 0x00002000
+#define WAVE_FORMAT_48M16 0x00004000
+#define WAVE_FORMAT_48S16 0x00008000
+#define WAVE_FORMAT_96M08 0x00010000
+#define WAVE_FORMAT_96S08 0x00020000
+#define WAVE_FORMAT_96M16 0x00040000
+#define WAVE_FORMAT_96S16 0x00080000
+#endif
+
+
+QAudioDeviceInfoPrivate::QAudioDeviceInfoPrivate(QByteArray dev, QAudio::Mode mode)
+{
+ device = QLatin1String(dev);
+ this->mode = mode;
+}
+
+QAudioDeviceInfoPrivate::~QAudioDeviceInfoPrivate()
+{
+ close();
+}
+
+bool QAudioDeviceInfoPrivate::isFormatSupported(const QAudioFormat& format) const
+{
+ return testSettings(format);
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::preferredFormat() const
+{
+ QAudioFormat nearest;
+ if(mode == QAudio::AudioOutput) {
+ nearest.setFrequency(44100);
+ nearest.setChannels(2);
+ nearest.setByteOrder(QAudioFormat::LittleEndian);
+ nearest.setSampleType(QAudioFormat::SignedInt);
+ nearest.setSampleSize(16);
+ nearest.setCodec(tr("audio/pcm"));
+ } else {
+ nearest.setFrequency(11025);
+ nearest.setChannels(1);
+ nearest.setSampleType(QAudioFormat::SignedInt);
+ nearest.setSampleSize(8);
+ nearest.setCodec(tr("audio/pcm"));
+ }
+ return nearest;
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::nearestFormat(const QAudioFormat& format) const
+{
+ if(testSettings(format))
+ return format;
+ else
+ return preferredFormat();
+}
+
+QString QAudioDeviceInfoPrivate::deviceName() const
+{
+ return device;
+}
+
+QStringList QAudioDeviceInfoPrivate::codecList()
+{
+ updateLists();
+ return codecz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::frequencyList()
+{
+ updateLists();
+ return freqz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::channelsList()
+{
+ updateLists();
+ return channelz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::sampleSizeList()
+{
+ updateLists();
+ return sizez;
+}
+
+QList<QAudioFormat::Endian> QAudioDeviceInfoPrivate::byteOrderList()
+{
+ updateLists();
+ return byteOrderz;
+}
+
+QList<QAudioFormat::SampleType> QAudioDeviceInfoPrivate::sampleTypeList()
+{
+ updateLists();
+ return typez;
+}
+
+
+bool QAudioDeviceInfoPrivate::open()
+{
+ return true;
+}
+
+void QAudioDeviceInfoPrivate::close()
+{
+}
+
+bool QAudioDeviceInfoPrivate::testSettings(const QAudioFormat& format) const
+{
+ // Set nearest to closest settings that do work.
+ // See if what is in settings will work (return value).
+
+ bool testChannel = false;
+ bool testCodec = false;
+ bool testFreq = false;
+
+ int err = 0;
+
+ // For now, just accept only audio/pcm codec
+ if(!format.codec().startsWith(tr("audio/pcm"))) {
+ err=-1;
+ } else
+ testCodec = true;
+
+ if(err>=0 && format.channels() != -1) {
+ testChannel = true;
+ }
+
+ if(err>=0 && format.frequency() != -1) {
+ testFreq = true;
+ }
+
+ if(err == 0) {
+ // settings work
+ return true;
+ }
+ return false;
+}
+
+void QAudioDeviceInfoPrivate::updateLists()
+{
+ // redo all lists based on current settings
+ bool base = false;
+ bool match = false;
+ DWORD fmt = NULL;
+ QString tmp;
+
+ if(device.compare(tr("default")) == 0)
+ base = true;
+
+ if(mode == QAudio::AudioOutput) {
+ WAVEOUTCAPS woc;
+ unsigned long iNumDevs,i;
+ iNumDevs = waveOutGetNumDevs();
+ for(i=0;i<iNumDevs;i++) {
+ if(waveOutGetDevCaps(i, &woc, sizeof(WAVEOUTCAPS))
+ == MMSYSERR_NOERROR) {
+ tmp = QString::fromUtf16((const unsigned short*)woc.szPname);
+ if(tmp.compare(device) == 0) {
+ match = true;
+ fmt = woc.dwFormats;
+ break;
+ }
+ if(base) {
+ match = true;
+ fmt = woc.dwFormats;
+ break;
+ }
+ }
+ }
+ } else {
+ WAVEINCAPS woc;
+ unsigned long iNumDevs,i;
+ iNumDevs = waveInGetNumDevs();
+ for(i=0;i<iNumDevs;i++) {
+ if(waveInGetDevCaps(i, &woc, sizeof(WAVEINCAPS))
+ == MMSYSERR_NOERROR) {
+ tmp = QString::fromUtf16((const unsigned short*)woc.szPname);
+ if(tmp.compare(device) == 0) {
+ match = true;
+ fmt = woc.dwFormats;
+ break;
+ }
+ if(base) {
+ match = true;
+ fmt = woc.dwFormats;
+ break;
+ }
+ }
+ }
+ }
+ sizez.clear();
+ freqz.clear();
+ channelz.clear();
+ byteOrderz.clear();
+ typez.clear();
+ codecz.clear();
+
+ if(match) {
+ if((fmt && WAVE_FORMAT_1M08)
+ || (fmt && WAVE_FORMAT_1S08)
+ || (fmt && WAVE_FORMAT_2M08)
+ || (fmt && WAVE_FORMAT_2S08)
+ || (fmt && WAVE_FORMAT_4M08)
+ || (fmt && WAVE_FORMAT_4S08)
+#ifndef Q_OS_WINCE
+ || (fmt && WAVE_FORMAT_48M08)
+ || (fmt && WAVE_FORMAT_48S08)
+ || (fmt && WAVE_FORMAT_96M08)
+ || (fmt && WAVE_FORMAT_96S08)
+#endif
+ ) {
+ sizez.append(8);
+ }
+ if((fmt && WAVE_FORMAT_1M16)
+ || (fmt && WAVE_FORMAT_1S16)
+ || (fmt && WAVE_FORMAT_2M16)
+ || (fmt && WAVE_FORMAT_2S16)
+ || (fmt && WAVE_FORMAT_4M16)
+ || (fmt && WAVE_FORMAT_4S16)
+#ifndef Q_OS_WINCE
+ || (fmt && WAVE_FORMAT_48M16)
+ || (fmt && WAVE_FORMAT_48S16)
+ || (fmt && WAVE_FORMAT_96M16)
+ || (fmt && WAVE_FORMAT_96S16)
+#endif
+ ) {
+ sizez.append(16);
+ }
+ if((fmt && WAVE_FORMAT_1M08)
+ || (fmt && WAVE_FORMAT_1S08)
+ || (fmt && WAVE_FORMAT_1M16)
+ || (fmt && WAVE_FORMAT_1S16)) {
+ freqz.append(11025);
+ }
+ if((fmt && WAVE_FORMAT_2M08)
+ || (fmt && WAVE_FORMAT_2S08)
+ || (fmt && WAVE_FORMAT_2M16)
+ || (fmt && WAVE_FORMAT_2S16)) {
+ freqz.append(22050);
+ }
+ if((fmt && WAVE_FORMAT_4M08)
+ || (fmt && WAVE_FORMAT_4S08)
+ || (fmt && WAVE_FORMAT_4M16)
+ || (fmt && WAVE_FORMAT_4S16)) {
+ freqz.append(44100);
+ }
+#ifndef Q_OS_WINCE
+ if((fmt && WAVE_FORMAT_48M08)
+ || (fmt && WAVE_FORMAT_48S08)
+ || (fmt && WAVE_FORMAT_48M16)
+ || (fmt && WAVE_FORMAT_48S16)) {
+ freqz.append(48000);
+ }
+ if((fmt && WAVE_FORMAT_96M08)
+ || (fmt && WAVE_FORMAT_96S08)
+ || (fmt && WAVE_FORMAT_96M16)
+ || (fmt && WAVE_FORMAT_96S16)) {
+ freqz.append(96000);
+ }
+#endif
+ channelz.append(1);
+ channelz.append(2);
+
+ byteOrderz.append(QAudioFormat::LittleEndian);
+
+ typez.append(QAudioFormat::SignedInt);
+ typez.append(QAudioFormat::UnSignedInt);
+
+ codecz.append(tr("audio/pcm"));
+ }
+}
+
+QList<QByteArray> QAudioDeviceInfoPrivate::deviceList(QAudio::Mode mode)
+{
+ Q_UNUSED(mode)
+
+ QList<QByteArray> devices;
+
+ devices.append("default");
+
+ if(mode == QAudio::AudioOutput) {
+ WAVEOUTCAPS woc;
+ unsigned long iNumDevs,i;
+ iNumDevs = waveOutGetNumDevs();
+ for(i=0;i<iNumDevs;i++) {
+ if(waveOutGetDevCaps(i, &woc, sizeof(WAVEOUTCAPS))
+ == MMSYSERR_NOERROR) {
+ devices.append(QString::fromUtf16((const unsigned short*)woc.szPname).toLocal8Bit().constData());
+ }
+ }
+ } else {
+ WAVEINCAPS woc;
+ unsigned long iNumDevs,i;
+ iNumDevs = waveInGetNumDevs();
+ for(i=0;i<iNumDevs;i++) {
+ if(waveInGetDevCaps(i, &woc, sizeof(WAVEINCAPS))
+ == MMSYSERR_NOERROR) {
+ devices.append(QString::fromUtf16((const unsigned short*)woc.szPname).toLocal8Bit().constData());
+ }
+ }
+
+ }
+ return devices;
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultOutputDevice()
+{
+ return QByteArray("default");
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultInputDevice()
+{
+ return QByteArray("default");
+}
+
diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.h b/src/multimedia/audio/qaudiodeviceinfo_win32_p.h
new file mode 100644
index 0000000..140a741
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_win32_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QAUDIODEVICEINFOWIN_H
+#define QAUDIODEVICEINFOWIN_H
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+
+const unsigned int MAX_SAMPLE_RATES = 5;
+const unsigned int SAMPLE_RATES[] = { 8000, 11025, 22050, 44100, 48000 };
+
+class QAudioDeviceInfoPrivate : public QAbstractAudioDeviceInfo
+{
+ Q_OBJECT
+
+public:
+ QAudioDeviceInfoPrivate(QByteArray dev,QAudio::Mode mode);
+ ~QAudioDeviceInfoPrivate();
+
+ bool open();
+ void close();
+
+ bool testSettings(const QAudioFormat& format) const;
+ void updateLists();
+ QAudioFormat preferredFormat() const;
+ bool isFormatSupported(const QAudioFormat& format) const;
+ QAudioFormat nearestFormat(const QAudioFormat& format) const;
+ QString deviceName() const;
+ QStringList codecList();
+ QList<int> frequencyList();
+ QList<int> channelsList();
+ QList<int> sampleSizeList();
+ QList<QAudioFormat::Endian> byteOrderList();
+ QList<QAudioFormat::SampleType> sampleTypeList();
+ static QByteArray defaultInputDevice();
+ static QByteArray defaultOutputDevice();
+ static QList<QByteArray> deviceList(QAudio::Mode);
+
+private:
+ QAudio::Mode mode;
+ QString device;
+ QAudioFormat nearest;
+ QList<int> freqz;
+ QList<int> channelz;
+ QList<int> sizez;
+ QList<QAudioFormat::Endian> byteOrderz;
+ QStringList codecz;
+ QList<QAudioFormat::SampleType> typez;
+};
+
+#endif
diff --git a/src/multimedia/audio/qaudioengine.cpp b/src/multimedia/audio/qaudioengine.cpp
new file mode 100644
index 0000000..930977e
--- /dev/null
+++ b/src/multimedia/audio/qaudioengine.cpp
@@ -0,0 +1,343 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtMultimedia/qaudioengine.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractAudioDeviceInfo
+ \brief The QAbstractAudioDeviceInfo class provides access for QAudioDeviceInfo to access the audio
+ device provided by the plugin.
+ \internal
+
+ \ingroup multimedia
+
+ This class implements the audio functionality for
+ QAudioDeviceInfo, i.e., QAudioDeviceInfo keeps a
+ QAbstractAudioDeviceInfo and routes function calls to it. For a
+ description of the functionality that QAbstractAudioDeviceInfo
+ implements, you can read the class and functions documentation of
+ QAudioDeviceInfo.
+
+ \sa QAudioDeviceInfo
+*/
+
+/*!
+ \fn virtual QAudioFormat QAbstractAudioDeviceInfo::preferredFormat() const
+ Returns the nearest settings.
+*/
+
+/*!
+ \fn virtual bool QAbstractAudioDeviceInfo::isFormatSupported(const QAudioFormat& format) const
+ Returns true if \a format is available from audio device.
+*/
+
+/*!
+ \fn virtual QAudioFormat QAbstractAudioDeviceInfo::nearestFormat(const QAudioFormat& format) const
+ Returns the nearest settings \a format.
+*/
+
+/*!
+ \fn virtual QString QAbstractAudioDeviceInfo::deviceName() const
+ Returns the audio device name.
+*/
+
+/*!
+ \fn virtual QStringList QAbstractAudioDeviceInfo::codecList()
+ Returns the list of currently available codecs.
+*/
+
+/*!
+ \fn virtual QList<int> QAbstractAudioDeviceInfo::frequencyList()
+ Returns the list of currently available frequencies.
+*/
+
+/*!
+ \fn virtual QList<int> QAbstractAudioDeviceInfo::channelsList()
+ Returns the list of currently available channels.
+*/
+
+/*!
+ \fn virtual QList<int> QAbstractAudioDeviceInfo::sampleSizeList()
+ Returns the list of currently available sample sizes.
+*/
+
+/*!
+ \fn virtual QList<QAudioFormat::Endian> QAbstractAudioDeviceInfo::byteOrderList()
+ Returns the list of currently available byte orders.
+*/
+
+/*!
+ \fn virtual QList<QAudioFormat::SampleType> QAbstractAudioDeviceInfo::sampleTypeList()
+ Returns the list of currently available sample types.
+*/
+
+/*!
+ \class QAbstractAudioOutput
+ \brief The QAbstractAudioOutput class provides access for QAudioOutput to access the audio
+ device provided by the plugin.
+ \internal
+
+ \ingroup multimedia
+
+ QAbstractAudioOutput implements audio functionality for
+ QAudioOutput, i.e., QAudioOutput routes function calls to
+ QAbstractAudioOutput. For a description of the functionality that
+ is implemented, see the QAudioOutput class and function
+ descriptions.
+
+ \sa QAudioOutput
+*/
+
+/*!
+ \fn virtual QIODevice* QAbstractAudioOutput::start(QIODevice* device)
+ Uses the \a device as the QIODevice to transfer data. If \a device is null then the class
+ creates an internal QIODevice. Returns a pointer to the QIODevice being used to handle
+ the data transfer. This QIODevice can be used to write() audio data directly. Passing a
+ QIODevice allows the data to be transfered without any extra code.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::stop()
+ Stops the audio output.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::reset()
+ Drops all audio data in the buffers, resets buffers to zero.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::suspend()
+ Stops processing audio data, preserving buffered audio data.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::resume()
+ Resumes processing audio data after a suspend()
+*/
+
+/*!
+ \fn virtual int QAbstractAudioOutput::bytesFree() const
+ Returns the free space available in bytes in the audio buffer.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioOutput::periodSize() const
+ Returns the period size in bytes.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::setBufferSize(int value)
+ Sets the audio buffer size to \a value in bytes.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioOutput::bufferSize() const
+ Returns the audio buffer size in bytes.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::setNotifyInterval(int ms)
+ Sets the interval for notify() signal to be emitted. This is based on the \a ms
+ of audio data processed not on actual real-time. The resolution of the timer
+ is platform specific.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioOutput::notifyInterval() const
+ Returns the notify interval in milliseconds.
+*/
+
+/*!
+ \fn virtual qint64 QAbstractAudioOutput::totalTime() const
+ Returns the amount of audio data processed since start() was called in milliseconds.
+*/
+
+/*!
+ \fn virtual qint64 QAbstractAudioOutput::clock() const
+ Returns the milliseconds since start() was called, including time in Idle and suspend states.
+*/
+
+/*!
+ \fn virtual QAudio::Error QAbstractAudioOutput::error() const
+ Returns the error state.
+*/
+
+/*!
+ \fn virtual QAudio::State QAbstractAudioOutput::state() const
+ Returns the state of audio processing.
+*/
+
+/*!
+ \fn virtual QAudioFormat QAbstractAudioOutput::format() const
+ Returns the QAudioFormat being used.
+*/
+
+/*!
+ \fn QAbstractAudioOutput::stateChanged(QAudio::State state)
+ This signal is emitted when the device \a state has changed.
+*/
+
+/*!
+ \fn QAbstractAudioOutput::notify()
+ This signal is emitted when x ms of audio data has been processed
+ the interval set by setNotifyInterval(x).
+*/
+
+
+/*!
+ \class QAbstractAudioInput
+ \brief The QAbstractAudioInput class provides access for QAudioInput to access the audio
+ device provided by the plugin.
+ \internal
+
+ \ingroup multimedia
+
+ QAudioDeviceInput keeps an instance of QAbstractAudioInput and
+ routes calls to functions of the same name to QAbstractAudioInput.
+ This means that it is QAbstractAudioInput that implements the
+ audio functionality. For a description of the functionality, see
+ the QAudioInput class description.
+
+ \sa QAudioInput
+*/
+
+/*!
+ \fn virtual QIODevice* QAbstractAudioInput::start(QIODevice* device)
+ Uses the \a device as the QIODevice to transfer data. If \a device is null
+ then the class creates an internal QIODevice. Returns a pointer to the
+ QIODevice being used to handle the data transfer. This QIODevice can be used to
+ read() audio data directly. Passing a QIODevice allows the data to be transfered
+ without any extra code.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::stop()
+ Stops the audio input.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::reset()
+ Drops all audio data in the buffers, resets buffers to zero.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::suspend()
+ Stops processing audio data, preserving buffered audio data.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::resume()
+ Resumes processing audio data after a suspend().
+*/
+
+/*!
+ \fn virtual int QAbstractAudioInput::bytesReady() const
+ Returns the amount of audio data available to read in bytes.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioInput::periodSize() const
+ Returns the period size in bytes.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::setBufferSize(int value)
+ Sets the audio buffer size to \a value in milliseconds.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioInput::bufferSize() const
+ Returns the audio buffer size in milliseconds.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::setNotifyInterval(int ms)
+ Sets the interval for notify() signal to be emitted. This is based
+ on the \a ms of audio data processed not on actual real-time.
+ The resolution of the timer is platform specific.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioInput::notifyInterval() const
+ Returns the notify interval in milliseconds.
+*/
+
+/*!
+ \fn virtual qint64 QAbstractAudioInput::totalTime() const
+ Returns the amount of audio data processed since start() was called in milliseconds.
+*/
+
+/*!
+ \fn virtual qint64 QAbstractAudioInput::clock() const
+ Returns the milliseconds since start() was called, including time in Idle and suspend states.
+*/
+
+/*!
+ \fn virtual QAudio::Error QAbstractAudioInput::error() const
+ Returns the error state.
+*/
+
+/*!
+ \fn virtual QAudio::State QAbstractAudioInput::state() const
+ Returns the state of audio processing.
+*/
+
+/*!
+ \fn virtual QAudioFormat QAbstractAudioInput::format() const
+ Returns the QAudioFormat being used
+*/
+
+/*!
+ \fn QAbstractAudioInput::stateChanged(QAudio::State state)
+ This signal is emitted when the device \a state has changed.
+*/
+
+/*!
+ \fn QAbstractAudioInput::notify()
+ This signal is emitted when x ms of audio data has been processed
+ the interval set by setNotifyInterval(x).
+*/
+
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudioengine.h b/src/multimedia/audio/qaudioengine.h
new file mode 100644
index 0000000..b0aa762
--- /dev/null
+++ b/src/multimedia/audio/qaudioengine.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QAUDIOENGINE_H
+#define QAUDIOENGINE_H
+
+#include <QtCore/qglobal.h>
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+class Q_MULTIMEDIA_EXPORT QAbstractAudioDeviceInfo : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual QAudioFormat preferredFormat() const = 0;
+ virtual bool isFormatSupported(const QAudioFormat &format) const = 0;
+ virtual QAudioFormat nearestFormat(const QAudioFormat &format) const = 0;
+ virtual QString deviceName() const = 0;
+ virtual QStringList codecList() = 0;
+ virtual QList<int> frequencyList() = 0;
+ virtual QList<int> channelsList() = 0;
+ virtual QList<int> sampleSizeList() = 0;
+ virtual QList<QAudioFormat::Endian> byteOrderList() = 0;
+ virtual QList<QAudioFormat::SampleType> sampleTypeList() = 0;
+};
+
+class Q_MULTIMEDIA_EXPORT QAbstractAudioOutput : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual QIODevice* start(QIODevice* device) = 0;
+ virtual void stop() = 0;
+ virtual void reset() = 0;
+ virtual void suspend() = 0;
+ virtual void resume() = 0;
+ virtual int bytesFree() const = 0;
+ virtual int periodSize() const = 0;
+ virtual void setBufferSize(int value) = 0;
+ virtual int bufferSize() const = 0;
+ virtual void setNotifyInterval(int milliSeconds) = 0;
+ virtual int notifyInterval() const = 0;
+ virtual qint64 totalTime() const = 0;
+ virtual qint64 clock() const = 0;
+ virtual QAudio::Error error() const = 0;
+ virtual QAudio::State state() const = 0;
+ virtual QAudioFormat format() const = 0;
+
+Q_SIGNALS:
+ void stateChanged(QAudio::State);
+ void notify();
+};
+
+class Q_MULTIMEDIA_EXPORT QAbstractAudioInput : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual QIODevice* start(QIODevice* device) = 0;
+ virtual void stop() = 0;
+ virtual void reset() = 0;
+ virtual void suspend() = 0;
+ virtual void resume() = 0;
+ virtual int bytesReady() const = 0;
+ virtual int periodSize() const = 0;
+ virtual void setBufferSize(int value) = 0;
+ virtual int bufferSize() const = 0;
+ virtual void setNotifyInterval(int milliSeconds) = 0;
+ virtual int notifyInterval() const = 0;
+ virtual qint64 totalTime() const = 0;
+ virtual qint64 clock() const = 0;
+ virtual QAudio::Error error() const = 0;
+ virtual QAudio::State state() const = 0;
+ virtual QAudioFormat format() const = 0;
+
+Q_SIGNALS:
+ void stateChanged(QAudio::State);
+ void notify();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOENGINE_H
diff --git a/src/multimedia/audio/qaudioengineplugin.cpp b/src/multimedia/audio/qaudioengineplugin.cpp
new file mode 100644
index 0000000..6e39004
--- /dev/null
+++ b/src/multimedia/audio/qaudioengineplugin.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtMultimedia/qaudioengineplugin.h>
+
+QT_BEGIN_NAMESPACE
+
+QAudioEnginePlugin::QAudioEnginePlugin(QObject* parent) :
+ QObject(parent)
+{}
+
+QAudioEnginePlugin::~QAudioEnginePlugin()
+{}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudioengineplugin.h b/src/multimedia/audio/qaudioengineplugin.h
new file mode 100644
index 0000000..8eab2d7
--- /dev/null
+++ b/src/multimedia/audio/qaudioengineplugin.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIOENGINEPLUGIN_H
+#define QAUDIOENGINEPLUGIN_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+struct Q_MULTIMEDIA_EXPORT QAudioEngineFactoryInterface : public QFactoryInterface
+{
+ virtual QList<QByteArray> deviceList(QAudio::Mode) const = 0;
+ virtual QAbstractAudioInput* createInput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0;
+ virtual QAbstractAudioOutput* createOutput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0;
+ virtual QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) = 0;
+};
+
+#define QAudioEngineFactoryInterface_iid \
+ "com.nokia.qt.QAudioEngineFactoryInterface"
+Q_DECLARE_INTERFACE(QAudioEngineFactoryInterface, QAudioEngineFactoryInterface_iid)
+
+class Q_MULTIMEDIA_EXPORT QAudioEnginePlugin : public QObject, public QAudioEngineFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QAudioEngineFactoryInterface:QFactoryInterface)
+
+public:
+ QAudioEnginePlugin(QObject *parent = 0);
+ ~QAudioEnginePlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QList<QByteArray> deviceList(QAudio::Mode) const = 0;
+ virtual QAbstractAudioInput* createInput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0;
+ virtual QAbstractAudioOutput* createOutput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0;
+ virtual QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOENGINEPLUGIN_H
diff --git a/src/multimedia/audio/qaudioformat.cpp b/src/multimedia/audio/qaudioformat.cpp
new file mode 100644
index 0000000..6632c63
--- /dev/null
+++ b/src/multimedia/audio/qaudioformat.cpp
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtMultimedia/qaudioformat.h>
+
+
+QT_BEGIN_NAMESPACE
+
+
+class QAudioFormatPrivate : public QSharedData
+{
+public:
+ QAudioFormatPrivate()
+ {
+ frequency = -1;
+ channels = -1;
+ sampleSize = -1;
+ byteOrder = QAudioFormat::Endian(QSysInfo::ByteOrder);
+ sampleType = QAudioFormat::Unknown;
+ }
+
+ QString codec;
+ QAudioFormat::Endian byteOrder;
+ QAudioFormat::SampleType sampleType;
+
+ int frequency;
+ int channels;
+ int sampleSize;
+};
+
+/*!
+ \class QAudioFormat
+ \brief The QAudioFormat class stores audio parameter information.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \since 4.6
+
+ An audio format specifies how data in an audio stream is arranged,
+ i.e, how the stream is to be interpreted. The encoding itself is
+ specified by the codec() used for the stream.
+
+ In addition to the encoding, QAudioFormat contains other
+ parameters that further specify how the audio data is arranged.
+ These are the frequency, the number of channels, the sample size,
+ the sample type, and the byte order. The following table describes
+ these in more detail.
+
+ \table
+ \header
+ \o Parameter
+ \o Description
+ \row
+ \o Frequency
+ \o Samples per second of audio data in Hertz.
+ \row
+ \o Number of channels
+ \o The number of audio channels (typically one for mono
+ or two for stereo)
+ \row
+ \o Sample size
+ \o How much data is stored in each sample (typically 8
+ or 16)
+ \row
+ \o Sample type
+ \o Numerical representation of sample (typically signed integer,
+ unsigned integer or float)
+ \row
+ \o Byte order
+ \o Byte ordering of sample (typically little endian, big endian)
+ \endtable
+
+ You can obtain audio formats compatible with the audio device used
+ through functions in QAudioDeviceInfo. This class also lets you
+ query available parameter values for a device, so that you can set
+ the parameters yourself. See the QAudioDeviceInfo class
+ description for details.
+*/
+
+/*!
+ Construct a new audio format.
+
+ Values are initialized as follows:
+ \list
+ \o frequency() = -1
+ \o channels() = -1
+ \o sampleSize() = -1
+ \o byteOrder() = QAudioFormat::Endian(QSysInfo::ByteOrder)
+ \o sampleType() = QAudioFormat::Unknown
+ \c codec() = ""
+ \endlist
+*/
+
+QAudioFormat::QAudioFormat():
+ d(new QAudioFormatPrivate)
+{
+}
+
+/*!
+ Construct a new audio format using \a other.
+*/
+
+QAudioFormat::QAudioFormat(const QAudioFormat &other):
+ d(other.d)
+{
+}
+
+/*!
+ Destroy this audio format.
+*/
+
+QAudioFormat::~QAudioFormat()
+{
+}
+
+/*!
+ Assigns \a other to this QAudioFormat implementation.
+*/
+
+QAudioFormat& QAudioFormat::operator=(const QAudioFormat &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns true if this QAudioFormat is equal to the \a other
+ QAudioFormat; otherwise returns false.
+
+ All elements of QAudioFormat are used for the comparison.
+*/
+
+bool QAudioFormat::operator==(const QAudioFormat &other) const
+{
+ return d->frequency == other.d->frequency &&
+ d->channels == other.d->channels &&
+ d->sampleSize == other.d->sampleSize &&
+ d->byteOrder == other.d->byteOrder &&
+ d->codec == other.d->codec &&
+ d->sampleType == other.d->sampleType;
+}
+
+/*!
+ Returns true if this QAudioFormat is not equal to the \a other
+ QAudioFormat; otherwise returns false.
+
+ All elements of QAudioFormat are used for the comparison.
+*/
+
+bool QAudioFormat::operator!=(const QAudioFormat& other) const
+{
+ return !(*this == other);
+}
+
+/*!
+ Returns true if any of the parameters are invalid.
+*/
+
+bool QAudioFormat::isNull() const
+{
+ return d->frequency == -1 && d->channels == -1 &&
+ d->sampleSize == -1 &&
+ d->byteOrder == QAudioFormat::Endian(QSysInfo::ByteOrder) &&
+ d->sampleType == QAudioFormat::Unknown &&
+ d->codec.isNull();
+}
+
+/*!
+ Sets the frequency to \a frequency.
+*/
+
+void QAudioFormat::setFrequency(int frequency)
+{
+ d->frequency = frequency;
+}
+
+/*!
+ Returns the current frequency value.
+*/
+
+int QAudioFormat::frequency() const
+{
+ return d->frequency;
+}
+
+/*!
+ Sets the channels to \a channels.
+*/
+
+void QAudioFormat::setChannels(int channels)
+{
+ d->channels = channels;
+}
+
+/*!
+ Returns the current channel value.
+*/
+
+int QAudioFormat::channels() const
+{
+ return d->channels;
+}
+
+/*!
+ Sets the sampleSize to \a sampleSize.
+*/
+
+void QAudioFormat::setSampleSize(int sampleSize)
+{
+ d->sampleSize = sampleSize;
+}
+
+/*!
+ Returns the current sampleSize value.
+*/
+
+int QAudioFormat::sampleSize() const
+{
+ return d->sampleSize;
+}
+
+/*!
+ Sets the codec to \a codec.
+
+ \sa QAudioDeviceInfo::supportedCodecs()
+*/
+
+void QAudioFormat::setCodec(QString codec)
+{
+ d->codec = codec;
+}
+
+/*!
+ Returns the current codec value.
+
+ \sa QAudioDeviceInfo::supportedCodecs()
+*/
+
+QString QAudioFormat::codec() const
+{
+ return d->codec;
+}
+
+/*!
+ Sets the byteOrder to \a byteOrder.
+*/
+
+void QAudioFormat::setByteOrder(QAudioFormat::Endian byteOrder)
+{
+ d->byteOrder = byteOrder;
+}
+
+/*!
+ Returns the current byteOrder value.
+*/
+
+QAudioFormat::Endian QAudioFormat::byteOrder() const
+{
+ return d->byteOrder;
+}
+
+/*!
+ Sets the sampleType to \a sampleType.
+*/
+
+void QAudioFormat::setSampleType(QAudioFormat::SampleType sampleType)
+{
+ d->sampleType = sampleType;
+}
+
+/*!
+ Returns the current SampleType value.
+*/
+
+QAudioFormat::SampleType QAudioFormat::sampleType() const
+{
+ return d->sampleType;
+}
+
+/*!
+ \enum QAudioFormat::SampleType
+
+ \value Unknown Not Set
+ \value SignedInt samples are signed integers
+ \value UnSignedInt samples are unsigned intergers
+ \value Float samples are floats
+*/
+
+/*!
+ \enum QAudioFormat::Endian
+
+ \value BigEndian samples are big endian byte order
+ \value LittleEndian samples are little endian byte order
+*/
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudioformat.h b/src/multimedia/audio/qaudioformat.h
new file mode 100644
index 0000000..c740969
--- /dev/null
+++ b/src/multimedia/audio/qaudioformat.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIOFORMAT_H
+#define QAUDIOFORMAT_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qshareddata.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAudioFormatPrivate;
+
+class Q_MULTIMEDIA_EXPORT QAudioFormat
+{
+public:
+ enum SampleType { Unknown, SignedInt, UnSignedInt, Float };
+ enum Endian { BigEndian = QSysInfo::BigEndian, LittleEndian = QSysInfo::LittleEndian };
+
+ QAudioFormat();
+ QAudioFormat(const QAudioFormat &other);
+ ~QAudioFormat();
+
+ QAudioFormat& operator=(const QAudioFormat &other);
+ bool operator==(const QAudioFormat &other) const;
+ bool operator!=(const QAudioFormat &other) const;
+
+ bool isNull() const;
+
+ void setFrequency(int frequency);
+ int frequency() const;
+
+ void setChannels(int channels);
+ int channels() const;
+
+ void setSampleSize(int sampleSize);
+ int sampleSize() const;
+
+ void setCodec(QString codec);
+ QString codec() const;
+
+ void setByteOrder(QAudioFormat::Endian byteOrder);
+ QAudioFormat::Endian byteOrder() const;
+
+ void setSampleType(QAudioFormat::SampleType sampleType);
+ QAudioFormat::SampleType sampleType() const;
+
+private:
+ QSharedDataPointer<QAudioFormatPrivate> d;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOFORMAT_H
diff --git a/src/multimedia/audio/qaudioinput.cpp b/src/multimedia/audio/qaudioinput.cpp
new file mode 100644
index 0000000..17cacc6
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput.cpp
@@ -0,0 +1,400 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+#include <QtMultimedia/qaudioinput.h>
+
+#include "qaudiodevicefactory_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioInput
+ \brief The QAudioInput class provides an interface for receiving audio data from an audio input device.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \since 4.6
+
+ You can construct an audio input with the system's
+ \l{QAudioDeviceInfo::defaultInputDevice()}{default audio input
+ device}. It is also possible to create QAudioInput with a
+ specific QAudioDeviceId. When you create the audio input, you
+ should also send in the QAudioFormat to be used for the recording
+ (see the QAudioFormat class description for details).
+
+ To record to a file:
+
+ QAudioInput lets you record audio with an audio input device. The
+ default constructor of this class will use the systems default
+ audio device, but you can also specify a QAudioDeviceId for a
+ specific device. You also need to pass in the QAudioFormat in
+ which you wish to record.
+
+ Starting up the QAudioInput is simply a matter of calling start()
+ with a QIODevice opened for writing. For instance, to record to a
+ file, you can:
+
+ \code
+ {
+ QFile outputFile;
+ outputFile.setFileName("/tmp/test.raw");
+ outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
+
+ QAudioFormat format;
+ // set up the format you want, eg.
+ format.setFrequency(8000);
+ format.setChannels(1);
+ format.setSampleSize(8);
+ format.setCodec("audio/pcm");
+ format.setByteOrder(QAudioFormat::LittleEndian);
+ format.setSampleType(QAudioFormat::UnSignedInt);
+
+ QAudioInput *audio = new QAudioInput(format, this);
+ QTimer::singleShot(3000, this, SLOT(stopRecording()));
+ audio->start(outputFile);
+ // Records audio for 3000ms
+ }
+ \endcode
+
+ This will start recording if the format specified is supported by
+ the input device (you can check this with
+ QAudioDeviceInfo::isFormatSupported(). In case there are any
+ snags, use the error() function to check what went wrong. We stop
+ recording in the \c stopRecording() slot.
+
+ \code
+ void stopRecording()
+ {
+ audio->stop();
+ outputFile->close();
+ }
+ \endcode
+
+ At any point in time, QAudioInput will be in one of four states:
+ active, suspended, stopped, or idle. These states are specified by
+ the QAudio::State enum. You can request a state change directly through
+ suspend(), resume(), stop(), reset(), and start(). The current
+ state is reported by state(). QAudioOutput will also signal you
+ when the state changes (stateChanged()).
+
+ QAudioInput provides several ways of measuring the time that has
+ passed since the start() of the recording. The \c totalTime()
+ function returns the length of the stream in microseconds written,
+ i.e., it leaves out the times the audio input was suspended or idle.
+ The clock() function returns the time elapsed since start() was called regardless of
+ which states the QAudioInput has been in.
+
+ If an error should occur, you can fetch its reason with error().
+ The possible error reasons are described by the QAudio::Error enum.
+
+ \sa QAudioOutput, QAudioDeviceInfo
+*/
+
+/*!
+ Construct a new audio input and attach it to \a parent.
+ The default audio input device is used with the output
+ \a format parameters.
+*/
+
+QAudioInput::QAudioInput(const QAudioFormat &format, QObject *parent):
+ QObject(parent)
+{
+ d = QAudioDeviceFactory::createDefaultInputDevice(format);
+ connect(d, SIGNAL(notify()), SIGNAL(notify()));
+ connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
+}
+
+/*!
+ Construct a new audio input and attach it to \a parent.
+ The \a id of the audio input device is used with the input
+ \a format parameters.
+*/
+
+QAudioInput::QAudioInput(const QAudioDeviceId &id, const QAudioFormat &format, QObject *parent):
+ QObject(parent)
+{
+ d = QAudioDeviceFactory::createInputDevice(id, format);
+ connect(d, SIGNAL(notify()), SIGNAL(notify()));
+ connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
+}
+
+/*!
+ Destroy this audio input.
+*/
+
+QAudioInput::~QAudioInput()
+{
+ delete d;
+}
+
+/*!
+ Uses the \a device as the QIODevice to transfer data.
+ If \a device is null then the class creates an internal QIODevice.
+ Returns a pointer to the QIODevice being used to handle the data
+ transfer. This QIODevice can be used to read() audio data
+ directly.
+ Passing a QIODevice allows the data to be transfered without any extra code.
+ All that is required is to open the QIODevice.
+
+ /sa QIODevice
+*/
+
+QIODevice* QAudioInput::start(QIODevice* device)
+{
+ /*
+ PULL MODE (valid QIODevice)
+ -If currently not StopState, stop
+ -If previous start was push mode, delete internal QIODevice.
+ -open audio input.
+ If ok, NoError and ActiveState, else OpenError and StopState.
+ -emit stateChanged()
+ -return device
+
+ PUSH MODE (device = 0)
+ -If currently not StopState, stop
+ -If no internal QIODevice, create one.
+ -open audio input.
+ -If ok, NoError and IdleState, else OpenError and StopState
+ -emit stateChanged()
+ -return internal QIODevice
+ */
+ return d->start(device);
+}
+
+/*!
+ Returns the QAudioFormat being used.
+*/
+
+QAudioFormat QAudioInput::format() const
+{
+ return d->format();
+}
+
+/*!
+ Stops the audio input.
+*/
+
+void QAudioInput::stop()
+{
+ /*
+ -If StopState, return
+ -set to StopState
+ -detach from audio device
+ -emit stateChanged()
+ */
+ d->stop();
+}
+
+/*!
+ Drops all audio data in the buffers, resets buffers to zero.
+*/
+
+void QAudioInput::reset()
+{
+ /*
+ -drop all buffered audio, set buffers to zero.
+ -call stop()
+ */
+ d->reset();
+}
+
+/*!
+ Stops processing audio data, preserving buffered audio data.
+*/
+
+void QAudioInput::suspend()
+{
+ /*
+ -If not ActiveState|IdleState, return
+ -stop processing audio, saving all buffered audio data
+ -set NoError and SuspendState
+ -emit stateChanged()
+ */
+ d->suspend();
+}
+
+/*!
+ Resumes processing audio data after a suspend().
+*/
+
+void QAudioInput::resume()
+{
+ /*
+ -If SuspendState, return
+ -resume audio
+ -(PULL MODE): set ActiveState, NoError
+ -(PUSH MODE): set IdleState, NoError
+ -kick start audio if needed
+ -emit stateChanged()
+ */
+ d->resume();
+}
+
+/*!
+ Sets the audio buffer size to \a value milliseconds.
+
+ Note: This function can be called anytime before start(), calls to this
+ are ignored after start(). It should not be assumed that the buffer size
+ set is the actual buffer size used, calling bufferSize() anytime after start()
+ will return the actual buffer size being used.
+
+*/
+
+void QAudioInput::setBufferSize(int value)
+{
+ d->setBufferSize(value);
+}
+
+/*!
+ Returns the audio buffer size in milliseconds.
+
+ If called before start(), returns platform default value.
+ If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
+ If called after start(), returns the actual buffer size being used. This may not be what was set previously
+ by setBufferSize().
+
+*/
+
+int QAudioInput::bufferSize() const
+{
+ return d->bufferSize();
+}
+
+/*!
+ Returns the amount of audio data available to read in bytes.
+*/
+
+int QAudioInput::bytesReady() const
+{
+ /*
+ -If not ActiveState|IdleState, return 0
+ -return amount of audio data available to read
+ */
+ return d->bytesReady();
+}
+
+/*!
+ Returns the period size in bytes.
+
+ Note: This is the recommended read size in bytes.
+*/
+
+int QAudioInput::periodSize() const
+{
+ return d->periodSize();
+}
+
+/*!
+ Sets the interval for notify() signal to be emitted.
+ This is based on the \a ms of audio data processed
+ not on actual real-time. The resolution of the timer is platform specific.
+*/
+
+void QAudioInput::setNotifyInterval(int ms)
+{
+ d->setNotifyInterval(ms);
+}
+
+/*!
+ Returns the notify interval in milliseconds.
+*/
+
+int QAudioInput::notifyInterval() const
+{
+ return d->notifyInterval();
+}
+
+/*!
+ Returns the amount of audio data processed since start()
+ was called in microseconds.
+*/
+
+qint64 QAudioInput::totalTime() const
+{
+ return d->totalTime();
+}
+
+/*!
+ Returns the microseconds since start() was called, including time in Idle and
+ Suspend states.
+*/
+
+qint64 QAudioInput::clock() const
+{
+ return d->clock();
+}
+
+/*!
+ Returns the error state.
+*/
+
+QAudio::Error QAudioInput::error() const
+{
+ return d->error();
+}
+
+/*!
+ Returns the state of audio processing.
+*/
+
+QAudio::State QAudioInput::state() const
+{
+ return d->state();
+}
+
+/*!
+ \fn QAudioInput::stateChanged(QAudio::State state)
+ This signal is emitted when the device \a state has changed.
+*/
+
+/*!
+ \fn QAudioInput::notify()
+ This signal is emitted when x ms of audio data has been processed
+ the interval set by setNotifyInterval(x).
+*/
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudioinput.h b/src/multimedia/audio/qaudioinput.h
new file mode 100644
index 0000000..b0f1aed
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIOINPUT_H
+#define QAUDIOINPUT_H
+
+#include <QtCore/qiodevice.h>
+#include <QtCore/qglobal.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodeviceid.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAbstractAudioInput;
+
+class Q_MULTIMEDIA_EXPORT QAudioInput : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QAudioInput(const QAudioFormat &format = QAudioFormat(), QObject *parent = 0);
+ explicit QAudioInput(const QAudioDeviceId &id, const QAudioFormat &format = QAudioFormat(), QObject *parent = 0);
+ ~QAudioInput();
+
+ QAudioFormat format() const;
+
+ QIODevice* start(QIODevice *device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+
+ void setBufferSize(int bytes);
+ int bufferSize() const;
+
+ int bytesReady() const;
+ int periodSize() const;
+
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+
+ qint64 totalTime() const;
+ qint64 clock() const;
+
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+Q_SIGNALS:
+ void stateChanged(QAudio::State);
+ void notify();
+
+private:
+ Q_DISABLE_COPY(QAudioInput);
+
+ QAbstractAudioInput* d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOINPUT_H
diff --git a/src/multimedia/audio/qaudioinput_alsa_p.cpp b/src/multimedia/audio/qaudioinput_alsa_p.cpp
new file mode 100644
index 0000000..6f00469
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_alsa_p.cpp
@@ -0,0 +1,688 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qcoreapplication.h>
+#include "qaudioinput_alsa_p.h"
+
+//#define DEBUG_AUDIO 1
+
+QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
+ settings(audioFormat)
+{
+ bytesAvailable = 0;
+ handle = 0;
+ ahandler = 0;
+ access = SND_PCM_ACCESS_RW_INTERLEAVED;
+ pcmformat = SND_PCM_FORMAT_S16;
+ buffer_size = 0;
+ period_size = 0;
+ buffer_time = 100000;
+ period_time = 20000;
+ totalTimeValue = 0;
+ intervalTime = 1000;
+ audioBuffer = 0;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::StopState;
+ audioSource = 0;
+ pullMode = true;
+ resuming = false;
+
+ QStringList list1 = QString(tr(device)).split(tr(":"));
+ m_device = QByteArray(list1.at(0).toLocal8Bit().constData());
+
+ timer = new QTimer(this);
+ connect(timer,SIGNAL(timeout()),SLOT(userFeed()));
+}
+
+QAudioInputPrivate::~QAudioInputPrivate()
+{
+ close();
+ disconnect(timer, SIGNAL(timeout()));
+ QCoreApplication::processEvents();
+ delete timer;
+}
+
+QAudio::Error QAudioInputPrivate::error() const
+{
+ return errorState;
+}
+
+QAudio::State QAudioInputPrivate::state() const
+{
+ return deviceState;
+}
+
+
+QAudioFormat QAudioInputPrivate::format() const
+{
+ return settings;
+}
+
+int QAudioInputPrivate::xrun_recovery(int err)
+{
+ int count = 0;
+ bool reset = false;
+
+ if(err == -EPIPE) {
+ errorState = QAudio::UnderrunError;
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+
+ } else if((err == -ESTRPIPE)||(err == -EIO)) {
+ errorState = QAudio::IOError;
+ while((err = snd_pcm_resume(handle)) == -EAGAIN){
+ usleep(100);
+ count++;
+ if(count > 5) {
+ reset = true;
+ break;
+ }
+ }
+ if(err < 0) {
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+ }
+ }
+ if(reset) {
+ close();
+ open();
+ snd_pcm_prepare(handle);
+ return 0;
+ }
+ return err;
+}
+
+int QAudioInputPrivate::setFormat()
+{
+ snd_pcm_format_t format = SND_PCM_FORMAT_S16;
+
+ if(settings.sampleSize() == 8) {
+ format = SND_PCM_FORMAT_U8;
+ } else if(settings.sampleSize() == 16) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_S16_LE;
+ else
+ format = SND_PCM_FORMAT_S16_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_U16_LE;
+ else
+ format = SND_PCM_FORMAT_U16_BE;
+ }
+ } else if(settings.sampleSize() == 24) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_S24_LE;
+ else
+ format = SND_PCM_FORMAT_S24_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_U24_LE;
+ else
+ format = SND_PCM_FORMAT_U24_BE;
+ }
+ } else if(settings.sampleSize() == 32) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_S32_LE;
+ else
+ format = SND_PCM_FORMAT_S32_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_U32_LE;
+ else
+ format = SND_PCM_FORMAT_U32_BE;
+ } else if(settings.sampleType() == QAudioFormat::Float) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_FLOAT_LE;
+ else
+ format = SND_PCM_FORMAT_FLOAT_BE;
+ }
+ } else if(settings.sampleSize() == 64) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_FLOAT64_LE;
+ else
+ format = SND_PCM_FORMAT_FLOAT64_BE;
+ }
+
+ return snd_pcm_hw_params_set_format( handle, hwparams, format);
+}
+
+QIODevice* QAudioInputPrivate::start(QIODevice* device)
+{
+ if(deviceState != QAudio::StopState)
+ close();
+
+ if(!pullMode && audioSource) {
+ delete audioSource;
+ }
+
+ if(device) {
+ //set to pull mode
+ pullMode = true;
+ audioSource = device;
+ } else {
+ //set to push mode
+ pullMode = false;
+ audioSource = new InputPrivate(this);
+ audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+ }
+
+ if( !open() )
+ return 0;
+
+ emit stateChanged(deviceState);
+
+ return audioSource;
+}
+
+void QAudioInputPrivate::stop()
+{
+ if(deviceState == QAudio::StopState)
+ return;
+
+ deviceState = QAudio::StopState;
+
+ close();
+ emit stateChanged(deviceState);
+}
+
+bool QAudioInputPrivate::open()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
+#endif
+ timeStamp.restart();
+
+ int dir;
+ int err=-1;
+ int count=0;
+ unsigned int freakuency=settings.frequency();
+
+ QString dev = QString(tr(m_device.constData()));
+ if(!dev.contains(tr("default"))) {
+ dev = QString(tr("default:CARD=%1")).arg(tr(m_device.constData()));
+ }
+
+ // Step 1: try and open the device
+ while((count < 5) && (err < 0)) {
+ err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
+ if(err < 0)
+ count++;
+ }
+ if (( err < 0)||(handle == 0)) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ return false;
+ }
+ snd_pcm_nonblock( handle, 0 );
+
+ // Step 2: Set the desired HW parameters.
+ snd_pcm_hw_params_alloca( &hwparams );
+
+ bool fatal = false;
+ QString errMessage;
+ unsigned int chunks = 8;
+
+ err = snd_pcm_hw_params_any( handle, hwparams );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_any: err = %1")).arg(err);
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_rate_resample: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_access( handle, hwparams, access );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_access: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = setFormat();
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_format: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_channels: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_rate_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_period_time_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_periods_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params(handle, hwparams);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params: err = %1")).arg(err);
+ }
+ }
+ if( err < 0) {
+ qWarning()<<errMessage;
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ return false;
+ }
+ snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames);
+ buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames);
+ snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir);
+ period_size = snd_pcm_frames_to_bytes(handle,period_frames);
+ snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
+ snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);
+
+ // Step 3: Set the desired SW parameters.
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_sw_params_alloca(&swparams);
+ snd_pcm_sw_params_current(handle, swparams);
+ snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames);
+ snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames);
+ snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames);
+ snd_pcm_sw_params(handle, swparams);
+
+ // Step 4: Prepare audio
+ if(audioBuffer == 0)
+ audioBuffer = new char[buffer_size];
+ snd_pcm_prepare( handle );
+ snd_pcm_start(handle);
+
+ // Step 5: Setup timer
+ bytesAvailable = bytesReady();
+
+ if(pullMode)
+ connect(audioSource,SIGNAL(readyRead()),this,SLOT(userFeed()));
+
+ // Step 6: Start audio processing
+ chunks = buffer_size/period_size;
+ timer->start(period_time*chunks/2000);
+
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+
+ totalTimeValue = 0;
+
+ return true;
+}
+
+void QAudioInputPrivate::close()
+{
+ deviceState = QAudio::StopState;
+ timer->stop();
+
+ if ( handle ) {
+ snd_pcm_drop( handle );
+ snd_pcm_close( handle );
+ handle = 0;
+ delete [] audioBuffer;
+ audioBuffer=0;
+ }
+}
+
+int QAudioInputPrivate::bytesReady() const
+{
+ if(resuming)
+ return period_size;
+
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+ int frames = snd_pcm_avail_update(handle);
+ if((int)frames > (int)buffer_frames)
+ frames = buffer_frames;
+
+ return snd_pcm_frames_to_bytes(handle, frames);
+}
+
+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();
+
+ int count=0, err = 0;
+ while(count < 5) {
+ int chunks = bytesAvailable/period_size;
+ int frames = chunks*period_frames;
+ if(frames > (int)buffer_frames)
+ frames = buffer_frames;
+ int readFrames = snd_pcm_readi(handle, audioBuffer, frames);
+ if (readFrames >= 0) {
+ err = snd_pcm_frames_to_bytes(handle, readFrames);
+#ifdef DEBUG_AUDIO
+ qDebug()<<QString(tr("PULL: read in bytes = %1 (frames=%2)")).arg(err).arg(readFrames).toLatin1().constData();
+#endif
+ break;
+ } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
+ errorState = QAudio::IOError;
+ err = 0;
+ break;
+ } else {
+ if(readFrames == -EPIPE) {
+ errorState = QAudio::UnderrunError;
+ err = snd_pcm_prepare(handle);
+ } else if(readFrames == -ESTRPIPE) {
+ err = snd_pcm_prepare(handle);
+ }
+ if(err != 0) break;
+ }
+ count++;
+ }
+ if(err > 0) {
+ // got some send it onward
+#ifdef DEBUG_AUDIO
+ qDebug()<<"PULL: frames to write to QIODevice = "<<
+ snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes";
+#endif
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+
+ qint64 l = audioSource->write(audioBuffer,err);
+ if(l < 0) {
+ close();
+ errorState = QAudio::IOError;
+ deviceState = QAudio::StopState;
+ 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();
+ resuming = false;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ }
+ return l;
+ }
+ return 0;
+}
+
+void QAudioInputPrivate::resume()
+{
+ if(deviceState == QAudio::SuspendState) {
+ int err = 0;
+
+ if(handle) {
+ err = snd_pcm_prepare( handle );
+ if(err < 0)
+ xrun_recovery(err);
+
+ err = snd_pcm_start(handle);
+ if(err < 0)
+ xrun_recovery(err);
+
+ bytesAvailable = buffer_size;
+ }
+ resuming = true;
+ deviceState = QAudio::ActiveState;
+ int chunks = buffer_size/period_size;
+ timer->start(buffer_time*chunks/2000);
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioInputPrivate::setBufferSize(int value)
+{
+ buffer_size = value;
+}
+
+int QAudioInputPrivate::bufferSize() const
+{
+ return buffer_size;
+}
+
+int QAudioInputPrivate::periodSize() const
+{
+ return period_size;
+}
+
+void QAudioInputPrivate::setNotifyInterval(int ms)
+{
+ intervalTime = ms;
+}
+
+int QAudioInputPrivate::notifyInterval() const
+{
+ return intervalTime;
+}
+
+qint64 QAudioInputPrivate::totalTime() const
+{
+ return totalTimeValue;
+}
+
+void QAudioInputPrivate::suspend()
+{
+ if(deviceState == QAudio::ActiveState||resuming) {
+ timer->stop();
+ deviceState = QAudio::SuspendState;
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioInputPrivate::userFeed()
+{
+ if(deviceState == QAudio::StopState || deviceState == QAudio::SuspendState)
+ return;
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() IN";
+#endif
+ deviceReady();
+}
+
+bool QAudioInputPrivate::deviceReady()
+{
+ if(pullMode) {
+ // reads some audio data and writes it to QIODevice
+ read(0,0);
+ } else {
+ // emits readyRead() so user will call read() on QIODevice to get some audio data
+ InputPrivate* a = qobject_cast<InputPrivate*>(audioSource);
+ a->trigger();
+ }
+ bytesAvailable = bytesReady();
+
+ if(deviceState != QAudio::ActiveState)
+ return true;
+
+ if(timeStamp.elapsed() > intervalTime && intervalTime > 50) {
+ emit notify();
+ timeStamp.restart();
+ }
+ return true;
+}
+
+qint64 QAudioInputPrivate::clock() const
+{
+ if(!handle)
+ return 0;
+
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+
+ 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 * 1000)+l/1000);
+ } else
+ return 0;
+}
+
+void QAudioInputPrivate::reset()
+{
+ if(handle)
+ snd_pcm_reset(handle);
+}
+
+void QAudioInputPrivate::drain()
+{
+ if(handle)
+ snd_pcm_drain(handle);
+}
+
+InputPrivate::InputPrivate(QAudioInputPrivate* audio)
+{
+ audioDevice = qobject_cast<QAudioInputPrivate*>(audio);
+}
+
+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(tr("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;
+}
+
+qint64 InputPrivate::writeData(const char* data, qint64 len)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(len)
+ return 0;
+}
+
+void InputPrivate::trigger()
+{
+ emit readyRead();
+}
+
diff --git a/src/multimedia/audio/qaudioinput_alsa_p.h b/src/multimedia/audio/qaudioinput_alsa_p.h
new file mode 100644
index 0000000..21c8064
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_alsa_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QAUDIOINPUTALSA_H
+#define QAUDIOINPUTALSA_H
+
+#include <alsa/asoundlib.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+class InputPrivate;
+
+class QAudioInputPrivate : public QAbstractAudioInput
+{
+ Q_OBJECT
+public:
+ QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat);
+ ~QAudioInputPrivate();
+
+ qint64 read(char* data, qint64 len);
+
+ QIODevice* start(QIODevice* device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+ int bytesReady() const;
+ int periodSize() const;
+ void setBufferSize(int value);
+ int bufferSize() const;
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+ qint64 totalTime() const;
+ qint64 clock() const;
+ QAudio::Error error() const;
+ QAudio::State state() const;
+ QAudioFormat format() const;
+ bool resuming;
+ snd_pcm_t* handle;
+ qint64 totalTimeValue;
+ QIODevice* audioSource;
+ QAudioFormat settings;
+ QAudio::Error errorState;
+ QAudio::State deviceState;
+
+private slots:
+ void userFeed();
+ bool deviceReady();
+
+private:
+ int xrun_recovery(int err);
+ int setFormat();
+ bool open();
+ void close();
+ void drain();
+
+ QTimer* timer;
+ QTime timeStamp;
+ int intervalTime;
+ char* audioBuffer;
+ int bytesAvailable;
+ QByteArray m_device;
+ bool pullMode;
+ int buffer_size;
+ int period_size;
+ unsigned int buffer_time;
+ unsigned int period_time;
+ snd_pcm_uframes_t buffer_frames;
+ snd_pcm_uframes_t period_frames;
+ snd_async_handler_t* ahandler;
+ snd_pcm_access_t access;
+ snd_pcm_format_t pcmformat;
+ snd_timestamp_t* timestamp;
+ snd_pcm_hw_params_t *hwparams;
+};
+
+class InputPrivate : public QIODevice
+{
+ Q_OBJECT
+public:
+ InputPrivate(QAudioInputPrivate* audio);
+ ~InputPrivate();
+
+ qint64 readData( char* data, qint64 len);
+ qint64 writeData(const char* data, qint64 len);
+
+ void trigger();
+private:
+ QAudioInputPrivate *audioDevice;
+};
+
+#endif
diff --git a/src/multimedia/audio/qaudioinput_mac_p.cpp b/src/multimedia/audio/qaudioinput_mac_p.cpp
new file mode 100644
index 0000000..5400c85
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_mac_p.cpp
@@ -0,0 +1,930 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qendian.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qdebug.h>
+
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioinput.h>
+
+#include "qaudio_mac_p.h"
+#include "qaudioinput_mac_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+
+namespace
+{
+
+static const int default_buffer_size = 4 * 1024;
+
+class QAudioBufferList
+{
+public:
+ QAudioBufferList(AudioStreamBasicDescription const& streamFormat):
+ owner(false),
+ sf(streamFormat)
+ {
+ const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
+ const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame;
+
+ dataSize = 0;
+
+ bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) +
+ (sizeof(AudioBuffer) * numberOfBuffers)));
+
+ bfs->mNumberBuffers = numberOfBuffers;
+ for (int i = 0; i < numberOfBuffers; ++i) {
+ bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
+ bfs->mBuffers[i].mDataByteSize = 0;
+ bfs->mBuffers[i].mData = 0;
+ }
+ }
+
+ QAudioBufferList(AudioStreamBasicDescription const& streamFormat, char* buffer, int bufferSize):
+ owner(false),
+ sf(streamFormat),
+ bfs(0)
+ {
+ dataSize = bufferSize;
+
+ bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) + sizeof(AudioBuffer)));
+
+ bfs->mNumberBuffers = 1;
+ bfs->mBuffers[0].mNumberChannels = 1;
+ bfs->mBuffers[0].mDataByteSize = dataSize;
+ bfs->mBuffers[0].mData = buffer;
+ }
+
+ QAudioBufferList(AudioStreamBasicDescription const& streamFormat, int framesToBuffer):
+ owner(true),
+ sf(streamFormat),
+ bfs(0)
+ {
+ const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
+ const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame;
+
+ dataSize = framesToBuffer * sf.mBytesPerFrame;
+
+ bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) +
+ (sizeof(AudioBuffer) * numberOfBuffers)));
+ bfs->mNumberBuffers = numberOfBuffers;
+ for (int i = 0; i < numberOfBuffers; ++i) {
+ bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
+ bfs->mBuffers[i].mDataByteSize = dataSize;
+ bfs->mBuffers[i].mData = qMalloc(dataSize);
+ }
+ }
+
+ ~QAudioBufferList()
+ {
+ if (owner) {
+ for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i)
+ qFree(bfs->mBuffers[i].mData);
+ }
+
+ qFree(bfs);
+ }
+
+ AudioBufferList* audioBufferList() const
+ {
+ return bfs;
+ }
+
+ char* data(int buffer = 0) const
+ {
+ return static_cast<char*>(bfs->mBuffers[buffer].mData);
+ }
+
+ qint64 bufferSize(int buffer = 0) const
+ {
+ return bfs->mBuffers[buffer].mDataByteSize;
+ }
+
+ int frameCount(int buffer = 0) const
+ {
+ return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerFrame;
+ }
+
+ int packetCount(int buffer = 0) const
+ {
+ return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerPacket;
+ }
+
+ int packetSize() const
+ {
+ return sf.mBytesPerPacket;
+ }
+
+ void reset()
+ {
+ for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i)
+ bfs->mBuffers[i].mDataByteSize = dataSize;
+ }
+
+private:
+ bool owner;
+ int dataSize;
+ AudioStreamBasicDescription sf;
+ AudioBufferList* bfs;
+};
+
+class QAudioPacketFeeder
+{
+public:
+ QAudioPacketFeeder(QAudioBufferList* abl):
+ audioBufferList(abl)
+ {
+ totalPackets = audioBufferList->packetCount();
+ position = 0;
+ }
+
+ bool feed(AudioBufferList& dst, UInt32& packetCount)
+ {
+ if (position == totalPackets) {
+ dst.mBuffers[0].mDataByteSize = 0;
+ packetCount = 0;
+ return false;
+ }
+
+ if (totalPackets - position < packetCount)
+ packetCount = totalPackets - position;
+
+ dst.mBuffers[0].mDataByteSize = packetCount * audioBufferList->packetSize();
+ dst.mBuffers[0].mData = audioBufferList->data() + (position * audioBufferList->packetSize());
+
+ position += packetCount;
+
+ return true;
+ }
+
+private:
+ UInt32 totalPackets;
+ UInt32 position;
+ QAudioBufferList* audioBufferList;
+};
+
+class QAudioInputBuffer : public QObject
+{
+ Q_OBJECT
+
+public:
+ QAudioInputBuffer(int bufferSize,
+ int maxPeriodSize,
+ AudioStreamBasicDescription const& inputFormat,
+ AudioStreamBasicDescription const& outputFormat,
+ QObject* parent):
+ QObject(parent),
+ m_deviceError(false),
+ m_inputFormat(inputFormat),
+ m_outputFormat(outputFormat)
+ {
+ m_maxPeriodSize = maxPeriodSize;
+ m_periodTime = m_maxPeriodSize / m_outputFormat.mBytesPerFrame * 1000 / m_outputFormat.mSampleRate;
+ m_buffer = new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize)));
+ m_inputBufferList = new QAudioBufferList(m_inputFormat);
+
+ m_flushTimer = new QTimer(this);
+ connect(m_flushTimer, SIGNAL(timeout()), SLOT(flushBuffer()));
+
+ if (inputFormat.mSampleRate != outputFormat.mSampleRate) {
+ if (AudioConverterNew(&m_inputFormat, &m_outputFormat, &m_audioConverter) != noErr) {
+ qWarning() << "QAudioInput: Unable to create an Audio Converter";
+ m_audioConverter = 0;
+ }
+ }
+ }
+
+ ~QAudioInputBuffer()
+ {
+ delete m_buffer;
+ }
+
+ qint64 renderFromDevice(AudioUnit audioUnit,
+ AudioUnitRenderActionFlags* ioActionFlags,
+ const AudioTimeStamp* inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames)
+ {
+ const bool wasEmpty = m_buffer->used() == 0;
+
+ OSStatus err;
+ qint64 framesRendered = 0;
+
+ m_inputBufferList->reset();
+ err = AudioUnitRender(audioUnit,
+ ioActionFlags,
+ inTimeStamp,
+ inBusNumber,
+ inNumberFrames,
+ m_inputBufferList->audioBufferList());
+
+ if (m_audioConverter != 0) {
+ QAudioPacketFeeder feeder(m_inputBufferList);
+
+ bool wecan = true;
+ int copied = 0;
+
+ const int available = m_buffer->free();
+
+ while (err == noErr && wecan) {
+ QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available);
+
+ if (region.second > 0) {
+ AudioBufferList output;
+ output.mNumberBuffers = 1;
+ output.mBuffers[0].mNumberChannels = 1;
+ output.mBuffers[0].mDataByteSize = region.second;
+ output.mBuffers[0].mData = region.first;
+
+ UInt32 packetSize = region.second / m_outputFormat.mBytesPerPacket;
+ err = AudioConverterFillComplexBuffer(m_audioConverter,
+ converterCallback,
+ &feeder,
+ &packetSize,
+ &output,
+ 0);
+
+ region.second = output.mBuffers[0].mDataByteSize;
+ copied += region.second;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+ else
+ wecan = false;
+ }
+
+ framesRendered += copied / m_outputFormat.mBytesPerFrame;
+ }
+ else {
+ const int available = m_inputBufferList->bufferSize();
+ bool wecan = true;
+ int copied = 0;
+
+ while (wecan && copied < available) {
+ QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available - copied);
+
+ if (region.second > 0) {
+ memcpy(region.first, m_inputBufferList->data() + copied, region.second);
+ copied += region.second;
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+
+ framesRendered = copied / m_outputFormat.mBytesPerFrame;
+ }
+
+ if (wasEmpty && framesRendered > 0)
+ emit readyRead();
+
+ return framesRendered;
+ }
+
+ qint64 readBytes(char* data, qint64 len)
+ {
+ bool wecan = true;
+ qint64 bytesCopied = 0;
+
+ len -= len % m_maxPeriodSize;
+ while (wecan && bytesCopied < len) {
+ QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(len - bytesCopied);
+
+ if (region.second > 0) {
+ memcpy(data + bytesCopied, region.first, region.second);
+ bytesCopied += region.second;
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseReadRegion(region);
+ }
+
+ return bytesCopied;
+ }
+
+ void setFlushDevice(QIODevice* device)
+ {
+ if (m_device != device)
+ m_device = device;
+ }
+
+ void startFlushTimer()
+ {
+ if (m_device != 0) {
+ m_flushTimer->start((m_buffer->size() - (m_maxPeriodSize * 2)) / m_maxPeriodSize * m_periodTime);
+ }
+ }
+
+ void stopFlushTimer()
+ {
+ m_flushTimer->stop();
+ }
+
+ void flush(bool all = false)
+ {
+ const int used = m_buffer->used();
+ const int readSize = all ? used : used - (used % m_maxPeriodSize);
+
+ if (readSize > 0) {
+ bool wecan = true;
+ int flushed = 0;
+
+ while (!m_deviceError && wecan && flushed < readSize) {
+ QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(readSize - flushed);
+
+ if (region.second > 0) {
+ int bytesWritten = m_device->write(region.first, region.second);
+ if (bytesWritten < 0) {
+ stopFlushTimer();
+ m_deviceError = true;
+ }
+ else {
+ region.second = bytesWritten;
+ flushed += bytesWritten;
+ wecan = bytesWritten != 0;
+ }
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseReadRegion(region);
+ }
+ }
+ }
+
+ void reset()
+ {
+ m_buffer->reset();
+ m_deviceError = false;
+ }
+
+ int available() const
+ {
+ return m_buffer->free();
+ }
+
+ int used() const
+ {
+ return m_buffer->used();
+ }
+
+signals:
+ void readyRead();
+
+private slots:
+ void flushBuffer()
+ {
+ flush();
+ }
+
+private:
+ bool m_deviceError;
+ int m_maxPeriodSize;
+ int m_periodTime;
+ QIODevice* m_device;
+ QTimer* m_flushTimer;
+ QAudioRingBuffer* m_buffer;
+ QAudioBufferList* m_inputBufferList;
+ AudioConverterRef m_audioConverter;
+ AudioStreamBasicDescription m_inputFormat;
+ AudioStreamBasicDescription m_outputFormat;
+
+ const static OSStatus as_empty = 'qtem';
+
+ // Converter callback
+ static OSStatus converterCallback(AudioConverterRef inAudioConverter,
+ UInt32* ioNumberDataPackets,
+ AudioBufferList* ioData,
+ AudioStreamPacketDescription** outDataPacketDescription,
+ void* inUserData)
+ {
+ Q_UNUSED(inAudioConverter);
+ Q_UNUSED(outDataPacketDescription);
+
+ QAudioPacketFeeder* feeder = static_cast<QAudioPacketFeeder*>(inUserData);
+
+ if (!feeder->feed(*ioData, *ioNumberDataPackets))
+ return as_empty;
+
+ return noErr;
+ }
+};
+
+
+class MacInputDevice : public QIODevice
+{
+ Q_OBJECT
+
+public:
+ MacInputDevice(QAudioInputBuffer* audioBuffer, QObject* parent):
+ QIODevice(parent),
+ m_audioBuffer(audioBuffer)
+ {
+ open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+ connect(m_audioBuffer, SIGNAL(readyRead()), SIGNAL(readyRead()));
+ }
+
+ qint64 readData(char* data, qint64 len)
+ {
+ return m_audioBuffer->readBytes(data, len);
+ }
+
+ qint64 writeData(const char* data, qint64 len)
+ {
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+
+ return 0;
+ }
+
+ bool isSequential() const
+ {
+ return true;
+ }
+
+private:
+ QAudioInputBuffer* m_audioBuffer;
+};
+
+}
+
+
+QAudioInputPrivate::QAudioInputPrivate(const QByteArray& device, QAudioFormat const& format):
+ audioFormat(format)
+{
+ QDataStream ds(device);
+ quint32 did, mode;
+
+ ds >> did >> mode;
+
+ if (QAudio::Mode(mode) == QAudio::AudioOutput)
+ errorCode = QAudio::OpenError;
+ else {
+ isOpen = false;
+ audioDeviceId = AudioDeviceID(did);
+ audioUnit = 0;
+ startTime = 0;
+ totalFrames = 0;
+ audioBuffer = 0;
+ internalBufferSize = default_buffer_size;
+ clockFrequency = AudioGetHostClockFrequency() / 1000;
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::StopState;
+
+ intervalTimer = new QTimer(this);
+ intervalTimer->setInterval(1000);
+ connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify()));
+ }
+}
+
+QAudioInputPrivate::~QAudioInputPrivate()
+{
+ close();
+}
+
+bool QAudioInputPrivate::open()
+{
+ UInt32 size = 0;
+
+ if (isOpen)
+ return true;
+
+ ComponentDescription cd;
+ cd.componentType = kAudioUnitType_Output;
+ cd.componentSubType = kAudioUnitSubType_HALOutput;
+ cd.componentManufacturer = kAudioUnitManufacturer_Apple;
+ cd.componentFlags = 0;
+ cd.componentFlagsMask = 0;
+
+ // Open
+ Component cp = FindNextComponent(NULL, &cd);
+ if (cp == 0) {
+ qWarning() << "QAudioInput: Failed to find HAL Output component";
+ return false;
+ }
+
+ if (OpenAComponent(cp, &audioUnit) != noErr) {
+ qWarning() << "QAudioInput: Unable to Open Output Component";
+ return false;
+ }
+
+ // Set mode
+ // switch to input mode
+ UInt32 enable = 1;
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioOutputUnitProperty_EnableIO,
+ kAudioUnitScope_Input,
+ 1,
+ &enable,
+ sizeof(enable)) != noErr) {
+ qWarning() << "QAudioInput: Unabled to switch to input mode (Enable Input)";
+ return false;
+ }
+
+ enable = 0;
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioOutputUnitProperty_EnableIO,
+ kAudioUnitScope_Output,
+ 0,
+ &enable,
+ sizeof(enable)) != noErr) {
+ qWarning() << "QAudioInput: Unabled to switch to input mode (Disable output)";
+ return false;
+ }
+
+ // register callback
+ AURenderCallbackStruct cb;
+ cb.inputProc = inputCallback;
+ cb.inputProcRefCon = this;
+
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioOutputUnitProperty_SetInputCallback,
+ kAudioUnitScope_Global,
+ 0,
+ &cb,
+ sizeof(cb)) != noErr) {
+ qWarning() << "QAudioInput: Failed to set AudioUnit callback";
+ return false;
+ }
+
+ // Set Audio Device
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioOutputUnitProperty_CurrentDevice,
+ kAudioUnitScope_Global,
+ 0,
+ &audioDeviceId,
+ sizeof(audioDeviceId)) != noErr) {
+ qWarning() << "QAudioInput: Unable to use configured device";
+ return false;
+ }
+
+ // Set format
+ streamFormat = toAudioStreamBasicDescription(audioFormat);
+
+ size = sizeof(deviceFormat);
+ if (AudioUnitGetProperty(audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input,
+ 1,
+ &deviceFormat,
+ &size) != noErr) {
+ qWarning() << "QAudioInput: Unable to retrieve device format";
+ return false;
+ }
+
+ // If the device frequency is different to the requested use a converter
+ if (deviceFormat.mSampleRate != streamFormat.mSampleRate) {
+ AudioUnitSetProperty(audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Output,
+ 1,
+ &deviceFormat,
+ sizeof(streamFormat));
+ }
+ else {
+ AudioUnitSetProperty(audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Output,
+ 1,
+ &streamFormat,
+ sizeof(streamFormat));
+ }
+
+ // Setup buffers
+ UInt32 numberOfFrames;
+ size = sizeof(UInt32);
+ if (AudioUnitGetProperty(audioUnit,
+ kAudioDevicePropertyBufferFrameSize,
+ kAudioUnitScope_Global,
+ 0,
+ &numberOfFrames,
+ &size) != noErr) {
+ qWarning() << "QAudioInput: Failed to get audio period size";
+ return false;
+ }
+
+ // Allocate buffer
+ periodSizeBytes = (numberOfFrames * streamFormat.mSampleRate / deviceFormat.mSampleRate) *
+ streamFormat.mBytesPerFrame;
+ if (internalBufferSize < periodSizeBytes * 2)
+ internalBufferSize = periodSizeBytes * 2;
+ else
+ internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame;
+
+ audioBuffer = new QAudioInputBuffer(internalBufferSize,
+ periodSizeBytes,
+ deviceFormat,
+ streamFormat,
+ this);
+
+ audioIO = new MacInputDevice(audioBuffer, this);
+
+ // Init
+ if (AudioUnitInitialize(audioUnit) != noErr) {
+ qWarning() << "QAudioInput: Failed to initialize AudioUnit";
+ return false;
+ }
+
+ isOpen = true;
+
+ return isOpen;
+}
+
+void QAudioInputPrivate::close()
+{
+ if (audioUnit != 0) {
+ AudioOutputUnitStop(audioUnit);
+ AudioUnitUninitialize(audioUnit);
+ CloseComponent(audioUnit);
+ }
+
+ delete audioBuffer;
+}
+
+QAudioFormat QAudioInputPrivate::format() const
+{
+ return audioFormat;
+}
+
+QIODevice* QAudioInputPrivate::start(QIODevice* device)
+{
+ QIODevice* op = device;
+
+ if (!open()) {
+ stateCode = QAudio::StopState;
+ errorCode = QAudio::OpenError;
+ return audioIO;
+ }
+
+ reset();
+ audioBuffer->reset();
+ audioBuffer->setFlushDevice(op);
+
+ if (op == 0)
+ op = audioIO;
+
+ // Start
+ startTime = AudioGetCurrentHostTime();
+ totalFrames = 0;
+
+ audioThreadStart();
+
+ return op;
+}
+
+void QAudioInputPrivate::stop()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode != QAudio::StopState) {
+ audioThreadStop();
+ audioBuffer->flush(true);
+
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::StopState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioInputPrivate::reset()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode != QAudio::StopState) {
+ audioThreadStop();
+
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::StopState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioInputPrivate::suspend()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState || stateCode == QAudio::IdleState) {
+ audioThreadStop();
+
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::SuspendState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioInputPrivate::resume()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::SuspendState) {
+ audioThreadStart();
+
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::ActiveState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+int QAudioInputPrivate::bytesReady() const
+{
+ return audioBuffer->used();
+}
+
+int QAudioInputPrivate::periodSize() const
+{
+ return periodSizeBytes;
+}
+
+void QAudioInputPrivate::setBufferSize(int bs)
+{
+ internalBufferSize = bs;
+}
+
+int QAudioInputPrivate::bufferSize() const
+{
+ return internalBufferSize;
+}
+
+void QAudioInputPrivate::setNotifyInterval(int milliSeconds)
+{
+ intervalTimer->setInterval(milliSeconds);
+}
+
+int QAudioInputPrivate::notifyInterval() const
+{
+ return intervalTimer->interval();
+}
+
+qint64 QAudioInputPrivate::totalTime() const
+{
+ return totalFrames * 1000000 / audioFormat.frequency();
+}
+
+qint64 QAudioInputPrivate::clock() const
+{
+ return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000);
+}
+
+QAudio::Error QAudioInputPrivate::error() const
+{
+ return errorCode;
+}
+
+QAudio::State QAudioInputPrivate::state() const
+{
+ return stateCode;
+}
+
+void QAudioInputPrivate::audioThreadStop()
+{
+ stopTimers();
+ if (audioThreadState.testAndSetAcquire(Running, Stopped))
+ threadFinished.wait(&mutex);
+}
+
+void QAudioInputPrivate::audioThreadStart()
+{
+ startTimers();
+ audioThreadState = Running;
+ AudioOutputUnitStart(audioUnit);
+}
+
+void QAudioInputPrivate::audioDeviceStop()
+{
+ AudioOutputUnitStop(audioUnit);
+ audioThreadState = Stopped;
+ threadFinished.wakeOne();
+}
+
+void QAudioInputPrivate::audioDeviceFull()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState) {
+ audioDeviceStop();
+
+ errorCode = QAudio::UnderrunError;
+ stateCode = QAudio::IdleState;
+ QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
+ }
+}
+
+void QAudioInputPrivate::audioDeviceError()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState) {
+ audioDeviceStop();
+
+ errorCode = QAudio::IOError;
+ stateCode = QAudio::StopState;
+ QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
+ }
+}
+
+void QAudioInputPrivate::startTimers()
+{
+ audioBuffer->startFlushTimer();
+ intervalTimer->start();
+}
+
+void QAudioInputPrivate::stopTimers()
+{
+ audioBuffer->stopFlushTimer();
+ intervalTimer->stop();
+}
+
+void QAudioInputPrivate::deviceStopped()
+{
+ stopTimers();
+ emit stateChanged(stateCode);
+}
+
+// Input callback
+OSStatus QAudioInputPrivate::inputCallback(void* inRefCon,
+ AudioUnitRenderActionFlags* ioActionFlags,
+ const AudioTimeStamp* inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList* ioData)
+{
+ Q_UNUSED(ioData);
+
+ QAudioInputPrivate* d = static_cast<QAudioInputPrivate*>(inRefCon);
+
+ const int threadState = d->audioThreadState.fetchAndAddAcquire(0);
+ if (threadState == Stopped)
+ d->audioDeviceStop();
+ else {
+ qint64 framesWritten;
+
+ framesWritten = d->audioBuffer->renderFromDevice(d->audioUnit,
+ ioActionFlags,
+ inTimeStamp,
+ inBusNumber,
+ inNumberFrames);
+
+ if (framesWritten > 0)
+ d->totalFrames += framesWritten;
+ else if (framesWritten == 0)
+ d->audioDeviceFull();
+ else if (framesWritten < 0)
+ d->audioDeviceError();
+ }
+
+ return noErr;
+}
+
+
+QT_END_NAMESPACE
+
+#include "qaudioinput_mac_p.moc"
+
diff --git a/src/multimedia/audio/qaudioinput_mac_p.h b/src/multimedia/audio/qaudioinput_mac_p.h
new file mode 100644
index 0000000..98ef9ce
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_mac_p.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QAUDIOINPUT_MAC_P_H
+#define QAUDIOINPUT_MAC_P_H
+
+#include <CoreServices/CoreServices.h>
+#include <CoreAudio/CoreAudio.h>
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtCore/qatomic.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudioengine.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTimer;
+class QIODevice;
+
+namespace
+{
+class QAudioInputBuffer;
+}
+
+class QAudioInputPrivate : public QAbstractAudioInput
+{
+ Q_OBJECT
+
+public:
+ bool isOpen;
+ int periodSizeBytes;
+ int internalBufferSize;
+ qint64 totalFrames;
+ QAudioFormat audioFormat;
+ QIODevice* audioIO;
+ AudioUnit audioUnit;
+ AudioDeviceID audioDeviceId;
+ Float64 clockFrequency;
+ UInt64 startTime;
+ QAudio::Error errorCode;
+ QAudio::State stateCode;
+ QAudioInputBuffer* audioBuffer;
+ QMutex mutex;
+ QWaitCondition threadFinished;
+ QAtomicInt audioThreadState;
+ QTimer* intervalTimer;
+ AudioStreamBasicDescription streamFormat;
+ AudioStreamBasicDescription deviceFormat;
+
+ QAudioInputPrivate(const QByteArray& device, QAudioFormat const& format);
+ ~QAudioInputPrivate();
+
+ bool open();
+ void close();
+
+ QAudioFormat format() const;
+
+ QIODevice* start(QIODevice* device);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+ void idle();
+
+ int bytesReady() const;
+ int periodSize() const;
+
+ void setBufferSize(int value);
+ int bufferSize() const;
+
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+
+ qint64 totalTime() const;
+ qint64 clock() const;
+
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+ void audioThreadStart();
+ void audioThreadStop();
+
+ void audioDeviceStop();
+ void audioDeviceFull();
+ void audioDeviceError();
+
+ void startTimers();
+ void stopTimers();
+
+signals:
+ void stateChanged(QAudio::State);
+ void notify();
+
+private slots:
+ void deviceStopped();
+
+private:
+ enum { Running, Stopped };
+
+ // Input callback
+ static OSStatus inputCallback(void* inRefCon,
+ AudioUnitRenderActionFlags* ioActionFlags,
+ const AudioTimeStamp* inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList* ioData);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOINPUT_MAC_P_H
diff --git a/src/multimedia/audio/qaudioinput_win32_p.cpp b/src/multimedia/audio/qaudioinput_win32_p.cpp
new file mode 100644
index 0000000..e5b6e0d
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_win32_p.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include "qaudioinput_win32_p.h"
+
+//#define DEBUG_AUDIO 1
+
+
+QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
+ settings(audioFormat)
+{
+ bytesAvailable = 0;
+ buffer_size = 0;
+ period_size = 0;
+ m_device = device;
+ totalTimeValue = 0;
+ intervalTime = 1000;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::StopState;
+ audioSource = 0;
+ pullMode = true;
+ resuming = false;
+
+ connect(this,SIGNAL(processMore()),SLOT(deviceReady()));
+
+ InitializeCriticalSection(&waveInCriticalSection);
+}
+
+QAudioInputPrivate::~QAudioInputPrivate()
+{
+ close();
+ DeleteCriticalSection(&waveInCriticalSection);
+}
+
+void CALLBACK QAudioInputPrivate::waveInProc( HWAVEIN hWaveIn, UINT uMsg,
+ DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
+{
+ Q_UNUSED(dwParam1)
+ Q_UNUSED(dwParam2)
+ Q_UNUSED(hWaveIn)
+
+ QAudioInputPrivate* qAudio;
+ qAudio = (QAudioInputPrivate*)(dwInstance);
+ if(!qAudio)
+ return;
+
+ switch(uMsg) {
+ case WIM_OPEN:
+ break;
+ case WIM_DATA:
+ EnterCriticalSection(&waveInCriticalSection);
+ if(qAudio->waveFreeBlockCount > 0)
+ qAudio->waveFreeBlockCount--;
+ LeaveCriticalSection(&waveInCriticalSection);
+ qAudio->feedback();
+ break;
+ case WIM_CLOSE:
+ break;
+ default:
+ return;
+ }
+}
+
+WAVEHDR* QAudioInputPrivate::allocateBlocks(int size, int count)
+{
+ int i;
+ unsigned char* buffer;
+ WAVEHDR* blocks;
+ DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count;
+
+ if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+ totalBufferSize)) == 0) {
+ qWarning("QAudioInput: Memory allocation error");
+ return 0;
+ }
+ blocks = (WAVEHDR*)buffer;
+ buffer += sizeof(WAVEHDR)*count;
+ for(i = 0; i < count; i++) {
+ blocks[i].dwBufferLength = size;
+ blocks[i].lpData = (LPSTR)buffer;
+ blocks[i].dwBytesRecorded=0;
+ blocks[i].dwUser = 0L;
+ blocks[i].dwFlags = 0L;
+ blocks[i].dwLoops = 0L;
+ result = waveInPrepareHeader(hWaveIn,&blocks[i], sizeof(WAVEHDR));
+ if(result != MMSYSERR_NOERROR) {
+ qWarning("QAudioInput: Can't prepare block %d",i);
+ return 0;
+ }
+ buffer += size;
+ }
+ return blocks;
+}
+
+void QAudioInputPrivate::freeBlocks(WAVEHDR* blockArray)
+{
+ HeapFree(GetProcessHeap(), 0, blockArray);
+}
+
+QAudio::Error QAudioInputPrivate::error() const
+{
+ return errorState;
+}
+
+QAudio::State QAudioInputPrivate::state() const
+{
+ return deviceState;
+}
+
+QAudioFormat QAudioInputPrivate::format() const
+{
+ return settings;
+}
+
+QIODevice* QAudioInputPrivate::start(QIODevice* device)
+{
+ if(deviceState != QAudio::StopState)
+ close();
+
+ if(!pullMode && audioSource) {
+ delete audioSource;
+ }
+
+ if(device) {
+ //set to pull mode
+ pullMode = true;
+ audioSource = device;
+ } else {
+ //set to push mode
+ pullMode = false;
+ audioSource = new InputPrivate(this);
+ audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+ }
+
+ if( !open() )
+ return 0;
+
+ emit stateChanged(deviceState);
+
+ return audioSource;
+}
+
+void QAudioInputPrivate::stop()
+{
+ if(deviceState == QAudio::StopState)
+ return;
+
+ deviceState = QAudio::StopState;
+
+ close();
+ emit stateChanged(deviceState);
+}
+
+bool QAudioInputPrivate::open()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
+#endif
+ header = 0;
+ if(buffer_size == 0) {
+ // Default buffer size, 100ms, default period size is 20ms
+ buffer_size = settings.frequency()*settings.channels()*(settings.sampleSize()/8)*0.1;
+ period_size = buffer_size/5;
+ } else {
+ period_size = buffer_size/5;
+ }
+ timeStamp.restart();
+ wfx.nSamplesPerSec = settings.frequency();
+ wfx.wBitsPerSample = settings.sampleSize();
+ wfx.nChannels = settings.channels();
+ wfx.cbSize = 0;
+
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
+
+ UINT_PTR devId = WAVE_MAPPER;
+
+ WAVEINCAPS wic;
+ unsigned long iNumDevs,ii;
+ iNumDevs = waveInGetNumDevs();
+ for(ii=0;ii<iNumDevs;ii++) {
+ if(waveInGetDevCaps(ii, &wic, sizeof(WAVEINCAPS))
+ == MMSYSERR_NOERROR) {
+ QString tmp;
+ tmp = QString::fromUtf16((const unsigned short*)wic.szPname);
+ if(tmp.compare(tr(m_device)) == 0) {
+ devId = ii;
+ break;
+ }
+ }
+ }
+
+ if(waveInOpen(&hWaveIn, devId, &wfx,
+ (DWORD_PTR)&waveInProc,
+ (DWORD_PTR) this,
+ CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ qWarning("QAudioInput: failed to open audio device");
+ return false;
+ }
+ waveBlocks = allocateBlocks(period_size, buffer_size/period_size);
+ waveFreeBlockCount = buffer_size/period_size;
+ waveCurrentBlock = 0;
+
+ for(int i=0; i<buffer_size/period_size; i++) {
+ result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR));
+ if(result != MMSYSERR_NOERROR) {
+ qWarning("QAudioInput: failed to setup block %d,err=%d",i,result);
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ return false;
+ }
+ }
+ result = waveInStart(hWaveIn);
+ if(result) {
+ qWarning("QAudioInput: failed to start audio input");
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ return false;
+ }
+ timeStampOpened.restart();
+ totalTimeValue = 0;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ return true;
+}
+
+void QAudioInputPrivate::close()
+{
+ deviceState = QAudio::StopState;
+ int delay = (buffer_size-bytesReady())*1000/(settings.frequency()
+ *settings.channels()*(settings.sampleSize()/8));
+ waveInReset(hWaveIn);
+ Sleep(delay+10);
+
+ for(int i=0; i<waveFreeBlockCount; i++) {
+ if(waveBlocks[i].dwFlags & WHDR_PREPARED)
+ waveInUnprepareHeader(hWaveIn,&waveBlocks[i],sizeof(WAVEHDR));
+ }
+ freeBlocks(waveBlocks);
+ waveInClose(hWaveIn);
+}
+
+int QAudioInputPrivate::bytesReady() const
+{
+ int buf = ((buffer_size/period_size)-waveFreeBlockCount)*period_size;
+ if(buf < 0)
+ buf = 0;
+ return buf;
+}
+
+qint64 QAudioInputPrivate::read(char* data, qint64 len)
+{
+ bool done = false;
+
+ char* p = data;
+ qint64 l = 0;
+ qint64 written = 0;
+ while(!done) {
+ // Read in some audio data
+ if(waveBlocks[header].dwBytesRecorded > 0) {
+ if(pullMode) {
+ l = audioSource->write(waveBlocks[header].lpData,
+ waveBlocks[header].dwBytesRecorded);
+#ifdef DEBUG_AUDIO
+ qDebug()<<"IN: "<<waveBlocks[header].dwBytesRecorded<<", OUT: "<<l;
+#endif
+ if(l < 0) {
+ // error
+ qWarning("QAudioInput: IOError");
+ errorState = QAudio::IOError;
+
+ } else if(l == 0) {
+ // cant write to IODevice
+ qWarning("QAudioInput: IOError, can't write to QIODevice");
+ errorState = QAudio::IOError;
+
+ } else {
+ totalTimeValue += waveBlocks[header].dwBytesRecorded
+ /((settings.channels()*settings.sampleSize()/8))
+ *10000/settings.frequency()*100;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ resuming = false;
+ }
+ } else {
+ // push mode
+ memcpy(p,waveBlocks[header].lpData,waveBlocks[header].dwBytesRecorded);
+ l = waveBlocks[header].dwBytesRecorded;
+#ifdef DEBUG_AUDIO
+ qDebug()<<"IN: "<<waveBlocks[header].dwBytesRecorded<<", OUT: "<<l;
+#endif
+ totalTimeValue += waveBlocks[header].dwBytesRecorded
+ /((settings.channels()*settings.sampleSize()/8))
+ *10000/settings.frequency()*100;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ resuming = false;
+ }
+ } else {
+ //no data, not ready yet, next time
+ return 0;
+ }
+ EnterCriticalSection(&waveInCriticalSection);
+ waveFreeBlockCount++;
+ LeaveCriticalSection(&waveInCriticalSection);
+ waveBlocks[header].dwBytesRecorded=0;
+ waveBlocks[header].dwFlags = 0L;
+ result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR));
+ if(result != MMSYSERR_NOERROR) {
+ qWarning("QAudioInput: failed to prepare block %d,err=%d",header,result);
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ }
+ result = waveInAddBuffer(hWaveIn, &waveBlocks[header], sizeof(WAVEHDR));
+ if(result != MMSYSERR_NOERROR) {
+ qWarning("QAudioInput: failed to setup block %d,err=%d",header,result);
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ }
+ header++;
+ if(header >= buffer_size/period_size)
+ header = 0;
+ p+=l;
+
+ if(!pullMode) {
+ if(l+period_size > len && waveFreeBlockCount == buffer_size/period_size)
+ done = true;
+ } else {
+ if(waveFreeBlockCount == buffer_size/period_size)
+ done = true;
+ }
+ written+=l;
+ }
+#ifdef DEBUG_AUDIO
+ qDebug()<<"read in len="<<written;
+#endif
+ return written;
+}
+
+void QAudioInputPrivate::resume()
+{
+ if(deviceState == QAudio::SuspendState) {
+ deviceState = QAudio::ActiveState;
+ for(int i=0; i<buffer_size/period_size; i++) {
+ result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR));
+ if(result != MMSYSERR_NOERROR) {
+ qWarning("QAudioInput: failed to setup block %d,err=%d",i,result);
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ return;
+ }
+ }
+ waveFreeBlockCount = buffer_size/period_size;
+ waveCurrentBlock = 0;
+ header = 0;
+ resuming = true;
+ waveInStart(hWaveIn);
+ QTimer::singleShot(20,this,SLOT(feedback()));
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioInputPrivate::setBufferSize(int value)
+{
+ buffer_size = value;
+}
+
+int QAudioInputPrivate::bufferSize() const
+{
+ return buffer_size;
+}
+
+int QAudioInputPrivate::periodSize() const
+{
+ return period_size;
+}
+
+void QAudioInputPrivate::setNotifyInterval(int ms)
+{
+ intervalTime = ms;
+}
+
+int QAudioInputPrivate::notifyInterval() const
+{
+ return intervalTime;
+}
+
+qint64 QAudioInputPrivate::totalTime() const
+{
+ return totalTimeValue;
+}
+
+void QAudioInputPrivate::suspend()
+{
+ if(deviceState == QAudio::ActiveState) {
+ waveInReset(hWaveIn);
+ deviceState = QAudio::SuspendState;
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioInputPrivate::feedback()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback() INPUT";
+#endif
+ bytesAvailable = bytesReady();
+
+ if(!(deviceState==QAudio::StopState||deviceState==QAudio::SuspendState))
+ emit processMore();
+}
+
+bool QAudioInputPrivate::deviceReady()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :deviceReady() INPUT";
+#endif
+ if(pullMode) {
+ // reads some audio data and writes it to QIODevice
+ read(0,0);
+ } else {
+ // emits readyRead() so user will call read() on QIODevice to get some audio data
+ InputPrivate* a = qobject_cast<InputPrivate*>(audioSource);
+ a->trigger();
+ }
+ if(deviceState != QAudio::ActiveState)
+ return true;
+
+ if(timeStamp.elapsed() > intervalTime && intervalTime > 50) {
+ emit notify();
+ timeStamp.restart();
+ }
+ return true;
+}
+
+qint64 QAudioInputPrivate::clock() const
+{
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+
+ return timeStampOpened.elapsed();
+}
+
+void QAudioInputPrivate::reset()
+{
+ close();
+}
+
+InputPrivate::InputPrivate(QAudioInputPrivate* audio)
+{
+ audioDevice = qobject_cast<QAudioInputPrivate*>(audio);
+}
+
+InputPrivate::~InputPrivate() {}
+
+qint64 InputPrivate::readData( char* data, qint64 len)
+{
+ // push mode, user read() called
+ if(audioDevice->deviceState != QAudio::ActiveState)
+ return 0;
+ // Read in some audio data
+ return audioDevice->read(data,len);
+}
+
+qint64 InputPrivate::writeData(const char* data, qint64 len)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(len)
+
+ emit readyRead();
+ return 0;
+}
+
+void InputPrivate::trigger()
+{
+ emit readyRead();
+}
+
diff --git a/src/multimedia/audio/qaudioinput_win32_p.h b/src/multimedia/audio/qaudioinput_win32_p.h
new file mode 100644
index 0000000..32464f0
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_win32_p.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIOINPUTWIN_H
+#define QAUDIOINPUTWIN_H
+
+#include <windows.h>
+#include <mmsystem.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+
+static CRITICAL_SECTION waveInCriticalSection;
+
+class QAudioInputPrivate : public QAbstractAudioInput
+{
+ Q_OBJECT
+public:
+ QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat);
+ ~QAudioInputPrivate();
+
+ qint64 read(char* data, qint64 len);
+
+ QAudioFormat format() const;
+ QIODevice* start(QIODevice* device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+ int bytesReady() const;
+ int periodSize() const;
+ void setBufferSize(int value);
+ int bufferSize() const;
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+ qint64 totalTime() const;
+ qint64 clock() const;
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+ QIODevice* audioSource;
+ QAudioFormat settings;
+ QAudio::Error errorState;
+ QAudio::State deviceState;
+
+private:
+ qint32 buffer_size;
+ qint32 period_size;
+ qint32 header;
+ QByteArray m_device;
+ int bytesAvailable;
+ int intervalTime;
+ QTime timeStamp;
+ QTime timeStampOpened;
+ qint64 totalTimeValue;
+ bool pullMode;
+ bool resuming;
+ WAVEFORMATEX wfx;
+ HWAVEIN hWaveIn;
+ MMRESULT result;
+ WAVEHDR* waveBlocks;
+ volatile int waveFreeBlockCount;
+ int waveCurrentBlock;
+
+ static void CALLBACK waveInProc( HWAVEIN hWaveIn, UINT uMsg,
+ DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 );
+
+ WAVEHDR* allocateBlocks(int size, int count);
+ void freeBlocks(WAVEHDR* blockArray);
+ bool open();
+ void close();
+
+private slots:
+ void feedback();
+ bool deviceReady();
+
+signals:
+ void processMore();
+};
+
+class InputPrivate : public QIODevice
+{
+ Q_OBJECT
+public:
+ InputPrivate(QAudioInputPrivate* audio);
+ ~InputPrivate();
+
+ qint64 readData( char* data, qint64 len);
+ qint64 writeData(const char* data, qint64 len);
+
+ void trigger();
+private:
+ QAudioInputPrivate *audioDevice;
+};
+
+#endif
diff --git a/src/multimedia/audio/qaudiooutput.cpp b/src/multimedia/audio/qaudiooutput.cpp
new file mode 100644
index 0000000..785da61
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+#include <QtMultimedia/qaudiooutput.h>
+
+#include "qaudiodevicefactory_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioOutput
+ \brief The QAudioOutput class provides an interface for sending audio data to an audio output device.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \since 4.6
+
+ You can construct an audio output with the system's
+ \l{QAudioDeviceInfo::defaultOutputDevice()}{default audio output
+ device}. It is also possible to create QAudioOutput with a
+ specific QAudioDeviceId. When you create the audio output, you
+ should also send in the QAudioFormat to be used for the playback
+ (see the QAudioFormat class description for details).
+
+ To play a file:
+
+ Starting to play an audio stream is simply a matter of calling
+ start() with a QIODevice. QAudioOutput will then fetch the data it
+ needs from the io device. So playing back an audio file is as
+ simple as:
+
+ \code
+ QFile inputFile;
+ inputFile.setFileName("/tmp/test.raw");
+ inputFile.open(QIODevice::ReadOnly);
+
+ QAudioFormat format;
+ // Set up the format, eg.
+ format.setFrequency(8000);
+ format.setChannels(1);
+ format.setSampleSize(8);
+ format.setCodec("audio/pcm");
+ format.setByteOrder(QAudioFormat::LittleEndian);
+ format.setSampleType(QAudioFormat::UnSignedInt);
+
+ QAudioOutput *audio = new QAudioOutput(format, this);
+ connect(audio,SIGNAL(stateChanged(QAudio::State)),SLOT(finishedPlaying(QAudio::State)));
+ audio->start(inputFile);
+
+ \endcode
+
+ The file will start playing assuming that the audio system and
+ output device support it. If you run out of luck, check what's
+ up with the error() function.
+
+ After the file has finished playing, we need to stop the device:
+
+ \code
+ void finishedPlaying(QAudio::State state)
+ {
+ if(state == QAudio::IdleState) {
+ audio->stop();
+ inputFile.close();
+ }
+ }
+ \endcode
+
+ At any given time, the QAudioOutput will be in one of four states:
+ active, suspended, stopped, or idle. These states are described
+ by the QAudio::State enum.
+ State changes are reported through the stateChanged() signal. You
+ can use this signal to, for instance, update the GUI of the
+ application; the mundane example here being changing the state of
+ a \c { play/pause } button. You request a state change directly
+ with suspend(), stop(), reset(), resume(), and start().
+
+ While the stream is playing, you can set a notify interval in
+ milliseconds with setNotifyInterval(). This interval specifies the
+ time between two emissions of the notify() signal. This is
+ relative to the position in the stream, i.e., if the QAudioOutput
+ is in the SuspendedState or the IdleState, the notify() signal is
+ not emitted. A typical use-case would be to update a
+ \l{QSlider}{slider} that allows seeking in the stream.
+ If you want the time since playback started regardless of which
+ states the audio output has been in, clock() is the function for you.
+
+ If an error occurs, you can fetch the \l{QAudio::Error}{error
+ type} with the error() function. Please see the QAudio::Error enum
+ for a description of the possible errors that are reported.
+
+ If an error is encountered state changes to QAudio::StopState.
+
+ \sa QAudioInput, QAudioDeviceInfo
+*/
+
+/*!
+ Construct a new audio output and attach it to \a parent.
+ The default audio output device is used with the output
+ \a format parameters.
+*/
+
+QAudioOutput::QAudioOutput(const QAudioFormat &format, QObject *parent):
+ QObject(parent)
+{
+ d = QAudioDeviceFactory::createDefaultOutputDevice(format);
+ connect(d, SIGNAL(notify()), SIGNAL(notify()));
+ connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
+}
+
+/*!
+ Construct a new audio output and attach it to \a parent.
+ The \a id of the audio output device is used with the output
+ \a format parameters.
+*/
+
+QAudioOutput::QAudioOutput(const QAudioDeviceId &id, const QAudioFormat &format, QObject *parent):
+ QObject(parent)
+{
+ d = QAudioDeviceFactory::createOutputDevice(id, format);
+ connect(d, SIGNAL(notify()), SIGNAL(notify()));
+ connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
+}
+
+/*!
+ Destroys this audio output.
+*/
+
+QAudioOutput::~QAudioOutput()
+{
+ delete d;
+}
+
+/*!
+ Returns the QAudioFormat being used.
+
+*/
+
+QAudioFormat QAudioOutput::format() const
+{
+ return d->format();
+}
+
+/*!
+ Uses the \a device as the QIODevice to transfer data.
+ If \a device is null then the class creates an internal QIODevice.
+ Returns a pointer to the QIODevice being used to handle the data
+ transfer. This QIODevice can be used to write() audio data
+ directly.
+ Passing a QIODevice allows the data to be transfered without any extra code.
+ All that is required is to open the QIODevice.
+
+ /sa QIODevice
+*/
+
+QIODevice* QAudioOutput::start(QIODevice* device)
+{
+ /*
+ PULL MODE (valid QIODevice)
+ -If currently not StopState, stop.
+ -If previous start was push mode, delete internal QIODevice.
+ -open audio output.
+ -If ok, NoError and ActiveState, else OpenError and StopState
+ -emit stateChanged()
+ -return device
+
+ PUSH MODE (device = 0)
+ -If currently not StopState, stop.
+ -If no internal QIODevice, create one.
+ -open audio output.
+ -If ok, NoError and IdleState, else OpenError and StopState
+ -emit stateChanged()
+ -return internal QIODevice
+ */
+ return d->start(device);
+}
+
+/*!
+ Stops the audio output.
+*/
+
+void QAudioOutput::stop()
+{
+ /*
+ -If StopState, return
+ -set to StopState
+ -detach from audio device
+ -emit stateChanged()
+ */
+ d->stop();
+}
+
+/*!
+ Drops all audio data in the buffers, resets buffers to zero.
+*/
+
+void QAudioOutput::reset()
+{
+ /*
+ -drop all buffered audio, set buffers to zero.
+ -call stop()
+ */
+ d->reset();
+}
+
+/*!
+ Stops processing audio data, preserving buffered audio data.
+*/
+
+void QAudioOutput::suspend()
+{
+ /*
+ -If not ActiveState|IdleState, return
+ -stop processing audio, saving all buffered audio data
+ -set NoError and SuspendState
+ -emit stateChanged()
+ */
+ d->suspend();
+}
+
+/*!
+ Resumes processing audio data after a suspend().
+*/
+
+void QAudioOutput::resume()
+{
+ /*
+ -If SuspendState, return
+ -resume audio
+ -(PULL MODE): set ActiveState, NoError
+ -(PUSH MODE): set IdleState, NoError
+ -kick start audio if needed
+ -emit stateChanged()
+ */
+ d->resume();
+}
+
+/*!
+ Returns the free space available in bytes in the audio buffer.
+*/
+
+int QAudioOutput::bytesFree() const
+{
+ /*
+ -If not ActiveState|IdleState, return 0
+ -return space available in audio buffer in bytes
+ */
+ return d->bytesFree();
+}
+
+/*!
+ Returns the period size in bytes.
+
+ Note: This is the recommended write size in bytes.
+*/
+
+int QAudioOutput::periodSize() const
+{
+ return d->periodSize();
+}
+
+/*!
+ Sets the audio buffer size to \a value in bytes.
+
+ Note: This function can be called anytime before start(), calls to this
+ are ignored after start(). It should not be assumed that the buffer size
+ set is the actual buffer size used, calling bufferSize() anytime after start()
+ will return the actual buffer size being used.
+*/
+
+void QAudioOutput::setBufferSize(int value)
+{
+ d->setBufferSize(value);
+}
+
+/*!
+ Returns the audio buffer size in bytes.
+
+ If called before start(), returns platform default value.
+ If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
+ If called after start(), returns the actual buffer size being used. This may not be what was set previously
+ by setBufferSize().
+
+*/
+
+int QAudioOutput::bufferSize() const
+{
+ return d->bufferSize();
+}
+
+/*!
+ Sets the interval for notify() signal to be emitted.
+ This is based on the \a ms of audio data processed
+ not on actual real-time. The resolution of the timer is platform specific.
+*/
+
+void QAudioOutput::setNotifyInterval(int ms)
+{
+ d->setNotifyInterval(ms);
+}
+
+/*!
+ Returns the notify interval in milliseconds.
+*/
+
+int QAudioOutput::notifyInterval() const
+{
+ return d->notifyInterval();
+}
+
+/*!
+ Returns the amount of audio data processed since start()
+ was called in microseconds.
+*/
+
+qint64 QAudioOutput::totalTime() const
+{
+ return d->totalTime();
+}
+
+/*!
+ Returns the microseconds since start() was called, including time in Idle and
+ Suspend states.
+*/
+
+qint64 QAudioOutput::clock() const
+{
+ return d->clock();
+}
+
+/*!
+ Returns the error state.
+*/
+
+QAudio::Error QAudioOutput::error() const
+{
+ return d->error();
+}
+
+/*!
+ Returns the state of audio processing.
+*/
+
+QAudio::State QAudioOutput::state() const
+{
+ return d->state();
+}
+
+/*!
+ \fn QAudioOutput::stateChanged(QAudio::State state)
+ This signal is emitted when the device \a state has changed.
+ This is the current state of the audio output.
+*/
+
+/*!
+ \fn QAudioOutput::notify()
+ This signal is emitted when x ms of audio data has been processed
+ the interval set by setNotifyInterval(x).
+*/
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiooutput.h b/src/multimedia/audio/qaudiooutput.h
new file mode 100644
index 0000000..95e28ea
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIOOUTPUT_H
+#define QAUDIOOUTPUT_H
+
+#include <QtCore/qiodevice.h>
+#include <QtCore/qglobal.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodeviceid.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAbstractAudioOutput;
+
+class Q_MULTIMEDIA_EXPORT QAudioOutput : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QAudioOutput(const QAudioFormat &format = QAudioFormat(), QObject *parent = 0);
+ explicit QAudioOutput(const QAudioDeviceId &id, const QAudioFormat &format = QAudioFormat(), QObject *parent = 0);
+ ~QAudioOutput();
+
+ QAudioFormat format() const;
+
+ QIODevice* start(QIODevice *device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+
+ void setBufferSize(int bytes);
+ int bufferSize() const;
+
+ int bytesFree() const;
+ int periodSize() const;
+
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+
+ qint64 totalTime() const;
+ qint64 clock() const;
+
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+Q_SIGNALS:
+ void stateChanged(QAudio::State);
+ void notify();
+
+private:
+ Q_DISABLE_COPY(QAudioOutput)
+
+ QAbstractAudioOutput* d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOOUTPUT_H
diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.cpp b/src/multimedia/audio/qaudiooutput_alsa_p.cpp
new file mode 100644
index 0000000..d41c449
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_alsa_p.cpp
@@ -0,0 +1,706 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qcoreapplication.h>
+#include "qaudiooutput_alsa_p.h"
+
+//#define DEBUG_AUDIO 1
+
+QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
+ settings(audioFormat)
+{
+ bytesAvailable = 0;
+ handle = 0;
+ ahandler = 0;
+ access = SND_PCM_ACCESS_RW_INTERLEAVED;
+ pcmformat = SND_PCM_FORMAT_S16;
+ buffer_frames = 0;
+ period_frames = 0;
+ buffer_size = 0;
+ period_size = 0;
+ buffer_time = 100000;
+ period_time = 20000;
+ totalTimeValue = 0;
+ intervalTime = 1000;
+ audioBuffer = 0;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::StopState;
+ audioSource = 0;
+ pullMode = true;
+ resuming = false;
+ opened = false;
+
+ QStringList list1 = QString(tr(device)).split(tr(":"));
+ m_device = QByteArray(list1.at(0).toLocal8Bit().constData());
+
+ timer = new QTimer(this);
+ connect(timer,SIGNAL(timeout()),SLOT(userFeed()));
+}
+
+QAudioOutputPrivate::~QAudioOutputPrivate()
+{
+ close();
+ disconnect(timer, SIGNAL(timeout()));
+ QCoreApplication::processEvents();
+ delete timer;
+}
+
+QAudio::Error QAudioOutputPrivate::error() const
+{
+ return errorState;
+}
+
+QAudio::State QAudioOutputPrivate::state() const
+{
+ return deviceState;
+}
+
+void QAudioOutputPrivate::async_callback(snd_async_handler_t *ahandler)
+{
+ QAudioOutputPrivate* audioOut;
+
+ audioOut = static_cast<QAudioOutputPrivate*>
+ (snd_async_handler_get_callback_private(ahandler));
+
+ if((audioOut->deviceState==QAudio::ActiveState)||(audioOut->resuming))
+ audioOut->feedback();
+}
+
+int QAudioOutputPrivate::xrun_recovery(int err)
+{
+ int count = 0;
+ bool reset = false;
+
+ if(err == -EPIPE) {
+ errorState = QAudio::UnderrunError;
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+
+ } else if((err == -ESTRPIPE)||(err == -EIO)) {
+ errorState = QAudio::IOError;
+ while((err = snd_pcm_resume(handle)) == -EAGAIN){
+ usleep(100);
+ count++;
+ if(count > 5) {
+ reset = true;
+ break;
+ }
+ }
+ if(err < 0) {
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+ }
+ }
+ if(reset) {
+ close();
+ open();
+ snd_pcm_prepare(handle);
+ return 0;
+ }
+ return err;
+}
+
+int QAudioOutputPrivate::setFormat()
+{
+ snd_pcm_format_t pcmformat = SND_PCM_FORMAT_S16;
+
+ if(settings.sampleSize() == 8) {
+ pcmformat = SND_PCM_FORMAT_U8;
+
+ } else if(settings.sampleSize() == 16) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_S16_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_S16_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_U16_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_U16_BE;
+ }
+ } else if(settings.sampleSize() == 24) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_S24_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_S24_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_U24_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_U24_BE;
+ }
+ } else if(settings.sampleSize() == 32) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_S32_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_S32_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_U32_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_U32_BE;
+ } else if(settings.sampleType() == QAudioFormat::Float) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_FLOAT_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_FLOAT_BE;
+ }
+ } else if(settings.sampleSize() == 64) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_FLOAT64_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_FLOAT64_BE;
+ }
+
+ return snd_pcm_hw_params_set_format( handle, hwparams, pcmformat);
+}
+
+QIODevice* QAudioOutputPrivate::start(QIODevice* device)
+{
+ if(deviceState != QAudio::StopState)
+ deviceState = QAudio::StopState;
+
+ errorState = QAudio::NoError;
+
+ // Handle change of mode
+ if(audioSource && pullMode && !device) {
+ // pull -> push
+ close();
+ audioSource = 0;
+ } else if(audioSource && !pullMode && device) {
+ // push -> pull
+ close();
+ delete audioSource;
+ audioSource = 0;
+ }
+
+ if(device) {
+ //set to pull mode
+ pullMode = true;
+ audioSource = device;
+ deviceState = QAudio::ActiveState;
+ } else {
+ //set to push mode
+ if(!audioSource) {
+ audioSource = new OutputPrivate(this);
+ audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
+ }
+ pullMode = false;
+ deviceState = QAudio::IdleState;
+ }
+
+ open();
+
+ emit stateChanged(deviceState);
+
+ return audioSource;
+}
+
+void QAudioOutputPrivate::stop()
+{
+ if(deviceState == QAudio::StopState)
+ return;
+ deviceState = QAudio::StopState;
+ close();
+ emit stateChanged(deviceState);
+}
+
+bool QAudioOutputPrivate::open()
+{
+ if(opened)
+ return true;
+
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
+#endif
+ timeStamp.restart();
+
+ int dir;
+ int err=-1;
+ int count=0;
+ unsigned int freakuency=settings.frequency();
+
+ QString dev = tr(m_device.constData());
+ if(!dev.contains(tr("default"))) {
+ dev = QString(tr("default:CARD=%1")).arg(tr(m_device.constData()));
+ }
+ // Step 1: try and open the device
+ while((count < 5) && (err < 0)) {
+ err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
+ if(err < 0)
+ count++;
+ }
+ if (( err < 0)||(handle == 0)) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ return false;
+ }
+ snd_pcm_nonblock( handle, 0 );
+
+ // Step 2: Set the desired HW parameters.
+ snd_pcm_hw_params_alloca( &hwparams );
+
+ bool fatal = false;
+ QString errMessage;
+ unsigned int chunks = 8;
+
+ err = snd_pcm_hw_params_any( handle, hwparams );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_any: err = %1")).arg(err);
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_rate_resample: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_access( handle, hwparams, access );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_access: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = setFormat();
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_format: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_channels: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_period_time_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_periods_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params(handle, hwparams);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params: err = %1")).arg(err);
+ }
+ }
+ if( err < 0) {
+ qWarning()<<errMessage;
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ return false;
+ }
+ snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames);
+ buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames);
+ snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir);
+ period_size = snd_pcm_frames_to_bytes(handle,period_frames);
+ snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
+ snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);
+
+ // Step 3: Set the desired SW parameters.
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_sw_params_alloca(&swparams);
+ snd_pcm_sw_params_current(handle, swparams);
+ snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames);
+ snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames);
+ snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames);
+ snd_pcm_sw_params(handle, swparams);
+
+ // Step 4: Prepare audio
+ if(audioBuffer == 0)
+ audioBuffer = new char[snd_pcm_frames_to_bytes(handle,buffer_frames)];
+ snd_pcm_prepare( handle );
+ snd_pcm_start(handle);
+
+ // Step 5: Setup callback and timer fallback
+ snd_async_add_pcm_handler(&ahandler, handle, async_callback, this);
+ bytesAvailable = bytesFree();
+
+ // Step 6: Start audio processing
+ timer->start(period_time/1000);
+
+ errorState = QAudio::NoError;
+ totalTimeValue = 0;
+ opened = true;
+
+ return true;
+}
+
+void QAudioOutputPrivate::close()
+{
+ deviceState = QAudio::StopState;
+ timer->stop();
+
+ if ( handle ) {
+ snd_pcm_drain( handle );
+ snd_pcm_close( handle );
+ handle = 0;
+ delete [] audioBuffer;
+ audioBuffer=0;
+ }
+ if(!pullMode && audioSource) {
+ delete audioSource;
+ audioSource = 0;
+ }
+ opened = false;
+}
+
+int QAudioOutputPrivate::bytesFree() const
+{
+ if(resuming)
+ return period_size;
+
+ if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
+ return 0;
+ int frames = snd_pcm_avail_update(handle);
+ if((int)frames > (int)buffer_frames)
+ frames = buffer_frames;
+
+ return snd_pcm_frames_to_bytes(handle, frames);
+}
+
+qint64 QAudioOutputPrivate::write( const char *data, qint64 len )
+{
+ // Write out some audio data
+ if ( !handle )
+ return 0;
+#ifdef DEBUG_AUDIO
+ qDebug()<<"frames to write out = "<<
+ snd_pcm_bytes_to_frames( handle, (int)len )<<" ("<<len<<") bytes";
+#endif
+ int frames, err;
+ int space = bytesFree();
+ if(len < space) {
+ // Just write it
+ frames = snd_pcm_bytes_to_frames( handle, (int)len );
+ err = snd_pcm_writei( handle, data, frames );
+ } else {
+ // Only write space worth
+ frames = snd_pcm_bytes_to_frames( handle, (int)space );
+ err = snd_pcm_writei( handle, data, frames );
+ }
+ if(err > 0) {
+ totalTimeValue += err*1000000/settings.frequency();
+ resuming = false;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ return snd_pcm_frames_to_bytes( handle, err );
+ } else
+ err = xrun_recovery(err);
+
+ if(err < 0) {
+ close();
+ errorState = QAudio::FatalError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ }
+ return 0;
+}
+
+int QAudioOutputPrivate::periodSize() const
+{
+ return period_size;
+}
+
+void QAudioOutputPrivate::setBufferSize(int value)
+{
+ if(deviceState == QAudio::StopState)
+ buffer_size = value;
+}
+
+int QAudioOutputPrivate::bufferSize() const
+{
+ return buffer_size;
+}
+
+void QAudioOutputPrivate::setNotifyInterval(int ms)
+{
+ intervalTime = ms;
+}
+
+int QAudioOutputPrivate::notifyInterval() const
+{
+ return intervalTime;
+}
+
+qint64 QAudioOutputPrivate::totalTime() const
+{
+ return totalTimeValue;
+}
+
+void QAudioOutputPrivate::resume()
+{
+ if(deviceState == QAudio::SuspendState) {
+ int err = 0;
+
+ if(handle) {
+ err = snd_pcm_prepare( handle );
+ if(err < 0)
+ xrun_recovery(err);
+
+ err = snd_pcm_start(handle);
+ if(err < 0)
+ xrun_recovery(err);
+
+ bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames);
+ }
+ resuming = true;
+ if(pullMode)
+ deviceState = QAudio::ActiveState;
+ else
+ deviceState = QAudio::IdleState;
+
+ errorState = QAudio::NoError;
+ timer->start(period_time/1000);
+ emit stateChanged(deviceState);
+ }
+}
+
+QAudioFormat QAudioOutputPrivate::format() const
+{
+ return settings;
+}
+
+void QAudioOutputPrivate::suspend()
+{
+ if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState || resuming) {
+ timer->stop();
+ deviceState = QAudio::SuspendState;
+ errorState = QAudio::NoError;
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioOutputPrivate::userFeed()
+{
+ if(deviceState == QAudio::StopState || deviceState == QAudio::SuspendState)
+ return;
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() OUT";
+#endif
+ if(deviceState == QAudio::IdleState)
+ bytesAvailable = bytesFree();
+
+ deviceReady();
+}
+
+void QAudioOutputPrivate::feedback()
+{
+ QMetaObject::invokeMethod(this, SLOT(updateAvailable()), Qt::QueuedConnection);
+}
+
+void QAudioOutputPrivate::updateAvailable()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :updateAvailable()";
+#endif
+ bytesAvailable = bytesFree();
+}
+
+bool QAudioOutputPrivate::deviceReady()
+{
+ if(pullMode) {
+ int l = 0;
+ int chunks = bytesAvailable/period_size;
+ if(chunks==0) {
+ bytesAvailable = bytesFree();
+ return false;
+ }
+#ifdef DEBUG_AUDIO
+ qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes";
+ qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<period_size*chunks;
+#endif
+ int input = period_frames*chunks;
+ if(input > (int)buffer_frames)
+ input = buffer_frames;
+ l = audioSource->read(audioBuffer,snd_pcm_frames_to_bytes(handle, input));
+ if(l > 0) {
+ // Got some data to output
+ if(deviceState != QAudio::ActiveState)
+ return true;
+ write(audioBuffer,l);
+ bytesAvailable = bytesFree();
+
+ } else if(l == 0) {
+ // Did not get any data to output
+ bytesAvailable = bytesFree();
+ if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) {
+ // Underrun
+ errorState = QAudio::UnderrunError;
+ deviceState = QAudio::IdleState;
+ emit stateChanged(deviceState);
+ }
+
+ } else if(l < 0) {
+ close();
+ errorState = QAudio::IOError;
+ emit stateChanged(deviceState);
+ }
+ } else
+ bytesAvailable = bytesFree();
+
+ if(deviceState != QAudio::ActiveState)
+ return true;
+
+ if(timeStamp.elapsed() > intervalTime && intervalTime > 50) {
+ emit notify();
+ timeStamp.restart();
+ }
+ return true;
+}
+
+qint64 QAudioOutputPrivate::clock() const
+{
+ if(!handle)
+ return 0;
+
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+
+ 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 * 1000)+l/1000);
+ } else
+ return 0;
+ return 0;
+}
+
+void QAudioOutputPrivate::reset()
+{
+ if(handle)
+ snd_pcm_reset(handle);
+
+ stop();
+}
+
+OutputPrivate::OutputPrivate(QAudioOutputPrivate* audio)
+{
+ audioDevice = qobject_cast<QAudioOutputPrivate*>(audio);
+}
+
+OutputPrivate::~OutputPrivate() {}
+
+qint64 OutputPrivate::readData( char* data, qint64 len)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(len)
+
+ return 0;
+}
+
+qint64 OutputPrivate::writeData(const char* data, qint64 len)
+{
+ int retry = 0;
+ qint64 written = 0;
+ if((audioDevice->deviceState == QAudio::ActiveState)
+ ||(audioDevice->deviceState == QAudio::IdleState)) {
+ while(written < len) {
+ int chunk = audioDevice->write(data+written,(len-written));
+ if(chunk <= 0)
+ retry++;
+ written+=chunk;
+ if(retry > 10)
+ return written;
+ }
+ }
+ return written;
+
+}
diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.h b/src/multimedia/audio/qaudiooutput_alsa_p.h
new file mode 100644
index 0000000..f243bad
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_alsa_p.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIOOUTPUTALSA_H
+#define QAUDIOOUTPUTALSA_H
+
+#include <alsa/asoundlib.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+class OutputPrivate;
+
+class QAudioOutputPrivate : public QAbstractAudioOutput
+{
+ friend class OutputPrivate;
+ Q_OBJECT
+public:
+ QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat);
+ ~QAudioOutputPrivate();
+
+ qint64 write( const char *data, qint64 len );
+
+ QIODevice* start(QIODevice* device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+ int bytesFree() const;
+ int periodSize() const;
+ void setBufferSize(int value);
+ int bufferSize() const;
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+ qint64 totalTime() const;
+ qint64 clock() const;
+ QAudio::Error error() const;
+ QAudio::State state() const;
+ QAudioFormat format() const;
+
+ QIODevice* audioSource;
+ QAudioFormat settings;
+ QAudio::Error errorState;
+ QAudio::State deviceState;
+
+private slots:
+ void userFeed();
+ void feedback();
+ void updateAvailable();
+ bool deviceReady();
+
+signals:
+ void processMore();
+
+private:
+ bool opened;
+ bool pullMode;
+ bool resuming;
+ int buffer_size;
+ int period_size;
+ int intervalTime;
+ qint64 totalTimeValue;
+ unsigned int buffer_time;
+ unsigned int period_time;
+ snd_pcm_uframes_t buffer_frames;
+ snd_pcm_uframes_t period_frames;
+ static void async_callback(snd_async_handler_t *ahandler);
+ int xrun_recovery(int err);
+
+ int setFormat();
+ bool open();
+ void close();
+
+ QTimer* timer;
+ QByteArray m_device;
+ int bytesAvailable;
+ QTime timeStamp;
+ char* audioBuffer;
+ snd_pcm_t* handle;
+ snd_async_handler_t* ahandler;
+ snd_pcm_access_t access;
+ snd_pcm_format_t pcmformat;
+ snd_timestamp_t* timestamp;
+ snd_pcm_hw_params_t *hwparams;
+};
+
+class OutputPrivate : public QIODevice
+{
+ friend class QAudioOutputPrivate;
+ Q_OBJECT
+public:
+ OutputPrivate(QAudioOutputPrivate* audio);
+ ~OutputPrivate();
+
+ qint64 readData( char* data, qint64 len);
+ qint64 writeData(const char* data, qint64 len);
+
+private:
+ QAudioOutputPrivate *audioDevice;
+};
+
+#endif
diff --git a/src/multimedia/audio/qaudiooutput_mac_p.cpp b/src/multimedia/audio/qaudiooutput_mac_p.cpp
new file mode 100644
index 0000000..0d6e615
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_mac_p.cpp
@@ -0,0 +1,700 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <CoreServices/CoreServices.h>
+#include <CoreAudio/CoreAudio.h>
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+#include <QtCore/qendian.h>
+#include <QtCore/qbuffer.h>
+#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"
+
+
+QT_BEGIN_NAMESPACE
+
+
+namespace
+{
+
+static const int default_buffer_size = 8 * 1024;
+
+
+class QAudioOutputBuffer : public QObject
+{
+ Q_OBJECT
+
+public:
+ QAudioOutputBuffer(int bufferSize, int maxPeriodSize, QAudioFormat const& audioFormat):
+ m_deviceError(false),
+ m_maxPeriodSize(maxPeriodSize),
+ m_device(0)
+ {
+ m_buffer = new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize)));
+ m_bytesPerFrame = (audioFormat.sampleSize() / 8) * audioFormat.channels();
+ m_periodTime = m_maxPeriodSize / m_bytesPerFrame * 1000 / audioFormat.frequency();
+
+ m_fillTimer = new QTimer(this);
+ connect(m_fillTimer, SIGNAL(timeout()), SLOT(fillBuffer()));
+ }
+
+ ~QAudioOutputBuffer()
+ {
+ delete m_buffer;
+ }
+
+ qint64 readFrames(char* data, qint64 maxFrames)
+ {
+ bool wecan = true;
+ qint64 framesRead = 0;
+
+ while (wecan && framesRead < maxFrames) {
+ QAudioRingBuffer::Region region = m_buffer->acquireReadRegion((maxFrames - framesRead) * m_bytesPerFrame);
+
+ if (region.second > 0) {
+ region.second -= region.second % m_bytesPerFrame;
+ memcpy(data + (framesRead * m_bytesPerFrame), region.first, region.second);
+ framesRead += region.second / m_bytesPerFrame;
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseReadRegion(region);
+ }
+
+ if (framesRead == 0 && m_deviceError)
+ framesRead = -1;
+
+ return framesRead;
+ }
+
+ qint64 writeBytes(const char* data, qint64 maxSize)
+ {
+ bool wecan = true;
+ qint64 bytesWritten = 0;
+
+ maxSize -= maxSize % m_bytesPerFrame;
+ while (wecan && bytesWritten < maxSize) {
+ QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(maxSize - bytesWritten);
+
+ if (region.second > 0) {
+ memcpy(region.first, data + bytesWritten, region.second);
+ bytesWritten += region.second;
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+
+ if (bytesWritten > 0)
+ emit readyRead();
+
+ return bytesWritten;
+ }
+
+ int available() const
+ {
+ return m_buffer->free();
+ }
+
+ void reset()
+ {
+ m_buffer->reset();
+ m_deviceError = false;
+ }
+
+ void setPrefetchDevice(QIODevice* device)
+ {
+ if (m_device != device) {
+ m_device = device;
+ if (m_device != 0)
+ fillBuffer();
+ }
+ }
+
+ void startFillTimer()
+ {
+ if (m_device != 0)
+ m_fillTimer->start(m_buffer->size() / 2 / m_maxPeriodSize * m_periodTime);
+ }
+
+ void stopFillTimer()
+ {
+ m_fillTimer->stop();
+ }
+
+signals:
+ void readyRead();
+
+private slots:
+ void fillBuffer()
+ {
+ const int free = m_buffer->free();
+ const int writeSize = free - (free % m_maxPeriodSize);
+
+ if (writeSize > 0) {
+ bool wecan = true;
+ int filled = 0;
+
+ while (!m_deviceError && wecan && filled < writeSize) {
+ QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(writeSize - filled);
+
+ if (region.second > 0) {
+ region.second = m_device->read(region.first, region.second);
+ if (region.second > 0)
+ filled += region.second;
+ else if (region.second == 0)
+ wecan = false;
+ else if (region.second < 0) {
+ m_fillTimer->stop();
+ region.second = 0;
+ m_deviceError = true;
+ }
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+
+ if (filled > 0)
+ emit readyRead();
+ }
+ }
+
+private:
+ bool m_deviceError;
+ int m_maxPeriodSize;
+ int m_bytesPerFrame;
+ int m_periodTime;
+ QIODevice* m_device;
+ QTimer* m_fillTimer;
+ QAudioRingBuffer* m_buffer;
+};
+
+
+}
+
+class MacOutputDevice : public QIODevice
+{
+ Q_OBJECT
+
+public:
+ MacOutputDevice(QAudioOutputBuffer* audioBuffer, QObject* parent):
+ QIODevice(parent),
+ m_audioBuffer(audioBuffer)
+ {
+ open(QIODevice::WriteOnly | QIODevice::Unbuffered);
+ }
+
+ qint64 readData(char* data, qint64 len)
+ {
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+
+ return 0;
+ }
+
+ qint64 writeData(const char* data, qint64 len)
+ {
+ return m_audioBuffer->writeBytes(data, len);
+ }
+
+ bool isSequential() const
+ {
+ return true;
+ }
+
+private:
+ QAudioOutputBuffer* m_audioBuffer;
+};
+
+
+QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray& device, const QAudioFormat& format):
+ audioFormat(format)
+{
+ QDataStream ds(device);
+ quint32 did, mode;
+
+ ds >> did >> mode;
+
+ if (QAudio::Mode(mode) == QAudio::AudioInput)
+ errorCode = QAudio::OpenError;
+ else {
+ isOpen = false;
+ audioDeviceId = AudioDeviceID(did);
+ audioUnit = 0;
+ audioIO = 0;
+ startTime = 0;
+ totalFrames = 0;
+ audioBuffer = 0;
+ internalBufferSize = default_buffer_size;
+ clockFrequency = AudioGetHostClockFrequency() / 1000;
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::StopState;
+ audioThreadState = Stopped;
+
+ intervalTimer = new QTimer(this);
+ intervalTimer->setInterval(1000);
+ connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify()));
+ }
+}
+
+QAudioOutputPrivate::~QAudioOutputPrivate()
+{
+ close();
+}
+
+bool QAudioOutputPrivate::open()
+{
+ if (errorCode != QAudio::NoError)
+ return false;
+
+ if (isOpen)
+ return true;
+
+ ComponentDescription cd;
+ cd.componentType = kAudioUnitType_Output;
+ cd.componentSubType = kAudioUnitSubType_HALOutput;
+ cd.componentManufacturer = kAudioUnitManufacturer_Apple;
+ cd.componentFlags = 0;
+ cd.componentFlagsMask = 0;
+
+ // Open
+ Component cp = FindNextComponent(NULL, &cd);
+ if (cp == 0) {
+ qWarning() << "QAudioOutput: Failed to find HAL Output component";
+ return false;
+ }
+
+ if (OpenAComponent(cp, &audioUnit) != noErr) {
+ qWarning() << "QAudioOutput: Unable to Open Output Component";
+ return false;
+ }
+
+ // register callback
+ AURenderCallbackStruct cb;
+ cb.inputProc = renderCallback;
+ cb.inputProcRefCon = this;
+
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioUnitProperty_SetRenderCallback,
+ kAudioUnitScope_Global,
+ 0,
+ &cb,
+ sizeof(cb)) != noErr) {
+ qWarning() << "QAudioOutput: Failed to set AudioUnit callback";
+ return false;
+ }
+
+ // Set Audio Device
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioOutputUnitProperty_CurrentDevice,
+ kAudioUnitScope_Global,
+ 0,
+ &audioDeviceId,
+ sizeof(audioDeviceId)) != noErr) {
+ qWarning() << "QAudioOutput: Unable to use configured device";
+ return false;
+ }
+
+ // Set stream format
+ streamFormat = toAudioStreamBasicDescription(audioFormat);
+
+ UInt32 size = sizeof(deviceFormat);
+ if (AudioUnitGetProperty(audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input,
+ 0,
+ &deviceFormat,
+ &size) != noErr) {
+ qWarning() << "QAudioOutput: Unable to retrieve device format";
+ return false;
+ }
+
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input,
+ 0,
+ &streamFormat,
+ sizeof(streamFormat)) != noErr) {
+ qWarning() << "QAudioOutput: Unable to Set Stream information";
+ return false;
+ }
+
+ // Allocate buffer
+ UInt32 numberOfFrames = 0;
+ size = sizeof(UInt32);
+ if (AudioUnitGetProperty(audioUnit,
+ kAudioDevicePropertyBufferFrameSize,
+ kAudioUnitScope_Global,
+ 0,
+ &numberOfFrames,
+ &size) != noErr) {
+ qWarning() << "QAudioInput: Failed to get audio period size";
+ return false;
+ }
+
+ periodSizeBytes = (numberOfFrames * streamFormat.mSampleRate / deviceFormat.mSampleRate) *
+ streamFormat.mBytesPerFrame;
+ if (internalBufferSize < periodSizeBytes * 2)
+ internalBufferSize = periodSizeBytes * 2;
+ else
+ internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame;
+
+ audioBuffer = new QAudioOutputBuffer(internalBufferSize, periodSizeBytes, audioFormat);
+ connect(audioBuffer, SIGNAL(readyRead()), SLOT(inputReady())); // Pull
+
+ audioIO = new MacOutputDevice(audioBuffer, this);
+
+ // Init
+ if (AudioUnitInitialize(audioUnit)) {
+ qWarning() << "QAudioOutput: Failed to initialize AudioUnit";
+ return false;
+ }
+
+ isOpen = true;
+
+ return true;
+}
+
+void QAudioOutputPrivate::close()
+{
+ if (audioUnit != 0) {
+ AudioOutputUnitStop(audioUnit);
+ AudioUnitUninitialize(audioUnit);
+ CloseComponent(audioUnit);
+ }
+
+ delete audioBuffer;
+}
+
+QAudioFormat QAudioOutputPrivate::format() const
+{
+ return audioFormat;
+}
+
+QIODevice* QAudioOutputPrivate::start(QIODevice* device)
+{
+ QIODevice* op = device;
+
+ if (!open()) {
+ stateCode = QAudio::StopState;
+ errorCode = QAudio::OpenError;
+ return audioIO;
+ }
+
+ reset();
+ audioBuffer->reset();
+ audioBuffer->setPrefetchDevice(op);
+
+ if (op == 0) {
+ op = audioIO;
+ stateCode = QAudio::IdleState;
+ }
+ else
+ stateCode = QAudio::ActiveState;
+
+ // Start
+ errorCode = QAudio::NoError;
+ totalFrames = 0;
+ startTime = AudioGetCurrentHostTime();
+
+ if (stateCode == QAudio::ActiveState)
+ audioThreadStart();
+
+ return op;
+}
+
+void QAudioOutputPrivate::stop()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode != QAudio::StopState) {
+ audioThreadDrain();
+
+ stateCode = QAudio::StopState;
+ errorCode = QAudio::NoError;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioOutputPrivate::reset()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode != QAudio::StopState) {
+ audioThreadStop();
+
+ stateCode = QAudio::StopState;
+ errorCode = QAudio::NoError;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioOutputPrivate::suspend()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState || stateCode == QAudio::IdleState) {
+ audioThreadStop();
+
+ stateCode = QAudio::SuspendState;
+ errorCode = QAudio::NoError;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioOutputPrivate::resume()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::SuspendState) {
+ audioThreadStart();
+
+ stateCode = QAudio::ActiveState;
+ errorCode = QAudio::NoError;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+int QAudioOutputPrivate::bytesFree() const
+{
+ return audioBuffer->available();
+}
+
+int QAudioOutputPrivate::periodSize() const
+{
+ return periodSizeBytes;
+}
+
+void QAudioOutputPrivate::setBufferSize(int bs)
+{
+ if (stateCode == QAudio::StopState)
+ internalBufferSize = bs;
+}
+
+int QAudioOutputPrivate::bufferSize() const
+{
+ return internalBufferSize;
+}
+
+void QAudioOutputPrivate::setNotifyInterval(int milliSeconds)
+{
+ intervalTimer->setInterval(milliSeconds);
+}
+
+int QAudioOutputPrivate::notifyInterval() const
+{
+ return intervalTimer->interval();
+}
+
+qint64 QAudioOutputPrivate::totalTime() const
+{
+ return totalFrames * 1000000 / audioFormat.frequency();
+}
+
+qint64 QAudioOutputPrivate::clock() const
+{
+ return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000);
+}
+
+QAudio::Error QAudioOutputPrivate::error() const
+{
+ return errorCode;
+}
+
+QAudio::State QAudioOutputPrivate::state() const
+{
+ return stateCode;
+}
+
+void QAudioOutputPrivate::audioThreadStart()
+{
+ startTimers();
+ audioThreadState = Running;
+ AudioOutputUnitStart(audioUnit);
+}
+
+void QAudioOutputPrivate::audioThreadStop()
+{
+ stopTimers();
+ if (audioThreadState.testAndSetAcquire(Running, Stopped))
+ threadFinished.wait(&mutex);
+}
+
+void QAudioOutputPrivate::audioThreadDrain()
+{
+ stopTimers();
+ if (audioThreadState.testAndSetAcquire(Running, Draining))
+ threadFinished.wait(&mutex);
+}
+
+void QAudioOutputPrivate::audioDeviceStop()
+{
+ AudioOutputUnitStop(audioUnit);
+ audioThreadState = Stopped;
+ threadFinished.wakeOne();
+}
+
+void QAudioOutputPrivate::audioDeviceIdle()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState) {
+ audioDeviceStop();
+
+ errorCode = QAudio::UnderrunError;
+ stateCode = QAudio::IdleState;
+ QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
+ }
+}
+
+void QAudioOutputPrivate::audioDeviceError()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState) {
+ audioDeviceStop();
+
+ errorCode = QAudio::IOError;
+ stateCode = QAudio::StopState;
+ QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
+ }
+}
+
+void QAudioOutputPrivate::startTimers()
+{
+ audioBuffer->startFillTimer();
+ intervalTimer->start();
+}
+
+void QAudioOutputPrivate::stopTimers()
+{
+ audioBuffer->stopFillTimer();
+ intervalTimer->stop();
+}
+
+
+void QAudioOutputPrivate::deviceStopped()
+{
+ intervalTimer->stop();
+ emit stateChanged(stateCode);
+}
+
+void QAudioOutputPrivate::inputReady()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::IdleState) {
+ audioThreadStart();
+
+ stateCode = QAudio::ActiveState;
+ errorCode = QAudio::NoError;
+
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+
+OSStatus QAudioOutputPrivate::renderCallback(void* inRefCon,
+ AudioUnitRenderActionFlags* ioActionFlags,
+ const AudioTimeStamp* inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList* ioData)
+{
+ Q_UNUSED(ioActionFlags)
+ Q_UNUSED(inTimeStamp)
+ Q_UNUSED(inBusNumber)
+ Q_UNUSED(inNumberFrames)
+
+ QAudioOutputPrivate* d = static_cast<QAudioOutputPrivate*>(inRefCon);
+
+ const int threadState = d->audioThreadState.fetchAndAddAcquire(0);
+ if (threadState == Stopped) {
+ ioData->mBuffers[0].mDataByteSize = 0;
+ d->audioDeviceStop();
+ }
+ else {
+ const UInt32 bytesPerFrame = d->streamFormat.mBytesPerFrame;
+ qint64 framesRead;
+
+ framesRead = d->audioBuffer->readFrames((char*)ioData->mBuffers[0].mData,
+ ioData->mBuffers[0].mDataByteSize / bytesPerFrame);
+
+ if (framesRead > 0) {
+ ioData->mBuffers[0].mDataByteSize = framesRead * bytesPerFrame;
+ d->totalFrames += framesRead;
+ }
+ else {
+ ioData->mBuffers[0].mDataByteSize = 0;
+ if (framesRead == 0) {
+ if (threadState == Draining)
+ d->audioDeviceStop();
+ else
+ d->audioDeviceIdle();
+ }
+ else
+ d->audioDeviceError();
+ }
+ }
+
+ return noErr;
+}
+
+
+QT_END_NAMESPACE
+
+#include "qaudiooutput_mac_p.moc"
+
diff --git a/src/multimedia/audio/qaudiooutput_mac_p.h b/src/multimedia/audio/qaudiooutput_mac_p.h
new file mode 100644
index 0000000..c85cab4
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_mac_p.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIOOUTPUT_MAC_P_H
+#define QAUDIOOUTPUT_MAC_P_H
+
+#include <CoreServices/CoreServices.h>
+#include <CoreAudio/CoreAudio.h>
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qatomic.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudioengine.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+namespace
+{
+class QAudioOutputBuffer;
+}
+
+class QAudioOutputPrivate : public QAbstractAudioOutput
+{
+ Q_OBJECT
+
+public:
+ bool isOpen;
+ int internalBufferSize;
+ int periodSizeBytes;
+ qint64 totalFrames;
+ QAudioFormat audioFormat;
+ QIODevice* audioIO;
+ AudioDeviceID audioDeviceId;
+ AudioUnit audioUnit;
+ Float64 clockFrequency;
+ UInt64 startTime;
+ AudioStreamBasicDescription deviceFormat;
+ AudioStreamBasicDescription streamFormat;
+ QAudioOutputBuffer* audioBuffer;
+ QAtomicInt audioThreadState;
+ QWaitCondition threadFinished;
+ QMutex mutex;
+ QTimer* intervalTimer;
+
+ QAudio::Error errorCode;
+ QAudio::State stateCode;
+
+ QAudioOutputPrivate(const QByteArray& device, const QAudioFormat& format);
+ ~QAudioOutputPrivate();
+
+ bool open();
+ void close();
+
+ QAudioFormat format() const;
+
+ QIODevice* start(QIODevice* device);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+
+ int bytesFree() const;
+ int periodSize() const;
+
+ void setBufferSize(int value);
+ int bufferSize() const;
+
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+
+ qint64 totalTime() const;
+ qint64 clock() const;
+
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+ void audioThreadStart();
+ void audioThreadStop();
+ void audioThreadDrain();
+
+ void audioDeviceStop();
+ void audioDeviceIdle();
+ void audioDeviceError();
+
+ void startTimers();
+ void stopTimers();
+
+signals:
+ void stateChanged(QAudio::State);
+ void notify();
+
+private slots:
+ void deviceStopped();
+ void inputReady();
+
+private:
+ enum { Running, Draining, Stopped };
+
+ static OSStatus renderCallback(void* inRefCon,
+ AudioUnitRenderActionFlags* ioActionFlags,
+ const AudioTimeStamp* inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList* ioData);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/multimedia/audio/qaudiooutput_win32_p.cpp b/src/multimedia/audio/qaudiooutput_win32_p.cpp
new file mode 100644
index 0000000..f681936
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_win32_p.cpp
@@ -0,0 +1,502 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qaudiooutput_win32_p.h"
+
+//#define DEBUG_AUDIO 1
+
+QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
+ settings(audioFormat)
+{
+ bytesAvailable = 0;
+ buffer_size = 0;
+ period_size = 0;
+ m_device = device;
+ totalTimeValue = 0;
+ intervalTime = 1000;
+ audioBuffer = 0;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::StopState;
+ audioSource = 0;
+ pullMode = true;
+ InitializeCriticalSection(&waveOutCriticalSection);
+}
+
+QAudioOutputPrivate::~QAudioOutputPrivate()
+{
+ close();
+ DeleteCriticalSection(&waveOutCriticalSection);
+}
+
+void CALLBACK QAudioOutputPrivate::waveOutProc( HWAVEOUT hWaveOut, UINT uMsg,
+ DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
+{
+ Q_UNUSED(dwParam1)
+ Q_UNUSED(dwParam2)
+ Q_UNUSED(hWaveOut)
+
+ QAudioOutputPrivate* qAudio;
+ qAudio = (QAudioOutputPrivate*)(dwInstance);
+ if(!qAudio)
+ return;
+
+ switch(uMsg) {
+ case WOM_OPEN:
+ qAudio->feedback();
+ break;
+ case WOM_CLOSE:
+ return;
+ case WOM_DONE:
+ EnterCriticalSection(&waveOutCriticalSection);
+ qAudio->waveFreeBlockCount++;
+ if(qAudio->waveFreeBlockCount >= qAudio->buffer_size/qAudio->period_size)
+ qAudio->waveFreeBlockCount = qAudio->buffer_size/qAudio->period_size;
+ LeaveCriticalSection(&waveOutCriticalSection);
+ qAudio->feedback();
+ break;
+ default:
+ return;
+ }
+}
+
+WAVEHDR* QAudioOutputPrivate::allocateBlocks(int size, int count)
+{
+ int i;
+ unsigned char* buffer;
+ WAVEHDR* blocks;
+ DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count;
+
+ if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+ totalBufferSize)) == 0) {
+ qWarning("QAudioOutput: Memory allocation error");
+ return 0;
+ }
+ blocks = (WAVEHDR*)buffer;
+ buffer += sizeof(WAVEHDR)*count;
+ for(i = 0; i < count; i++) {
+ blocks[i].dwBufferLength = size;
+ blocks[i].lpData = (LPSTR)buffer;
+ buffer += size;
+ }
+ return blocks;
+}
+
+void QAudioOutputPrivate::freeBlocks(WAVEHDR* blockArray)
+{
+ HeapFree(GetProcessHeap(), 0, blockArray);
+}
+
+QAudioFormat QAudioOutputPrivate::format() const
+{
+ return settings;
+}
+
+QIODevice* QAudioOutputPrivate::start(QIODevice* device)
+{
+ if(deviceState != QAudio::StopState)
+ close();
+
+ if(!pullMode && audioSource) {
+ delete audioSource;
+ }
+
+ if(device) {
+ //set to pull mode
+ pullMode = true;
+ audioSource = device;
+ deviceState = QAudio::ActiveState;
+ } else {
+ //set to push mode
+ pullMode = false;
+ audioSource = new OutputPrivate(this);
+ audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
+ deviceState = QAudio::IdleState;
+ }
+
+ if( !open() )
+ return 0;
+
+ emit stateChanged(deviceState);
+
+ return audioSource;
+}
+
+void QAudioOutputPrivate::stop()
+{
+ if(deviceState == QAudio::StopState)
+ return;
+ deviceState = QAudio::StopState;
+ close();
+ if(!pullMode && audioSource) {
+ delete audioSource;
+ audioSource = 0;
+ }
+ emit stateChanged(deviceState);
+}
+
+bool QAudioOutputPrivate::open()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
+#endif
+ 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);
+ waveFreeBlockCount = buffer_size/period_size;
+ waveCurrentBlock = 0;
+
+ if(audioBuffer == 0)
+ audioBuffer = new char[buffer_size];
+
+ timeStamp.restart();
+
+ wfx.nSamplesPerSec = settings.frequency();
+ wfx.wBitsPerSample = settings.sampleSize();
+ wfx.nChannels = settings.channels();
+ wfx.cbSize = 0;
+
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
+
+ UINT_PTR devId = WAVE_MAPPER;
+
+ WAVEOUTCAPS woc;
+ unsigned long iNumDevs,ii;
+ iNumDevs = waveOutGetNumDevs();
+ for(ii=0;ii<iNumDevs;ii++) {
+ if(waveOutGetDevCaps(ii, &woc, sizeof(WAVEOUTCAPS))
+ == MMSYSERR_NOERROR) {
+ QString tmp;
+ tmp = QString::fromUtf16((const unsigned short*)woc.szPname);
+ if(tmp.compare(tr(m_device)) == 0) {
+ devId = ii;
+ break;
+ }
+ }
+ }
+
+ if(waveOutOpen(&hWaveOut, devId, &wfx,
+ (DWORD_PTR)&waveOutProc,
+ (DWORD_PTR) this,
+ CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ qWarning("QAudioOutput: open error");
+ return false;
+ }
+
+ totalTimeValue = 0;
+ timeStampOpened.restart();
+
+ errorState = QAudio::NoError;
+ if(pullMode) {
+ deviceState = QAudio::ActiveState;
+ QTimer::singleShot(10, this, SLOT(feedback()));
+ } else
+ deviceState = QAudio::IdleState;
+
+ return true;
+}
+
+void QAudioOutputPrivate::close()
+{
+ if(deviceState == QAudio::StopState)
+ return;
+
+ deviceState = QAudio::StopState;
+ int delay = (buffer_size-bytesFree())*1000/(settings.frequency()
+ *settings.channels()*(settings.sampleSize()/8));
+ waveOutReset(hWaveOut);
+ Sleep(delay+10);
+
+ freeBlocks(waveBlocks);
+ waveOutClose(hWaveOut);
+ delete [] audioBuffer;
+ audioBuffer = 0;
+ buffer_size = 0;
+}
+
+int QAudioOutputPrivate::bytesFree() const
+{
+ int buf;
+ buf = waveFreeBlockCount*period_size;
+ return buf;
+}
+
+int QAudioOutputPrivate::periodSize() const
+{
+ return period_size;
+}
+
+void QAudioOutputPrivate::setBufferSize(int value)
+{
+ if(deviceState == QAudio::StopState)
+ buffer_size = value;
+}
+
+int QAudioOutputPrivate::bufferSize() const
+{
+ return buffer_size;
+}
+
+void QAudioOutputPrivate::setNotifyInterval(int ms)
+{
+ intervalTime = ms;
+}
+
+int QAudioOutputPrivate::notifyInterval() const
+{
+ return intervalTime;
+}
+
+qint64 QAudioOutputPrivate::totalTime() const
+{
+ return totalTimeValue;
+}
+
+qint64 QAudioOutputPrivate::write( const char *data, qint64 len )
+{
+ // Write out some audio data
+
+ char* p = (char*)data;
+ int l = (int)len;
+
+ WAVEHDR* current;
+ int remain;
+ current = &waveBlocks[waveCurrentBlock];
+ while(l > 0) {
+ if(waveFreeBlockCount==0)
+ break;
+
+ if(current->dwFlags & WHDR_PREPARED)
+ waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));
+
+ if(l < period_size)
+ remain = l;
+ else
+ remain = period_size;
+ memcpy(current->lpData, p, remain);
+
+ l -= remain;
+ p += remain;
+ current->dwBufferLength = remain;
+ waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
+ waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
+
+ EnterCriticalSection(&waveOutCriticalSection);
+ waveFreeBlockCount--;
+ LeaveCriticalSection(&waveOutCriticalSection);
+#ifdef DEBUG_AUDIO
+ qDebug("write out l=%d, waveFreeBlockCount=%d",
+ current->dwBufferLength,waveFreeBlockCount);
+#endif
+ totalTimeValue += current->dwBufferLength
+ /(settings.channels()*(settings.sampleSize()/8))
+ *1000000/settings.frequency();;
+ waveCurrentBlock++;
+ waveCurrentBlock %= buffer_size/period_size;
+ current = &waveBlocks[waveCurrentBlock];
+ current->dwUser = 0;
+ }
+ return (len-l);
+}
+
+void QAudioOutputPrivate::resume()
+{
+ if(deviceState == QAudio::SuspendState) {
+ deviceState = QAudio::ActiveState;
+ errorState = QAudio::NoError;
+ waveOutRestart(hWaveOut);
+ QTimer::singleShot(10, this, SLOT(feedback()));
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioOutputPrivate::suspend()
+{
+ if(deviceState == QAudio::ActiveState) {
+ waveOutPause(hWaveOut);
+ deviceState = QAudio::SuspendState;
+ errorState = QAudio::NoError;
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioOutputPrivate::feedback()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback()";
+#endif
+ bytesAvailable = bytesFree();
+
+ if(!(deviceState==QAudio::StopState||deviceState==QAudio::SuspendState)) {
+ if(bytesAvailable >= period_size)
+ QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection);
+ }
+}
+
+bool QAudioOutputPrivate::deviceReady()
+{
+ if(pullMode) {
+ int i = 0;
+ int chunks = bytesAvailable/period_size;
+#ifdef DEBUG_AUDIO
+ qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes";
+ qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<chunks*period_size;
+#endif
+ bool startup = false;
+ if(totalTimeValue == 0)
+ startup = true;
+
+ if(startup)
+ waveOutPause(hWaveOut);
+ int input = period_size*chunks;
+ int l = audioSource->read(audioBuffer,input);
+ if(l > 0) {
+ int out= write(audioBuffer,l);
+ if(out > 0)
+ deviceState = QAudio::ActiveState;
+ if(startup)
+ waveOutRestart(hWaveOut);
+ } else if(l == 0) {
+ bytesAvailable = bytesFree();
+ if(waveFreeBlockCount == buffer_size/period_size) {
+ errorState = QAudio::UnderrunError;
+ deviceState = QAudio::IdleState;
+ emit stateChanged(deviceState);
+ }
+
+ } else if(i < 0) {
+ bytesAvailable = bytesFree();
+ errorState = QAudio::IOError;
+ }
+ }
+ if(deviceState != QAudio::ActiveState)
+ return true;
+
+ if(timeStamp.elapsed() > intervalTime && intervalTime > 50) {
+ emit notify();
+ timeStamp.restart();
+ }
+
+ return true;
+}
+
+qint64 QAudioOutputPrivate::clock() const
+{
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+
+ return timeStampOpened.elapsed();
+}
+
+QAudio::Error QAudioOutputPrivate::error() const
+{
+ return errorState;
+}
+
+QAudio::State QAudioOutputPrivate::state() const
+{
+ return deviceState;
+}
+
+void QAudioOutputPrivate::reset()
+{
+ close();
+}
+
+OutputPrivate::OutputPrivate(QAudioOutputPrivate* audio)
+{
+ audioDevice = qobject_cast<QAudioOutputPrivate*>(audio);
+}
+
+OutputPrivate::~OutputPrivate() {}
+
+qint64 OutputPrivate::readData( char* data, qint64 len)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(len)
+
+ return 0;
+}
+
+qint64 OutputPrivate::writeData(const char* data, qint64 len)
+{
+ int retry = 0;
+ qint64 written = 0;
+
+ if((audioDevice->deviceState == QAudio::ActiveState)
+ ||(audioDevice->deviceState == QAudio::IdleState)) {
+ qint64 l = len;
+ while(written < l) {
+ int chunk = audioDevice->write(data+written,(l-written));
+ if(chunk <= 0)
+ retry++;
+ else
+ written+=chunk;
+
+ if(retry > 10)
+ return written;
+ }
+ audioDevice->deviceState = QAudio::ActiveState;
+ }
+ return written;
+}
diff --git a/src/multimedia/audio/qaudiooutput_win32_p.h b/src/multimedia/audio/qaudiooutput_win32_p.h
new file mode 100644
index 0000000..91f14f5
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_win32_p.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIOOUTPUTWIN_H
+#define QAUDIOOUTPUTWIN_H
+
+#include <windows.h>
+#include <mmsystem.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+
+static CRITICAL_SECTION waveOutCriticalSection;
+
+class QAudioOutputPrivate : public QAbstractAudioOutput
+{
+ Q_OBJECT
+public:
+ QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat);
+ ~QAudioOutputPrivate();
+
+ qint64 write( const char *data, qint64 len );
+
+ QAudioFormat format() const;
+ QIODevice* start(QIODevice* device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+ int bytesFree() const;
+ int periodSize() const;
+ void setBufferSize(int value);
+ int bufferSize() const;
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+ qint64 totalTime() const;
+ qint64 clock() const;
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+ QIODevice* audioSource;
+ QAudioFormat settings;
+ QAudio::Error errorState;
+ QAudio::State deviceState;
+
+private slots:
+ void feedback();
+ bool deviceReady();
+
+signals:
+ void stateChanged(QAudio::State);
+ void notify();
+
+private:
+ QByteArray m_device;
+ bool resuming;
+ int bytesAvailable;
+ QTime timeStamp;
+ QTime timeStampOpened;
+ qint32 buffer_size;
+ qint32 period_size;
+ qint64 totalTimeValue;
+ bool pullMode;
+ int intervalTime;
+ static void CALLBACK waveOutProc( HWAVEOUT hWaveOut, UINT uMsg,
+ DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 );
+
+ WAVEHDR* allocateBlocks(int size, int count);
+ void freeBlocks(WAVEHDR* blockArray);
+ bool open();
+ void close();
+
+ WAVEFORMATEX wfx;
+ HWAVEOUT hWaveOut;
+ MMRESULT result;
+ WAVEHDR header;
+ WAVEHDR* waveBlocks;
+ volatile int waveFreeBlockCount;
+ int waveCurrentBlock;
+ char* audioBuffer;
+};
+
+class OutputPrivate : public QIODevice
+{
+ Q_OBJECT
+public:
+ OutputPrivate(QAudioOutputPrivate* audio);
+ ~OutputPrivate();
+
+ qint64 readData( char* data, qint64 len);
+ qint64 writeData(const char* data, qint64 len);
+
+private:
+ QAudioOutputPrivate *audioDevice;
+};
+
+#endif
diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro
new file mode 100644
index 0000000..7d38afa
--- /dev/null
+++ b/src/multimedia/multimedia.pro
@@ -0,0 +1,11 @@
+TARGET = QtMultimedia
+QPRO_PWD = $$PWD
+QT = core
+DEFINES += QT_BUILD_MULTIMEDIA_LIB
+
+win32-msvc*:QMAKE_LIBS += $$QMAKE_LIBS_CORE
+
+unix:QMAKE_PKGCONFIG_REQUIRES = QtCore
+
+include(../qbase.pri)
+include(audio/audio.pri)