diff options
author | Scott Murray <scott.murray@konsulko.com> | 2017-04-02 12:49:28 -0400 |
---|---|---|
committer | Scott Murray <scott.murray@konsulko.com> | 2017-04-10 09:21:36 -0400 |
commit | aeb67506173a7b8cef089fa725c3abe1f629dc67 (patch) | |
tree | ef427cbebb92d873d9a2903445c32320ab20c8eb /radio_output.cpp | |
parent | a30670cd12e03dc874d2f22c48f497817c78ecdc (diff) |
Switch to using Qt's QAudioOutput for outputHEADflounder_5.99.1flounder/5.99.1dab_3.99.1dab/3.99.15.99.13.99.1master
The underlying issue in the hang reported in SPEC-455 is that due to
the synchronous nature of the pa_simple_* PulseAudio API, the
pa_simple_write call used blocks when a stream is corked . That
prevents the tuner plugin's output thread from exiting when playback is
stopped, resulting in the observed hang. After examining the available
options, it seemed like switching to Qt's QAudioOutput class made sense
since it allows using the asynchronous PulseAudio API easily, and like
the QRadio class the tuner plugin implements, it is part of QtMultimedia
itself.
Note that the radio_output.* files have been removed as the code is no
longer used, and a new pair of OutputBuffer source files have been added
to contain the small class that is used to connect the RTL-SDR output to
QAudioOutput.
Bug-AGL: SPEC-455
Change-Id: I0d690143b9c70fdca24f9fbf3b016feef8ae627b
Signed-off-by: Scott Murray <scott.murray@konsulko.com>
Diffstat (limited to 'radio_output.cpp')
-rw-r--r-- | radio_output.cpp | 152 |
1 files changed, 0 insertions, 152 deletions
diff --git a/radio_output.cpp b/radio_output.cpp deleted file mode 100644 index 350bf75..0000000 --- a/radio_output.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * A standalone AM/FM Radio QML plugin (for RTL2832U and Maxim hardware) - * Copyright © 2015-2016 Manuel Bachmann <manuel.bachmann@iot.bzh> - * Copyright © 2016 Scott Murray <scott.murray@konsulko.com> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <iostream> -#include "radio_output.h" -#include "rtl_fm.h" - -RadioOutputAlsa::RadioOutputAlsa() : RadioOutputImplementation(), - dev(NULL), - hw_params(NULL) -{ - unsigned int rate = 24000; - - if (snd_pcm_open(&dev, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) { - std::cerr << "Could not open primary ALSA device" << std::endl; - works = false; - return; - } - - snd_pcm_hw_params_malloc(&hw_params); - snd_pcm_hw_params_any(dev, hw_params); - - snd_pcm_hw_params_set_access (dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); - snd_pcm_hw_params_set_format (dev, hw_params, SND_PCM_FORMAT_S16_LE); - snd_pcm_hw_params_set_rate_near (dev, hw_params, &rate, 0); - snd_pcm_hw_params_set_channels (dev, hw_params, 2); - - if (snd_pcm_hw_params (dev, hw_params) < 0) { - std::cerr << "Could not set hardware parameters" << std::endl; - works = false; - } else { - works = true; - } - snd_pcm_hw_params_free (hw_params); - - snd_pcm_prepare (dev); -} - -RadioOutputAlsa::~RadioOutputAlsa() -{ - snd_pcm_close (dev); -} - -bool RadioOutputAlsa::play(void *buf, int len) -{ - int16_t *cbuf = (int16_t *)buf; - int frames = len / 2; - int res; - - if ((res = snd_pcm_writei(dev, cbuf, frames)) != frames) { - snd_pcm_recover(dev, res, 0); - snd_pcm_prepare(dev); - } - //snd_pcm_drain(dev); - - return true; -} - - -RadioOutputPulse::RadioOutputPulse() : RadioOutputImplementation(), - pa(NULL), - pa_spec(NULL) -{ - int error; - - pa_spec = (pa_sample_spec*) malloc(sizeof(pa_sample_spec)); - pa_spec->format = PA_SAMPLE_S16LE; - pa_spec->rate = 24000; - pa_spec->channels = 2; - - if (!(pa = pa_simple_new(NULL, "qtmultimedia-rtlfm-radio-plugin", PA_STREAM_PLAYBACK, NULL, - "radio-output", pa_spec, NULL, NULL, &error))) { - std::cerr << "Error connecting to PulseAudio : " << pa_strerror(error) << std::endl; - works = false; - } else { - std::cerr << "RadioOutputPulse::RadioOutputPulse: Connected to PulseAudio" << std::endl; - works = true; - } - - extra = 0; - output_buf = new unsigned char[RTL_FM_MAXIMUM_BUF_LENGTH]; - - free(pa_spec); -} - -RadioOutputPulse::~RadioOutputPulse() -{ - pa_simple_free(pa); - delete [] output_buf; -} - -bool RadioOutputPulse::play(void *buf, int len) -{ - int error; - size_t n = len * 2; - void *p; - - if (!buf) { - std::cerr << "Error buf == null!" << std::endl; - return false; - } - - // Handle the rtl_fm code giving us an odd number of samples, which - // PA does not like. This extra buffer copying approach is not - // particularly efficient, but works for now. It looks feasible to - // hack in something in the demod and output thread routines in - // rtl_fm.c to handle it there if more performance is required. - p = output_buf; - if(extra) { - memcpy(output_buf, extra_buf, sizeof(int16_t)); - if((extra + len) % 2) { - // We end up with len + 1 samples, n remains the same, store the extra - memcpy(output_buf + sizeof(int16_t), buf, n - 2); - memcpy(extra_buf, ((unsigned char*) buf) + n - 2, sizeof(int16_t)); - } else { - // We end up with an extra sample - memcpy(output_buf + sizeof(int16_t), buf, n); - n += 2; - extra = 0; - } - } else if(len % 2) { - // We have an extra sample, store it, and decrease n - n -= 2; - memcpy(output_buf + sizeof(int16_t), buf, n); - memcpy(extra_buf, ((unsigned char*) buf) + n, sizeof(int16_t)); - extra = 1; - } else { - p = buf; - } - - if (pa_simple_write(pa, p, n, &error) < 0) - std::cerr << "Error writing " << n << " bytes to PulseAudio : " << pa_strerror(error) << std::endl; - //pa_simple_drain(pa, &error); - - return true; -} |