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