File indexing completed on 2024-05-05 04:44:40

0001 /*  This file is part of the KDE project
0002     Copyright (C) 2007-2008 Matthias Kretz <kretz@kde.org>
0003 
0004     This library is free software; you can redistribute it and/or
0005     modify it under the terms of the GNU Lesser General Public
0006     License as published by the Free Software Foundation; either
0007     version 2.1 of the License, or (at your option) version 3, or any
0008     later version accepted by the membership of KDE e.V. (or its
0009     successor approved by the membership of KDE e.V.), Nokia Corporation
0010     (or its successors, if any) and the KDE Free Qt Foundation, which shall
0011     act as a proxy defined in Section 6 of version 3 of the license.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Lesser General Public License for more details.
0017 
0018     You should have received a copy of the GNU Lesser General Public 
0019     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0020 
0021 */
0022 
0023 #include "abstractmediastream2.h"
0024 #include "abstractmediastream2_p.h"
0025 #include "mediaobjectinterface.h"
0026 #include "mediaobject_p.h"
0027 #include "phononnamespace_p.h"
0028 
0029 #include <QAbstractEventDispatcher>
0030 #include <QEvent>
0031 
0032 namespace Phonon
0033 {
0034 
0035 bool AbstractMediaStream2::event(QEvent *e)
0036 {
0037     if (e->type() == QEvent::ThreadChange) {
0038         Q_D(AbstractMediaStream2);
0039         if (d->eventDispatcher) {
0040             pWarning() << "Do not call moveToThread on an AbstractMediaStream2 object when it is in use.";
0041             QObject::disconnect(d->eventDispatcher, SIGNAL(awake()), this, SLOT(_k_handleStreamEvent()));
0042             d->eventDispatcher = 0;
0043         }
0044     }
0045     return AbstractMediaStream::event(e);
0046 }
0047 
0048 void AbstractMediaStream2Private::dataReady()
0049 {
0050     Q_Q(AbstractMediaStream2);
0051     if (!eventDispatcher) {
0052         eventDispatcher = QAbstractEventDispatcher::instance(q->thread());
0053         if (!eventDispatcher) {
0054             pError() << "AbstractMediaStream2 needs to run in a thread with QEventLoop";
0055             return;
0056         } else {
0057             QObject::connect(eventDispatcher, SIGNAL(awake()), q, SLOT(_k_handleStreamEvent()), Qt::DirectConnection);
0058         }
0059     }
0060     eventDispatcher->wakeUp();
0061 }
0062 
0063 void AbstractMediaStream2Private::_k_handleStreamEvent()
0064 {
0065     Q_ASSERT(streamEventQueue);
0066     Q_Q(AbstractMediaStream2);
0067     StreamEventQueue::Command c;
0068     while (streamEventQueue->nextCommandForFrontend(&c)) {
0069         switch (c.command) {
0070         case StreamEventQueue::SetStreamSize:
0071         case StreamEventQueue::SetSeekable:
0072         case StreamEventQueue::Write:
0073         case StreamEventQueue::EndOfData:
0074         case StreamEventQueue::SeekDone:
0075         case StreamEventQueue::ResetDone:
0076         case StreamEventQueue::ConnectDone:
0077             pFatal("AbstractMediaStream2 received wrong Command");
0078             break;
0079         case StreamEventQueue::NeedData:
0080             q->needData(qvariant_cast<quint32>(c.data));
0081             break;
0082         case StreamEventQueue::EnoughData:
0083             q->enoughData();
0084             break;
0085         case StreamEventQueue::Seek:
0086             q->seekStream(qvariant_cast<quint64>(c.data));
0087             break;
0088         case StreamEventQueue::Reset:
0089             q->reset();
0090             break;
0091         case StreamEventQueue::Connect:
0092             if (firstConnect) {
0093                 firstConnect = false;
0094                 streamEventQueue->sendToBackend(StreamEventQueue::ConnectDone);
0095                 streamEventQueue->sendToBackend(StreamEventQueue::SetSeekable, streamSeekable);
0096                 if (streamSize != 0) {
0097                     streamEventQueue->sendToBackend(StreamEventQueue::SetStreamSize, streamSize);
0098                 }
0099             } else {
0100                 ++connectReset;
0101                 q->reset();
0102             }
0103             break;
0104         }
0105     }
0106 }
0107 
0108 AbstractMediaStream2::AbstractMediaStream2(QObject *parent)
0109     : AbstractMediaStream(*new AbstractMediaStream2Private, parent)
0110 {
0111 }
0112 
0113 AbstractMediaStream2::AbstractMediaStream2(AbstractMediaStream2Private &dd, QObject *parent)
0114     : AbstractMediaStream(dd, parent)
0115 {
0116 }
0117 
0118 void AbstractMediaStream2Private::setStreamSize(qint64 newSize)
0119 {
0120     streamSize = newSize;
0121     streamEventQueue->sendToBackend(StreamEventQueue::SetStreamSize, newSize);
0122 }
0123 
0124 void AbstractMediaStream2Private::setStreamSeekable(bool s)
0125 {
0126     streamSeekable = s;
0127     streamEventQueue->sendToBackend(StreamEventQueue::SetSeekable, s);
0128 }
0129 
0130 void AbstractMediaStream2Private::writeData(const QByteArray &data)
0131 {
0132     streamEventQueue->sendToBackend(StreamEventQueue::Write, data);
0133 }
0134 
0135 void AbstractMediaStream2Private::endOfData()
0136 {
0137     streamEventQueue->sendToBackend(StreamEventQueue::EndOfData);
0138 }
0139 
0140 void AbstractMediaStream2::resetDone()
0141 {
0142     Q_D(AbstractMediaStream2);
0143     if (d->connectReset > 0) {
0144         --d->connectReset;
0145         d->streamEventQueue->sendToBackend(StreamEventQueue::ConnectDone);
0146     } else {
0147         d->streamEventQueue->sendToBackend(StreamEventQueue::ResetDone);
0148     }
0149     d->streamEventQueue->sendToBackend(StreamEventQueue::SetSeekable, d->streamSeekable);
0150     if (d->streamSize != 0) {
0151         d->streamEventQueue->sendToBackend(StreamEventQueue::SetStreamSize, d->streamSize);
0152     }
0153 }
0154 
0155 void AbstractMediaStream2::seekStreamDone()
0156 {
0157     d_func()->streamEventQueue->sendToBackend(StreamEventQueue::SeekDone);
0158 }
0159 
0160 AbstractMediaStream2Private::AbstractMediaStream2Private()
0161     : streamEventQueue(new StreamEventQueue),
0162     eventDispatcher(0),
0163     connectReset(0),
0164     firstConnect(true)
0165 {
0166     streamEventQueue->ref();
0167     streamEventQueue->setFrontendCommandHandler(this);
0168 }
0169 
0170 AbstractMediaStream2Private::~AbstractMediaStream2Private()
0171 {
0172     // setFrontendCommandHandler blocks internally until a handler that might be called right now is
0173     // done. That means AbstractMediaStream2Private::dataReady will either not run again or it will
0174     // be done before this object and our q object are deleted.
0175     streamEventQueue->setFrontendCommandHandler(0);
0176     streamEventQueue->deref();
0177     streamEventQueue = 0;
0178     // if eventDispatcher->wakeUp() was called and we are now still connected to its awake() signal
0179     // then the QObject will be deleted until execution reaches the event loop again and
0180     // _k_handleStreamEvent will not get called
0181 }
0182 
0183 } // namespace Phonon
0184 
0185 #include "moc_abstractmediastream2.cpp"
0186 
0187 // vim: sw=4 sts=4 et tw=100