From 68ee7799a4eeb4148cd4628113ebf9ea3f94a211 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sat, 7 Oct 2017 10:31:04 +0200 Subject: Make all inputs use the same interface --- src/AlsaInput.cpp | 70 +++++++++++++++++++---------------- src/AlsaInput.h | 70 ++++++++++++++++++----------------- src/FileInput.cpp | 68 +++++++++++++++++----------------- src/FileInput.h | 34 ++++++++--------- src/InputInterface.h | 34 +++++++++++++++++ src/JackInput.cpp | 42 +++++++++++---------- src/JackInput.h | 32 ++++++---------- src/VLCInput.cpp | 101 ++++++++++++++++++++++++++------------------------- src/VLCInput.h | 29 ++++++--------- src/odr-audioenc.cpp | 73 +++++++++++++------------------------ 10 files changed, 281 insertions(+), 272 deletions(-) create mode 100644 src/InputInterface.h (limited to 'src') 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 +#include #include #include #include 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 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 #include - +#include #include -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 -#include +#include +#include +#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 +#include + +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 #include @@ -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& 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 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 -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 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 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 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"); -- cgit v1.2.3