--- 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);
+}