summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/phonon/waveout
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/phonon/waveout')
-rw-r--r--src/3rdparty/phonon/waveout/audiooutput.cpp78
-rw-r--r--src/3rdparty/phonon/waveout/audiooutput.h65
-rw-r--r--src/3rdparty/phonon/waveout/backend.cpp131
-rw-r--r--src/3rdparty/phonon/waveout/backend.h69
-rw-r--r--src/3rdparty/phonon/waveout/mediaobject.cpp686
-rw-r--r--src/3rdparty/phonon/waveout/mediaobject.h162
6 files changed, 1191 insertions, 0 deletions
diff --git a/src/3rdparty/phonon/waveout/audiooutput.cpp b/src/3rdparty/phonon/waveout/audiooutput.cpp
new file mode 100644
index 0000000..f842dc9
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/audiooutput.cpp
@@ -0,0 +1,78 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audiooutput.h"
+#include "mediaobject.h"
+
+#include <QtCore/QVector>
+
+#include <cmath>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace WaveOut
+ {
+ AudioOutput::AudioOutput(Backend *, QObject *parent)
+ {
+ setParent(parent);
+ m_volume = 0xffff;
+ }
+
+ AudioOutput::~AudioOutput()
+ {
+ }
+
+ int AudioOutput::outputDevice() const
+ {
+ return 0;
+ }
+
+ void AudioOutput::setVolume(qreal newVolume)
+ {
+ m_volume = newVolume;
+ emit volumeChanged(newVolume);
+ }
+
+ void AudioOutput::setCrossFadingProgress(short currentIndex, qreal progress)
+ {
+ Q_UNUSED(currentIndex);
+ Q_UNUSED(progress);
+ }
+
+ bool AudioOutput::setOutputDevice(const AudioOutputDevice & newDevice)
+ {
+ return setOutputDevice(newDevice.index());
+ }
+
+ qreal AudioOutput::volume() const
+ {
+ return m_volume;
+ }
+
+ bool AudioOutput::setOutputDevice(int newDevice)
+ {
+
+ return (newDevice == 0);
+ }
+
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/3rdparty/phonon/waveout/audiooutput.h b/src/3rdparty/phonon/waveout/audiooutput.h
new file mode 100644
index 0000000..43f8222
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/audiooutput.h
@@ -0,0 +1,65 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_AUDIOOUTPUT_H
+#define PHONON_AUDIOOUTPUT_H
+
+#include <QtCore/QFile>
+#include <phonon/audiooutputinterface.h>
+
+#include "backend.h"
+
+struct IBaseFilter;
+struct IBasicAudio;
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace WaveOut
+ {
+ class AudioOutput : public QObject, public Phonon::AudioOutputInterface
+ {
+ Q_OBJECT
+
+ Q_INTERFACES(Phonon::AudioOutputInterface)
+ public:
+ AudioOutput(Backend *back, QObject *parent);
+ ~AudioOutput();
+
+ // Attributes Getters:
+ qreal volume() const;
+ int outputDevice() const;
+ void setVolume(qreal newVolume);
+ bool setOutputDevice(int newDevice);
+ bool setOutputDevice(const AudioOutputDevice & newDevice);
+ void setCrossFadingProgress(short currentIndex, qreal progress);
+
+ Q_SIGNALS:
+ void audioDeviceFailed();
+ void volumeChanged(qreal);
+ private:
+ unsigned int m_volume;
+
+
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // PHONON_AUDIOOUTPUT_H
diff --git a/src/3rdparty/phonon/waveout/backend.cpp b/src/3rdparty/phonon/waveout/backend.cpp
new file mode 100644
index 0000000..8faa26e
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/backend.cpp
@@ -0,0 +1,131 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "backend.h"
+
+
+#include "audiooutput.h"
+#include "mediaobject.h"
+
+
+
+#include <QtCore/QSettings>
+#include <QtCore/QSet>
+#include <QtCore/QVariant>
+#include <QtCore/QStringList>
+
+#include <QtCore/QtPlugin>
+
+
+QT_BEGIN_NAMESPACE
+
+// export as Qt/KDE factory as required
+
+Q_EXPORT_PLUGIN2(phonon_waveout, Phonon::WaveOut::Backend);
+
+namespace Phonon
+{
+ namespace WaveOut
+ {
+
+ Backend::Backend(QObject *parent, const QVariantList &)
+ : QObject(parent)
+ {
+ }
+
+ Backend::~Backend()
+ {
+ }
+
+ QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
+ {
+ Q_UNUSED(args);
+ switch (c)
+ {
+ case MediaObjectClass:
+ return new MediaObject(parent);
+ case AudioOutputClass:
+ return new AudioOutput(this, parent);
+ default:
+ return 0;
+ }
+ }
+
+ bool Backend::supportsVideo() const
+ {
+ return false;
+ }
+
+ QStringList Backend::availableMimeTypes() const
+ {
+ QStringList ret;
+ return ret;
+ }
+
+
+ QList<int> Backend::objectDescriptionIndexes(Phonon::ObjectDescriptionType type) const
+ {
+ QList<int> r;
+ if (type == Phonon::AudioOutputDeviceType)
+ r.append(0);
+ return r;
+ }
+
+ QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(Phonon::ObjectDescriptionType type, int index) const
+ {
+ Q_UNUSED(index);
+ QHash<QByteArray, QVariant> r;
+ if (type == Phonon::AudioOutputDeviceType)
+ r["name"] = QLatin1String("default audio device");
+ return r;
+ }
+
+
+ bool Backend::connectNodes(QObject *node1, QObject *node2)
+ {
+ MediaObject *mediaObject = qobject_cast<MediaObject*> (node1);
+ AudioOutput *audioOutput = qobject_cast<AudioOutput*> (node2);
+
+ if (mediaObject && audioOutput)
+ mediaObject->setAudioOutput(audioOutput);
+ return true;
+ }
+
+ bool Backend::disconnectNodes(QObject *node1, QObject *node2)
+ {
+ Q_UNUSED(node1);
+ Q_UNUSED(node2);
+ return true;
+ }
+
+ //transaction management
+ bool Backend::startConnectionChange(QSet<QObject *>)
+ {
+ return true;
+ }
+
+ bool Backend::endConnectionChange(QSet<QObject *>)
+ {
+ return true;
+ }
+
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_backend.cpp"
diff --git a/src/3rdparty/phonon/waveout/backend.h b/src/3rdparty/phonon/waveout/backend.h
new file mode 100644
index 0000000..060d853
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/backend.h
@@ -0,0 +1,69 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_BACKEND_H
+#define PHONON_BACKEND_H
+
+#include <phonon/backendinterface.h>
+#include <phonon/phononnamespace.h>
+
+#include <QtCore/QList>
+
+
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace WaveOut
+ {
+ class AudioOutput;
+ class MediaObject;
+
+ class Backend : public QObject, public Phonon::BackendInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::BackendInterface)
+ public:
+ Backend(QObject *parent = 0, const QVariantList & = QVariantList());
+ virtual ~Backend();
+
+ QObject *createObject(Phonon::BackendInterface::Class, QObject *parent, const QList<QVariant> &args);
+
+ bool supportsVideo() const;
+ QStringList availableMimeTypes() const;
+
+ QList<int> objectDescriptionIndexes(Phonon::ObjectDescriptionType type) const;
+ QHash<QByteArray, QVariant> objectDescriptionProperties(Phonon::ObjectDescriptionType type, int index) const;
+
+ bool connectNodes(QObject *, QObject *);
+ bool disconnectNodes(QObject *, QObject *);
+
+ //transaction management
+ bool startConnectionChange(QSet<QObject *>);
+ bool endConnectionChange(QSet<QObject *>);
+
+ Q_SIGNALS:
+ void objectDescriptionChanged(ObjectDescriptionType);
+
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // PHONON_BACKEND_H
diff --git a/src/3rdparty/phonon/waveout/mediaobject.cpp b/src/3rdparty/phonon/waveout/mediaobject.cpp
new file mode 100644
index 0000000..fdd81a7
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/mediaobject.cpp
@@ -0,0 +1,686 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "mediaobject.h"
+#include "audiooutput.h"
+
+#include <QtCore/QVector>
+#include <QtCore/QTimerEvent>
+#include <QtCore/QTimer>
+#include <QtCore/QTime>
+#include <QtCore/QLibrary>
+#include <QtCore/QUrl>
+#include <QtCore/QWriteLocker>
+
+#include <phonon/streaminterface.h>
+
+
+#define WAVEHEADER_OFFSET_FORMATTAG 20
+#define WAVEHEADER_OFFSET_CHANNELS 22
+#define WAVEHEADER_OFFSET_SAMPLESPERSEC 24
+#define WAVEHEADER_OFFSET_AVGBYTESPERSEC 28
+#define WAVEHEADER_OFFSET_BLOCKALIGN 32
+#define WAVEHEADER_OFFSET_BITSPERSAMPLE 34
+#define WAVEHEADER_OFFSET_DATA 44
+#define WAVEHEADER_SIZE WAVEHEADER_OFFSET_DATA
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace WaveOut
+ {
+ static unsigned int buffer_size = (16 * 1024 * 4);
+
+ QString getErrorText(MMRESULT error)
+ {
+ ushort b[256];
+ waveOutGetErrorText(error, (LPWSTR)b, 256);
+ return QString((const QChar *)b);
+ }
+
+ class WorkerThread : public QThread
+ {
+ Q_OBJECT
+ public slots:
+ void stream(QIODevice *file, QByteArray *buffer, bool *finished);
+ };
+
+ void WorkerThread::stream(QIODevice *ioStream, QByteArray *buffer, bool *finished)
+ {
+ (*finished) = false;
+ memset((void*) buffer->data(), 0, buffer->size());
+ qint64 i = ioStream->read(buffer->data(), buffer_size);
+ buffer->resize(i);
+ (*finished) = true;
+ }
+
+
+ void QT_WIN_CALLBACK MediaObject::WaveOutCallBack(HWAVEOUT m_hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
+ {
+ Q_UNUSED(m_hWaveOut);
+ Q_UNUSED(dwInstance);
+ Q_UNUSED(dwParam2);
+
+ switch(uMsg)
+ {
+ case WOM_OPEN:
+ break;
+ case WOM_DONE:
+ {
+ WAVEHDR *waveHeader = (WAVEHDR*)dwParam1;
+ MediaObject* mediaObject = reinterpret_cast<MediaObject *>(waveHeader->dwUser);
+ if (mediaObject) {
+ mediaObject->swapBuffers();
+ }
+ }
+ break;
+ case WOM_CLOSE:
+ break;
+ }
+ }
+
+ class StreamReader : public Phonon::StreamInterface
+ {
+ public:
+ StreamReader(QObject *parent, const Phonon::MediaSource &source) :
+ m_seekable(false), m_pos(0), m_size(-1)
+ {
+ Q_UNUSED(parent);
+ connectToSource(source);
+ }
+
+ //for Phonon::StreamInterface
+ void writeData(const QByteArray &data)
+ {
+ QWriteLocker locker(&m_lock);
+ m_pos += data.size();
+ m_buffer += data;
+ }
+
+ void endOfData()
+ {
+ }
+
+ void setStreamSize(qint64 newSize)
+ {
+ QWriteLocker locker(&m_lock);
+ m_size = newSize;
+ }
+
+ qint64 streamSize() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_size;
+ }
+
+ void setStreamSeekable(bool s)
+ {
+ QWriteLocker locker(&m_lock);
+ m_seekable = s;
+ }
+
+ bool streamSeekable() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_seekable;
+ }
+
+ void setCurrentPos(qint64 pos)
+ {
+ QWriteLocker locker(&m_lock);
+ m_pos = pos;
+ seekStream(pos);
+ m_buffer.clear();
+ }
+
+ qint64 currentPos() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_pos;
+ }
+
+ int currentBufferSize() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_buffer.size();
+ }
+
+ //for Phonon::StreamInterface
+ QByteArray m_buffer;
+ bool m_seekable;
+ qint64 m_pos;
+ qint64 m_size;
+ mutable QReadWriteLock m_lock;
+ };
+
+ class IOWrapper : public QIODevice {
+ public:
+ IOWrapper(QObject *parent, const Phonon::MediaSource &source) : m_streamReader(this, source)
+ {
+ Q_UNUSED(parent);
+ setOpenMode(QIODevice::ReadOnly);
+ }
+ bool seek(qint64 pos);
+ qint64 size() const;
+ qint64 pos();
+ bool isReadable() const;
+ protected:
+ qint64 readData (char * data, qint64 maxSize);
+ qint64 writeData(const char *,qint64);
+ private:
+ StreamReader m_streamReader;
+ };
+
+ bool IOWrapper::isReadable () const
+ {
+ return true;
+ }
+
+ qint64 IOWrapper::pos()
+ {
+ return (m_streamReader.streamSeekable() ? m_streamReader.currentPos() : 0);
+ }
+
+ bool IOWrapper::seek( qint64 pos)
+ {
+ if (!m_streamReader.streamSeekable())
+ return false;
+ m_streamReader.setCurrentPos(pos);
+ return true;
+ }
+
+ qint64 IOWrapper::size() const
+ {
+ return m_streamReader.streamSize();
+ }
+
+ qint64 IOWrapper::readData(char * data, qint64 maxSize)
+ {
+ int oldSize = m_streamReader.currentBufferSize();
+ while (m_streamReader.currentBufferSize() < maxSize) {
+ m_streamReader.needData();
+ if (oldSize == m_streamReader.currentBufferSize()) {
+ break; //we didn't get any data
+ }
+ oldSize = m_streamReader.currentBufferSize();
+ }
+
+ qint64 bytesRead = qMin(qint64(m_streamReader.currentBufferSize()), maxSize);
+ {
+ QWriteLocker locker(&m_streamReader.m_lock);
+ qMemCopy(data, m_streamReader.m_buffer.data(), bytesRead);
+ //truncate the buffer
+ m_streamReader.m_buffer = m_streamReader.m_buffer.mid(bytesRead);
+ }
+ return bytesRead;
+ }
+
+ qint64 IOWrapper::writeData(const char *,qint64)
+ {
+ return 0;
+ }
+
+ MediaObject::MediaObject(QObject *parent) : m_file(0), m_stream(0),
+ m_hWaveOut(0), m_nextBufferIndex(1),
+ m_mediaSize(-1), m_bufferingFinished(0),
+ m_paused(0), m_tickInterval(0),
+ m_hasNextSource(0), m_hasSource(0),
+ m_sourceIsValid(0), m_errorType(Phonon::NoError),
+ m_currentTime(0), m_transitionTime(0),
+ m_tick(0), m_volume(100), m_prefinishMark(0),
+ m_tickIntervalResolution(0), m_bufferPrepared(0),
+ m_stopped(0)
+ {
+ m_thread = new WorkerThread();
+ connect(this, SIGNAL(outOfData(QIODevice*,QByteArray*,bool*)), m_thread, SLOT(stream(QIODevice*,QByteArray*,bool*)));
+ m_thread->start();
+ m_soundBuffer1.waveHeader = new WAVEHDR;
+ m_soundBuffer2.waveHeader = new WAVEHDR;
+ setParent(parent);
+ setState(Phonon::LoadingState);
+ }
+
+ MediaObject::~MediaObject()
+ {
+ stop();
+ disconnect(this, SIGNAL(outOfData(QIODevice*,QByteArray*,bool*)), m_thread, SLOT(stream(QIODevice*,QByteArray*,bool*)));
+ do { //The event loop of m_thread might not be started, yet
+ m_thread->quit(); //If the event loop is not started yet quit() does nothing
+ m_thread->wait(100);
+ } while (m_thread->isRunning());
+ delete m_thread;
+ deleteValidWaveOutDevice();
+ delete m_soundBuffer1.waveHeader;
+ delete m_soundBuffer2.waveHeader;
+ }
+
+ Phonon::State MediaObject::state() const
+ {
+ return m_state;
+ }
+
+ bool MediaObject::hasVideo() const
+ {
+ return false;
+ }
+
+ bool MediaObject::isSeekable() const
+ {
+ if (!m_stream)
+ return false;
+ return !m_stream->isSequential();
+ }
+
+ qint64 MediaObject::totalTime() const
+ {
+ return m_totalTime;
+ }
+
+ qint64 MediaObject::currentTime() const
+ {
+ //this handles inaccuracy when stopping on a title
+ return m_currentTime;
+ }
+
+ qint32 MediaObject::tickInterval() const
+ {
+ return m_tickInterval * m_tickIntervalResolution;
+ }
+
+ void MediaObject::setTickInterval(qint32 newTickInterval)
+ {
+ if ((m_tickIntervalResolution == 0) || (newTickInterval == 0))
+ return;
+ m_tickInterval = newTickInterval / m_tickIntervalResolution;
+ if ((newTickInterval > 0) && (m_tickInterval == 0))
+ m_tickInterval = 1;
+ }
+
+ void MediaObject::pause()
+ {
+ if (!m_paused) {
+ m_paused = true;
+ setState(Phonon::PausedState);
+ if (!(waveOutPause(m_hWaveOut) == MMSYSERR_NOERROR))
+ {
+ setError(Phonon::NormalError, QLatin1String("cannot pause (system error)"));
+ }
+ }
+ }
+
+ void MediaObject::stop()
+ {
+ setState(Phonon::StoppedState);
+ m_stopped = true;
+ m_paused = false;
+ seek(0);
+ if (!(waveOutReset(m_hWaveOut) == MMSYSERR_NOERROR))
+ setError(Phonon::NormalError, QLatin1String("cannot stop (system error)"));
+ }
+
+ void MediaObject::play()
+ {
+ if ((m_state == Phonon::PlayingState) && !m_paused && !m_stopped)
+ return;
+ if ((m_state == Phonon::LoadingState) ||
+ (m_state == Phonon::BufferingState) ||
+ (m_state == Phonon::ErrorState)) {
+ setError(Phonon::FatalError, QLatin1String("illegale state for playback"));
+ return;
+ }
+
+ if (m_state == Phonon::StoppedState)
+ stop();
+ if (m_sourceIsValid) {
+ setState(Phonon::PlayingState);
+ if (!m_paused) {
+ m_nextBufferIndex = true;
+ m_stopped = false;
+ playBuffer(m_soundBuffer1.waveHeader);
+ playBuffer(m_soundBuffer2.waveHeader);
+ } else {
+ if (!(waveOutRestart(m_hWaveOut) == MMSYSERR_NOERROR))
+ setError(Phonon::NormalError, QLatin1String("cannot resume (system)"));
+ }
+ } else {
+ setError(Phonon::FatalError, QLatin1String("cannot playback invalid source"));
+ }
+ m_paused = false;
+ }
+
+ QString MediaObject::errorString() const
+ {
+
+ return m_errorString;
+ }
+
+ Phonon::ErrorType MediaObject::errorType() const
+ {
+ return Phonon::ErrorType();
+ }
+
+ qint32 MediaObject::prefinishMark() const
+ {
+ return m_prefinishMark;
+ }
+
+ void MediaObject::setPrefinishMark(qint32 newPrefinishMark)
+ {
+ m_prefinishMark = newPrefinishMark;
+ }
+
+ qint32 MediaObject::transitionTime() const
+ {
+ return m_transitionTime;
+ }
+
+ void MediaObject::setTransitionTime(qint32 time)
+ {
+ m_transitionTime = time;
+ }
+
+ qint64 MediaObject::remainingTime() const
+ {
+ return m_totalTime - m_currentTime;
+ }
+
+ Phonon::MediaSource MediaObject::source() const
+ {
+ return Phonon::MediaSource();
+ }
+
+ void MediaObject::setNextSource(const Phonon::MediaSource &source)
+ {
+ m_nextSource = source;
+ m_hasNextSource = true;
+ }
+
+ void MediaObject::setSource(const Phonon::MediaSource &source)
+ {
+ if (m_state == Phonon::PlayingState)
+ {
+ setError(Phonon::NormalError, QLatin1String("source changed while playing"));
+ stop();
+ }
+
+ m_source = source;
+ m_hasSource = true;
+ m_sourceIsValid = false;
+
+ emit currentSourceChanged(source);
+
+ if (source.type() == Phonon::MediaSource::LocalFile) {
+ if (!openWaveFile(source.fileName())) {
+ setError(Phonon::FatalError, QLatin1String("cannot open media file"));
+ return ;
+ }
+ } else if (source.type() == Phonon::MediaSource::Stream) {
+ if (m_stream)
+ delete m_stream;
+ m_stream = new IOWrapper(this, source);
+ m_mediaSize = m_stream->size();
+ } else if (source.type() == Phonon::MediaSource::Url) {
+ if (!openWaveFile(source.url().toLocalFile())) {
+ setError(Phonon::FatalError, QLatin1String("cannot open media file"));
+ return ;
+ }
+ } else {
+ setError(Phonon::FatalError, QLatin1String("type of source not supported"));
+ return ;
+ }
+ setState(Phonon::LoadingState);
+
+ if (!readHeader())
+ setError(Phonon::FatalError, QLatin1String("invalid header"));
+ else if (!getWaveOutDevice())
+ setError(Phonon::FatalError, QLatin1String("No waveOut device available"));
+ else if (!fillBuffers())
+ setError(Phonon::FatalError, QLatin1String("no data for buffering"));
+ else if (!prepareBuffers())
+ setError(Phonon::FatalError, QLatin1String("cannot prepare buffers"));
+ else
+ m_sourceIsValid = true;
+
+ if (m_sourceIsValid)
+ setState(Phonon::StoppedState);
+ }
+
+ void MediaObject::seek(qint64 time)
+ {
+ if (!m_sourceIsValid) {
+ setError(Phonon::NormalError, QLatin1String("source is not valid"));
+ return;
+ }
+ if ((time >= 0) && (time < m_totalTime)) {
+ int counter = 0;
+ while (!m_bufferingFinished && (counter < 200)) {
+ Sleep(20);
+ counter ++;
+ }
+ if (counter >= 200) {
+ setError(Phonon::NormalError, QLatin1String("buffering timed out"));
+ return;
+ }
+
+ m_stream->seek(WAVEHEADER_SIZE + time * m_waveFormatEx.nSamplesPerSec * m_waveFormatEx.wBitsPerSample * m_waveFormatEx.nChannels / 8 / 1000);
+ m_currentTime = time;
+ if (m_state == Phonon::PlayingState)
+ play();
+ } else {
+ setError(Phonon::NormalError, QLatin1String("seeking out of range"));
+ }
+ }
+
+ void MediaObject::unPrepareBuffers()
+ {
+ if (m_bufferPrepared) {
+ DWORD err1 = waveOutUnprepareHeader(m_hWaveOut, m_soundBuffer1.waveHeader, sizeof(WAVEHDR));
+ DWORD err2 = waveOutUnprepareHeader(m_hWaveOut, m_soundBuffer2.waveHeader, sizeof(WAVEHDR));
+ if (!(err1 == MMSYSERR_NOERROR) || !(err2 == MMSYSERR_NOERROR))
+ setError(Phonon::NormalError, QLatin1String("cannot unprepare buffer") + getErrorText(err1) + getErrorText(err2));
+ }
+ m_bufferPrepared = false;
+ }
+
+ bool MediaObject::prepareBuffers()
+ {
+ memset((void*)m_soundBuffer1.waveHeader, 0, sizeof(WAVEHDR));
+ m_soundBuffer1.waveHeader->lpData = m_soundBuffer1.data.data();
+ m_soundBuffer1.waveHeader->dwBufferLength = m_soundBuffer1.data.size();
+ m_soundBuffer1.waveHeader->dwUser = (DWORD_PTR) this;
+
+ ZeroMemory((void*)m_soundBuffer2.waveHeader, sizeof(WAVEHDR));
+ m_soundBuffer2.waveHeader->lpData = m_soundBuffer2.data.data();
+ m_soundBuffer2.waveHeader->dwBufferLength = m_soundBuffer1.data.size();
+ m_soundBuffer2.waveHeader->dwUser = (DWORD_PTR) this;
+
+ m_bufferPrepared = (waveOutPrepareHeader(m_hWaveOut, m_soundBuffer1.waveHeader, sizeof(WAVEHDR)) == MMSYSERR_NOERROR)
+ && (waveOutPrepareHeader(m_hWaveOut, m_soundBuffer2.waveHeader, sizeof(WAVEHDR)) == MMSYSERR_NOERROR);
+ return m_bufferPrepared;
+ }
+
+ void MediaObject::deleteValidWaveOutDevice()
+ {
+ if (m_hWaveOut) {
+ unPrepareBuffers();
+ if (!(waveOutClose(m_hWaveOut) == MMSYSERR_NOERROR))
+ setError(Phonon::NormalError, QLatin1String("cannot close wave device"));
+ }
+ }
+
+ bool MediaObject::getWaveOutDevice()
+ {
+ deleteValidWaveOutDevice();
+
+ for(UINT deviceId = 0; deviceId < waveOutGetNumDevs(); deviceId++)
+ {
+ if(deviceId == waveOutGetNumDevs())
+ return false;
+ if(waveOutOpen(&m_hWaveOut, WAVE_MAPPER, &m_waveFormatEx, (DWORD)WaveOutCallBack, 0, CALLBACK_FUNCTION) == MMSYSERR_NOERROR)
+ return m_hWaveOut; //m_hWaveOut !=0;
+ }
+ return false;
+ }
+
+ bool MediaObject::openWaveFile(QString fileName)
+ {
+ if (m_file)
+ delete m_file;
+ m_file = new QFile(fileName);
+ m_file->setParent(this);
+ m_stream = m_file;
+ m_mediaSize = m_file->size();
+ return (m_file->open(QIODevice::ReadOnly));
+ }
+
+ bool MediaObject::readHeader()
+ {
+ QByteArray header = m_stream->read(WAVEHEADER_SIZE);
+
+ if (header.size() == WAVEHEADER_SIZE) {
+
+ m_waveFormatEx.wFormatTag = *((WORD* )(header.data() + WAVEHEADER_OFFSET_FORMATTAG ));
+ m_waveFormatEx.nChannels = *((WORD* )(header.data() + WAVEHEADER_OFFSET_CHANNELS ));
+ m_waveFormatEx.nSamplesPerSec = *((DWORD*)(header.data() + WAVEHEADER_OFFSET_SAMPLESPERSEC ));
+ m_waveFormatEx.nAvgBytesPerSec = *((DWORD*)(header.data() + WAVEHEADER_OFFSET_AVGBYTESPERSEC));
+ m_waveFormatEx.nBlockAlign = *((WORD* )(header.data() + WAVEHEADER_OFFSET_BLOCKALIGN ));
+ m_waveFormatEx.wBitsPerSample = *((WORD* )(header.data() + WAVEHEADER_OFFSET_BITSPERSAMPLE ));
+
+ m_tickIntervalResolution = (qint64(buffer_size) * 8 * 1000) / m_waveFormatEx.nSamplesPerSec / m_waveFormatEx.wBitsPerSample / m_waveFormatEx.nChannels;
+ if (m_mediaSize > 0)
+ m_totalTime = ((m_mediaSize - WAVEHEADER_SIZE) * 8 * 1000) / m_waveFormatEx.nSamplesPerSec / m_waveFormatEx.wBitsPerSample / m_waveFormatEx.nChannels;
+ else
+ m_totalTime = -1;
+ emit totalTimeChanged(m_totalTime);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool MediaObject::fillBuffers()
+ {
+
+ m_soundBuffer1.data = m_stream->read(buffer_size);
+ m_soundBuffer2.data = m_stream->read(buffer_size);
+
+ m_bufferingFinished = true;
+
+ if (!(m_soundBuffer1.data.size() > 0))
+ setError(Phonon::NormalError, QLatin1String("cannot read source"));
+ return true;
+ }
+
+ void MediaObject::setState(Phonon::State newState)
+ {
+ if (m_state == newState)
+ return;
+ emit stateChanged(newState, m_state);
+ m_state = newState;
+ }
+
+ void MediaObject::setError(ErrorType errorType, QString errorMessage)
+ {
+ m_errorType = errorType;
+ setState(Phonon::ErrorState);
+ m_errorString = errorMessage;
+ }
+
+ void MediaObject::setAudioOutput(QObject *audioOutput)
+ {
+ m_audioOutput = qobject_cast<AudioOutput*>(audioOutput);
+
+ if (m_audioOutput) {
+ m_volume = m_audioOutput->volume();
+ connect(m_audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(setVolume(qreal)));
+ }
+ }
+
+ void MediaObject::setVolume(qreal newVolume)
+ {
+ m_volume = newVolume;
+ }
+
+ void MediaObject::swapBuffers()
+ {
+ if (m_stopped || m_paused)
+ return;
+
+ m_currentTime += m_tickIntervalResolution;
+ if (m_tickInterval) {
+ m_tick ++;
+ if (m_tick > (m_tickInterval - 1)) {
+ emit tick(m_currentTime);
+ m_tick = 0;
+ }
+ }
+ if ((m_prefinishMark > 0)&& (m_prefinishMark < m_currentTime))
+ emit prefinishMarkReached(m_totalTime - m_currentTime);
+
+ while (!m_bufferingFinished) {
+ setState(Phonon::BufferingState);
+ qWarning() << QLatin1String("buffer underun");
+ Sleep(20);
+ }
+
+ setState(Phonon::PlayingState);
+
+ //if size == o then stop...
+ if (m_nextBufferIndex) {
+ int size = m_soundBuffer1.waveHeader->dwBufferLength = m_soundBuffer1.data.size();
+ if (size == buffer_size) {
+ playBuffer(m_soundBuffer1.waveHeader);
+ emit outOfData(m_stream, &m_soundBuffer1.data, &m_bufferingFinished);
+ } else {
+ playBuffer(m_soundBuffer1.waveHeader);
+ m_stopped = true;
+ setState(Phonon::StoppedState);
+ emit finished();
+ seek(0);
+ }
+ } else {
+ int size = m_soundBuffer2.waveHeader->dwBufferLength = m_soundBuffer2.data.size();
+ if (size == buffer_size) {
+ playBuffer(m_soundBuffer2.waveHeader);
+ emit outOfData(m_stream, &m_soundBuffer2.data, &m_bufferingFinished);
+ } else {
+ playBuffer(m_soundBuffer2.waveHeader);
+ m_stopped = true;
+ setState(Phonon::StoppedState);
+ emit finished();
+ seek(0);
+ }
+ }
+ m_nextBufferIndex =! m_nextBufferIndex;
+ }
+
+
+ void MediaObject::playBuffer(WAVEHDR *waveHeader)
+ {
+ DWORD err = waveOutWrite(m_hWaveOut, waveHeader, sizeof(WAVEHDR));
+ if (!err == MMSYSERR_NOERROR) {
+ setError(Phonon::FatalError, QLatin1String("cannot play sound buffer (system) ") + getErrorText(err));
+ m_stopped = true;
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "mediaobject.moc"
diff --git a/src/3rdparty/phonon/waveout/mediaobject.h b/src/3rdparty/phonon/waveout/mediaobject.h
new file mode 100644
index 0000000..bb1410a
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/mediaobject.h
@@ -0,0 +1,162 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_MEDIAOBJECT_H
+#define PHONON_MEDIAOBJECT_H
+
+#include <phonon/mediaobjectinterface.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QObject>
+#include <QtCore/QQueue>
+#include <QtCore/QBasicTimer>
+#include <QtCore/QWaitCondition>
+#include <QtCore/QMutex>
+#include <QtCore/QThread>
+#include <QFile>
+#include <QIODevice>
+
+#include <windows.h>
+
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ class MediaSource;
+
+ namespace WaveOut
+ {
+ class WorkerThread;
+ class AudioOutput;
+
+ class MediaObject : public QObject, public Phonon::MediaObjectInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::MediaObjectInterface)
+
+ public:
+ MediaObject(QObject *parent);
+ ~MediaObject();
+ Phonon::State state() const;
+ bool hasVideo() const;
+ bool isSeekable() const;
+ qint64 currentTime() const;
+ qint32 tickInterval() const;
+
+ void setTickInterval(qint32 newTickInterval);
+ void play();
+ void pause();
+ void stop();
+ void seek(qint64 time);
+
+ QString errorString() const;
+ Phonon::ErrorType errorType() const;
+ qint64 totalTime() const;
+ qint32 prefinishMark() const;
+ void setPrefinishMark(qint32 newPrefinishMark);
+ qint32 transitionTime() const;
+ void setTransitionTime(qint32);
+ qint64 remainingTime() const;
+ MediaSource source() const;
+ void setSource(const MediaSource &source);
+ void setNextSource(const MediaSource &source);
+
+
+ Q_SIGNALS:
+ void stateChanged(Phonon::State newstate, Phonon::State oldstate);
+ void tick(qint64 time);
+ void metaDataChanged(QMultiMap<QString, QString>);
+ void seekableChanged(bool);
+ void hasVideoChanged(bool);
+ void bufferStatus(int);
+ void finished();
+ void prefinishMarkReached(qint32);
+ void aboutToFinish();
+ void totalTimeChanged(qint64 length) const;
+ void currentSourceChanged(const MediaSource &);
+ void outOfData(QIODevice *ioStream, QByteArray *buffer, bool *m_bufferingFinshed);
+
+ protected:
+ void setAudioOutput(QObject *audioOutput);
+
+ private Q_SLOTS:
+ void setVolume(qreal newVolume);
+
+ private:
+ bool m_nextBufferIndex;
+ bool prepareBuffers();
+ void unPrepareBuffers();
+ bool getWaveOutDevice();
+ bool openWaveFile(QString fileName);
+ bool readHeader();
+ bool boolUpdateBuffer();
+ bool fillBuffers();
+ void swapBuffers();
+ void setState(Phonon::State newState);
+ void setError(ErrorType errorType, QString errorMessage);
+ void deleteValidWaveOutDevice();
+ void playBuffer(WAVEHDR *waveHeader);
+
+ static void QT_WIN_CALLBACK WaveOutCallBack(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
+
+ struct {
+ WAVEHDR *waveHeader;
+ QByteArray data;
+ } m_soundBuffer1, m_soundBuffer2;
+
+ WAVEFORMATEX m_waveFormatEx;
+ HWAVEOUT m_hWaveOut;
+
+ QFile *m_file;
+ QIODevice *m_stream;
+ QString m_errorString;
+
+ WorkerThread *m_thread;
+
+ MediaSource m_source;
+ MediaSource m_nextSource;
+ AudioOutput *m_audioOutput;
+ ErrorType m_errorType;
+
+ qreal m_volume;
+ qint64 m_mediaSize;
+ qint64 m_totalTime;
+ qint64 m_currentTime;
+ qint64 m_transitionTime;
+ qint64 m_prefinishMark;
+ qint64 m_tickIntervalResolution;
+ qint32 m_tickInterval;
+ qint32 m_tick;
+ Phonon::State m_state;
+
+ bool m_bufferingFinished;
+ bool m_paused;
+ bool m_stopped;
+ bool m_hasNextSource;
+ bool m_hasSource;
+ bool m_sourceIsValid;
+ bool m_bufferPrepared;
+
+ friend class Backend;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // PHONON_MEDIAOBJECT_H