Restructure the source code a little.

Change-Id: I995b0fb33bdda7f01bf6266c1c50a1b17eba6760
Reviewed-by: Jonas Rabbe <jonas.rabbe@nokia.com>
This commit is contained in:
Michael Goddard
2012-01-04 16:05:55 +10:00
committed by Qt by Nokia
parent 6ee1977d60
commit 502d3c8eb3
123 changed files with 198 additions and 169 deletions

View File

@@ -1,17 +1,24 @@
INCLUDEPATH += audio
PUBLIC_HEADERS += audio/qaudio.h \
PUBLIC_HEADERS += \
audio/qaudio.h \
audio/qaudioformat.h \
audio/qaudioinput.h \
audio/qaudiooutput.h \
audio/qaudiodeviceinfo.h \
audio/qaudiosystemplugin.h \
audio/qaudiosystem.h
audio/qaudiosystem.h \
audio/qsoundeffect.h \
audio/qsound.h
PRIVATE_HEADERS += audio/qaudiodevicefactory_p.h audio/qaudiopluginloader_p.h
PRIVATE_HEADERS += \
audio/qaudiodevicefactory_p.h \
audio/qaudiopluginloader_p.h \
audio/qwavedecoder_p.h \
audio/qsamplecache_p.h
SOURCES += audio/qaudio.cpp \
SOURCES += \
audio/qaudio.cpp \
audio/qaudioformat.cpp \
audio/qaudiodeviceinfo.cpp \
audio/qaudiooutput.cpp \
@@ -19,7 +26,11 @@ SOURCES += audio/qaudio.cpp \
audio/qaudiosystemplugin.cpp \
audio/qaudiosystem.cpp \
audio/qaudiodevicefactory.cpp \
audio/qaudiopluginloader.cpp
audio/qaudiopluginloader.cpp \
audio/qsoundeffect.cpp \
audio/qwavedecoder_p.cpp \
audio/qsamplecache_p.cpp \
audio/qsound.cpp
mac {
PRIVATE_HEADERS += audio/qaudioinput_mac_p.h \
@@ -46,15 +57,29 @@ win32 {
unix:!mac {
contains(config_test_pulseaudio, yes) {
DEFINES += QT_NO_AUDIO_BACKEND
}
else:contains(config_test_alsa, yes) {
linux-*|freebsd-*|openbsd-* {
CONFIG += link_pkgconfig
PKGCONFIG += libpulse
DEFINES += QT_MULTIMEDIA_PULSEAUDIO
PRIVATE_HEADERS += audio/qsoundeffect_pulse_p.h
SOURCES += audio/qsoundeffect_pulse_p.cpp
!maemo*:DEFINES += QTM_PULSEAUDIO_DEFAULTBUFFER
} else {
DEFINES += QT_MULTIMEDIA_QMEDIAPLAYER
PRIVATE_HEADERS += audio/qsoundeffect_qmedia_p.h
SOURCES += audio/qsoundeffect_qmedia_p.cpp
contains(config_test_alsa, yes):linux-*|freebsd-*|openbsd-* {
DEFINES += HAS_ALSA
PRIVATE_HEADERS += audio/qaudiooutput_alsa_p.h audio/qaudioinput_alsa_p.h audio/qaudiodeviceinfo_alsa_p.h
SOURCES += audio/qaudiodeviceinfo_alsa_p.cpp \
audio/qaudiooutput_alsa_p.cpp \
audio/qaudioinput_alsa_p.cpp
audio/qaudiooutput_alsa_p.cpp \
audio/qaudioinput_alsa_p.cpp
LIBS_PRIVATE += -lasound
}
}
} else {
DEFINES += QT_MULTIMEDIA_QMEDIAPLAYER
PRIVATE_HEADERS += audio/qsoundeffect_qmedia_p.h
SOURCES += audio/qsoundeffect_qmedia_p.cpp
}

View File

@@ -0,0 +1,401 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.1, 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsamplecache_p.h"
#include "qwavedecoder_p.h"
#include <QtNetwork>
//#define QT_SAMPLECACHE_DEBUG
QT_BEGIN_NAMESPACE
/*!
\class QSampleCache
\internal
When you want to get a sound sample data, you need to request the QSample reference from QSampleCache.
\since 1.1
\code
QSample *m_sample; // class member.
private Q_SLOTS:
void decoderError();
void sampleReady();
\endcode
\code
Q_GLOBAL_STATIC(QSampleCache, sampleCache) //declare a singleton manager
\endcode
\code
m_sample = sampleCache()->requestSample(url);
switch(m_sample->state()) {
case QSample::Ready:
sampleReady();
break;
case QSample::Error:
decoderError();
break;
default:
connect(m_sample, SIGNAL(error()), this, SLOT(decoderError()));
connect(m_sample, SIGNAL(ready()), this, SLOT(sampleReady()));
break;
}
\endcode
When you no longer need the sound sample data, you need to release it:
\code
if (m_sample) {
m_sample->release();
m_sample = 0;
}
\endcode
*/
QSampleCache::QSampleCache()
: m_networkAccessManager(0)
, m_mutex(QMutex::Recursive)
, m_capacity(0)
, m_usage(0)
{
m_loadingThread.setObjectName(QLatin1String("QSampleCache::LoadingThread"));
}
QNetworkAccessManager& QSampleCache::networkAccessManager()
{
if (!m_networkAccessManager)
m_networkAccessManager = new QNetworkAccessManager();
return *m_networkAccessManager;
}
QSampleCache::~QSampleCache()
{
QMutexLocker m(&m_mutex);
m_loadingThread.quit();
m_loadingThread.wait();
// Killing the loading thread means that no samples can be
// deleted using deleteLater. And some samples that had deleteLater
// already called won't have been processed (m_staleSamples)
foreach (QSample* sample, m_samples)
delete sample;
foreach (QSample* sample, m_staleSamples)
delete sample; // deleting a sample does affect the m_staleSamples list, but foreach copies it
delete m_networkAccessManager;
}
QSample* QSampleCache::requestSample(const QUrl& url)
{
if (!m_loadingThread.isRunning())
m_loadingThread.start();
#ifdef QT_SAMPLECACHE_DEBUG
qDebug() << "QSampleCache: request sample [" << url << "]";
#endif
QMutexLocker locker(&m_mutex);
QMap<QUrl, QSample*>::iterator it = m_samples.find(url);
QSample* sample;
if (it == m_samples.end()) {
sample = new QSample(url, this);
m_samples.insert(url, sample);
sample->moveToThread(&m_loadingThread);
} else {
sample = *it;
}
sample->addRef();
locker.unlock();
sample->loadIfNecessary();
return sample;
}
void QSampleCache::setCapacity(qint64 capacity)
{
QMutexLocker locker(&m_mutex);
if (m_capacity == capacity)
return;
#ifdef QT_SAMPLECACHE_DEBUG
qDebug() << "QSampleCache: capacity changes from " << m_capacity << "to " << capacity;
#endif
if (m_capacity > 0 && capacity <= 0) { //memory management strategy changed
for (QMap<QUrl, QSample*>::iterator it = m_samples.begin(); it != m_samples.end();) {
QSample* sample = *it;
if (sample->m_ref == 0) {
unloadSample(sample);
it = m_samples.erase(it);
} else
it++;
}
}
m_capacity = capacity;
refresh(0);
}
// Called locked
void QSampleCache::unloadSample(QSample *sample)
{
m_usage -= sample->m_soundData.size();
m_staleSamples.insert(sample);
sample->deleteLater();
}
// Called in both threads
void QSampleCache::refresh(qint64 usageChange)
{
QMutexLocker locker(&m_mutex);
m_usage += usageChange;
if (m_capacity <= 0 || m_usage <= m_capacity)
return;
#ifdef QT_SAMPLECACHE_DEBUG
qint64 recoveredSize = 0;
#endif
//free unused samples to keep usage under capacity limit.
for (QMap<QUrl, QSample*>::iterator it = m_samples.begin(); it != m_samples.end();) {
QSample* sample = *it;
if (sample->m_ref > 0) {
++it;
continue;
}
#ifdef QT_SAMPLECACHE_DEBUG
recoveredSize += sample->m_soundData.size();
#endif
unloadSample(sample);
it = m_samples.erase(it);
if (m_usage <= m_capacity)
return;
}
#ifdef QT_SAMPLECACHE_DEBUG
qDebug() << "QSampleCache: refresh(" << usageChange
<< ") recovered size =" << recoveredSize
<< "new usage =" << m_usage;
#endif
if (m_usage > m_capacity)
qWarning() << "QSampleCache: usage[" << m_usage << " out of limit[" << m_capacity << "]";
}
// Called in both threads
void QSampleCache::removeUnreferencedSample(QSample *sample)
{
QMutexLocker m(&m_mutex);
m_staleSamples.remove(sample);
}
// Called in loader thread (since this lives in that thread)
// Also called from application thread after loader thread dies.
QSample::~QSample()
{
// Remove ourselves from our parent
m_parent->removeUnreferencedSample(this);
QMutexLocker locker(&m_mutex);
#ifdef QT_SAMPLECACHE_DEBUG
qDebug() << "~QSample" << this << ": deleted [" << m_url << "]" << QThread::currentThread();
#endif
cleanup();
}
// Called in application thread
void QSample::loadIfNecessary()
{
QMutexLocker locker(&m_mutex);
if (m_state == QSample::Error || m_state == QSample::Creating) {
m_state = QSample::Loading;
QMetaObject::invokeMethod(this, "load", Qt::QueuedConnection);
}
}
// Called in both threads
bool QSampleCache::notifyUnreferencedSample(QSample* sample)
{
QMutexLocker locker(&m_mutex);
if (m_capacity > 0)
return false;
m_samples.remove(sample->m_url);
m_staleSamples.insert(sample);
sample->deleteLater();
return true;
}
// Called in application threadd
void QSample::release()
{
QMutexLocker locker(&m_mutex);
#ifdef QT_SAMPLECACHE_DEBUG
qDebug() << "Sample:: release" << this << QThread::currentThread() << m_ref;
#endif
m_ref--;
if (m_ref == 0)
m_parent->notifyUnreferencedSample(this);
}
// Called in dtor and when stream is loaded
// must be called locked.
void QSample::cleanup()
{
if (m_waveDecoder)
m_waveDecoder->deleteLater();
if (m_stream)
m_stream->deleteLater();
m_waveDecoder = 0;
m_stream = 0;
}
// Called in application thread
void QSample::addRef()
{
m_ref++;
}
// Called in loading thread
void QSample::readSample()
{
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
QMutexLocker m(&m_mutex);
#ifdef QT_SAMPLECACHE_DEBUG
qDebug() << "QSample: readSample";
#endif
qint64 read = m_waveDecoder->read(m_soundData.data() + m_sampleReadLength,
qMin(m_waveDecoder->bytesAvailable(),
qint64(m_waveDecoder->size() - m_sampleReadLength)));
if (read > 0)
m_sampleReadLength += read;
if (m_sampleReadLength < m_waveDecoder->size())
return;
Q_ASSERT(m_sampleReadLength == qint64(m_soundData.size()));
onReady();
}
// Called in loading thread
void QSample::decoderReady()
{
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
QMutexLocker m(&m_mutex);
#ifdef QT_SAMPLECACHE_DEBUG
qDebug() << "QSample: decoder ready";
#endif
m_parent->refresh(m_waveDecoder->size());
m_soundData.resize(m_waveDecoder->size());
m_sampleReadLength = 0;
qint64 read = m_waveDecoder->read(m_soundData.data(), m_waveDecoder->size());
if (read > 0)
m_sampleReadLength += read;
if (m_sampleReadLength >= m_waveDecoder->size())
onReady();
}
// Called in all threads
QSample::State QSample::state() const
{
QMutexLocker m(&m_mutex);
return m_state;
}
// Called in loading thread
// Essentially a second ctor, doesn't need locks (?)
void QSample::load()
{
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
#ifdef QT_SAMPLECACHE_DEBUG
qDebug() << "QSample: load [" << m_url << "]";
#endif
m_stream = m_parent->networkAccessManager().get(QNetworkRequest(m_url));
connect(m_stream, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(decoderError()));
m_waveDecoder = new QWaveDecoder(m_stream);
connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady()));
connect(m_waveDecoder, SIGNAL(parsingError()), SLOT(decoderError()));
connect(m_waveDecoder, SIGNAL(readyRead()), SLOT(readSample()));
}
// Called in loading thread
void QSample::decoderError()
{
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
QMutexLocker m(&m_mutex);
#ifdef QT_SAMPLECACHE_DEBUG
qDebug() << "QSample: decoder error";
#endif
cleanup();
m_state = QSample::Error;
emit error();
}
// Called in loading thread from decoder when sample is done. Locked already.
void QSample::onReady()
{
Q_ASSERT(QThread::currentThread()->objectName() == QLatin1String("QSampleCache::LoadingThread"));
#ifdef QT_SAMPLECACHE_DEBUG
qDebug() << "QSample: load ready";
#endif
m_audioFormat = m_waveDecoder->audioFormat();
cleanup();
m_state = QSample::Ready;
emit ready();
}
// Called in application thread, then moved to loader thread
QSample::QSample(const QUrl& url, QSampleCache *parent)
: m_parent(parent)
, m_stream(0)
, m_waveDecoder(0)
, m_url(url)
, m_sampleReadLength(0)
, m_state(Creating)
, m_ref(0)
{
}
QT_END_NAMESPACE
#include "moc_qsamplecache_p.cpp"

View File

@@ -0,0 +1,161 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.1, 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSAMPLECACHE_P_H
#define QSAMPLECACHE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qobject.h>
#include <QtCore/qthread.h>
#include <QtCore/qurl.h>
#include <QtCore/qmutex.h>
#include <QtCore/qmap.h>
#include <QtCore/qset.h>
#include <qaudioformat.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Multimedia)
class QNetworkAccessManager;
class QSampleCache;
class QWaveDecoder;
// Lives in application thread
class QSample : public QObject
{
Q_OBJECT
public:
friend class QSampleCache;
enum State
{
Creating,
Loading,
Error,
Ready,
};
State state() const;
// These are not (currently) locked because they are only meant to be called after these
// variables are updated to their final states
const QByteArray& data() const { Q_ASSERT(state() == Ready); return m_soundData; }
const QAudioFormat& format() const { Q_ASSERT(state() == Ready); return m_audioFormat; }
void release();
Q_SIGNALS:
void error();
void ready();
protected:
QSample(const QUrl& url, QSampleCache *parent);
private Q_SLOTS:
void load();
void decoderError();
void readSample();
void decoderReady();
private:
void onReady();
void cleanup();
void addRef();
void loadIfNecessary();
QSample();
~QSample();
mutable QMutex m_mutex;
QSampleCache *m_parent;
QByteArray m_soundData;
QAudioFormat m_audioFormat;
QIODevice *m_stream;
QWaveDecoder *m_waveDecoder;
QUrl m_url;
qint64 m_sampleReadLength;
State m_state;
int m_ref;
};
class QSampleCache
{
public:
friend class QSample;
QSampleCache();
~QSampleCache();
QSample* requestSample(const QUrl& url);
void setCapacity(qint64 capacity);
private:
QMap<QUrl, QSample*> m_samples;
QSet<QSample*> m_staleSamples;
QNetworkAccessManager *m_networkAccessManager;
QMutex m_mutex;
qint64 m_capacity;
qint64 m_usage;
QThread m_loadingThread;
QNetworkAccessManager& networkAccessManager();
void refresh(qint64 usageChange);
bool notifyUnreferencedSample(QSample* sample);
void removeUnreferencedSample(QSample* sample);
void unloadSample(QSample* sample);
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QSAMPLECACHE_P_H

View File

@@ -0,0 +1,236 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.1, 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsound.h"
#include "qsoundeffect.h"
#include "qcoreapplication.h"
/*!
\class QSound
\brief The QSound class provides a way to play .wav sound files.
\ingroup multimedia
Qt provides the most commonly required audio operation in GUI
applications: asynchronously playing a sound file. This is most
easily accomplished using the static play() function:
\snippet doc/src/snippets/multimedia-snippets/qsound.cpp 0
Alternatively, create a QSound object from the sound file first
and then call the play() slot:
\snippet doc/src/snippets/multimedia-snippets/qsound.cpp 1
Once created a QSound object can be queried for its fileName() and
total number of loops() (i.e. the number of times the sound will
play). The number of repetitions can be altered using the
setLoops() function. While playing the sound, the loopsRemaining()
function returns the remaining number of repetitions. Use the
isFinished() function to determine whether the sound has finished
playing.
Sounds played using a QSound object may use more memory than the
static play() function, but it may also play more immediately
(depending on the underlying platform audio facilities).
*/
/*!
Plays the sound stored in the file specified by the given \a filename.
\since 5.0
\sa stop(), loopsRemaining(), isFinished()
*/
void QSound::play(const QString& filename)
{
// Object destruction is generaly handled via deleteOnComplete
// Unexpected cases will be handled via parenting of QSound objects to qApp
QSound *sound = new QSound(filename, qApp);
sound->connect(sound->m_soundEffect, SIGNAL(playingChanged()), SLOT(deleteOnComplete()));
sound->play();
}
/*!
Constructs a QSound object from the file specified by the given \a
filename and with the given \a parent.
\since 5.0
\sa play()
*/
QSound::QSound(const QString& filename, QObject* parent)
: QObject(parent)
{
m_soundEffect = new QSoundEffect(this);
m_soundEffect->setSource(QUrl::fromLocalFile(filename));
}
/*!
Destroys this sound object. If the sound is not finished playing,
the stop() function is called before the sound object is
destroyed.
\since 5.0
\sa stop(), isFinished()
*/
QSound::~QSound()
{
if (!isFinished())
stop();
}
/*!
Returns true if the sound has finished playing; otherwise returns false.
*/
bool QSound::isFinished() const
{
return !m_soundEffect->isPlaying();
}
/*!
\overload
Starts playing the sound specified by this QSound object.
The function returns immediately. Depending on the platform audio
facilities, other sounds may stop or be mixed with the new
sound. The sound can be played again at any time, possibly mixing
or replacing previous plays of the sound.
\since 5.0
\sa fileName()
*/
void QSound::play()
{
m_soundEffect->play();
}
/*!
Returns the number of times the sound will play.
Return value of \c QSound::Infinite indicates infinite number of loops
\since 5.0
\sa loopsRemaining(), setLoops()
*/
int QSound::loops() const
{
// retain old API value for infite loops
int loopCount = m_soundEffect->loopCount();
if (loopCount == QSoundEffect::Infinite)
loopCount = Infinite;
return loopCount;
}
/*!
Returns the remaining number of times the sound will loop (for all
positive values this value decreases each time the sound is played).
Return value of \c QSound::Infinite indicates infinite number of loops
\since 5.0
\sa loops(), isFinished()
*/
int QSound::loopsRemaining() const
{
// retain old API value for infite loops
int loopsRemaining = m_soundEffect->loopsRemaining();
if (loopsRemaining == QSoundEffect::Infinite)
loopsRemaining = Infinite;
return loopsRemaining;
}
/*!
\fn void QSound::setLoops(int number)
Sets the sound to repeat the given \a number of times when it is
played.
Note that passing the value \c QSound::Infinite will cause the sound to loop
indefinitely.
\since 5.0
\sa loops()
*/
void QSound::setLoops(int n)
{
if (n == Infinite)
n = QSoundEffect::Infinite;
m_soundEffect->setLoopCount(n);
}
/*!
Returns the filename associated with this QSound object.
\since 5.0
\sa QSound()
*/
QString QSound::fileName() const
{
return m_soundEffect->source().toLocalFile();
}
/*!
Stops the sound playing.
\since 5.0
\sa play()
*/
void QSound::stop()
{
m_soundEffect->stop();
}
/*!
\internal
\since 5.0
*/
void QSound::deleteOnComplete()
{
if (!m_soundEffect->isPlaying())
deleteLater();
}
#include "moc_qsound.cpp"

View File

@@ -0,0 +1,93 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.1, 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSOUND_H
#define QSOUND_H
#include <qtmultimediadefs.h>
#include <QtCore/qobject.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Multimedia)
class QSoundEffect;
class Q_MULTIMEDIA_EXPORT QSound : public QObject
{
Q_OBJECT
public:
enum Loop
{
Infinite = -1,
};
static void play(const QString& filename);
explicit QSound(const QString& filename, QObject* parent = 0);
~QSound();
int loops() const;
int loopsRemaining() const;
void setLoops(int);
QString fileName() const;
bool isFinished() const;
public Q_SLOTS:
void play();
void stop();
private Q_SLOTS:
void deleteOnComplete();
private:
QSoundEffect *m_soundEffect;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QSOUND_H

View File

@@ -0,0 +1,311 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.1, 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsoundeffect.h"
#if defined(QT_MULTIMEDIA_PULSEAUDIO)
#include "qsoundeffect_pulse_p.h"
#elif(QT_MULTIMEDIA_QMEDIAPLAYER)
#include "qsoundeffect_qmedia_p.h"
#endif
QT_BEGIN_NAMESPACE
/*!
\qmlclass SoundEffect QSoundEffect
\brief The SoundEffect element provides a way to play sound effects in QML.
\since 1.0
\inmodule QtMultimedia
This element is part of the \bold{QtMultimedia 4.0} module.
The following example plays a WAV file on mouse click.
\snippet doc/src/snippets/multimedia-snippets/soundeffect.qml complete snippet
*/
/*!
\qmlproperty url SoundEffect::source
\since 1.0
This property provides a way to control the sound to play.
*/
/*!
\qmlproperty int SoundEffect::loops
\since 1.0
This property provides a way to control the number of times to repeat the sound on each play().
Set to -1 (infinite) to enable infinite loop.
*/
/*!
\qmlproperty qreal SoundEffect::volume
\since 1.0
This property holds the volume of the playback, from 0.0 (silent) to 1.0 (maximum volume).
Note: Currently this has no effect on Mac OS X.
*/
/*!
\qmlproperty bool SoundEffect::muted
\since 1.0
This property provides a way to control muting.
*/
/*!
\qmlproperty bool SoundEffect::playing
\since 1.1
This property indicates if the soundeffect is playing or not.
*/
/*!
\qmlproperty int SoundEffect::status
\since 1.0
This property indicates the following status of the soundeffect.
Null: no source has been set or is null.
Loading: the soundeffect is trying to load the source.
Ready: the source is loaded and ready for play.
Error: some error happened during operation, such as failure of loading the source.
*/
/*!
\qmlsignal SoundEffect::sourceChanged()
\since 1.0
This handler is called when the source has changed.
*/
/*!
\qmlsignal SoundEffect::loopCountChanged()
\since 1.0
This handler is called when the initial number of loops has changed.
*/
/*!
\qmlsignal SoundEffect::loopsRemainingChanged()
\since 1.0
This handler is called when the remaining number of loops has changed.
*/
/*!
\qmlsignal SoundEffect::volumeChanged()
\since 1.0
This handler is called when the volume has changed.
*/
/*!
\qmlsignal SoundEffect::mutedChanged()
\since 1.0
This handler is called when the mute state has changed.
*/
/*!
\qmlsignal SoundEffect::playingChanged()
\since 1.0
This handler is called when the playing property has changed.
*/
/*!
\qmlsignal SoundEffect::statusChanged()
This handler is called when the status property has changed.
\since 1.0
*/
/*!
\since 1.0
*/
QSoundEffect::QSoundEffect(QObject *parent) :
QObject(parent)
{
d = new QSoundEffectPrivate(this);
connect(d, SIGNAL(loopsRemainingChanged()), SIGNAL(loopsRemainingChanged()));
connect(d, SIGNAL(volumeChanged()), SIGNAL(volumeChanged()));
connect(d, SIGNAL(mutedChanged()), SIGNAL(mutedChanged()));
connect(d, SIGNAL(loadedChanged()), SIGNAL(loadedChanged()));
connect(d, SIGNAL(playingChanged()), SIGNAL(playingChanged()));
connect(d, SIGNAL(statusChanged()), SIGNAL(statusChanged()));
}
QSoundEffect::~QSoundEffect()
{
d->release();
}
QStringList QSoundEffect::supportedMimeTypes()
{
return QSoundEffectPrivate::supportedMimeTypes();
}
QUrl QSoundEffect::source() const
{
return d->source();
}
void QSoundEffect::setSource(const QUrl &url)
{
if (d->source() == url)
return;
d->setSource(url);
emit sourceChanged();
}
int QSoundEffect::loopCount() const
{
return d->loopCount();
}
int QSoundEffect::loopsRemaining() const
{
return d->loopsRemaining();
}
void QSoundEffect::setLoopCount(int loopCount)
{
if (loopCount < 0 && loopCount != Infinite) {
qWarning("SoundEffect: loops should be SoundEffect.Infinite, 0 or positive integer");
return;
}
if (loopCount == 0)
loopCount = 1;
if (d->loopCount() == loopCount)
return;
d->setLoopCount(loopCount);
emit loopCountChanged();
}
qreal QSoundEffect::volume() const
{
return qreal(d->volume()) / 100;
}
void QSoundEffect::setVolume(qreal volume)
{
if (volume < 0 || volume > 1) {
qWarning("SoundEffect: volume should be between 0.0 and 1.0");
return;
}
int iVolume = qRound(volume * 100);
if (d->volume() == iVolume)
return;
d->setVolume(iVolume);
}
bool QSoundEffect::isMuted() const
{
return d->isMuted();
}
void QSoundEffect::setMuted(bool muted)
{
if (d->isMuted() == muted)
return;
d->setMuted(muted);
}
bool QSoundEffect::isLoaded() const
{
return d->isLoaded();
}
/*!
\qmlmethod SoundEffect::play()
Start playback of the sound effect, looping the effect for the number of
times as specificed in the loops property.
This is the default method for SoundEffect.
\snippet doc/src/snippets/multimedia-snippets/soundeffect.qml play sound on click
\since 1.0
*/
void QSoundEffect::play()
{
d->play();
}
bool QSoundEffect::isPlaying() const
{
return d->isPlaying();
}
QSoundEffect::Status QSoundEffect::status() const
{
return d->status();
}
/*!
\qmlmethod SoundEffect::stop()
Stop current playback.
Note that if the backend is PulseAudio, due to the limitation of the underlying API,
tis stop will only prevent next looping but will not be able to stop current playback immediately.
\since 1.0
*/
void QSoundEffect::stop()
{
d->stop();
}
QT_END_NAMESPACE
#include "moc_qsoundeffect.cpp"

View File

@@ -0,0 +1,135 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.1, 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSOUNDEFFECT_H
#define QSOUNDEFFECT_H
#include <qtmultimediadefs.h>
#include <QtCore/qobject.h>
#include <QtCore/qurl.h>
#include <QtCore/qstringlist.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Multimedia)
class QSoundEffectPrivate;
class Q_MULTIMEDIA_EXPORT QSoundEffect : public QObject
{
Q_OBJECT
Q_CLASSINFO("DefaultMethod", "play()")
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
Q_PROPERTY(int loops READ loopCount WRITE setLoopCount NOTIFY loopCountChanged)
Q_PROPERTY(int loopsRemaining READ loopsRemaining NOTIFY loopsRemainingChanged)
Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
Q_PROPERTY(bool playing READ isPlaying NOTIFY playingChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_ENUMS(Loop)
Q_ENUMS(Status)
public:
enum Loop
{
Infinite = -2,
};
enum Status
{
Null,
Loading,
Ready,
Error
};
explicit QSoundEffect(QObject *parent = 0);
~QSoundEffect();
static QStringList supportedMimeTypes();
QUrl source() const;
void setSource(const QUrl &url);
int loopCount() const;
int loopsRemaining() const;
void setLoopCount(int loopCount);
qreal volume() const;
void setVolume(qreal volume);
bool isMuted() const;
void setMuted(bool muted);
bool isLoaded() const;
bool isPlaying() const;
Status status() const;
Q_SIGNALS:
void sourceChanged();
void loopCountChanged();
void loopsRemainingChanged();
void volumeChanged();
void mutedChanged();
void loadedChanged();
void playingChanged();
void statusChanged();
public Q_SLOTS:
void play();
void stop();
private:
Q_DISABLE_COPY(QSoundEffect)
QSoundEffectPrivate* d;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QSOUNDEFFECT_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,170 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.1, 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSOUNDEFFECT_PULSE_H
#define QSOUNDEFFECT_PULSE_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qsoundeffect.h"
#include <QtCore/qobject.h>
#include <QtCore/qdatetime.h>
#include <qmediaplayer.h>
#include <pulse/pulseaudio.h>
#include "qsamplecache_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Multimedia)
class QSoundEffectRef;
class QSoundEffectPrivate : public QObject
{
Q_OBJECT
public:
explicit QSoundEffectPrivate(QObject* parent);
~QSoundEffectPrivate();
static QStringList supportedMimeTypes();
QUrl source() const;
void setSource(const QUrl &url);
int loopCount() const;
int loopsRemaining() const;
void setLoopCount(int loopCount);
int volume() const;
void setVolume(int volume);
bool isMuted() const;
void setMuted(bool muted);
bool isLoaded() const;
bool isPlaying() const;
QSoundEffect::Status status() const;
void release();
public Q_SLOTS:
void play();
void stop();
Q_SIGNALS:
void loopsRemainingChanged();
void volumeChanged();
void mutedChanged();
void loadedChanged();
void playingChanged();
void statusChanged();
private Q_SLOTS:
void decoderError();
void sampleReady();
void uploadSample();
void contextReady();
void underRun();
void prepare();
void streamReady();
void emptyComplete();
void updateVolume();
void updateMuted();
private:
void playSample();
void emptyStream();
void createPulseStream();
void unloadPulseStream();
void setPlaying(bool playing);
void setStatus(QSoundEffect::Status status);
void setLoopsRemaining(int loopsRemaining);
static void stream_write_callback(pa_stream *s, size_t length, void *userdata);
static void stream_state_callback(pa_stream *s, void *userdata);
static void stream_underrun_callback(pa_stream *s, void *userdata);
static void stream_cork_callback(pa_stream *s, int success, void *userdata);
static void stream_flush_callback(pa_stream *s, int success, void *userdata);
static void stream_write_done_callback(void *p);
static void stream_adjust_prebuffer_callback(pa_stream *s, int success, void *userdata);
static void stream_reset_buffer_callback(pa_stream *s, int success, void *userdata);
static void setvolume_callback(pa_context *c, int success, void *userdata);
static void setmuted_callback(pa_context *c, int success, void *userdata);
pa_stream *m_pulseStream;
int m_sinkInputId;
pa_sample_spec m_pulseSpec;
int m_pulseBufferSize;
bool m_emptying;
bool m_sampleReady;
bool m_playing;
QSoundEffect::Status m_status;
bool m_muted;
bool m_playQueued;
bool m_stopping;
int m_volume;
int m_loopCount;
int m_runningCount;
QUrl m_source;
QByteArray m_name;
QSample *m_sample;
int m_position;
QSoundEffectRef *m_ref;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QSOUNDEFFECT_PULSE_H

View File

@@ -0,0 +1,254 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.1, 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// INTERNAL USE ONLY: Do NOT use for any other purpose.
//
#include "qsoundeffect_qmedia_p.h"
#include <QtCore/qcoreapplication.h>
#include "qmediacontent.h"
#include "qmediaplayer.h"
QT_BEGIN_NAMESPACE
QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent):
QObject(parent),
m_loopCount(1),
m_runningCount(0),
m_playing(false),
m_status(QSoundEffect::Null),
m_player(0)
{
m_player = new QMediaPlayer(this, QMediaPlayer::LowLatency);
connect(m_player, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(stateChanged(QMediaPlayer::State)));
connect(m_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus)));
connect(m_player, SIGNAL(error(QMediaPlayer::Error)), SLOT(error(QMediaPlayer::Error)));
connect(m_player, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged()));
connect(m_player, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged()));
}
void QSoundEffectPrivate::release()
{
this->deleteLater();
}
QSoundEffectPrivate::~QSoundEffectPrivate()
{
}
QStringList QSoundEffectPrivate::supportedMimeTypes()
{
return QMediaPlayer::supportedMimeTypes();
}
QUrl QSoundEffectPrivate::source() const
{
return m_player->media().canonicalUrl();
}
void QSoundEffectPrivate::setSource(const QUrl &url)
{
m_player->setMedia(url);
}
int QSoundEffectPrivate::loopCount() const
{
return m_loopCount;
}
int QSoundEffectPrivate::loopsRemaining() const
{
return m_runningCount;
}
void QSoundEffectPrivate::setLoopCount(int loopCount)
{
m_loopCount = loopCount;
}
int QSoundEffectPrivate::volume() const
{
return m_player->volume();
}
void QSoundEffectPrivate::setVolume(int volume)
{
m_player->setVolume(volume);
}
bool QSoundEffectPrivate::isMuted() const
{
return m_player->isMuted();
}
void QSoundEffectPrivate::setMuted(bool muted)
{
m_player->setMuted(muted);
}
bool QSoundEffectPrivate::isLoaded() const
{
return m_status == QSoundEffect::Ready;
}
bool QSoundEffectPrivate::isPlaying() const
{
return m_playing;
}
QSoundEffect::Status QSoundEffectPrivate::status() const
{
return m_status;
}
void QSoundEffectPrivate::play()
{
if (m_status == QSoundEffect::Null || m_status == QSoundEffect::Error)
return;
if (m_loopCount < 0) {
setLoopsRemaining(-1);
}
else {
if (m_runningCount < 0)
setLoopsRemaining(0);
setLoopsRemaining(m_runningCount + m_loopCount);
}
m_player->play();
}
void QSoundEffectPrivate::stop()
{
setLoopsRemaining(0);
m_player->stop();
}
void QSoundEffectPrivate::stateChanged(QMediaPlayer::State state)
{
if (state == QMediaPlayer::StoppedState) {
if (m_runningCount < 0) {
m_player->play();
} else if (m_runningCount == 0) {
setPlaying(false);
return;
} else {
setLoopsRemaining(m_runningCount - 1);
if (m_runningCount > 0) {
m_player->play();
} else {
setPlaying(false);
}
}
} else {
setPlaying(true);
}
}
void QSoundEffectPrivate::mediaStatusChanged(QMediaPlayer::MediaStatus status)
{
switch(status) {
case QMediaPlayer::LoadingMedia:
setStatus(QSoundEffect::Loading);
break;
case QMediaPlayer::NoMedia:
setStatus(QSoundEffect::Null);
break;
case QMediaPlayer::InvalidMedia:
setStatus(QSoundEffect::Error);
break;
default:
setStatus(QSoundEffect::Ready);
break;
}
}
void QSoundEffectPrivate::error(QMediaPlayer::Error err)
{
bool playingDirty = false;
if (m_playing) {
m_playing = false;
playingDirty = true;
}
setStatus(QSoundEffect::Error);
if (playingDirty)
emit playingChanged();
}
void QSoundEffectPrivate::setStatus(QSoundEffect::Status status)
{
if (m_status == status)
return;
bool oldLoaded = isLoaded();
m_status = status;
emit statusChanged();
if (oldLoaded != isLoaded())
emit loadedChanged();
}
void QSoundEffectPrivate::setPlaying(bool playing)
{
if (m_playing == playing)
return;
m_playing = playing;
emit playingChanged();
}
void QSoundEffectPrivate::setLoopsRemaining(int loopsRemaining)
{
if (m_runningCount == loopsRemaining)
return;
m_runningCount = loopsRemaining;
emit loopsRemainingChanged();
}
QT_END_NAMESPACE
#include "moc_qsoundeffect_qmedia_p.cpp"

View File

@@ -0,0 +1,127 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.1, 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSOUNDEFFECT_QMEDIA_H
#define QSOUNDEFFECT_QMEDIA_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qobject.h>
#include <QtCore/qurl.h>
#include "qmediaplayer.h"
#include "qsoundeffect.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Multimedia)
class QSoundEffectPrivate : public QObject
{
Q_OBJECT
public:
explicit QSoundEffectPrivate(QObject* parent);
~QSoundEffectPrivate();
static QStringList supportedMimeTypes();
QUrl source() const;
void setSource(const QUrl &url);
int loopCount() const;
int loopsRemaining() const;
void setLoopCount(int loopCount);
int volume() const;
void setVolume(int volume);
bool isMuted() const;
void setMuted(bool muted);
bool isLoaded() const;
bool isPlaying() const;
QSoundEffect::Status status() const;
void release();
public Q_SLOTS:
void play();
void stop();
Q_SIGNALS:
void loopsRemainingChanged();
void volumeChanged();
void mutedChanged();
void loadedChanged();
void playingChanged();
void statusChanged();
private Q_SLOTS:
void stateChanged(QMediaPlayer::State);
void mediaStatusChanged(QMediaPlayer::MediaStatus);
void error(QMediaPlayer::Error);
private:
void setStatus(QSoundEffect::Status status);
void setPlaying(bool playing);
void setLoopsRemaining(int loopsRemaining);
int m_loopCount;
int m_runningCount;
bool m_playing;
QSoundEffect::Status m_status;
QMediaPlayer *m_player;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QSOUNDEFFECT_QMEDIA_H

View File

@@ -0,0 +1,307 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.1, 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qwavedecoder_p.h"
#include <QtCore/qtimer.h>
#include <QtCore/qendian.h>
QT_BEGIN_NAMESPACE
QWaveDecoder::QWaveDecoder(QIODevice *s, QObject *parent):
QIODevice(parent),
haveFormat(false),
dataSize(0),
source(s),
state(QWaveDecoder::InitialState),
junkToSkip(0),
bigEndian(false)
{
open(QIODevice::ReadOnly | QIODevice::Unbuffered);
if (enoughDataAvailable())
QTimer::singleShot(0, this, SLOT(handleData()));
else
connect(source, SIGNAL(readyRead()), SLOT(handleData()));
}
QWaveDecoder::~QWaveDecoder()
{
}
QAudioFormat QWaveDecoder::audioFormat() const
{
return format;
}
int QWaveDecoder::duration() const
{
return size() * 1000 / (format.sampleSize() / 8) / format.channels() / format.frequency();
}
qint64 QWaveDecoder::size() const
{
return haveFormat ? dataSize : 0;
}
bool QWaveDecoder::isSequential() const
{
return source->isSequential();
}
qint64 QWaveDecoder::bytesAvailable() const
{
return haveFormat ? source->bytesAvailable() : 0;
}
qint64 QWaveDecoder::readData(char *data, qint64 maxlen)
{
return haveFormat ? source->read(data, maxlen) : 0;
}
qint64 QWaveDecoder::writeData(const char *data, qint64 len)
{
Q_UNUSED(data);
Q_UNUSED(len);
return -1;
}
void QWaveDecoder::parsingFailed()
{
Q_ASSERT(source);
source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData()));
emit parsingError();
}
void QWaveDecoder::handleData()
{
// As a special "state", if we have junk to skip, we do
if (junkToSkip > 0) {
discardBytes(junkToSkip); // this also updates junkToSkip
// If we couldn't skip all the junk, return
if (junkToSkip > 0) {
// We might have run out
if (source->atEnd())
parsingFailed();
return;
}
}
if (state == QWaveDecoder::InitialState) {
if (source->bytesAvailable() < qint64(sizeof(RIFFHeader)))
return;
RIFFHeader riff;
source->read(reinterpret_cast<char *>(&riff), sizeof(RIFFHeader));
// RIFF = little endian RIFF, RIFX = big endian RIFF
if (((qstrncmp(riff.descriptor.id, "RIFF", 4) != 0) && (qstrncmp(riff.descriptor.id, "RIFX", 4) != 0))
|| qstrncmp(riff.type, "WAVE", 4) != 0) {
parsingFailed();
return;
} else {
state = QWaveDecoder::WaitingForFormatState;
if (qstrncmp(riff.descriptor.id, "RIFX", 4) == 0)
bigEndian = true;
else
bigEndian = false;
}
}
if (state == QWaveDecoder::WaitingForFormatState) {
if (findChunk("fmt ")) {
chunk descriptor;
peekChunk(&descriptor);
if (source->bytesAvailable() < qint64(descriptor.size + sizeof(chunk)))
return;
WAVEHeader wave;
source->read(reinterpret_cast<char *>(&wave), sizeof(WAVEHeader));
if (descriptor.size > sizeof(WAVEHeader))
discardBytes(descriptor.size - sizeof(WAVEHeader));
// Swizzle this
if (bigEndian) {
wave.audioFormat = qFromBigEndian<quint16>(wave.audioFormat);
}
if (wave.audioFormat != 0 && wave.audioFormat != 1) {
// 32bit wave files have format == 0xFFFE (WAVE_FORMAT_EXTENSIBLE).
// but don't support them at the moment.
parsingFailed();
return;
} else {
format.setCodec(QLatin1String("audio/pcm"));
if (bigEndian) {
int bps = qFromBigEndian<quint16>(wave.bitsPerSample);
format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
format.setByteOrder(QAudioFormat::BigEndian);
format.setFrequency(qFromBigEndian<quint32>(wave.sampleRate));
format.setSampleSize(bps);
format.setChannels(qFromBigEndian<quint16>(wave.numChannels));
} else {
int bps = qFromLittleEndian<quint16>(wave.bitsPerSample);
format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
format.setByteOrder(QAudioFormat::LittleEndian);
format.setFrequency(qFromLittleEndian<quint32>(wave.sampleRate));
format.setSampleSize(bps);
format.setChannels(qFromLittleEndian<quint16>(wave.numChannels));
}
state = QWaveDecoder::WaitingForDataState;
}
}
}
if (state == QWaveDecoder::WaitingForDataState) {
if (findChunk("data")) {
source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData()));
chunk descriptor;
source->read(reinterpret_cast<char *>(&descriptor), sizeof(chunk));
if (bigEndian)
descriptor.size = qFromBigEndian<quint32>(descriptor.size);
dataSize = descriptor.size;
haveFormat = true;
connect(source, SIGNAL(readyRead()), SIGNAL(readyRead()));
emit formatKnown();
return;
}
}
// If we hit the end without finding data, it's a parsing error
if (source->atEnd()) {
parsingFailed();
}
}
bool QWaveDecoder::enoughDataAvailable()
{
chunk descriptor;
if (!peekChunk(&descriptor))
return false;
// This is only called for the RIFF/RIFX header, before bigEndian is set,
// so we have to manually swizzle
if (qstrncmp(descriptor.id, "RIFX", 4) == 0)
descriptor.size = qFromBigEndian<quint32>(descriptor.size);
if (source->bytesAvailable() < qint64(sizeof(chunk) + descriptor.size))
return false;
return true;
}
bool QWaveDecoder::findChunk(const char *chunkId)
{
chunk descriptor;
if (!peekChunk(&descriptor))
return false;
if (qstrncmp(descriptor.id, chunkId, 4) == 0)
return true;
// It's possible that bytes->available() is less than the chunk size
// if it's corrupt.
junkToSkip = qint64(sizeof(chunk) + descriptor.size);
while (source->bytesAvailable() > 0) {
// Skip the current amount
if (junkToSkip > 0)
discardBytes(junkToSkip);
// If we still have stuff left, just exit and try again later
// since we can't call peekChunk
if (junkToSkip > 0)
return false;
if (!peekChunk(&descriptor))
return false;
if (qstrncmp(descriptor.id, chunkId, 4) == 0)
return true;
}
return false;
}
// Handles endianness
bool QWaveDecoder::peekChunk(chunk *pChunk)
{
if (source->bytesAvailable() < qint64(sizeof(chunk)))
return false;
source->peek(reinterpret_cast<char *>(pChunk), sizeof(chunk));
if (bigEndian)
pChunk->size = qFromBigEndian<quint32>(pChunk->size);
return true;
}
void QWaveDecoder::discardBytes(qint64 numBytes)
{
// Discards a number of bytes
// If the iodevice doesn't have this many bytes in it,
// remember how much more junk we have to skip.
if (source->isSequential()) {
QByteArray r = source->read(qMin(numBytes, qint64(16384))); // uggh, wasted memory, limit to a max of 16k
if (r.size() < numBytes)
junkToSkip = numBytes - r.size();
else
junkToSkip = 0;
} else {
quint64 origPos = source->pos();
source->seek(source->pos() + numBytes);
junkToSkip = origPos + numBytes - source->pos();
}
}
QT_END_NAMESPACE
#include "moc_qwavedecoder_p.cpp"

