Switch to side-by-side view

--- a
+++ b/sc2src/songcastreceiver.cpp
@@ -0,0 +1,197 @@
+/* Copyright (C) 2018 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 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.
+ */
+
+#include <unistd.h>
+
+#include "songcastreceiver.h"
+#include "log.h"
+
+using namespace std;
+
+SongcastReceiver::SongcastReceiver(AudioEater *eater, AudioEater::Context *ctxt)
+    : m_eater(eater), iConnected(false)
+{
+    audioqueue.start(1, m_eater->worker, ctxt);
+}
+
+SongcastReceiver::~SongcastReceiver()
+{
+    delete m_decoder;
+}
+
+void SongcastReceiver::Add(OhmMsg& aMsg)
+{
+    aMsg.Process(*this);
+    aMsg.RemoveRef();
+}
+
+void SongcastReceiver::Timestamp(OhmMsg& /*aMsg*/)
+{
+}
+
+void SongcastReceiver::Started()
+{
+    LOGDEB("=== STARTED ====\n");
+}
+
+void SongcastReceiver::Connected()
+{
+    m_obs.reset();
+    printf("CONNECTED\n");
+    fflush(stdout);
+    LOGDEB("=== CONNECTED ====\n");
+    iConnected = true;
+}
+
+void SongcastReceiver::Playing()
+{
+    LOGDEB("=== PLAYING ====\n");
+    iConnected = true;
+    if (m_eater->playing)
+        m_eater->playing();
+}
+
+void SongcastReceiver::Disconnected()
+{
+    LOGDEB("=== DISCONNECTED ====\n");
+    iConnected = false;
+}
+
+void SongcastReceiver::Stopped()
+{
+    LOGDEB("=== STOPPED ====\n");
+    if (m_eater->stopped)
+        m_eater->stopped();
+}
+
+TBool SongcastReceiver::IsConnected()
+{
+    return iConnected;
+}
+
+// Debug and stats only, not needed for main function
+void SongcastReceiver::Observer::process(OhmMsgAudio& aMsg)
+{
+    if (++iCount == 400 || aMsg.Halt()) {
+        LOGDEB("OhmRcvDrv::Process:audio: samplerate " << aMsg.SampleRate() <<
+               " bitdepth " << aMsg.BitDepth() << " channels " <<
+               aMsg.Channels() << " samples " << aMsg.Samples() << 
+               " Halted ? " << aMsg.Halt() << endl);
+
+#if 0
+        static unsigned long long last_timestamp;
+        unsigned long long timestamp = aMsg.MediaTimestamp();
+        if (last_timestamp) {
+            long long intervalus = 
+                ((timestamp - last_timestamp) * 1000000) / (256*48000);
+            long long atsus = 
+                ((timestamp) * 1000000) / (256*48000);
+
+            // Not too sure what this did. amicros not in chrono.cpp any more
+            long long absus = chron.amicros() - 1430477861905884LL;
+            LOGDEB("Computed-uS: " << intervalus  << 
+                   " Elapsed-uS: " << chron.urestart() << 
+                   " Timestamp-uS: " << atsus <<
+                   " Abs-uS: " << absus << 
+                   " Diff-mS " << (absus - atsus) / 1000 <<
+                   endl);
+        }
+        last_timestamp = timestamp;
+#endif
+
+        if (!aMsg.Halt() && aMsg.Codec() == Brn("PCM")) {
+            unsigned int bytes = 
+                aMsg.Samples() * (aMsg.BitDepth() / 8) * aMsg.Channels();
+
+            if (bytes != aMsg.Audio().Bytes()) {
+                LOGERR("OhmRcvDrv::Process:audio: computed bytes " << bytes << 
+                       " !=  buffer's " << aMsg.Audio().Bytes() << endl);
+                bytes = aMsg.Audio().Bytes();
+            }
+            const unsigned char *icp = 
+                (const unsigned char *)aMsg.Audio().Ptr();
+            bool silence = true;
+            for (unsigned int i = 0; i < bytes; i++) {
+                if (icp[i]) {
+                    silence = false;
+                    break;
+                }
+            }
+            if (silence) {
+                LOGDEB("OhmRcvDrv::Process:audio: silence buffer" << endl);
+            }
+            if (dumpfd >= 0) {
+                if (write(dumpfd, icp, bytes) != int(bytes)) {
+                    ;
+                }
+            }
+        }
+
+        iCount = 0;
+    }
+
+    if (iReset) {
+        iFrame = aMsg.Frame();
+        iReset = false;
+    } else {
+        if (aMsg.Frame() != iFrame + 1) {
+            LOGINF("Missed frames between " << iFrame << " and " << 
+                   aMsg.Frame() << endl);
+        }
+        iFrame = aMsg.Frame();
+    }
+}
+
+void SongcastReceiver::Process(OhmMsgAudio& aMsg)
+{
+    m_obs.process(aMsg);
+
+    if (m_decoder == nullptr) {
+        LOGDEB("SongcastReceiver: Create decoder " << aMsg.Codec().Ptr()
+                                                   << endl);
+        m_decoder = AudioDecoder::CreateAudioDecoder(
+                                            aMsg.Codec(),
+                                            needswap(m_eater->input_border));
+        m_decoder->start();
+    }
+
+    m_decoder->decode(aMsg);
+
+    if (aMsg.Halt()) {
+        LOGDEB("SongcastReceiver: Finish decoder " << aMsg.Codec().Ptr()
+                                                   << endl);
+        m_decoder->finish();
+        delete m_decoder;
+        m_decoder = nullptr;
+    }
+}
+
+void SongcastReceiver::Process(OhmMsgTrack& aMsg)
+{
+    Brhz uri(aMsg.Uri());
+    Brhz metadata(aMsg.Metadata());
+    LOGDEB("OhmRcvDrv::Process:trk: TRACK SEQ " << aMsg.Sequence() <<
+           " URI " << uri.CString() <<
+           " METADATA " << metadata.CString() << endl);
+}
+
+void SongcastReceiver::Process(OhmMsgMetatext& aMsg)
+{
+    Brhz metatext(aMsg.Metatext());
+    LOGDEB("OhmRcvDrv::Process:meta: METATEXT SEQUENCE " <<  aMsg.Sequence() <<
+           " METATEXT " << metatext.CString() << endl);
+}