aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2017-10-07 10:31:04 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2017-10-07 10:31:04 +0200
commit68ee7799a4eeb4148cd4628113ebf9ea3f94a211 (patch)
tree974962f0f9a2552b8a9665b18563e5e14602453e /src
parent39e95f67515f97030f4e4dee03abde33ce35a99a (diff)
downloadODR-AudioEnc-68ee7799a4eeb4148cd4628113ebf9ea3f94a211.tar.gz
ODR-AudioEnc-68ee7799a4eeb4148cd4628113ebf9ea3f94a211.tar.bz2
ODR-AudioEnc-68ee7799a4eeb4148cd4628113ebf9ea3f94a211.zip
Make all inputs use the same interface
Diffstat (limited to 'src')
-rw-r--r--src/AlsaInput.cpp70
-rw-r--r--src/AlsaInput.h70
-rw-r--r--src/FileInput.cpp68
-rw-r--r--src/FileInput.h34
-rw-r--r--src/InputInterface.h34
-rw-r--r--src/JackInput.cpp42
-rw-r--r--src/JackInput.h32
-rw-r--r--src/VLCInput.cpp101
-rw-r--r--src/VLCInput.h29
-rw-r--r--src/odr-audioenc.cpp73
10 files changed, 281 insertions, 272 deletions
diff --git a/src/AlsaInput.cpp b/src/AlsaInput.cpp
index 293232f..af3c284 100644
--- a/src/AlsaInput.cpp
+++ b/src/AlsaInput.cpp
@@ -1,6 +1,6 @@
/* ------------------------------------------------------------------
* Copyright (C) 2011 Martin Storsjo
- * Copyright (C) 2013,2014 Matthias P. Braendli
+ * Copyright (C) 2017 Matthias P. Braendli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,13 +22,28 @@
#include "AlsaInput.h"
#include <cstdio>
+#include <stdexcept>
#include <string>
#include <alsa/asoundlib.h>
#include <sys/time.h>
using namespace std;
-int AlsaInput::prepare()
+AlsaInput::~AlsaInput()
+{
+ if (m_alsa_handle) {
+ snd_pcm_close(m_alsa_handle);
+ m_alsa_handle = nullptr;
+ }
+}
+
+static std::string alsa_strerror(int err)
+{
+ string s(snd_strerror(err));
+ return s;
+}
+
+void AlsaInput::m_init_alsa()
{
int err;
snd_pcm_hw_params_t *hw_params;
@@ -39,67 +54,54 @@ int AlsaInput::prepare()
if ((err = snd_pcm_open(&m_alsa_handle, m_alsa_dev.c_str(),
SND_PCM_STREAM_CAPTURE, open_mode)) < 0) {
- fprintf (stderr, "cannot open audio device %s (%s)\n",
- m_alsa_dev.c_str(), snd_strerror(err));
- return 1;
+ throw runtime_error("cannot open audio device " +
+ m_alsa_dev + "(" + alsa_strerror(err) + ")");
}
if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
- fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
- snd_strerror(err));
- return 1;
+ throw runtime_error("cannot allocate hardware parameter structure (" +
+ alsa_strerror(err) + ")");
}
if ((err = snd_pcm_hw_params_any(m_alsa_handle, hw_params)) < 0) {
- fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
- snd_strerror(err));
- return 1;
+ throw runtime_error("cannot initialize hardware parameter structure (" +
+ alsa_strerror(err) + ")");
}
if ((err = snd_pcm_hw_params_set_access(m_alsa_handle, hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
- fprintf (stderr, "cannot set access type (%s)\n",
- snd_strerror(err));
- return 1;
+ throw runtime_error("cannot set access type (" + alsa_strerror(err) + ")");
}
if ((err = snd_pcm_hw_params_set_format(m_alsa_handle, hw_params,
SND_PCM_FORMAT_S16_LE)) < 0) {
- fprintf (stderr, "cannot set sample format (%s)\n",
- snd_strerror(err));
- return 1;
+ throw runtime_error("cannot set sample format (" +
+ alsa_strerror(err) + ")");
}
if ((err = snd_pcm_hw_params_set_rate_near(m_alsa_handle,
hw_params, &m_rate, 0)) < 0) {
- fprintf (stderr, "cannot set sample rate (%s)\n",
- snd_strerror(err));
- return 1;
+ throw runtime_error("cannot set sample rate (" + alsa_strerror(err) + ")");
}
if ((err = snd_pcm_hw_params_set_channels(m_alsa_handle,
hw_params, m_channels)) < 0) {
- fprintf (stderr, "cannot set channel count (%s)\n",
- snd_strerror(err));
- return 1;
+ throw runtime_error("cannot set channel count (" +
+ alsa_strerror(err) + ")");
}
if ((err = snd_pcm_hw_params(m_alsa_handle, hw_params)) < 0) {
- fprintf (stderr, "cannot set parameters (%s)\n",
- snd_strerror(err));
- return 1;
+ throw runtime_error("cannot set parameters (" + alsa_strerror(err) + ")");
}
snd_pcm_hw_params_free (hw_params);
if ((err = snd_pcm_prepare(m_alsa_handle)) < 0) {
- fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
- snd_strerror(err));
- return 1;
+ throw runtime_error("cannot prepare audio interface for use (" +
+ alsa_strerror(err) + ")");
}
fprintf(stderr, "ALSA init done.\n");
- return 0;
}
ssize_t AlsaInput::m_read(uint8_t* buf, snd_pcm_uframes_t length)
@@ -122,12 +124,14 @@ ssize_t AlsaInput::m_read(uint8_t* buf, snd_pcm_uframes_t length)
return err;
}
-void AlsaInputThreaded::start()
+void AlsaInputThreaded::prepare()
{
if (m_fault) {
fprintf(stderr, "Cannot start alsa input. Fault detected previsouly!\n");
}
else {
+ m_init_alsa();
+
m_running = true;
m_thread = std::thread(&AlsaInputThreaded::process, this);
}
@@ -149,6 +153,10 @@ void AlsaInputThreaded::process()
}
}
+void AlsaInputDirect::prepare()
+{
+ m_init_alsa();
+}
ssize_t AlsaInputDirect::read(uint8_t* buf, size_t length)
{
diff --git a/src/AlsaInput.h b/src/AlsaInput.h
index a261f37..7f88341 100644
--- a/src/AlsaInput.h
+++ b/src/AlsaInput.h
@@ -1,6 +1,6 @@
/* ------------------------------------------------------------------
* Copyright (C) 2011 Martin Storsjo
- * Copyright (C) 2013,2014 Matthias P. Braendli
+ * Copyright (C) 2017 Matthias P. Braendli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,8 +21,7 @@
* This input uses libasound to get audio data.
*/
-#ifndef __ALSA_H_
-#define __ALSA_H_
+#pragma once
#include "config.h"
@@ -37,12 +36,13 @@
#include "SampleQueue.h"
#include "common.h"
+#include "InputInterface.h"
/*! Common functionality for the direct alsa input and the
* threaded alsa input. The threaded one is used for
* drift compensation.
*/
-class AlsaInput
+class AlsaInput : public InputInterface
{
public:
AlsaInput(const std::string& alsa_dev,
@@ -50,31 +50,27 @@ class AlsaInput
unsigned int rate) :
m_alsa_dev(alsa_dev),
m_channels(channels),
- m_rate(rate),
- m_alsa_handle(NULL) { }
+ m_rate(rate) { }
- ~AlsaInput() {
+ AlsaInput(const AlsaInput& other) = delete;
+ AlsaInput& operator=(const AlsaInput& other) = delete;
- if (m_alsa_handle) {
- snd_pcm_close(m_alsa_handle);
- m_alsa_handle = NULL;
- }
- }
-
- /* Prepare the audio input */
- int prepare();
+ virtual ~AlsaInput();
protected:
+ /* Read from the ALSA device. Returns number of samples,
+ * or -1 in case of error
+ */
ssize_t m_read(uint8_t* buf, snd_pcm_uframes_t length);
+ /* Open the ALSA device and set it up */
+ void m_init_alsa(void);
+
std::string m_alsa_dev;
unsigned int m_channels;
unsigned int m_rate;
- snd_pcm_t *m_alsa_handle;
-
- private:
- AlsaInput(const AlsaInput& other) {}
+ snd_pcm_t *m_alsa_handle = nullptr;
};
class AlsaInputDirect : public AlsaInput
@@ -85,16 +81,31 @@ class AlsaInputDirect : public AlsaInput
unsigned int rate) :
AlsaInput(alsa_dev, channels, rate) { }
+#if 0
+ AlsaInputDirect(AlsaInputDirect&& other) :
+ AlsaInput(other.m_alsa_dev, other.m_channels, other.m_rate) {
+ m_alsa_handle = other.m_alsa_handle;
+ other.m_alsa_handle = nullptr;
+ }
+
+ AlsaInputDirect& operator=(AlsaInputDirect&& other) {
+ m_alsa_dev = other.m_alsa_dev;
+ m_channels = other.m_channels;
+ m_rate = other.m_rate;
+ m_alsa_handle = other.m_alsa_handle;
+ other.m_alsa_handle = nullptr;
+ return *this;
+ }
+#endif
+
+ virtual void prepare(void) override;
+
/*! Read length Bytes from from the alsa device.
* length must be a multiple of channels * bytes_per_sample.
*
* \return the number of bytes read.
*/
ssize_t read(uint8_t* buf, size_t length);
-
- private:
- AlsaInputDirect(const AlsaInputDirect& other) :
- AlsaInput("", 0, 0) { }
};
class AlsaInputThreaded : public AlsaInput
@@ -109,7 +120,7 @@ class AlsaInputThreaded : public AlsaInput
m_running(false),
m_queue(queue) { }
- ~AlsaInputThreaded()
+ virtual ~AlsaInputThreaded()
{
if (m_running) {
m_running = false;
@@ -118,15 +129,11 @@ class AlsaInputThreaded : public AlsaInput
}
/*! Start the ALSA thread that fills the queue */
- virtual void start();
+ virtual void prepare(void) override;
- bool fault_detected() { return m_fault; };
+ bool fault_detected() const { return m_fault; };
private:
- AlsaInputThreaded(const AlsaInputThreaded& other) :
- AlsaInput("", 0, 0),
- m_queue(other.m_queue) {}
-
void process();
std::atomic<bool> m_fault;
@@ -139,6 +146,3 @@ class AlsaInputThreaded : public AlsaInput
#endif // HAVE_ALSA
-#endif // __ALSA_H_
-
-
diff --git a/src/FileInput.cpp b/src/FileInput.cpp
index 1bad495..89e1dab 100644
--- a/src/FileInput.cpp
+++ b/src/FileInput.cpp
@@ -1,5 +1,5 @@
/* ------------------------------------------------------------------
- * Copyright (C) 2016 Matthias P. Braendli
+ * Copyright (C) 2017 Matthias P. Braendli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,17 +20,30 @@
#include "wavfile.h"
#include <cstring>
#include <cstdio>
-
+#include <stdexcept>
#include <stdint.h>
-int FileInput::prepare(void)
+using namespace std;
+
+FileInput::~FileInput()
+{
+ if (m_raw_input and m_in_fh) {
+ fclose(m_in_fh);
+ }
+ else if (m_wav) {
+ wav_read_close(m_wav);
+ }
+}
+
+void FileInput::prepare(void)
{
+ const char* fname = m_filename.c_str();
+
if (m_raw_input) {
- if (m_filename && strcmp(m_filename, "-")) {
- m_in_fh = fopen(m_filename, "rb");
+ if (fname && strcmp(fname, "-")) {
+ m_in_fh = fopen(fname, "rb");
if (!m_in_fh) {
- fprintf(stderr, "Can't open input file!\n");
- return 1;
+ throw runtime_error("Can't open input file!");
}
}
else {
@@ -43,37 +56,32 @@ int FileInput::prepare(void)
int wav_format = 0;
int sample_rate = 0;
- m_wav = wav_read_open(m_filename);
+ m_wav = wav_read_open(fname);
if (!m_wav) {
- fprintf(stderr, "Unable to open wav file %s\n", m_filename);
- return 1;
+ throw runtime_error("Unable to open wav file " + m_filename);
}
if (!wav_get_header(m_wav, &wav_format, &channels, &sample_rate,
- &bits_per_sample, NULL)) {
- fprintf(stderr, "Bad wav file %s\n", m_filename);
- return 1;
+ &bits_per_sample, nullptr)) {
+ throw runtime_error("Bad wav file" + m_filename);
}
if (wav_format != 1) {
- fprintf(stderr, "Unsupported WAV format %d\n", wav_format);
- return 1;
+ throw runtime_error("Unsupported WAV format " + to_string(wav_format));
}
if (bits_per_sample != 16) {
- fprintf(stderr, "Unsupported WAV sample depth %d\n", bits_per_sample);
- return 1;
+ throw runtime_error("Unsupported WAV sample depth " +
+ to_string(bits_per_sample));
}
if ( !(channels == 1 or channels == 2)) {
- fprintf(stderr, "Unsupported WAV channels %d\n", channels);
- return 1;
+ throw runtime_error("Unsupported WAV channels " + to_string(channels));
}
if (m_sample_rate != sample_rate) {
- fprintf(stderr,
- "WAV sample rate %d doesn't correspond to desired sample rate %d\n",
- sample_rate, m_sample_rate);
- return 1;
+ throw runtime_error(
+ "WAV sample rate " +
+ to_string(sample_rate) +
+ " doesn't correspond to desired sample rate " +
+ to_string(m_sample_rate));
}
}
-
- return 0;
}
ssize_t FileInput::read(uint8_t* buf, size_t length)
@@ -104,13 +112,3 @@ int FileInput::eof()
}
-FileInput::~FileInput()
-{
- if (m_raw_input && m_in_fh) {
- fclose(m_in_fh);
- }
- else if (m_wav) {
- wav_read_close(m_wav);
- }
-}
-
diff --git a/src/FileInput.h b/src/FileInput.h
index 937cbd4..c66441a 100644
--- a/src/FileInput.h
+++ b/src/FileInput.h
@@ -1,5 +1,5 @@
/* ------------------------------------------------------------------
- * Copyright (C) 2016 Matthias P. Braendli
+ * Copyright (C) 2017 Matthias P. Braendli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,30 +26,29 @@
* line (number of channels, rate)
*/
-#ifndef _FILE_INPUT_H_
-#define _FILE_INPUT_H_
+#pragma once
#include <stdint.h>
-#include <stdio.h>
+#include <cstdio>
+#include <string>
+#include "InputInterface.h"
-class FileInput
+class FileInput : public InputInterface
{
public:
- FileInput(const char* filename,
+ FileInput(const std::string& filename,
bool raw_input,
int sample_rate) :
m_filename(filename),
m_raw_input(raw_input),
- m_sample_rate(sample_rate),
- m_wav(nullptr) { }
+ m_sample_rate(sample_rate) {}
~FileInput();
+ FileInput(const FileInput& other) = delete;
+ FileInput& operator=(const FileInput& other) = delete;
- /*! Open the file and prepare the wav decoder.
- *
- * \return nonzero on error
- */
- int prepare(void);
+ /*! Open the file and prepare the wav decoder. */
+ virtual void prepare(void) override;
/*! Read length bytes into buf.
*
@@ -59,15 +58,12 @@ class FileInput
int eof();
protected:
- const char* m_filename;
+ std::string m_filename;
bool m_raw_input;
int m_sample_rate;
/* handle to the wav reader */
- void *m_wav;
-
- FILE* m_in_fh;
+ void *m_wav = nullptr;
+ FILE* m_in_fh = nullptr;
};
-#endif
-
diff --git a/src/InputInterface.h b/src/InputInterface.h
new file mode 100644
index 0000000..739ca3f
--- /dev/null
+++ b/src/InputInterface.h
@@ -0,0 +1,34 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 2017 Matthias P. Braendli
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+/*! \section Input intefrace definition
+ *
+ * This describes the interface all inputs must implement.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdio.h>
+
+class InputInterface {
+ public:
+ /*! Open the input interface. In case of failure, throws a
+ * runtime_error.
+ */
+ virtual void prepare(void) = 0;
+};
diff --git a/src/JackInput.cpp b/src/JackInput.cpp
index a94f2e7..70c354f 100644
--- a/src/JackInput.cpp
+++ b/src/JackInput.cpp
@@ -1,6 +1,6 @@
/* ------------------------------------------------------------------
* Copyright (C) 2011 Martin Storsjo
- * Copyright (C) 2016 Matthias P. Braendli
+ * Copyright (C) 2017 Matthias P. Braendli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,20 +32,28 @@ extern "C" {
using namespace std;
-int JackInput::prepare()
+JackInput::~JackInput()
+{
+ if (m_client) {
+ jack_client_close(m_client);
+ }
+}
+
+void JackInput::prepare()
{
jack_options_t options = JackNullOption;
jack_status_t status;
const char *server_name = NULL;
- m_client = jack_client_open(m_jack_name, options, &status, server_name);
+ m_client = jack_client_open(m_jack_name.c_str(), options, &status, server_name);
if (m_client == NULL) {
- fprintf(stderr, "jack_client_open() failed, "
- "status = 0x%2.0x\n", status);
if (status & JackServerFailed) {
- fprintf(stderr, "Unable to connect to JACK server\n");
+ throw runtime_error("Unable to connect to JACK server");
+ }
+ else {
+ throw runtime_error("jack_client_open() failed, status = " +
+ to_string(status));
}
- return -1;
}
if (status & JackServerStarted) {
@@ -53,8 +61,7 @@ int JackInput::prepare()
}
if (status & JackNameNotUnique) {
- fprintf(stderr, "JACK name '%s' not unique!\n", m_jack_name);
- return -1;
+ throw runtime_error("JACK name '" + m_jack_name + "' not unique!");
}
/* Set up real-time process callback */
@@ -66,11 +73,10 @@ int JackInput::prepare()
jack_on_shutdown(m_client, shutdown_cb, this);
if (m_rate != jack_get_sample_rate(m_client)) {
- fprintf(stderr, "JACK uses different sample_rate %d "
- "than requested (%d)!\n",
- jack_get_sample_rate(m_client),
- m_rate);
- return -1;
+ throw runtime_error(
+ "JACK uses different sample_rate " +
+ to_string(jack_get_sample_rate(m_client)) +
+ " than requested (" + to_string(m_rate) + ")!");
}
/* create ports */
@@ -85,8 +91,7 @@ int JackInput::prepare()
0);
if (input_port == NULL) {
- fprintf(stderr, "no more JACK ports available\n");
- return -1;
+ throw runtime_error("no more JACK ports available");
}
m_input_ports.push_back(input_port);
@@ -95,11 +100,8 @@ int JackInput::prepare()
/* Tell the JACK server that we are ready to roll. Our
* process() callback will start running now. */
if (jack_activate(m_client)) {
- fprintf (stderr, "JACK: cannot activate client");
- return -1;
+ throw runtime_error("JACK: cannot activate client");
}
-
- return 0;
}
void JackInput::jack_process(jack_nframes_t nframes)
diff --git a/src/JackInput.h b/src/JackInput.h
index 23fd4b6..8cbda45 100644
--- a/src/JackInput.h
+++ b/src/JackInput.h
@@ -1,6 +1,6 @@
/* ------------------------------------------------------------------
* Copyright (C) 2011 Martin Storsjo
- * Copyright (C) 2016 Matthias P. Braendli
+ * Copyright (C) 2017 Matthias P. Braendli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,8 +22,8 @@
* compensation, because there is no blocking way to read from JACK.
*/
-#ifndef __JACK_INPUT_H
-#define __JACK_INPUT_H
+#pragma once
+
#include "config.h"
#include <cstdio>
#include <string>
@@ -35,14 +35,15 @@ extern "C" {
}
#include "SampleQueue.h"
+#include "InputInterface.h"
// 16 bits per sample is fine for now
#define BYTES_PER_SAMPLE 2
-class JackInput
+class JackInput : public InputInterface
{
public:
- JackInput(const char* jack_name,
+ JackInput(const std::string& jack_name,
unsigned int channels,
unsigned int samplerate,
SampleQueue<uint8_t>& queue) :
@@ -52,26 +53,19 @@ class JackInput
m_rate(samplerate),
m_queue(queue) { }
- ~JackInput() {
- if (m_client) {
- jack_client_close(m_client);
- }
- }
+ JackInput(const JackInput& other) = delete;
+ JackInput& operator=(const JackInput& other) = delete;
- /*! Prepare the audio input
- *
- * \return 0 on success
- */
- int prepare();
+ virtual ~JackInput();
- private:
- JackInput(const JackInput& other);
+ virtual void prepare() override;
+ private:
jack_client_t *m_client;
std::vector<jack_port_t*> m_input_ports;
- const char* m_jack_name;
+ std::string m_jack_name;
unsigned int m_channels;
unsigned int m_rate;
@@ -105,5 +99,3 @@ class JackInput
#endif // HAVE_JACK
-#endif
-
diff --git a/src/VLCInput.cpp b/src/VLCInput.cpp
index c0c9433..9c424bb 100644
--- a/src/VLCInput.cpp
+++ b/src/VLCInput.cpp
@@ -1,5 +1,5 @@
/* ------------------------------------------------------------------
- * Copyright (C) 2016 Matthias P. Braendli
+ * Copyright (C) 2017 Matthias P. Braendli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,7 +33,12 @@ const size_t bytes_per_float_sample = sizeof(float);
#include <sys/time.h>
-int check_vlc_uses_size_t();
+enum class vlc_data_type_e {
+ vlc_uses_size_t,
+ vlc_uses_unsigned_int
+};
+
+static vlc_data_type_e check_vlc_uses_size_t();
using namespace std;
@@ -117,33 +122,32 @@ void handleVLCExit(void* opaque)
((VLCInput*)opaque)->exit_cb();
}
-int VLCInput::prepare()
+void VLCInput::prepare()
{
+ if (m_fault) {
+ throw runtime_error("Cannot start VLC input. Fault detected previously!");
+ }
+
fprintf(stderr, "Initialising VLC...\n");
long long int handleStream_address;
long long int prepareRender_address;
- int vlc_version_check = check_vlc_uses_size_t();
- if (vlc_version_check == 0) {
- fprintf(stderr, "You are using VLC with unsigned int size callbacks\n");
+ switch (check_vlc_uses_size_t()) {
+ case vlc_data_type_e::vlc_uses_unsigned_int:
+ fprintf(stderr, "You are using VLC with unsigned int size callbacks\n");
- handleStream_address = (long long int)(intptr_t)(void*)&handleStream;
- prepareRender_address = (long long int)(intptr_t)(void*)&prepareRender;
- }
- else if (vlc_version_check == 1) {
- fprintf(stderr, "You are using VLC with size_t size callbacks\n");
+ handleStream_address = (long long int)(intptr_t)(void*)&handleStream;
+ prepareRender_address = (long long int)(intptr_t)(void*)&prepareRender;
+ break;
+ case vlc_data_type_e::vlc_uses_size_t:
+ fprintf(stderr, "You are using VLC with size_t size callbacks\n");
- handleStream_address = (long long int)(intptr_t)(void*)&handleStream_size_t;
- prepareRender_address = (long long int)(intptr_t)(void*)&prepareRender_size_t;
- }
- else {
- fprintf(stderr, "Error detecting VLC version!\n");
- fprintf(stderr, " you are using %s\n", libvlc_get_version());
- return -1;
+ handleStream_address = (long long int)(intptr_t)(void*)&handleStream_size_t;
+ prepareRender_address = (long long int)(intptr_t)(void*)&prepareRender_size_t;
+ break;
}
-
// VLC options
std::stringstream transcode_options_ss;
transcode_options_ss << "acodec=fl32";
@@ -199,8 +203,7 @@ int VLCInput::prepare()
vlc_args[arg_ix++] = opt.c_str();
}
else {
- fprintf(stderr, "Too many VLC options given");
- return 1;
+ throw runtime_error("Too many VLC options given");
}
}
@@ -241,7 +244,12 @@ int VLCInput::prepare()
}
}
- return ret;
+ if (ret == -1) {
+ throw runtime_error("VLC input did not start playing media");
+ }
+
+ m_running = true;
+ m_thread = std::thread(&VLCInput::process, this);
}
void VLCInput::preRender_cb(uint8_t** pp_pcm_buffer, size_t size)
@@ -347,17 +355,20 @@ ssize_t VLCInput::m_read(uint8_t* buf, size_t length)
break;
}
- // handle meta data
+ // handle meta data. Warning: do not leak these!
char* artist_sz = libvlc_media_get_meta(media, libvlc_meta_Artist);
char* title_sz = libvlc_media_get_meta(media, libvlc_meta_Title);
- if (artist_sz && title_sz) {
+ if (artist_sz and title_sz) {
// use Artist and Title
std::lock_guard<std::mutex> lock(m_nowplaying_mutex);
m_nowplaying.useArtistTitle(artist_sz, title_sz);
- } else {
+ }
+ else {
// try fallback to NowPlaying
- char* nowplaying_sz = libvlc_media_get_meta(media, libvlc_meta_NowPlaying);
+ char* nowplaying_sz = libvlc_media_get_meta(media,
+ libvlc_meta_NowPlaying);
+
if (nowplaying_sz) {
std::lock_guard<std::mutex> lock(m_nowplaying_mutex);
m_nowplaying.useNowPlaying(nowplaying_sz);
@@ -387,7 +398,7 @@ bool write_icy_to_file(const ICY_TEXT_T text, const std::string& filename, bool
FILE* fd = fopen(filename.c_str(), "wb");
if (fd) {
bool ret = true;
- bool artist_title_used = !text.artist.empty() && !text.title.empty();
+ bool artist_title_used = !text.artist.empty() and !text.title.empty();
// if desired, prepend DL Plus information
if (dl_plus) {
@@ -418,7 +429,8 @@ bool write_icy_to_file(const ICY_TEXT_T text, const std::string& filename, bool
ret &= fputs(text.artist.c_str(), fd) >= 0;
ret &= fputs(VLCInput::ICY_TEXT_SEPARATOR.c_str(), fd) >= 0;
ret &= fputs(text.title.c_str(), fd) >= 0;
- } else {
+ }
+ else {
ret &= fputs(text.now_playing.c_str(), fd) >= 0;
}
fclose(fd);
@@ -457,16 +469,6 @@ void VLCInput::write_icy_text(const std::string& filename, bool dl_plus)
}
-void VLCInput::start()
-{
- if (m_fault) {
- fprintf(stderr, "Cannot start VLC input. Fault detected previsouly!\n");
- }
- else {
- m_running = true;
- m_thread = std::thread(&VLCInput::process, this);
- }
-}
/*! How many samples we insert into the queue each call
* 10 samples @ 32kHz = 3.125ms
@@ -495,17 +497,11 @@ void VLCInput::process()
/*! VLC up to version 2.1.0 used a different callback function signature.
* VLC 2.2.0 uses size_t
- *
- * \return 1 if the callback with size_t size should be used.
- * 0 if the callback with unsigned int size should be used.
- * -1 if there was an error.
*/
-int check_vlc_uses_size_t()
+vlc_data_type_e check_vlc_uses_size_t()
{
- int retval = -1;
-
- char libvlc_version[256];
- strncpy(libvlc_version, libvlc_get_version(), 256);
+ char libvlc_version[256] = {};
+ strncpy(libvlc_version, libvlc_get_version(), 255);
char *space_position = strstr(libvlc_version, " ");
@@ -522,11 +518,18 @@ int check_vlc_uses_size_t()
if (minor_ver_sz) {
int minor_ver = atoi(minor_ver_sz);
- retval = (major_ver >= 2 && minor_ver >= 2) ? 1 : 0;
+ if (major_ver >= 2 && minor_ver >= 2) {
+ return vlc_data_type_e::vlc_uses_size_t;
+ }
+ else {
+ return vlc_data_type_e::vlc_uses_unsigned_int;
+ }
}
}
- return retval;
+ fprintf(stderr, "Error detecting VLC version!\n");
+ fprintf(stderr, " you are using %s\n", libvlc_get_version());
+ throw runtime_error("Cannot identify VLC datatype!");
}
diff --git a/src/VLCInput.h b/src/VLCInput.h
index 63975e7..789bc70 100644
--- a/src/VLCInput.h
+++ b/src/VLCInput.h
@@ -1,5 +1,5 @@
/* ------------------------------------------------------------------
- * Copyright (C) 2016 Matthias P. Braendli
+ * Copyright (C) 2017 Matthias P. Braendli
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,8 +21,7 @@
* the encoder to use all inputs VLC supports.
*/
-#ifndef __VLC_INPUT_H_
-#define __VLC_INPUT_H_
+#pragma once
#include "config.h"
@@ -41,6 +40,7 @@
#include "SampleQueue.h"
#include "common.h"
+#include "InputInterface.h"
extern "C" {
#include "utils.h"
@@ -57,19 +57,19 @@ struct ICY_TEXT_T {
bool operator==(const ICY_TEXT_T& other) const {
return
- artist == other.artist &&
- title == other.title &&
+ artist == other.artist and
+ title == other.title and
now_playing == other.now_playing;
}
bool operator!=(const ICY_TEXT_T& other) const {
return !(*this == other);
}
- void useArtistTitle(std::string artist, std::string title) {
+ void useArtistTitle(const std::string& artist, const std::string& title) {
this->artist = artist;
this->title = title;
now_playing = "";
}
- void useNowPlaying(std::string now_playing) {
+ void useNowPlaying(const std::string& now_playing) {
artist = "";
title = "";
this->now_playing = now_playing;
@@ -77,7 +77,7 @@ struct ICY_TEXT_T {
};
-class VLCInput
+class VLCInput : public InputInterface
{
public:
VLCInput(const std::string& uri,
@@ -113,14 +113,9 @@ class VLCInput
cleanup();
}
- /*! Prepare the audio input
- *
- * \return 0 on success
- */
- int prepare();
-
- /*! Start the libVLC thread that fills m_samplequeue */
- void start();
+ /*! Initialise VLC and start playing, and start
+ * the libVLC thread that fills m_samplequeue */
+ virtual void prepare() override;
/*! Write the last received ICY-Text to the
* file.
@@ -215,5 +210,3 @@ class VLCInput
#endif // HAVE_VLC
-#endif
-
diff --git a/src/odr-audioenc.cpp b/src/odr-audioenc.cpp
index 8fc3808..ea546f7 100644
--- a/src/odr-audioenc.cpp
+++ b/src/odr-audioenc.cpp
@@ -130,12 +130,12 @@ void usage(const char* name)
fprintf(stderr,
" For the alsa input:\n"
#if HAVE_ALSA
- " -d, --device=alsa_device Set ALSA input device (default: \"default\").\n"
+ " -d, --device=alsa_device Set ALSA input device.\n"
#else
" The Alsa input was disabled at compile time\n"
#endif
" For the file input:\n"
- " -i, --input=FILENAME Input filename (default: stdin).\n"
+ " -i, --input=FILENAME Input filename (use -i - for stdin).\n"
" -f, --format={ wav, raw } Set input file format (default: wav).\n"
" --fifo-silence Input file is fifo and encoder generates silence when fifo is empty. Ignore EOF.\n"
" For the JACK input:\n"
@@ -391,10 +391,10 @@ int main(int argc, char *argv[])
encoder_selection_t selected_encoder = encoder_selection_t::fdk_dabplus;
// For the ALSA input
- const char *alsa_device = NULL;
+ string alsa_device;
// For the file input
- const char *infile = NULL;
+ string infile;
int raw_input = 0;
// For the VLC input
@@ -409,7 +409,7 @@ int main(int argc, char *argv[])
// For the file output
FILE *out_fh = NULL;
- const char *jack_name = NULL;
+ string jack_name;
std::vector<std::string> output_uris;
@@ -640,9 +640,9 @@ int main(int argc, char *argv[])
}
int num_inputs = 0;
- if (alsa_device) num_inputs++;
- if (infile) num_inputs++;
- if (jack_name) num_inputs++;
+ if (not alsa_device.empty()) num_inputs++;
+ if (not infile.empty()) num_inputs++;
+ if (not jack_name.empty()) num_inputs++;
if (vlc_uri != "") num_inputs++;
if (num_inputs == 0) {
@@ -865,11 +865,6 @@ int main(int argc, char *argv[])
return 1;
}
- /* No input defined ? default to alsa "default" */
- if (!alsa_device) {
- alsa_device = "default";
- }
-
// We'll use one of the tree possible inputs
#if HAVE_ALSA
AlsaInputThreaded alsa_in_threaded(alsa_device, channels, sample_rate, queue);
@@ -883,53 +878,37 @@ int main(int argc, char *argv[])
VLCInput vlc_input(vlc_uri, sample_rate, channels, verbosity, vlc_gain, vlc_cache, vlc_additional_opts, queue);
#endif
- if (infile) {
- if (file_in.prepare() != 0) {
- fprintf(stderr, "File input preparation failed\n");
- return 1;
- }
+ InputInterface *input = nullptr;
+
+ if (not infile.empty()) {
+ input = &file_in;
}
#if HAVE_JACK
- else if (jack_name) {
- if (jack_in.prepare() != 0) {
- fprintf(stderr, "JACK preparation failed\n");
- return 1;
- }
+ else if (not jack_name.empty()) {
+ input = &jack_in;
}
#endif
#if HAVE_VLC
- else if (vlc_uri != "") {
- if (vlc_input.prepare() != 0) {
- fprintf(stderr, "VLC with drift compensation: preparation failed\n");
- return 1;
- }
-
- fprintf(stderr, "Start VLC thread\n");
- vlc_input.start();
+ else if (not vlc_uri.empty()) {
+ input = &vlc_input;
}
#endif
#if HAVE_ALSA
else if (drift_compensation) {
- if (alsa_in_threaded.prepare() != 0) {
- fprintf(stderr, "Alsa with drift compensation: preparation failed\n");
- return 1;
- }
-
- fprintf(stderr, "Start ALSA capture thread\n");
- alsa_in_threaded.start();
+ input = &alsa_in_threaded;
}
else {
- if (alsa_in_direct.prepare() != 0) {
- fprintf(stderr, "Alsa preparation failed\n");
- return 1;
- }
+ input = &alsa_in_direct;
}
-#else
- else {
+#endif
+
+ if (input == nullptr) {
fprintf(stderr, "No input defined\n");
return 1;
}
-#endif
+ else {
+ input->prepare();
+ }
int outbuf_size;
vec_u8 zmqframebuf;
@@ -1020,7 +999,7 @@ int main(int argc, char *argv[])
* \c drift_compensation_delay() function handles rate throttling.
*/
- if (infile) {
+ if (not infile.empty()) {
read_bytes = file_in.read(&input_buf[0], input_buf.size());
if (read_bytes < 0) {
break;
@@ -1086,7 +1065,7 @@ int main(int argc, char *argv[])
}
}
#endif
- else if (drift_compensation || jack_name) {
+ else if (drift_compensation or not jack_name.empty()) {
#if HAVE_ALSA
if (drift_compensation && alsa_in_threaded.fault_detected()) {
fprintf(stderr, "Detected fault in alsa input!\n");