File indexing completed on 2024-04-21 15:38:26

0001 /**
0002   This file belong to the KMPlayer project, a movie player plugin for Konqueror
0003   Copyright (C) 2007  Koos Vriezen <koos.vriezen@gmail.com>
0004 
0005   This library is free software; you can redistribute it and/or
0006   modify it under the terms of the GNU Lesser General Public
0007   License as published by the Free Software Foundation; either
0008   version 2 of the License, or (at your option) any later version.
0009 
0010   This library is distributed in the hope that it will be useful,
0011   but WITHOUT ANY WARRANTY; without even the implied warranty of
0012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013   Lesser General Public License for more details.
0014 
0015   You should have received a copy of the GNU Lesser General Public
0016   License along with this library; if not, write to the Free Software
0017   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0018 **/
0019 
0020 #include <sys/types.h>
0021 #include <unistd.h>
0022 
0023 #include "phononplayer.h"
0024 
0025 #include <QApplication>
0026 #include <QBoxLayout>
0027 #include <QtDBus/QtDBus>
0028 #include <QtCore/QMap>
0029 #include <QtCore/QTimer>
0030 #include <QtCore/QUrl>
0031 #include <QX11Info>
0032 
0033 #include <phonon/audiooutput.h>
0034 #include <phonon/mediaobject.h>
0035 #include <phonon/videoplayer.h>
0036 #include <phonon/videowidget.h>
0037 
0038 #include "slaveadaptor.h"
0039 #include "streamslaveadaptor.h"
0040 
0041 #include <xcb/xcb.h>
0042 
0043 static QString control_service;
0044 static QString control_path;
0045 static Slave *slave;
0046 typedef QMap <uint64_t, Stream *> SlaveMap;
0047 static SlaveMap slave_map;
0048 
0049 Slave::Slave () : stay_alive_timer (0) {
0050     QString service = QString ("org.kde.kphononplayer-%1").arg (getpid ());
0051     (void) new SlaveAdaptor (this);
0052     QDBusConnection::sessionBus().registerObject ("/phonon", this);
0053     if (QDBusConnection::sessionBus().interface()->registerService (service) ==
0054             QDBusConnectionInterface::ServiceNotRegistered) {
0055         qDebug ("%s", qPrintable(QDBusConnection::sessionBus().lastError().message()));
0056         service = QDBusConnection::sessionBus().baseService ();
0057     }
0058     qDebug ("register as %s", qPrintable (service));
0059     if (!control_service.isEmpty ()) {
0060         QDBusMessage msg = QDBusMessage::createMethodCall (
0061                 control_service, control_path, "org.kde.kmplayer.Master",
0062                 "running");
0063         msg << service;
0064         QDBusConnection::sessionBus().send (msg);
0065     }
0066 }
0067 
0068 void Slave::newStream (const QString &url, uint64_t wid) {
0069     if (stay_alive_timer) {
0070         killTimer (stay_alive_timer);
0071         stay_alive_timer = 0;
0072     }
0073     slave_map.insert (wid, new Stream (NULL, url, wid));
0074 }
0075 
0076 void Slave::quit () {
0077     qDebug ("quit");
0078     qApp->quit ();
0079 }
0080 
0081 void Slave::streamDestroyed (uint64_t wid) {
0082     slave_map.remove (wid);
0083     if (!slave_map.size ())
0084         stay_alive_timer = startTimer (5000);
0085 }
0086 
0087 void Slave::timerEvent (QTimerEvent *) {
0088     quit ();
0089 }
0090 
0091 Stream::Stream (QWidget *parent, const QString &url, unsigned long wid)
0092     : QX11EmbedWidget (parent), m_url (url), video_handle (wid)
0093     //: QWidget (parent), video_handle (wid)
0094 {
0095     setAttribute(Qt::WA_NativeWindow);
0096     setAttribute(Qt::WA_DontCreateNativeAncestors);
0097     createWinId();
0098     xcb_reparent_window(QX11Info::connection(), winId(), wid, 0, 0);
0099     //embedInto (wid);
0100     show ();
0101     m_master_stream_path = QString ("%1/stream_%2").arg(control_path).arg (wid);
0102     QTimer::singleShot (0, this, SLOT (init ()));
0103     qDebug ("newStream xembed cont: %lu", wid);
0104 }
0105 
0106 void Stream::init () {
0107     (void) new StreamSlaveAdaptor (this);
0108     QDBusConnection::sessionBus().registerObject (
0109             QString ("/stream_%1").arg (video_handle), this);
0110 
0111     m_media = new Phonon::MediaObject(this);
0112     // might need VideoCategory here
0113     m_aoutput = new Phonon::AudioOutput (Phonon::MusicCategory, this);
0114     m_vwidget = new Phonon::VideoWidget(this);
0115     Phonon::createPath (m_media, m_aoutput);
0116     Phonon::createPath (m_media, m_vwidget);
0117 
0118     QVBoxLayout *layout = new QVBoxLayout(this);
0119     layout->setContentsMargins (0, 0, 0, 0);
0120     layout->addWidget(m_vwidget);
0121     m_vwidget->hide();
0122 
0123     connect(m_media,SIGNAL(hasVideoChanged(bool)), SLOT(hasVideoChanged(bool)));
0124     connect (m_media, SIGNAL (bufferStatus (int)), SLOT (bufferStatus (int)));
0125     connect (m_media, SIGNAL (metaDataChanged ()), SLOT (metaDataChanged ()));
0126     connect (m_media, SIGNAL (tick (qint64)), SLOT (tick (qint64)));
0127     connect (m_media, SIGNAL (stateChanged(Phonon::State, Phonon::State)),
0128             SLOT (stateChanged (Phonon::State, Phonon::State)));
0129     connect (m_media, SIGNAL (finished ()), SLOT (finished ()));
0130 
0131     if (m_url.startsWith ("dvd:"))
0132         m_media->setCurrentSource (Phonon::Dvd);
0133     else if (m_url.startsWith ("vcd:"))
0134         m_media->setCurrentSource (Phonon::Vcd);
0135     else if (m_url.startsWith ("cdda:"))
0136         m_media->setCurrentSource (Phonon::Cd);
0137     else if (m_url.startsWith ("/"))
0138         m_media->setCurrentSource (m_url);
0139     else
0140         m_media->setCurrentSource (QUrl (m_url));
0141     play ();
0142 }
0143 
0144 Stream::~Stream () {
0145     delete m_media;
0146     slave->streamDestroyed (video_handle);
0147 }
0148 
0149 /*bool Stream::x11Event (XEvent *event) {
0150     switch (event->type) {
0151         case PropertyNotify:
0152             return QWidget::x11Event (event);
0153     }
0154     return QX11EmbedWidget::x11Event (event);
0155 }*/
0156 
0157 void Stream::play () {
0158     qDebug ("play %s@%lu", qPrintable (m_url), video_handle);
0159     m_media->setTickInterval (500);
0160     m_media->play ();
0161     m_vwidget->setVisible (m_media->hasVideo ());
0162 }
0163 
0164 void Stream::pause () {
0165     if (m_media->state () == Phonon::PausedState)
0166         m_media->play ();
0167     else
0168         m_media->pause ();
0169 }
0170 
0171 void Stream::stop () {
0172     qDebug() << "stop" << video_handle;
0173     m_media->stop ();
0174     delete this;
0175 }
0176 
0177 void Stream::seek (uint64_t position, bool /*absolute*/) {
0178     m_media->seek (position * 100);
0179 }
0180 
0181 void Stream::volume (int value) {
0182     m_aoutput->setVolume (1.0 * value / 100);
0183 }
0184 
0185 void Stream::hasVideoChanged (bool hasVideo) {
0186     qDebug ("hasVideoChanged %d", hasVideo);
0187     m_vwidget->setVisible (hasVideo);
0188 }
0189 
0190 void Stream::bufferStatus (int percent_filled) {
0191     QDBusMessage msg = QDBusMessage::createMethodCall (
0192             control_service, m_master_stream_path,
0193             "org.kde.kmplayer.StreamMaster", "loading");
0194     msg << percent_filled;
0195     QDBusConnection::sessionBus().send (msg);
0196 }
0197 
0198 void Stream::metaDataChanged () {
0199     QString info;
0200 
0201     QString artist = m_media->metaData (Phonon::ArtistMetaData).join (" ");
0202     QString title = m_media->metaData (Phonon::TitleMetaData).join (" ");
0203     QString desc = m_media->metaData (Phonon::DescriptionMetaData).join (" ");
0204     qDebug ("metadata artist:%s title:%s desc:%s",
0205             artist.toUtf8 ().data (), title.toUtf8 ().data (), desc.toUtf8 ().data ());
0206     if (!title.isEmpty ()) {
0207         if (artist.isEmpty ())
0208             info = QString ("<b>") + title + QString ("</b>");
0209         else
0210             info = QString ("<b>") + artist + QString( " - " ) + title + QString ("</b>");
0211     }
0212     if (!desc.isEmpty ()) {
0213         if (!info.isEmpty ())
0214             info += QString ("<hr>");
0215         info += QString ("<i>") + desc + QString ("</i>");
0216     }
0217 
0218     QDBusMessage msg = QDBusMessage::createMethodCall (
0219             control_service, m_master_stream_path,
0220             "org.kde.kmplayer.StreamMaster", "streamMetaInfo");
0221     msg << info;
0222     QDBusConnection::sessionBus().send (msg);
0223 }
0224 
0225 void Stream::tick (qint64 t) {
0226     QDBusMessage msg = QDBusMessage::createMethodCall (
0227             control_service, m_master_stream_path,
0228             "org.kde.kmplayer.StreamMaster", "progress");
0229     msg << (qulonglong) t/100;
0230     QDBusConnection::sessionBus().send (msg);
0231 }
0232 
0233 void Stream::stateChanged (Phonon::State newstate, Phonon::State) {
0234     if (Phonon::PlayingState == newstate) {
0235         qDebug() << "playing" << video_handle << "len:" << m_media->totalTime();
0236         QDBusMessage msg = QDBusMessage::createMethodCall (
0237                 control_service, m_master_stream_path,
0238                 "org.kde.kmplayer.StreamMaster", "streamInfo");
0239         msg << (qulonglong) m_media->totalTime()/100 << (double)0.0; //FIXME:
0240         QDBusConnection::sessionBus().send (msg);
0241 
0242         QDBusMessage msg2 = QDBusMessage::createMethodCall (
0243                 control_service, m_master_stream_path,
0244                 "org.kde.kmplayer.StreamMaster", "playing");
0245         QDBusConnection::sessionBus().send (msg2);
0246     }
0247 }
0248 
0249 void Stream::finished () {
0250     qDebug ("finished %lu", video_handle);
0251     QDBusMessage msg = QDBusMessage::createMethodCall (
0252             control_service, m_master_stream_path,
0253             "org.kde.kmplayer.StreamMaster", "eof");
0254     QDBusConnection::sessionBus().send (msg);
0255     delete this;
0256 }
0257 
0258 int main (int argc, char **argv) {
0259     QString url;
0260     QApplication app (argc, argv);
0261     QApplication::setApplicationName ("Phonon Slave");
0262     for (int i = 1; i < argc; i++) {
0263         if (!strcmp (argv[i], "-cb") && ++i < argc) {
0264             QString s (argv[i]);
0265             int p = s.indexOf (QChar ('/'));
0266             if (p > -1) {
0267                 control_service = s.left (p);
0268                 control_path = s.mid (p);
0269             }
0270         } else {
0271             url = argv[i];
0272         }
0273     }
0274     slave = new Slave;
0275     if (!url.isEmpty ()) {
0276         new Stream (NULL, url, 0);
0277         //mw.show ();
0278         //mw.play ();
0279     }
0280     return app.exec ();
0281 }
0282 
0283 #include "phononplayer.moc"