Restructure the source code a little.
Change-Id: I995b0fb33bdda7f01bf6266c1c50a1b17eba6760 Reviewed-by: Jonas Rabbe <jonas.rabbe@nokia.com>
This commit is contained in:
committed by
Qt by Nokia
parent
6ee1977d60
commit
502d3c8eb3
@@ -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
|
||||
}
|
||||
|
||||
401
src/multimedia/audio/qsamplecache_p.cpp
Normal file
401
src/multimedia/audio/qsamplecache_p.cpp
Normal 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"
|
||||
161
src/multimedia/audio/qsamplecache_p.h
Normal file
161
src/multimedia/audio/qsamplecache_p.h
Normal 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
|
||||
236
src/multimedia/audio/qsound.cpp
Normal file
236
src/multimedia/audio/qsound.cpp
Normal 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"
|
||||
93
src/multimedia/audio/qsound.h
Normal file
93
src/multimedia/audio/qsound.h
Normal 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
|
||||
311
src/multimedia/audio/qsoundeffect.cpp
Normal file
311
src/multimedia/audio/qsoundeffect.cpp
Normal 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"
|
||||
135
src/multimedia/audio/qsoundeffect.h
Normal file
135
src/multimedia/audio/qsoundeffect.h
Normal 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
|
||||
1100
src/multimedia/audio/qsoundeffect_pulse_p.cpp
Normal file
1100
src/multimedia/audio/qsoundeffect_pulse_p.cpp
Normal file
File diff suppressed because it is too large
Load Diff
170
src/multimedia/audio/qsoundeffect_pulse_p.h
Normal file
170
src/multimedia/audio/qsoundeffect_pulse_p.h
Normal 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
|
||||
254
src/multimedia/audio/qsoundeffect_qmedia_p.cpp
Normal file
254
src/multimedia/audio/qsoundeffect_qmedia_p.cpp
Normal 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"
|
||||
127
src/multimedia/audio/qsoundeffect_qmedia_p.h
Normal file
127
src/multimedia/audio/qsoundeffect_qmedia_p.h
Normal 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
|
||||
307
src/multimedia/audio/qwavedecoder_p.cpp
Normal file
307
src/multimedia/audio/qwavedecoder_p.cpp
Normal 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"
|
||||
141
src/multimedia/audio/qwavedecoder_p.h
Normal file
141
src/multimedia/audio/qwavedecoder_p.h
Normal 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
|
||||
Reference in New Issue
Block a user