summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2016-01-10 17:02:50 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2016-01-10 17:18:45 +0100
commite4821033a325b748c1c69848554b349c76ba6f59 (patch)
tree5626e72fc145e23ea5766984720c5adf643730d5 /src
parentc36c65f341429d8b6412be23205f6f9d1b0c864c (diff)
downloadODR-AudioEnc-e4821033a325b748c1c69848554b349c76ba6f59.tar.gz
ODR-AudioEnc-e4821033a325b748c1c69848554b349c76ba6f59.tar.bz2
ODR-AudioEnc-e4821033a325b748c1c69848554b349c76ba6f59.zip
Add VLC variant with drift compensation
Diffstat (limited to 'src')
-rw-r--r--src/VLCInput.cpp34
-rw-r--r--src/VLCInput.h44
-rw-r--r--src/dabplus-enc.cpp69
3 files changed, 132 insertions, 15 deletions
diff --git a/src/VLCInput.cpp b/src/VLCInput.cpp
index 7f6aae8..890de01 100644
--- a/src/VLCInput.cpp
+++ b/src/VLCInput.cpp
@@ -354,6 +354,40 @@ void VLCInput::write_icy_text(const std::string& filename)
}
}
+
+// ==================== VLCInputThreaded ====================
+
+void VLCInputThreaded::start()
+{
+ if (m_fault) {
+ fprintf(stderr, "Cannot start VLC input. Fault detected previsouly!\n");
+ }
+ else {
+ m_running = true;
+ m_thread = std::thread(&VLCInputThreaded::process, this);
+ }
+}
+
+void VLCInputThreaded::process()
+{
+ uint8_t samplebuf[NUM_SAMPLES_PER_CALL * BYTES_PER_SAMPLE * m_channels];
+ while (m_running) {
+ ssize_t n = m_read(samplebuf, NUM_SAMPLES_PER_CALL);
+
+ if (n < 0) {
+ m_running = false;
+ m_fault = true;
+ break;
+ }
+
+ m_queue.push(samplebuf, BYTES_PER_SAMPLE*m_channels*n);
+ }
+}
+
+
+
+
+
/* VLC up to version 2.1.0 used a different callback function signature.
* VLC 2.2.0 uses size_t
*
diff --git a/src/VLCInput.h b/src/VLCInput.h
index 710a0c6..f880642 100644
--- a/src/VLCInput.h
+++ b/src/VLCInput.h
@@ -38,6 +38,9 @@
// 16 bits per sample is fine for now
#define BYTES_PER_SAMPLE 2
+// How many samples we insert into the queue each call
+#define NUM_SAMPLES_PER_CALL 10 // 10 samples @ 32kHz = 3.125ms
+
/* Common functionality for the direct libvlc input and the
* threaded libvlc input
*/
@@ -143,6 +146,47 @@ class VLCInputDirect : public VLCInput
};
+class VLCInputThreaded : public VLCInput
+{
+ public:
+ VLCInputThreaded(const std::string& uri,
+ int rate,
+ unsigned channels,
+ unsigned verbosity,
+ std::string& gain,
+ std::string& cache,
+ SampleQueue<uint8_t>& queue) :
+ VLCInput(uri, rate, channels, verbosity, gain, cache),
+ m_fault(false),
+ m_running(false),
+ m_queue(queue) {}
+
+ ~VLCInputThreaded()
+ {
+ if (m_running) {
+ m_running = false;
+ m_thread.join();
+ }
+ }
+
+ /* Start the libVLC thread that fills the queue */
+ virtual void start();
+
+ bool fault_detected() { return m_fault; };
+
+ private:
+ VLCInputThreaded(const VLCInputThreaded& other) = delete;
+ VLCInputThreaded& operator=(const VLCInputThreaded& other) = delete;
+
+ void process();
+
+ std::atomic<bool> m_fault;
+ std::atomic<bool> m_running;
+ std::thread m_thread;
+ SampleQueue<uint8_t>& m_queue;
+
+};
+
#endif // HAVE_VLC
#endif
diff --git a/src/dabplus-enc.cpp b/src/dabplus-enc.cpp
index cab87b7..2e7f4fa 100644
--- a/src/dabplus-enc.cpp
+++ b/src/dabplus-enc.cpp
@@ -64,7 +64,7 @@ void usage(const char* name) {
"because it would have to throw away or insert a full DAB+ superframe,\n"
"which would create audible artifacts. This drift compensation can\n"
"make sure that the encoding rate is correct by inserting or deleting\n"
- "audio samples.\n"
+ "audio samples. It can be used for both ALSA and VLC inputs.\n"
"\n"
"When this option is enabled, you will see U and O printed in the\n"
"console. These correspond to audio underruns and overruns caused\n"
@@ -84,7 +84,6 @@ void usage(const char* name) {
fprintf(stderr,
" For the alsa input:\n"
" -d, --device=alsa_device Set ALSA input device (default: \"default\").\n"
- " -D, --drift-comp Enable ALSA sound card drift compensation.\n"
" For the file input:\n"
" -i, --input=FILENAME Input filename (default: stdin).\n"
" -f, --format={ wav, raw } Set input file format (default: wav).\n"
@@ -106,6 +105,8 @@ void usage(const char* name) {
#else
" The VLC input was disabled at compile-time\n"
#endif
+ " Drift compensation\n"
+ " -D, --drift-comp Enable ALSA/VLC sound card drift compensation.\n"
" Encoder parameters:\n"
" -b, --bitrate={ 8, 16, ..., 192 } Output bitrate in kbps. Must be a multiple of 8.\n"
" -A, --no-afterburner Disable AAC encoder quality increaser.\n"
@@ -605,7 +606,8 @@ int main(int argc, char *argv[])
JackInput jack_in(jack_name, channels, sample_rate, queue);
#endif
#if HAVE_VLC
- VLCInputDirect vlc_in(vlc_uri, sample_rate, channels, verbosity, vlc_gain, vlc_cache);
+ VLCInputDirect vlc_in_direct(vlc_uri, sample_rate, channels, verbosity, vlc_gain, vlc_cache);
+ VLCInputThreaded vlc_in_threaded(vlc_uri, sample_rate, channels, verbosity, vlc_gain, vlc_cache, queue);
#endif
if (infile) {
@@ -624,15 +626,26 @@ int main(int argc, char *argv[])
#endif
#if HAVE_VLC
else if (vlc_uri != "") {
- if (vlc_in.prepare() != 0) {
- fprintf(stderr, "VLC preparation failed\n");
- return 1;
+ if (drift_compensation) {
+ if (vlc_in_threaded.prepare() != 0) {
+ fprintf(stderr, "VLC with drift compensation: preparation failed\n");
+ return 1;
+ }
+
+ fprintf(stderr, "Start VLC thread\n");
+ vlc_in_threaded.start();
+ }
+ else {
+ if (vlc_in_direct.prepare() != 0) {
+ fprintf(stderr, "VLC preparation failed\n");
+ return 1;
+ }
}
}
#endif
else if (drift_compensation) {
if (alsa_in_threaded.prepare() != 0) {
- fprintf(stderr, "Alsa preparation failed\n");
+ fprintf(stderr, "Alsa with drift compensation: preparation failed\n");
return 1;
}
@@ -759,18 +772,44 @@ int main(int argc, char *argv[])
}
#if HAVE_VLC
else if (not vlc_uri.empty()) {
- read = vlc_in.read(input_buf, input_size);
- if (read < 0) {
- fprintf(stderr, "Detected fault in VLC input!\n");
- break;
+ VLCInput* vlc_in = nullptr;
+
+ if (drift_compensation) {
+ vlc_in = &vlc_in_threaded;
+
+ if (drift_compensation && vlc_in_threaded.fault_detected()) {
+ fprintf(stderr, "Detected fault in VLC input!\n");
+ retval = 5;
+ break;
+ }
+
+ size_t overruns;
+ read = queue.pop(input_buf, input_size, &overruns); // returns bytes
+
+ if (read != input_size) {
+ status |= STATUS_UNDERRUN;
+ }
+
+ if (overruns) {
+ status |= STATUS_OVERRUN;
+ }
}
- else if (read != input_size) {
- fprintf(stderr, "Short VLC read !\n");
- break;
+ else {
+ vlc_in = &vlc_in_direct;
+
+ read = vlc_in_direct.read(input_buf, input_size);
+ if (read < 0) {
+ fprintf(stderr, "Detected fault in VLC input!\n");
+ break;
+ }
+ else if (read != input_size) {
+ fprintf(stderr, "Short VLC read !\n");
+ break;
+ }
}
if (not vlc_icytext_file.empty()) {
- vlc_in.write_icy_text(vlc_icytext_file);
+ vlc_in->write_icy_text(vlc_icytext_file);
}
}
#endif