summaryrefslogtreecommitdiffstats
path: root/src/multimedia/effects
diff options
context:
space:
mode:
Diffstat (limited to 'src/multimedia/effects')
-rw-r--r--src/multimedia/effects/effects.pri25
-rw-r--r--src/multimedia/effects/qsoundeffect.cpp255
-rw-r--r--src/multimedia/effects/qsoundeffect_p.h123
-rw-r--r--src/multimedia/effects/qsoundeffect_pulse_p.cpp509
-rw-r--r--src/multimedia/effects/qsoundeffect_pulse_p.h138
-rw-r--r--src/multimedia/effects/qsoundeffect_qmedia_p.cpp167
-rw-r--r--src/multimedia/effects/qsoundeffect_qmedia_p.h109
-rw-r--r--src/multimedia/effects/qsoundeffect_qsound_p.cpp225
-rw-r--r--src/multimedia/effects/qsoundeffect_qsound_p.h129
-rw-r--r--src/multimedia/effects/wavedecoder_p.cpp151
-rw-r--r--src/multimedia/effects/wavedecoder_p.h133
11 files changed, 1964 insertions, 0 deletions
diff --git a/src/multimedia/effects/effects.pri b/src/multimedia/effects/effects.pri
new file mode 100644
index 0000000..ff762e8
--- /dev/null
+++ b/src/multimedia/effects/effects.pri
@@ -0,0 +1,25 @@
+
+
+unix {
+ unix:contains(QT_CONFIG, pulseaudio) {
+ DEFINES += QT_MULTIMEDIA_PULSEAUDIO
+ HEADERS += $$PWD/qsoundeffect_pulse_p.h
+ SOURCES += $$PWD/qsoundeffect_pulse_p.cpp
+ LIBS += -lpulse
+ } else {
+ DEFINES += QT_MULTIMEDIA_QMEDIAPLAYER
+ HEADERS += $$PWD/qsoundeffect_qmedia_p.h
+ SOURCES += $$PWD/qsoundeffect_qmedia_p.cpp
+ }
+} else {
+ HEADERS += $$PWD/qsoundeffect_qsound_p.h
+ SOURCES += $$PWD/qsoundeffect_qsound_p.cpp
+}
+
+HEADERS += \
+ $$PWD/qsoundeffect_p.h \
+ $$PWD/wavedecoder_p.h
+
+SOURCES += \
+ $$PWD/qsoundeffect.cpp \
+ $$PWD/wavedecoder_p.cpp
diff --git a/src/multimedia/effects/qsoundeffect.cpp b/src/multimedia/effects/qsoundeffect.cpp
new file mode 100644
index 0000000..541e6c9
--- /dev/null
+++ b/src/multimedia/effects/qsoundeffect.cpp
@@ -0,0 +1,255 @@
+/****************************************************************************
+**
+** 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 QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmediacontent.h"
+#include "qmediaplayer.h"
+
+#include "qsoundeffect_p.h"
+
+#if defined(QT_MULTIMEDIA_PULSEAUDIO)
+#include "qsoundeffect_pulse_p.h"
+#elif(QT_MULTIMEDIA_QMEDIAPLAYER)
+#include "qsoundeffect_qmedia_p.h"
+#else
+#include "qsoundeffect_qsound_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass SoundEffect QSoundEffect
+ \since 4.7
+ \brief The SoundEffect element provides a way to play sound effects in qml.
+
+ The following example plays a wav file on mouse click.
+
+ \qml
+ SoundEffect {
+ id: playSound
+ source: "test.wav"
+ }
+ MouseRegion {
+ id: playArea
+ anchors.fill: parent
+ onPressed: {
+ playSound.play()
+ }
+ }
+ \endqml
+
+ \sa SoundEffect
+*/
+
+/*!
+ \qmlproperty QUrl SoundEffect::source
+
+ This property provides a way to control the sound to play.
+*/
+
+/*!
+ \qmlproperty int SoundEffect::loopCount
+
+ This property provides a way to control the number of times to repeat the sound on each play().
+*/
+
+/*!
+ \qmlproperty int SoundEffect::volume
+
+ This property provides a way to control the volume for playback.
+*/
+
+/*!
+ \qmlproperty bool SoundEffect::muted
+
+ This property provides a way to control muting.
+*/
+
+/*!
+ \qmlproperty int SoundEffect::duration
+
+ This property holds the duration in milliseconds of the current source audio.
+*/
+
+/*!
+ \qmlsignal SoundEffect::sourceChanged()
+
+ This handler is called when the source has changed.
+*/
+
+/*!
+ \qmlsignal SoundEffect::loopCountChanged()
+
+ This handler is called when the number of loops has changes.
+*/
+
+/*!
+ \qmlsignal SoundEffect::volumeChanged()
+
+ This handler is called when the volume has changed.
+*/
+
+/*!
+ \qmlsignal SoundEffect::mutedChanged()
+
+ This handler is called when the mute state has changed.
+*/
+
+/*!
+ \qmlsignal SoundEffect::durationChanged()
+
+ This handler is called when the duration has changed.
+*/
+
+QSoundEffect::QSoundEffect(QObject *parent) :
+ QObject(parent),
+ m_loopCount(1),
+ m_vol(100),
+ m_muted(false),
+ m_runningCount(0)
+{
+ d = new QSoundEffectPrivate(this);
+ connect(d, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged()));
+ connect(d, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged()));
+ connect(d, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged()));
+ connect(d, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(repeat()));
+}
+
+QSoundEffect::~QSoundEffect()
+{
+ delete d;
+}
+
+QUrl QSoundEffect::source() const
+{
+ return d != 0 ? d->media().canonicalUrl() : QUrl();
+}
+
+void QSoundEffect::setSource(const QUrl &url)
+{
+ if (d != 0 && d->media().canonicalUrl() == url)
+ return;
+
+ d->setVolume(m_vol);
+ d->setMuted(m_muted);
+ d->setMedia(url);
+
+ if (url.isEmpty())
+ return;
+
+ emit sourceChanged();
+}
+
+int QSoundEffect::loopCount() const
+{
+ return m_loopCount;
+}
+
+void QSoundEffect::setLoopCount(int loopCount)
+{
+ if (m_loopCount == loopCount)
+ return;
+
+ m_loopCount = loopCount;
+ emit loopCountChanged();
+}
+
+int QSoundEffect::volume() const
+{
+ return d != 0 ? d->volume() : m_vol;
+}
+
+void QSoundEffect::setVolume(int volume)
+{
+ if (m_vol == volume)
+ return;
+
+ m_vol = volume;
+ if (d != 0)
+ d->setVolume(volume);
+ else
+ emit volumeChanged();
+}
+
+bool QSoundEffect::isMuted() const
+{
+ return d != 0 ? d->isMuted() : m_muted;
+}
+
+void QSoundEffect::setMuted(bool muted)
+{
+ if (m_muted == muted)
+ return;
+
+ m_muted = muted;
+ if (d != 0)
+ d->setMuted(muted);
+ else
+ emit mutedChanged();
+}
+
+int QSoundEffect::duration() const
+{
+ return d != 0 ? d->duration() : 0;
+}
+
+void QSoundEffect::play()
+{
+ m_runningCount = 0;
+
+ if (d != 0)
+ d->play();
+}
+
+void QSoundEffect::stop()
+{
+ if (d != 0)
+ d->stop();
+}
+
+void QSoundEffect::repeat()
+{
+ if (d->state() == QMediaPlayer::StoppedState) {
+ if (++m_runningCount < m_loopCount)
+ d->play();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/effects/qsoundeffect_p.h b/src/multimedia/effects/qsoundeffect_p.h
new file mode 100644
index 0000000..c5554bf
--- /dev/null
+++ b/src/multimedia/effects/qsoundeffect_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** 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 QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSOUNDEFFECT_H
+#define QSOUNDEFFECT_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>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSoundEffectPrivate;
+class Q_MULTIMEDIA_EXPORT QSoundEffect : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount NOTIFY loopCountChanged)
+ Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged)
+ Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
+ Q_PROPERTY(int duration READ duration NOTIFY durationChanged)
+
+public:
+ explicit QSoundEffect(QObject *parent = 0);
+ ~QSoundEffect();
+
+ QUrl source() const;
+ void setSource(const QUrl &url);
+
+ int loopCount() const;
+ void setLoopCount(int loopCount);
+
+ int volume() const;
+ void setVolume(int volume);
+
+ bool isMuted() const;
+ void setMuted(bool muted);
+
+ int duration() const;
+
+signals:
+ void sourceChanged();
+ void loopCountChanged();
+ void volumeChanged();
+ void mutedChanged();
+ void durationChanged();
+
+public slots:
+ void play();
+ void stop();
+
+private slots:
+ void repeat();
+
+private:
+ Q_DISABLE_COPY(QSoundEffect)
+
+ int m_loopCount;
+ int m_vol;
+ bool m_muted;
+ int m_runningCount;
+
+ QSoundEffectPrivate* d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+
+#endif // QSOUNDEFFECT_H
diff --git a/src/multimedia/effects/qsoundeffect_pulse_p.cpp b/src/multimedia/effects/qsoundeffect_pulse_p.cpp
new file mode 100644
index 0000000..d99bf4b
--- /dev/null
+++ b/src/multimedia/effects/qsoundeffect_pulse_p.cpp
@@ -0,0 +1,509 @@
+/****************************************************************************
+**
+** 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 QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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.
+//
+// We mean it.
+//
+
+#include <QtCore/qcoreapplication.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtNetwork>
+#include <QTime>
+
+#include "qmediacontent.h"
+#include "qmediaplayer.h"
+#include "qsoundeffect_p.h"
+
+#include "wavedecoder_p.h"
+
+#include "qsoundeffect_pulse_p.h"
+
+#if defined(Q_WS_MAEMO_5)
+#include <pulse/ext-stream-restore.h>
+#endif
+
+#include <unistd.h>
+
+// Less than ideal
+#define PA_SCACHE_ENTRY_SIZE_MAX (1024*1024*16)
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+inline pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format)
+{
+ pa_sample_spec spec;
+
+ spec.rate = format.frequency();
+ spec.channels = format.channels();
+
+ if (format.sampleSize() == 8)
+ spec.format = PA_SAMPLE_U8;
+ else if (format.sampleSize() == 16) {
+ switch (format.byteOrder()) {
+ case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S16BE; break;
+ case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S16LE; break;
+ }
+ }
+ else if (format.sampleSize() == 32) {
+ switch (format.byteOrder()) {
+ case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S32BE; break;
+ case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S32LE; break;
+ }
+ }
+
+ return spec;
+}
+
+class PulseDaemon
+{
+public:
+ PulseDaemon():m_prepared(false)
+ {
+ prepare();
+ }
+
+ ~PulseDaemon()
+ {
+ if (m_prepared)
+ release();
+ }
+
+ inline void lock()
+ {
+ pa_threaded_mainloop_lock(m_mainLoop);
+ }
+
+ inline void unlock()
+ {
+ pa_threaded_mainloop_unlock(m_mainLoop);
+ }
+
+ inline pa_context *context() const
+ {
+ return m_context;
+ }
+
+ int volume()
+ {
+ return m_vol;
+ }
+
+private:
+ void prepare()
+ {
+ m_vol = 100;
+
+ m_mainLoop = pa_threaded_mainloop_new();
+ if (m_mainLoop == 0) {
+ qWarning("PulseAudioService: unable to create pulseaudio mainloop");
+ return;
+ }
+
+ if (pa_threaded_mainloop_start(m_mainLoop) != 0) {
+ qWarning("PulseAudioService: unable to start pulseaudio mainloop");
+ pa_threaded_mainloop_free(m_mainLoop);
+ return;
+ }
+
+ m_mainLoopApi = pa_threaded_mainloop_get_api(m_mainLoop);
+
+ lock();
+ m_context = pa_context_new(m_mainLoopApi, QString(QLatin1String("QtPulseAudio:%1")).arg(::getpid()).toAscii().constData());
+
+#if defined(Q_WS_MAEMO_5)
+ pa_context_set_state_callback(m_context, context_state_callback, this);
+#endif
+ if (m_context == 0) {
+ qWarning("PulseAudioService: Unable to create new pulseaudio context");
+ pa_threaded_mainloop_free(m_mainLoop);
+ return;
+ }
+
+ if (pa_context_connect(m_context, NULL, (pa_context_flags_t)0, NULL) < 0) {
+ qWarning("PulseAudioService: pa_context_connect() failed");
+ pa_context_unref(m_context);
+ pa_threaded_mainloop_free(m_mainLoop);
+ return;
+ }
+ unlock();
+
+ m_prepared = true;
+ }
+
+ void release()
+ {
+ if (!m_prepared) return;
+ pa_threaded_mainloop_stop(m_mainLoop);
+ pa_threaded_mainloop_free(m_mainLoop);
+ m_prepared = false;
+ }
+
+#if defined(Q_WS_MAEMO_5)
+ static void context_state_callback(pa_context *c, void *userdata)
+ {
+ PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata);
+ switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+ case PA_CONTEXT_READY:
+ pa_ext_stream_restore_set_subscribe_cb(c, &stream_restore_monitor_callback, self);
+ pa_ext_stream_restore_subscribe(c, 1, NULL, self);
+ break;
+ default:
+ break;
+ }
+ }
+ static void stream_restore_monitor_callback(pa_context *c, void *userdata)
+ {
+ PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata);
+ pa_ext_stream_restore2_read(c, &stream_restore_info_callback, self);
+ }
+ static void stream_restore_info_callback(pa_context *c, const pa_ext_stream_restore2_info *info,
+ int eol, void *userdata)
+ {
+ Q_UNUSED(c)
+
+ PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata);
+
+ if (!eol) {
+ if (QString(info->name).startsWith(QLatin1String("sink-input-by-media-role:x-maemo"))) {
+ const unsigned str_length = 256;
+ char str[str_length];
+ pa_cvolume_snprint(str, str_length, &info->volume);
+ self->m_vol = QString(str).replace(" ","").replace("%","").mid(2).toInt();
+ }
+ }
+ }
+#endif
+
+ int m_vol;
+ bool m_prepared;
+ pa_context *m_context;
+ pa_threaded_mainloop *m_mainLoop;
+ pa_mainloop_api *m_mainLoopApi;
+};
+}
+
+Q_GLOBAL_STATIC(PulseDaemon, daemon)
+
+
+QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent):
+ QObject(parent),
+ m_muted(false),
+ m_playQueued(false),
+ m_vol(100),
+ m_duration(0),
+ m_dataUploaded(0),
+ m_state(QMediaPlayer::StoppedState),
+ m_status(QMediaPlayer::NoMedia),
+ m_reply(0),
+ m_stream(0),
+ m_networkAccessManager(0)
+{
+}
+
+QSoundEffectPrivate::~QSoundEffectPrivate()
+{
+ delete m_reply;
+ unloadSample();
+}
+
+qint64 QSoundEffectPrivate::duration() const
+{
+ return m_duration;
+}
+
+int QSoundEffectPrivate::volume() const
+{
+ return m_vol;
+}
+
+bool QSoundEffectPrivate::isMuted() const
+{
+ return m_muted;
+}
+
+QMediaContent QSoundEffectPrivate::media() const
+{
+ return m_media;
+}
+
+QMediaPlayer::State QSoundEffectPrivate::state() const
+{
+ return m_state;
+}
+
+QMediaPlayer::MediaStatus QSoundEffectPrivate::mediaStatus() const
+{
+ return m_status;
+}
+
+void QSoundEffectPrivate::play()
+{
+ if (m_status == QMediaPlayer::LoadingMedia) {
+ m_playQueued = true;
+ return;
+ }
+
+ if (m_status != QMediaPlayer::BufferedMedia ||
+ m_state == QMediaPlayer::PlayingState)
+ return;
+
+ pa_volume_t m_vol = PA_VOLUME_NORM;
+
+ daemon()->lock();
+#if defined(Q_WS_MAEMO_5)
+ m_vol = PA_VOLUME_NORM/100*((daemon()->volume()+m_vol)/2);
+#endif
+ pa_operation_unref(
+ pa_context_play_sample(daemon()->context(),
+ m_name.constData(),
+ 0,
+ m_vol,
+ play_callback,
+ this)
+ );
+ daemon()->unlock();
+
+ m_playbackTime.start();
+
+ emit stateChanged(m_state = QMediaPlayer::PlayingState);
+}
+
+void QSoundEffectPrivate::stop()
+{
+ emit stateChanged(m_state = QMediaPlayer::StoppedState);
+}
+
+void QSoundEffectPrivate::setVolume(int volume)
+{
+ m_vol = volume;
+}
+
+void QSoundEffectPrivate::setMuted(bool muted)
+{
+ m_muted = muted;
+}
+
+void QSoundEffectPrivate::setMedia(const QMediaContent &media)
+{
+ if (media.isNull()) {
+ m_media = QMediaContent();
+ unloadSample();
+ return;
+ }
+ if (m_media == media)
+ return;
+ m_media = media;
+
+ if (m_networkAccessManager == 0)
+ m_networkAccessManager = new QNetworkAccessManager(this);
+
+ m_stream = m_networkAccessManager->get(QNetworkRequest(m_media.canonicalUrl()));
+
+ unloadSample();
+ loadSample();
+
+ emit mediaChanged(m_media);
+}
+
+void QSoundEffectPrivate::decoderReady()
+{
+ if (m_waveDecoder->size() >= PA_SCACHE_ENTRY_SIZE_MAX) {
+ m_status = QMediaPlayer::InvalidMedia;
+ emit mediaStatusChanged(m_status);
+ qWarning("QtPulseAudio: attempting to load to large a sample");
+ return;
+ }
+
+ if (m_name.isNull())
+ m_name = QString(QLatin1String("QtPulseSample-%1-%2")).arg(::getpid()).arg(quintptr(this)).toUtf8();
+
+ pa_sample_spec spec = audioFormatToSampleSpec(m_waveDecoder->audioFormat());
+
+ daemon()->lock();
+ pa_stream *stream = pa_stream_new(daemon()->context(), m_name.constData(), &spec, 0);
+ pa_stream_set_state_callback(stream, stream_state_callback, this);
+ pa_stream_set_write_callback(stream, stream_write_callback, this);
+ pa_stream_connect_upload(stream, (size_t)m_waveDecoder->size());
+ daemon()->unlock();
+}
+
+void QSoundEffectPrivate::decoderError()
+{
+ emit mediaStatusChanged(m_status = QMediaPlayer::InvalidMedia);
+}
+
+void QSoundEffectPrivate::checkPlayTime()
+{
+ int elapsed = m_playbackTime.elapsed();
+
+ if (elapsed >= m_duration) {
+ m_state = QMediaPlayer::StoppedState;
+ emit stateChanged(m_state);
+ }
+ else
+ startTimer(m_duration - elapsed);
+}
+
+void QSoundEffectPrivate::loadSample()
+{
+ m_waveDecoder = new WaveDecoder(m_stream);
+ connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady()));
+ connect(m_waveDecoder, SIGNAL(invalidFormat()), SLOT(decoderError()));
+
+ m_status = QMediaPlayer::LoadingMedia;
+ emit mediaStatusChanged(m_status);
+}
+
+void QSoundEffectPrivate::unloadSample()
+{
+ if (m_status != QMediaPlayer::BufferedMedia)
+ return;
+
+ m_status = QMediaPlayer::NoMedia;
+
+ daemon()->lock();
+ pa_context_remove_sample(daemon()->context(), m_name.constData(), NULL, NULL);
+ daemon()->unlock();
+
+ m_duration = 0;
+ m_dataUploaded = 0;
+}
+
+void QSoundEffectPrivate::timerEvent(QTimerEvent *event)
+{
+ if (m_state == QMediaPlayer::PlayingState) {
+ m_state = QMediaPlayer::StoppedState;
+ emit stateChanged(m_state);
+ }
+
+ killTimer(event->timerId());
+}
+
+void QSoundEffectPrivate::stream_write_callback(pa_stream *s, size_t length, void *userdata)
+{
+ Q_UNUSED(length);
+
+ QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata);
+
+ size_t bufferSize = qMin(pa_stream_writable_size(s),
+ size_t(self->m_waveDecoder->bytesAvailable()));
+ char buffer[bufferSize];
+
+ size_t len = 0;
+ while (len < length) {
+ qint64 read = self->m_waveDecoder->read(buffer, qMin(bufferSize, length -len));
+ if (read > 0) {
+ if (pa_stream_write(s, buffer, size_t(read), 0, 0, PA_SEEK_RELATIVE) == 0)
+ len += size_t(read);
+ else
+ break;
+ }
+ }
+ self->m_dataUploaded += len;
+
+ if (self->m_waveDecoder->size() == self->m_dataUploaded) {
+ pa_stream_finish_upload(s);
+
+ self->m_duration = self->m_waveDecoder->duration();
+ emit self->durationChanged(self->m_duration);
+
+ self->m_status = QMediaPlayer::BufferedMedia;
+ emit self->mediaStatusChanged(self->m_status);
+
+ self->m_waveDecoder->deleteLater();
+ if (!self->m_media.isNull())
+ self->m_stream->deleteLater();
+
+ if (self->m_playQueued) {
+ self->m_playQueued = false;
+ QMetaObject::invokeMethod(self, "play");
+ }
+ }
+}
+
+void QSoundEffectPrivate::stream_state_callback(pa_stream *s, void *userdata)
+{
+ QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata);
+
+ switch (pa_stream_get_state(s)) {
+ case PA_STREAM_CREATING:
+ case PA_STREAM_READY:
+ case PA_STREAM_TERMINATED:
+ break;
+
+ case PA_STREAM_FAILED:
+ default:
+ self->m_status = QMediaPlayer::InvalidMedia;
+ emit self->mediaStatusChanged(self->m_status);
+ break;
+ }
+}
+
+void QSoundEffectPrivate::play_callback(pa_context *c, int success, void *userdata)
+{
+ Q_UNUSED(c);
+
+ QSoundEffectPrivate *self = reinterpret_cast<QSoundEffectPrivate*>(userdata);
+
+ if (success == 1)
+ QMetaObject::invokeMethod(self, "checkPlayTime", Qt::QueuedConnection);
+ else {
+ self->m_state = QMediaPlayer::StoppedState;
+ emit self->stateChanged(self->m_state);
+ }
+}
+
+QT_END_NAMESPACE
+
+
diff --git a/src/multimedia/effects/qsoundeffect_pulse_p.h b/src/multimedia/effects/qsoundeffect_pulse_p.h
new file mode 100644
index 0000000..247f8a3
--- /dev/null
+++ b/src/multimedia/effects/qsoundeffect_pulse_p.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** 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 QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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_p.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qdatetime.h>
+#include <QtMultimedia/qmediaplayer.h>
+#include <pulse/pulseaudio.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QNetworkAccessManager;
+class WaveDecoder;
+
+class QSoundEffectPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QSoundEffectPrivate(QObject* parent);
+ ~QSoundEffectPrivate();
+
+ qint64 duration() const;
+ int volume() const;
+ bool isMuted() const;
+ QMediaContent media() const;
+ QMediaPlayer::State state() const;
+ QMediaPlayer::MediaStatus mediaStatus() const;
+
+public Q_SLOTS:
+ void play();
+ void stop();
+ void setVolume(int volume);
+ void setMuted(bool muted);
+ void setMedia(const QMediaContent &media);
+
+Q_SIGNALS:
+ void mediaChanged(const QMediaContent &media);
+ void mediaStatusChanged(QMediaPlayer::MediaStatus status);
+ void stateChanged(QMediaPlayer::State newState);
+ void durationChanged(qint64 duration);
+ void volumeChanged(int volume);
+ void mutedChanged(bool muted);
+ void error(QMediaPlayer::Error error);
+
+private slots:
+ void decoderReady();
+ void decoderError();
+ void checkPlayTime();
+
+private:
+ void loadSample();
+ void unloadSample();
+
+ void timerEvent(QTimerEvent *event);
+
+ 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 play_callback(pa_context *c, int success, void *userdata);
+
+ bool m_muted;
+ bool m_playQueued;
+ int m_vol;
+ int m_duration;
+ int m_dataUploaded;
+ QTime m_playbackTime;
+ QMediaPlayer::State m_state;
+ QMediaPlayer::MediaStatus m_status;
+ QByteArray m_name;
+ QMediaContent m_media;
+ QNetworkReply *m_reply;
+ WaveDecoder *m_waveDecoder;
+ QIODevice *m_stream;
+ QNetworkAccessManager *m_networkAccessManager;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSOUNDEFFECT_PULSE_H
diff --git a/src/multimedia/effects/qsoundeffect_qmedia_p.cpp b/src/multimedia/effects/qsoundeffect_qmedia_p.cpp
new file mode 100644
index 0000000..48fb257
--- /dev/null
+++ b/src/multimedia/effects/qsoundeffect_qmedia_p.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** 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 QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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.
+//
+// We mean it.
+//
+
+#include <QtCore/qcoreapplication.h>
+
+#include "qmediacontent.h"
+#include "qmediaplayer.h"
+
+#include "qsoundeffect_p.h"
+#include "qsoundeffect_qmedia_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent):
+ QObject(parent),
+ m_muted(false),
+ m_vol(100),
+ m_player(0)
+{
+}
+
+QSoundEffectPrivate::~QSoundEffectPrivate()
+{
+ if (m_player) delete m_player;
+}
+
+qint64 QSoundEffectPrivate::duration() const
+{
+ if (m_player) return m_player->duration();
+
+ return 0;
+}
+
+int QSoundEffectPrivate::volume() const
+{
+ if (m_player) return m_player->volume();
+
+ return m_vol;
+}
+
+bool QSoundEffectPrivate::isMuted() const
+{
+ if (m_player) return m_player->isMuted();
+
+ return m_muted;
+}
+
+QMediaContent QSoundEffectPrivate::media() const
+{
+ if (m_player) return m_player->media();
+
+ return QMediaContent();
+}
+
+QMediaPlayer::State QSoundEffectPrivate::state() const
+{
+ if (m_player) return m_player->state();
+
+ return QMediaPlayer::StoppedState;
+}
+
+QMediaPlayer::MediaStatus QSoundEffectPrivate::mediaStatus() const
+{
+ if (m_player) return m_player->mediaStatus();
+
+ return QMediaPlayer::UnknownMediaStatus;
+}
+
+void QSoundEffectPrivate::play()
+{
+ if (m_player && !m_player->isMuted())
+ m_player->play();
+}
+
+void QSoundEffectPrivate::stop()
+{
+ if (m_player)
+ m_player->stop();
+}
+
+void QSoundEffectPrivate::setVolume(int volume)
+{
+ m_vol = volume;
+
+ if (m_player)
+ m_player->setVolume(volume);
+}
+
+void QSoundEffectPrivate::setMuted(bool muted)
+{
+ m_muted = muted;
+
+ if (m_player)
+ m_player->setMuted(muted);
+}
+
+void QSoundEffectPrivate::setMedia(const QMediaContent &media)
+{
+ if (media.isNull())
+ return;
+
+ if (m_player == 0) {
+ m_player = new QMediaPlayer(this, QMediaPlayer::LowLatency);
+ m_player->setVolume(m_vol);
+ m_player->setMuted(m_muted);
+
+ connect(m_player, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int)));
+ connect(m_player, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool)));
+ connect(m_player, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64)));
+ connect(m_player, SIGNAL(stateChanged(QMediaPlayer::State)), SIGNAL(stateChanged(QMediaPlayer::State)));
+ }
+
+ m_player->setMedia(media.canonicalUrl());
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/effects/qsoundeffect_qmedia_p.h b/src/multimedia/effects/qsoundeffect_qmedia_p.h
new file mode 100644
index 0000000..8267f79
--- /dev/null
+++ b/src/multimedia/effects/qsoundeffect_qmedia_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** 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 QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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 <QtMultimedia/qmediaplayer.h>
+#include "qsoundeffect_p.h"
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class WaveDecoder;
+
+class QSoundEffectPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QSoundEffectPrivate(QObject* parent);
+ ~QSoundEffectPrivate();
+
+ qint64 duration() const;
+ int volume() const;
+ bool isMuted() const;
+ QMediaContent media() const;
+ QMediaPlayer::State state() const;
+ QMediaPlayer::MediaStatus mediaStatus() const;
+
+public Q_SLOTS:
+ void play();
+ void stop();
+ void setVolume(int volume);
+ void setMuted(bool muted);
+ void setMedia(const QMediaContent &media);
+
+Q_SIGNALS:
+ void mediaChanged(const QMediaContent &media);
+ void mediaStatusChanged(QMediaPlayer::MediaStatus status);
+ void stateChanged(QMediaPlayer::State newState);
+ void durationChanged(qint64 duration);
+ void volumeChanged(int volume);
+ void mutedChanged(bool muted);
+ void error(QMediaPlayer::Error error);
+
+private:
+ bool m_muted;
+ int m_vol;
+ QMediaPlayer *m_player;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSOUNDEFFECT_QMEDIA_H
diff --git a/src/multimedia/effects/qsoundeffect_qsound_p.cpp b/src/multimedia/effects/qsoundeffect_qsound_p.cpp
new file mode 100644
index 0000000..df160a9
--- /dev/null
+++ b/src/multimedia/effects/qsoundeffect_qsound_p.cpp
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** 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 QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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.
+//
+// We mean it.
+//
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qfile.h>
+#include <QtGui/qsound.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QDebug>
+
+#include "qmediacontent.h"
+#include "qmediaplayer.h"
+#include "qsoundeffect_p.h"
+
+#include "wavedecoder_p.h"
+
+#include "qsoundeffect_qsound_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent):
+ QObject(parent),
+ m_queued(false),
+ m_muted(false),
+ m_state(QMediaPlayer::StoppedState),
+ m_status(QMediaPlayer::NoMedia),
+ m_file(0),
+ m_sound(0)
+{
+ m_timer = new QTimer(this);
+ connect(m_timer,SIGNAL(timeout()),SLOT(checkPlayTime()));
+ m_media = QMediaContent();
+}
+
+QSoundEffectPrivate::~QSoundEffectPrivate()
+{
+ if (m_sound) delete m_sound;
+ if (m_waveDecoder) delete m_waveDecoder;
+ m_file->close();
+}
+
+qint64 QSoundEffectPrivate::duration() const
+{
+ if (m_waveDecoder)
+ return m_waveDecoder->size();
+
+ return 0;
+}
+
+int QSoundEffectPrivate::volume() const
+{
+ return 100;
+}
+
+bool QSoundEffectPrivate::isMuted() const
+{
+ return m_muted;
+}
+
+QMediaContent QSoundEffectPrivate::media() const
+{
+ return m_media;
+}
+
+QMediaPlayer::State QSoundEffectPrivate::state() const
+{
+ return m_state;
+}
+
+QMediaPlayer::MediaStatus QSoundEffectPrivate::mediaStatus() const
+{
+ return m_status;
+}
+
+void QSoundEffectPrivate::play()
+{
+ if (m_sound && !m_muted) {
+ m_queued = false;
+ m_timer->start(20);
+ m_playbackTime.start();
+ m_sound->play();
+ emit stateChanged(m_state = QMediaPlayer::PlayingState);
+ } else if (m_status == QMediaPlayer::LoadingMedia)
+ m_queued = true;
+}
+
+void QSoundEffectPrivate::stop()
+{
+ m_timer->stop();
+
+ if (m_sound) {
+ m_sound->stop();
+ emit stateChanged(m_state = QMediaPlayer::StoppedState);
+ }
+}
+
+void QSoundEffectPrivate::setVolume(int volume)
+{
+ Q_UNUSED(volume)
+}
+
+void QSoundEffectPrivate::setMuted(bool muted)
+{
+ m_muted = muted;
+}
+
+void QSoundEffectPrivate::setMedia(const QMediaContent &media)
+{
+ m_queued = false;
+
+ if (media.isNull() || media.canonicalUrl().scheme() != QLatin1String("file")) {
+ m_media = QMediaContent();
+ return;
+ }
+ if (m_media == media)
+ return;
+
+ m_media = media;
+ m_file = new QFile(m_media.canonicalUrl().toLocalFile());
+ m_file->open(QIODevice::ReadOnly|QIODevice::Unbuffered);
+
+ unloadSample();
+ loadSample();
+
+ emit mediaChanged(m_media);
+}
+
+void QSoundEffectPrivate::decoderReady()
+{
+ m_file->close();
+ m_sound = new QSound(m_media.canonicalUrl().toLocalFile());
+ emit mediaStatusChanged(m_status = QMediaPlayer::LoadedMedia);
+
+ if (m_queued)
+ play();
+}
+
+void QSoundEffectPrivate::decoderError()
+{
+ m_file->close();
+ emit mediaStatusChanged(m_status = QMediaPlayer::InvalidMedia);
+}
+
+void QSoundEffectPrivate::checkPlayTime()
+{
+ if (m_sound->isFinished()) {
+ m_timer->stop();
+ m_state = QMediaPlayer::StoppedState;
+ emit stateChanged(m_state);
+ }
+}
+
+void QSoundEffectPrivate::loadSample()
+{
+ m_waveDecoder = new WaveDecoder(m_file);
+ connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady()));
+ connect(m_waveDecoder, SIGNAL(invalidFormat()), SLOT(decoderError()));
+
+ m_status = QMediaPlayer::LoadingMedia;
+ emit mediaStatusChanged(m_status);
+}
+
+void QSoundEffectPrivate::unloadSample()
+{
+ if (m_sound == 0)
+ return;
+
+ m_status = QMediaPlayer::NoMedia;
+
+ if (m_sound)
+ delete m_sound;
+
+ m_sound = 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/effects/qsoundeffect_qsound_p.h b/src/multimedia/effects/qsoundeffect_qsound_p.h
new file mode 100644
index 0000000..45c0888
--- /dev/null
+++ b/src/multimedia/effects/qsoundeffect_qsound_p.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** 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 QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSOUNDEFFECT_QSOUND_H
+#define QSOUNDEFFECT_QSOUND_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/qdatetime.h>
+#include <QtMultimedia/qmediaplayer.h>
+
+#include "qsoundeffect_p.h"
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTimer;
+class QSound;
+class QFile;
+class WaveDecoder;
+
+class QSoundEffectPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QSoundEffectPrivate(QObject* parent);
+ ~QSoundEffectPrivate();
+
+ qint64 duration() const;
+ int volume() const;
+ bool isMuted() const;
+ QMediaContent media() const;
+ QMediaPlayer::State state() const;
+ QMediaPlayer::MediaStatus mediaStatus() const;
+
+public Q_SLOTS:
+ void play();
+ void stop();
+ void setVolume(int volume);
+ void setMuted(bool muted);
+ void setMedia(const QMediaContent &media);
+
+Q_SIGNALS:
+ void mediaChanged(const QMediaContent &media);
+ void mediaStatusChanged(QMediaPlayer::MediaStatus status);
+ void stateChanged(QMediaPlayer::State newState);
+ void durationChanged(qint64 duration);
+ void volumeChanged(int volume);
+ void mutedChanged(bool muted);
+ void error(QMediaPlayer::Error error);
+
+private slots:
+ void decoderReady();
+ void decoderError();
+ void checkPlayTime();
+
+private:
+ void loadSample();
+ void unloadSample();
+
+ bool m_queued;
+ bool m_muted;
+ QTime m_playbackTime;
+ QMediaPlayer::State m_state;
+ QMediaPlayer::MediaStatus m_status;
+ QFile *m_file;
+ QByteArray m_name;
+ QMediaContent m_media;
+ WaveDecoder *m_waveDecoder;
+ QSound *m_sound;
+ QTimer *m_timer;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSOUNDEFFECT_QSOUND_H
diff --git a/src/multimedia/effects/wavedecoder_p.cpp b/src/multimedia/effects/wavedecoder_p.cpp
new file mode 100644
index 0000000..b534ded
--- /dev/null
+++ b/src/multimedia/effects/wavedecoder_p.cpp
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** 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 QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "wavedecoder_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtCore/qendian.h>
+
+QT_BEGIN_NAMESPACE
+
+WaveDecoder::WaveDecoder(QIODevice *s, QObject *parent):
+ QIODevice(parent),
+ haveFormat(false),
+ dataSize(0),
+ remaining(0),
+ source(s)
+{
+ open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+
+ if (source->bytesAvailable() >= qint64(sizeof(CombinedHeader) + sizeof(DATAHeader) + sizeof(quint16)))
+ QTimer::singleShot(0, this, SLOT(handleData()));
+ else
+ connect(source, SIGNAL(readyRead()), SLOT(handleData()));
+}
+
+WaveDecoder::~WaveDecoder()
+{
+}
+
+QAudioFormat WaveDecoder::audioFormat() const
+{
+ return format;
+}
+
+int WaveDecoder::duration() const
+{
+ return size() * 1000 / (format.sampleSize() / 8) / format.channels() / format.frequency();
+}
+
+qint64 WaveDecoder::size() const
+{
+ return haveFormat ? dataSize : 0;
+}
+
+bool WaveDecoder::isSequential() const
+{
+ return source->isSequential();
+}
+
+qint64 WaveDecoder::bytesAvailable() const
+{
+ return haveFormat ? source->bytesAvailable() : 0;
+}
+
+qint64 WaveDecoder::readData(char *data, qint64 maxlen)
+{
+ return haveFormat ? source->read(data, maxlen) : 0;
+}
+
+qint64 WaveDecoder::writeData(const char *data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+
+ return -1;
+}
+
+void WaveDecoder::handleData()
+{
+ if (source->bytesAvailable() < qint64(sizeof(CombinedHeader) + sizeof(DATAHeader) + sizeof(quint16)))
+ return;
+
+ source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData()));
+ source->read((char*)&header, sizeof(CombinedHeader));
+
+ if (qstrncmp(header.riff.descriptor.id, "RIFF", 4) != 0 ||
+ qstrncmp(header.riff.type, "WAVE", 4) != 0 ||
+ qstrncmp(header.wave.descriptor.id, "fmt ", 4) != 0 ||
+ (header.wave.audioFormat != 0 && header.wave.audioFormat != 1)) {
+
+ emit invalidFormat();
+ }
+ else {
+ DATAHeader dataHeader;
+
+ if (qFromLittleEndian<quint32>(header.wave.descriptor.size) > sizeof(WAVEHeader)) {
+ // Extended data available
+ quint16 extraFormatBytes;
+ source->peek((char*)&extraFormatBytes, sizeof(quint16));
+ extraFormatBytes = qFromLittleEndian<quint16>(extraFormatBytes);
+ source->read(sizeof(quint16) + extraFormatBytes); // dump it all
+ }
+
+ source->read((char*)&dataHeader, sizeof(DATAHeader));
+
+ int bps = qFromLittleEndian<quint16>(header.wave.bitsPerSample);
+
+ format.setCodec(QLatin1String("audio/pcm"));
+ format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
+ format.setByteOrder(QAudioFormat::LittleEndian);
+ format.setFrequency(qFromLittleEndian<quint32>(header.wave.sampleRate));
+ format.setSampleSize(bps);
+ format.setChannels(qFromLittleEndian<quint16>(header.wave.numChannels));
+
+ dataSize = qFromLittleEndian<quint32>(dataHeader.descriptor.size);
+
+ haveFormat = true;
+ connect(source, SIGNAL(readyRead()), SIGNAL(readyRead()));
+ emit formatKnown();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/effects/wavedecoder_p.h b/src/multimedia/effects/wavedecoder_p.h
new file mode 100644
index 0000000..fa1f77e
--- /dev/null
+++ b/src/multimedia/effects/wavedecoder_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** 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 QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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 <QtMultimedia/qaudioformat.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class WaveDecoder : public QIODevice
+{
+ Q_OBJECT
+
+public:
+ explicit WaveDecoder(QIODevice *source, QObject *parent = 0);
+ ~WaveDecoder();
+
+ QAudioFormat audioFormat() const;
+ int duration() const;
+
+ qint64 size() const;
+ bool isSequential() const;
+ qint64 bytesAvailable() const;
+
+signals:
+ void formatKnown();
+ void invalidFormat();
+
+private slots:
+ void handleData();
+
+private:
+ qint64 readData(char *data, qint64 maxlen);
+ qint64 writeData(const char *data, qint64 len);
+
+ struct chunk
+ {
+ char id[4];
+ quint32 size;
+ };
+ struct RIFFHeader
+ {
+ chunk descriptor;
+ char type[4];
+ };
+ struct WAVEHeader
+ {
+ chunk descriptor;
+ quint16 audioFormat;
+ quint16 numChannels;
+ quint32 sampleRate;
+ quint32 byteRate;
+ quint16 blockAlign;
+ quint16 bitsPerSample;
+ };
+ struct DATAHeader
+ {
+ chunk descriptor;
+ };
+ struct CombinedHeader
+ {
+ RIFFHeader riff;
+ WAVEHeader wave;
+ };
+
+ bool haveFormat;
+ qint64 dataSize;
+ qint64 remaining;
+ QAudioFormat format;
+ QIODevice *source;
+ CombinedHeader header;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // WAVEDECODER_H