--- a/sc2src/sc2mpd.cpp
+++ b/sc2src/sc2mpd.cpp
@@ -40,6 +40,11 @@
#include "log.h"
#include "conftree.h"
#include "chrono.h"
+
+#ifdef WITH_WAVSC2
+#include "openaudio.h"
+#include "audioreader.h"
+#endif
#include <vector>
#include <stdio.h>
@@ -356,6 +361,83 @@
" METATEXT " << metatext.CString() << endl);
}
+#ifdef WITH_WAVSC2
+static int playWav(const string& wavfile, AudioEater *eater,
+ AudioEater::Context *ctxt)
+{
+ audioqueue.start(1, eater->worker, ctxt);
+
+ AudioReader *audio = openAudio(wavfile, "", true);
+
+ if (!audio || !audio->open() || audio->bytesPerSample() == 0 ||
+ audio->numChannels() == 0) {
+ cerr << "Audio file open failed" << endl;
+ return 1;
+ }
+ LOGDEB("sample rate: " << audio->sampleRate() << endl);
+ LOGDEB("sample size: " << audio->bytesPerSample() << endl);
+ LOGDEB("channels: " << audio->numChannels() << endl);
+
+ size_t packetBytes = 441 * 16 *2;
+ while (true) {
+ const unsigned char *ibuf = audio->data(packetBytes);
+ if (ibuf == 0) {
+ return 1;
+ }
+ // We allocate a bit more space to avoir reallocations in the resampler
+ unsigned int allocbytes = packetBytes + 100;
+ char *buf = (char *)malloc(allocbytes);
+ if (buf == 0) {
+ LOGERR("playWav: can't allocate " << allocbytes << " bytes\n");
+ return 1;
+ }
+
+ // Songcast data is always msb-first. Convert to desired order:
+ // depends on what downstream wants, and just as well we do it
+ // here because we copy the buf anyway.
+ bool needswap = false;
+ switch (eater->input_border) {
+ case AudioEater::BO_MSB:
+ break;
+ case AudioEater::BO_LSB:
+ needswap = true;
+ break;
+ case AudioEater::BO_HOST:
+#ifdef WORDS_BIGENDIAN
+ needswap = false;
+#else
+ needswap = true;
+#endif
+ break;
+ }
+
+ int bitDepth = 8 * audio->bytesPerSample();
+ if (needswap) {
+ copyswap((unsigned char *)buf, ibuf, packetBytes, bitDepth);
+ } else {
+ memcpy(buf, ibuf, packetBytes);
+ }
+
+ // The constructor wants the number of frames as input (frame
+ // being all samples at given timepoint, typically 2 for
+ // stereo)
+ int frames = packetBytes /
+ (audio->bytesPerSample() * audio->numChannels());
+ AudioMessage *ap = new
+ AudioMessage(bitDepth, audio->numChannels(), frames,
+ audio->sampleRate(), buf, allocbytes);
+
+ // There is nothing special we can do if put fails: no way to
+ // return status. Should we just exit ?
+ if (!audioqueue.put(ap, false)) {
+ LOGERR("sc2mpd: queue dead: exiting\n");
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
int CDECL main(int aArgc, char* aArgv[])
{
string logfilename;
@@ -386,22 +468,15 @@
"http stream");
parser.AddOption(&optionDevice);
+#ifdef WITH_WAVSC2
+ OptionString optionWav("-w", "--wav", Brn(""),
+ "Test audio with wav file instead of sender");
+ parser.AddOption(&optionWav);
+#endif
+
if (!parser.Parse(aArgc, aArgv)) {
return (1);
}
-
- InitialisationParams* initParams = InitialisationParams::Create();
-
- Library* lib = new Library(initParams);
-
- std::vector<NetworkAdapter*>* subnetList = lib->CreateSubnetList();
- TIpAddress subnet = (*subnetList)[optionAdapter.Value()]->Subnet();
- TIpAddress adapter = (*subnetList)[optionAdapter.Value()]->Address();
- Library::DestroySubnetList(subnetList);
-
-
- TUint ttl = optionTtl.Value();
- Brhz uri(optionUri.Value());
string uconfigfile = (const char *)optionConfig.Value().Ptr();
@@ -427,12 +502,37 @@
}
Logger::getTheLog("")->setLogLevel(Logger::LogLevel(loglevel));
+ AudioEater::Context *ctxt = new AudioEater::Context(&audioqueue);
+ ctxt->config = &config;
+
+#ifdef WITH_WAVSC2
+ string wavname(Brhz(optionWav.Value()).CString());
+ if (!wavname.empty()) {
+ string value;
+ if (!config.get("sccvttype", value) ||
+ value.compare("NONE")) {
+ cerr << "Wav input play test. NEEDS sccvttype == NONE\n";
+ return 1;
+ }
+ return playWav(wavname, &alsaAudioEater, ctxt);
+ }
+#endif
+
+ InitialisationParams* initParams = InitialisationParams::Create();
+
+ Library* lib = new Library(initParams);
+
+ std::vector<NetworkAdapter*>* subnetList = lib->CreateSubnetList();
+ TIpAddress subnet = (*subnetList)[optionAdapter.Value()]->Subnet();
+ TIpAddress adapter = (*subnetList)[optionAdapter.Value()]->Address();
+ Library::DestroySubnetList(subnetList);
+
+ TUint ttl = optionTtl.Value();
+ Brhz uri(optionUri.Value());
+
LOGINF("scmpdcli: using subnet " << (subnet & 0xff) << "." <<
((subnet >> 8) & 0xff) << "." << ((subnet >> 16) & 0xff) << "." <<
((subnet >> 24) & 0xff) << endl);
-
- AudioEater::Context *ctxt = new AudioEater::Context(&audioqueue);
- ctxt->config = &config;
OhmReceiverDriver* driver =
new OhmReceiverDriver(optionDevice.Value() ?