Switch to side-by-side view

--- a/upqo/avtransport_qo.h
+++ b/upqo/avtransport_qo.h
@@ -1,18 +1,18 @@
 /* Copyright (C) 2014 J.F.Dockes
- *	 This program is free software; you can redistribute it and/or modify
- *	 it under the terms of the GNU General Public License as published by
- *	 the Free Software Foundation; either version 2 of the License, or
- *	 (at your option) any later version.
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
  *
- *	 This program 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 General Public License for more details.
+ *   This program 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 General Public License for more details.
  *
- *	 You should have received a copy of the GNU General Public License
- *	 along with this program; if not, write to the
- *	 Free Software Foundation, Inc.,
- *	 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the
+ *   Free Software Foundation, Inc.,
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 #ifndef _AVTRANSPORT_QO_INCLUDED
 #define _AVTRANSPORT_QO_INCLUDED
@@ -35,7 +35,7 @@
 };
 
 class AVTransportQO : public QObject, public UPnPClient::VarEventReporter {
-Q_OBJECT
+    Q_OBJECT;
 
 public:
     AVTransportQO(UPnPClient::AVTH avt, QObject *parent = 0)
@@ -43,36 +43,51 @@
           m_cursecs(-1),
           m_sent_end_of_track_sig(false),
           m_in_ending(false),
-          m_tpstate(AVTransport::Unknown)
-    {
+          m_tpstate(AVTransport::Unknown) {
+
         m_timer = new QTimer(this);
         connect(m_timer, SIGNAL(timeout()), this, SLOT(update()));
         m_timer->start(1000);
-        qRegisterMetaType<UPnPClient::UPnPDirObject>("UPnPClient::UPnPDirObject");
+
+        qRegisterMetaType<UPnPClient::UPnPDirObject>
+            ("UPnPClient::UPnPDirObject");
+
         m_srv->installReporter(this);
-        // We are handling the playlist: set the renderer in "normal" mode.
+
+        // We are handling the playlist: set the renderer in "normal"
+        // mode. Actually, I don't think that this is relevant at all,
+        // we never consider that the renderer may have an internal
+        // playlist.
         m_srv->setPlayMode(UPnPClient::AVTransport::PM_Normal);
     }
+
     virtual ~AVTransportQO() {
         m_srv->installReporter(0);
     }
 
     const char *tpstatetostr(int tps) {
-        switch(tps) {
+        switch (tps) {
         default:
-        case UPnPClient::AVTransport::Unknown: return "Unknown";
-        case UPnPClient::AVTransport::Stopped: return "Stopped";
-        case UPnPClient::AVTransport::Playing: return "Playing";
-        case UPnPClient::AVTransport::Transitioning: return "Transitionning";
-        case UPnPClient::AVTransport::PausedPlayback: return "PausedPlay";
-        case UPnPClient::AVTransport::PausedRecording: return "PausedRecord";
-        case UPnPClient::AVTransport::Recording: return "Recording";
-        case UPnPClient::AVTransport::NoMediaPresent: return "No Media";
-        }
-    }
-
-    virtual void changed(const char *nm, int value)
-    {
+        case UPnPClient::AVTransport::Unknown:
+            return "Unknown";
+        case UPnPClient::AVTransport::Stopped:
+            return "Stopped";
+        case UPnPClient::AVTransport::Playing:
+            return "Playing";
+        case UPnPClient::AVTransport::Transitioning:
+            return "Transitionning";
+        case UPnPClient::AVTransport::PausedPlayback:
+            return "PausedPlay";
+        case UPnPClient::AVTransport::PausedRecording:
+            return "PausedRecord";
+        case UPnPClient::AVTransport::Recording:
+            return "Recording";
+        case UPnPClient::AVTransport::NoMediaPresent:
+            return "No Media";
+        }
+    }
+
+    virtual void changed(const char *nm, int value) {
         if (!strcmp(nm, "CurrentTrackDuration")) {
             // This is normally part of LastChange? but some renderers
             // apparently don't send it (bubble?). So use the value
@@ -83,9 +98,11 @@
             //qDebug() << "AVT: Changed: " << nm << " " << tpstatetostr(value);
             m_tpstate = AVTransport::TransportState(value);
             emit tpStateChanged(value);
-            if (value == UPnPClient::AVTransport::Stopped && m_in_ending) {
+            if (m_in_ending &&
+                (value == UPnPClient::AVTransport::Stopped ||
+                 value == UPnPClient::AVTransport::NoMediaPresent)) {
                 m_in_ending = false;
-                // qDebug() << "AVT: stoppedAtEOT";
+                qDebug() << "AVT EVT: emitting stoppedAtEOT";
                 emit stoppedAtEOT();
             }
         } else if (!strcmp(nm, "CurrentTransportActions")) {
@@ -111,8 +128,9 @@
         //qDebug() << "AVT: Changed: " << nm << " (char*): " << value;
         if (!strcmp(nm, "AVTransportURI")) {
             if (m_cururi.compare(value) &&
-                (m_tpstate == UPnPClient::AVTransport::Playing ||
-                 m_tpstate == UPnPClient::AVTransport::PausedPlayback) ) {
+                    (m_tpstate == UPnPClient::AVTransport::Playing ||
+                     m_tpstate == UPnPClient::AVTransport::Transitioning ||
+                     m_tpstate == UPnPClient::AVTransport::PausedPlayback)) {
                 //qDebug() << "AVT: ext track change: cur [" << m_cururi.c_str()
                 //         << "] new [" << value << "]";
                 setcururi(value);
@@ -123,8 +141,8 @@
 
     virtual void changed(const char *nm, UPnPClient::UPnPDirObject meta) {
         if (!strcmp(nm, "AVTransportURIMetaData")) {
-            qDebug() << "AVT: Changed: " << nm << " (dirc): " << 
-                meta.dump().c_str();
+            qDebug() << "AVT: Changed: " << nm << " (dirc): " <<
+                     meta.dump().c_str();
             // Don't use this if no resources are set. XBMC/Kodi does
             // this for some reason. Else we'd end-up with
             // resource-less unplayable entries in the
@@ -134,8 +152,8 @@
             // explicitely told to switch tracks (not even at regular
             // track changes).
             if (!meta.m_resources.empty() &&
-                (m_tpstate == UPnPClient::AVTransport::Playing ||
-                 m_tpstate == UPnPClient::AVTransport::PausedPlayback) ) {
+                    (m_tpstate == UPnPClient::AVTransport::Playing ||
+                     m_tpstate == UPnPClient::AVTransport::PausedPlayback)) {
                 emit currentMetadata(meta);
             }
         }
@@ -163,7 +181,8 @@
         // setcururi(uri);
     }
 
-    virtual void prepareNextTrack(const std::string& uri,const AVTMetadata* md){
+    virtual void prepareNextTrack(const std::string& uri,
+                                  const AVTMetadata* md) {
         qDebug() << "AVT:prepareNextTrack: " << uri.c_str();
         m_srv->setNextAVTransportURI(uri, md->getDidl());
     }
@@ -190,58 +209,73 @@
             return;
         }
         m_errcnt = 0;
-        //qDebug() << "AVT: update: posinfo: reltime " << info.reltime << 
-        //    " tdur " << info.trackduration << " meta " << 
-        //    info.trackmeta.dump().c_str();
-        emit secsInSongChanged(info.reltime);
         m_cursecs = info.trackduration;
-        if (m_cursecs > 0) {
-            if (info.reltime > m_cursecs - 10) {
-                if (!m_sent_end_of_track_sig) {
-                    qDebug() << "Emitting prepare for end";
-                    emit endOfTrackIsNear();
-                    m_sent_end_of_track_sig = true;
-                }
-                m_in_ending = true;
-            } else if (info.reltime > 0 && info.reltime < 5) {
-                // This is for the case where we are playing 2
-                // consecutive identical URIs: heuristic try to detect
-                // the change
-                if (m_in_ending == true) {
-                    qDebug() << "Was in end, seeing start: trackswitch";
-                    setcururi(info.trackuri);
-                    emit newTrackPlaying(u8s2qs(info.trackuri));
-                }
-            }
-        }
+
         UPnPClient::AVTransport::TransportInfo tinfo;
         if ((error = m_srv->getTransportInfo(tinfo)) != 0) {
             qDebug() << "getTransportInfo failed with error " << error;
             return;
         }
+
+        //qDebug() << "AVT: update: posinfo: reltime " << info.reltime <<
+        //    " tdur " << info.trackduration << " meta " <<
+        //    info.trackmeta.dump().c_str();
+
+        if (m_tpstate == UPnPClient::AVTransport::Playing) {
+            // Time-related stuff
+            emit secsInSongChanged(info.reltime);
+            if (m_cursecs > 0) {
+                if (info.reltime > m_cursecs - 10) {
+                    if (!m_sent_end_of_track_sig) {
+                        qDebug() << "AVT: Emitting endOfTrackIsNear()";
+                        emit endOfTrackIsNear();
+                        m_sent_end_of_track_sig = true;
+                    }
+                    m_in_ending = true;
+                } else if (info.reltime > 0 && info.reltime < 5) {
+                    // This is for the case where we are playing 2
+                    // consecutive identical URIs: heuristic try to detect
+                    // the change
+                    if (m_in_ending == true) {
+                        qDebug() << "AVT: was in end, seeing start: trkswitch";
+                        setcururi(info.trackuri);
+                        emit newTrackPlaying(u8s2qs(info.trackuri));
+                    }
+                }
+            }
+        }
+        
         if (force || tinfo.tpstate != m_tpstate) {
+            qDebug() << "AVT: emitting tpStateChanged:" <<
+                tpstatetostr(tinfo.tpstate);
             emit tpStateChanged(tinfo.tpstate);
             m_tpstate = tinfo.tpstate;
         }
         if (force || (m_cururi.compare(info.trackuri) &&
-            (m_tpstate == UPnPClient::AVTransport::Playing ||
-             m_tpstate == UPnPClient::AVTransport::PausedPlayback)) ) {
-            qDebug() << "AVT: update: ext track change: cur [" << 
-                m_cururi.c_str() << "] new [" <<                     
-                info.trackuri.c_str() << "]";
+                      (m_tpstate == UPnPClient::AVTransport::Playing ||
+                       m_tpstate == UPnPClient::AVTransport::Transitioning ||
+                       m_tpstate == UPnPClient::AVTransport::PausedPlayback))) {
+            qDebug() << "AVT: update: ext track change: cur [" <<
+                     m_cururi.c_str() << "] new [" <<
+                     info.trackuri.c_str() << "]";
             setcururi(info.trackuri);
             if (!info.trackmeta.m_resources.empty()) {
                 // Don't emit bogus meta which would unplayable
                 // entries in the playlist. The only moment when Kodi
                 // will emit usable metadata is when told to change
                 // tracks. MediaInfo returns the same data.
+                qDebug() << "AVT: emitting currentMetadata";
                 emit currentMetadata(info.trackmeta);
             }
+            qDebug() << "AVT: emitting newTrackPlaying:" <<
+                u8s2qs(info.trackuri);
             emit newTrackPlaying(u8s2qs(info.trackuri));
         }
-        if (tinfo.tpstate == UPnPClient::AVTransport::Stopped && m_in_ending) {
+        if (m_in_ending &&
+            (tinfo.tpstate == UPnPClient::AVTransport::Stopped ||
+             tinfo.tpstate == UPnPClient::AVTransport::NoMediaPresent)) {
             m_in_ending = false;
-            // qDebug() << "AVT: stoppedAtEOT";
+            qDebug() << "AVT: emitting stoppedAtEOT";
             emit stoppedAtEOT();
         }
     }