View File

@@ -0,0 +1,141 @@
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.1, 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef WAVEDECODER_H
#define WAVEDECODER_H
//
// 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/qiodevice.h>
#include <qaudioformat.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Multimedia)
class QWaveDecoder : public QIODevice
{
Q_OBJECT
public:
explicit QWaveDecoder(QIODevice *source, QObject *parent = 0);
~QWaveDecoder();
QAudioFormat audioFormat() const;
int duration() const;
qint64 size() const;
bool isSequential() const;
qint64 bytesAvailable() const;
Q_SIGNALS:
void formatKnown();
void parsingError();
private Q_SLOTS:
void handleData();
private:
qint64 readData(char *data, qint64 maxlen);
qint64 writeData(const char *data, qint64 len);
bool enoughDataAvailable();
bool findChunk(const char *chunkId);
void discardBytes(qint64 numBytes);
void parsingFailed();
enum State {
InitialState,
WaitingForFormatState,
WaitingForDataState
};
struct chunk
{
char id[4];
quint32 size;
};
bool peekChunk(chunk* pChunk);
struct RIFFHeader
{
chunk descriptor;
char type[4];
};
struct WAVEHeader
{
chunk descriptor;
quint16 audioFormat;
quint16 numChannels;
quint32 sampleRate;
quint32 byteRate;
quint16 blockAlign;
quint16 bitsPerSample;
};
bool haveFormat;
qint64 dataSize;
QAudioFormat format;
QIODevice *source;
State state;
quint32 junkToSkip;
bool bigEndian;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // WAVEDECODER_H