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"