|
a/sc2src/sc2mpd.cpp |
|
b/sc2src/sc2mpd.cpp |
|
... |
|
... |
38 |
#include "workqueue.h"
|
38 |
#include "workqueue.h"
|
39 |
#include "rcvqueue.h"
|
39 |
#include "rcvqueue.h"
|
40 |
#include "log.h"
|
40 |
#include "log.h"
|
41 |
#include "conftree.h"
|
41 |
#include "conftree.h"
|
42 |
#include "chrono.h"
|
42 |
#include "chrono.h"
|
|
|
43 |
|
|
|
44 |
#ifdef WITH_WAVSC2
|
|
|
45 |
#include "openaudio.h"
|
|
|
46 |
#include "audioreader.h"
|
|
|
47 |
#endif
|
43 |
|
48 |
|
44 |
#include <vector>
|
49 |
#include <vector>
|
45 |
#include <stdio.h>
|
50 |
#include <stdio.h>
|
46 |
#include <iostream>
|
51 |
#include <iostream>
|
47 |
|
52 |
|
|
... |
|
... |
354 |
Brhz metatext(aMsg.Metatext());
|
359 |
Brhz metatext(aMsg.Metatext());
|
355 |
LOGDEB("OhmRcvDrv::Process:meta: METATEXT SEQUENCE " << aMsg.Sequence() <<
|
360 |
LOGDEB("OhmRcvDrv::Process:meta: METATEXT SEQUENCE " << aMsg.Sequence() <<
|
356 |
" METATEXT " << metatext.CString() << endl);
|
361 |
" METATEXT " << metatext.CString() << endl);
|
357 |
}
|
362 |
}
|
358 |
|
363 |
|
|
|
364 |
#ifdef WITH_WAVSC2
|
|
|
365 |
static int playWav(const string& wavfile, AudioEater *eater,
|
|
|
366 |
AudioEater::Context *ctxt)
|
|
|
367 |
{
|
|
|
368 |
audioqueue.start(1, eater->worker, ctxt);
|
|
|
369 |
|
|
|
370 |
AudioReader *audio = openAudio(wavfile, "", true);
|
|
|
371 |
|
|
|
372 |
if (!audio || !audio->open() || audio->bytesPerSample() == 0 ||
|
|
|
373 |
audio->numChannels() == 0) {
|
|
|
374 |
cerr << "Audio file open failed" << endl;
|
|
|
375 |
return 1;
|
|
|
376 |
}
|
|
|
377 |
LOGDEB("sample rate: " << audio->sampleRate() << endl);
|
|
|
378 |
LOGDEB("sample size: " << audio->bytesPerSample() << endl);
|
|
|
379 |
LOGDEB("channels: " << audio->numChannels() << endl);
|
|
|
380 |
|
|
|
381 |
size_t packetBytes = 441 * 16 *2;
|
|
|
382 |
while (true) {
|
|
|
383 |
const unsigned char *ibuf = audio->data(packetBytes);
|
|
|
384 |
if (ibuf == 0) {
|
|
|
385 |
return 1;
|
|
|
386 |
}
|
|
|
387 |
// We allocate a bit more space to avoir reallocations in the resampler
|
|
|
388 |
unsigned int allocbytes = packetBytes + 100;
|
|
|
389 |
char *buf = (char *)malloc(allocbytes);
|
|
|
390 |
if (buf == 0) {
|
|
|
391 |
LOGERR("playWav: can't allocate " << allocbytes << " bytes\n");
|
|
|
392 |
return 1;
|
|
|
393 |
}
|
|
|
394 |
|
|
|
395 |
// Songcast data is always msb-first. Convert to desired order:
|
|
|
396 |
// depends on what downstream wants, and just as well we do it
|
|
|
397 |
// here because we copy the buf anyway.
|
|
|
398 |
bool needswap = false;
|
|
|
399 |
switch (eater->input_border) {
|
|
|
400 |
case AudioEater::BO_MSB:
|
|
|
401 |
break;
|
|
|
402 |
case AudioEater::BO_LSB:
|
|
|
403 |
needswap = true;
|
|
|
404 |
break;
|
|
|
405 |
case AudioEater::BO_HOST:
|
|
|
406 |
#ifdef WORDS_BIGENDIAN
|
|
|
407 |
needswap = false;
|
|
|
408 |
#else
|
|
|
409 |
needswap = true;
|
|
|
410 |
#endif
|
|
|
411 |
break;
|
|
|
412 |
}
|
|
|
413 |
|
|
|
414 |
int bitDepth = 8 * audio->bytesPerSample();
|
|
|
415 |
if (needswap) {
|
|
|
416 |
copyswap((unsigned char *)buf, ibuf, packetBytes, bitDepth);
|
|
|
417 |
} else {
|
|
|
418 |
memcpy(buf, ibuf, packetBytes);
|
|
|
419 |
}
|
|
|
420 |
|
|
|
421 |
// The constructor wants the number of frames as input (frame
|
|
|
422 |
// being all samples at given timepoint, typically 2 for
|
|
|
423 |
// stereo)
|
|
|
424 |
int frames = packetBytes /
|
|
|
425 |
(audio->bytesPerSample() * audio->numChannels());
|
|
|
426 |
AudioMessage *ap = new
|
|
|
427 |
AudioMessage(bitDepth, audio->numChannels(), frames,
|
|
|
428 |
audio->sampleRate(), buf, allocbytes);
|
|
|
429 |
|
|
|
430 |
// There is nothing special we can do if put fails: no way to
|
|
|
431 |
// return status. Should we just exit ?
|
|
|
432 |
if (!audioqueue.put(ap, false)) {
|
|
|
433 |
LOGERR("sc2mpd: queue dead: exiting\n");
|
|
|
434 |
return 1;
|
|
|
435 |
}
|
|
|
436 |
}
|
|
|
437 |
return 0;
|
|
|
438 |
}
|
|
|
439 |
#endif
|
|
|
440 |
|
359 |
int CDECL main(int aArgc, char* aArgv[])
|
441 |
int CDECL main(int aArgc, char* aArgv[])
|
360 |
{
|
442 |
{
|
361 |
string logfilename;
|
443 |
string logfilename;
|
362 |
int loglevel(Logger::LLINF);
|
444 |
int loglevel(Logger::LLINF);
|
363 |
|
445 |
|
|
... |
|
... |
384 |
OptionBool optionDevice("-d", "--direct-alsa",
|
466 |
OptionBool optionDevice("-d", "--direct-alsa",
|
385 |
"[stream] Use alsa directly instead of producing "
|
467 |
"[stream] Use alsa directly instead of producing "
|
386 |
"http stream");
|
468 |
"http stream");
|
387 |
parser.AddOption(&optionDevice);
|
469 |
parser.AddOption(&optionDevice);
|
388 |
|
470 |
|
|
|
471 |
#ifdef WITH_WAVSC2
|
|
|
472 |
OptionString optionWav("-w", "--wav", Brn(""),
|
|
|
473 |
"Test audio with wav file instead of sender");
|
|
|
474 |
parser.AddOption(&optionWav);
|
|
|
475 |
#endif
|
|
|
476 |
|
389 |
if (!parser.Parse(aArgc, aArgv)) {
|
477 |
if (!parser.Parse(aArgc, aArgv)) {
|
390 |
return (1);
|
478 |
return (1);
|
391 |
}
|
479 |
}
|
392 |
|
|
|
393 |
InitialisationParams* initParams = InitialisationParams::Create();
|
|
|
394 |
|
|
|
395 |
Library* lib = new Library(initParams);
|
|
|
396 |
|
|
|
397 |
std::vector<NetworkAdapter*>* subnetList = lib->CreateSubnetList();
|
|
|
398 |
TIpAddress subnet = (*subnetList)[optionAdapter.Value()]->Subnet();
|
|
|
399 |
TIpAddress adapter = (*subnetList)[optionAdapter.Value()]->Address();
|
|
|
400 |
Library::DestroySubnetList(subnetList);
|
|
|
401 |
|
|
|
402 |
|
|
|
403 |
TUint ttl = optionTtl.Value();
|
|
|
404 |
Brhz uri(optionUri.Value());
|
|
|
405 |
|
480 |
|
406 |
string uconfigfile = (const char *)optionConfig.Value().Ptr();
|
481 |
string uconfigfile = (const char *)optionConfig.Value().Ptr();
|
407 |
|
482 |
|
408 |
bool cfspecified = true;
|
483 |
bool cfspecified = true;
|
409 |
if (uconfigfile.empty()) {
|
484 |
if (uconfigfile.empty()) {
|
|
... |
|
... |
425 |
cerr << "Can't initialize log" << endl;
|
500 |
cerr << "Can't initialize log" << endl;
|
426 |
return 1;
|
501 |
return 1;
|
427 |
}
|
502 |
}
|
428 |
Logger::getTheLog("")->setLogLevel(Logger::LogLevel(loglevel));
|
503 |
Logger::getTheLog("")->setLogLevel(Logger::LogLevel(loglevel));
|
429 |
|
504 |
|
|
|
505 |
AudioEater::Context *ctxt = new AudioEater::Context(&audioqueue);
|
|
|
506 |
ctxt->config = &config;
|
|
|
507 |
|
|
|
508 |
#ifdef WITH_WAVSC2
|
|
|
509 |
string wavname(Brhz(optionWav.Value()).CString());
|
|
|
510 |
if (!wavname.empty()) {
|
|
|
511 |
string value;
|
|
|
512 |
if (!config.get("sccvttype", value) ||
|
|
|
513 |
value.compare("NONE")) {
|
|
|
514 |
cerr << "Wav input play test. NEEDS sccvttype == NONE\n";
|
|
|
515 |
return 1;
|
|
|
516 |
}
|
|
|
517 |
return playWav(wavname, &alsaAudioEater, ctxt);
|
|
|
518 |
}
|
|
|
519 |
#endif
|
|
|
520 |
|
|
|
521 |
InitialisationParams* initParams = InitialisationParams::Create();
|
|
|
522 |
|
|
|
523 |
Library* lib = new Library(initParams);
|
|
|
524 |
|
|
|
525 |
std::vector<NetworkAdapter*>* subnetList = lib->CreateSubnetList();
|
|
|
526 |
TIpAddress subnet = (*subnetList)[optionAdapter.Value()]->Subnet();
|
|
|
527 |
TIpAddress adapter = (*subnetList)[optionAdapter.Value()]->Address();
|
|
|
528 |
Library::DestroySubnetList(subnetList);
|
|
|
529 |
|
|
|
530 |
TUint ttl = optionTtl.Value();
|
|
|
531 |
Brhz uri(optionUri.Value());
|
|
|
532 |
|
430 |
LOGINF("scmpdcli: using subnet " << (subnet & 0xff) << "." <<
|
533 |
LOGINF("scmpdcli: using subnet " << (subnet & 0xff) << "." <<
|
431 |
((subnet >> 8) & 0xff) << "." << ((subnet >> 16) & 0xff) << "." <<
|
534 |
((subnet >> 8) & 0xff) << "." << ((subnet >> 16) & 0xff) << "." <<
|
432 |
((subnet >> 24) & 0xff) << endl);
|
535 |
((subnet >> 24) & 0xff) << endl);
|
433 |
|
|
|
434 |
AudioEater::Context *ctxt = new AudioEater::Context(&audioqueue);
|
|
|
435 |
ctxt->config = &config;
|
|
|
436 |
|
536 |
|
437 |
OhmReceiverDriver* driver =
|
537 |
OhmReceiverDriver* driver =
|
438 |
new OhmReceiverDriver(optionDevice.Value() ?
|
538 |
new OhmReceiverDriver(optionDevice.Value() ?
|
439 |
&alsaAudioEater : &httpAudioEater, ctxt);
|
539 |
&alsaAudioEater : &httpAudioEater, ctxt);
|
440 |
|
540 |
|