/* 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);
}