diff options
Diffstat (limited to 'rtlfmradiotunercontrol.cpp')
-rw-r--r-- | rtlfmradiotunercontrol.cpp | 113 |
1 files changed, 78 insertions, 35 deletions
diff --git a/rtlfmradiotunercontrol.cpp b/rtlfmradiotunercontrol.cpp index 27a8d08..937411a 100644 --- a/rtlfmradiotunercontrol.cpp +++ b/rtlfmradiotunercontrol.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2016, The Qt Company Ltd. All Rights Reserved. - * Copyright (C) 2016, Scott Murray <scott.murray@konsulko.com> + * Copyright (C) 2016, 2017 Konsulko Group * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -8,12 +8,13 @@ */ #include "rtlfmradiotunercontrol.h" -#include "radio_output.h" #include "rtl_fm.h" #include <QtCore/QDebug> #include <QtCore/QTimer> #include <QtCore/QSettings> +#include <QtMultimedia/QAudioOutput> +#include "OutputBuffer.h" // Structure to describe FM band plans, all values in Hz. struct fmBandPlan { @@ -22,12 +23,23 @@ struct fmBandPlan { unsigned int freqStep; }; +// Structure to hold output context for RTL-SDR callback +struct OutputContext { + OutputBuffer *buffer; + bool muted; +}; + class RtlFmRadioTunerControl::Private { public: Private(RtlFmRadioTunerControl *parent); ~Private(); + bool muted() { return mOutputContext.muted; } + void setMuted(bool muted) { mOutputContext.muted = muted; } + void outputStart(void); + void outputStop(void); + private: RtlFmRadioTunerControl *q; @@ -38,7 +50,6 @@ public: QRadioTuner::StereoMode stereoMode; int signalStrength; int volume; - static bool muted; bool searching; QRadioTuner::Error error; QString errorString; @@ -49,6 +60,13 @@ public: struct fmBandPlan fmBandPlan; private: + void outputInit(void); + + static void rtlOutputThreadFunc(int16_t *result, int result_len, void *ctx); + + QAudioOutput* mAudioOutput; + OutputContext mOutputContext; + QMap<QString, struct fmBandPlan> knownFmBandPlans = { { QString::fromUtf8("US"), { .minFreq = 87900000, .maxFreq = 107900000, .freqStep = 200000 } }, { QString::fromUtf8("JP"), { .minFreq = 76100000, .maxFreq = 89900000, .freqStep = 100000 } }, @@ -56,14 +74,8 @@ private: { QString::fromUtf8("ITU-1"), { .minFreq = 87500000, .maxFreq = 108000000, .freqStep = 50000 } }, { QString::fromUtf8("ITU-2"), { .minFreq = 87900000, .maxFreq = 107900000, .freqStep = 50000 } } }; - - static void output_thread_fn(int16_t *result, int result_len, void *ctx); - static RadioOutputImplementation *mRadioOutput; }; -bool RtlFmRadioTunerControl::Private::muted; -RadioOutputImplementation *RtlFmRadioTunerControl::Private::mRadioOutput; - RtlFmRadioTunerControl::Private::Private(RtlFmRadioTunerControl *parent) : q(parent), state(QRadioTuner::StoppedState), @@ -76,28 +88,11 @@ RtlFmRadioTunerControl::Private::Private(RtlFmRadioTunerControl *parent) searchOne(true), step(0) { - mRadioOutput = NULL; - muted = false; - - // Initialize output - // Note that the optional ALSA support is currently not entirely - // functional and needs further debugging. - char *impl_env = getenv("RADIO_OUTPUT"); - if (impl_env) { - if (strcasecmp(impl_env, "Pulse") == 0) - mRadioOutput = new RadioOutputPulse(); - if (strcasecmp(impl_env, "Alsa") == 0) - mRadioOutput = new RadioOutputAlsa(); - } - if (!mRadioOutput) { - mRadioOutput = new RadioOutputPulse(); - if (!mRadioOutput->works) - mRadioOutput = new RadioOutputAlsa(); - } + outputInit(); // Initialize RTL-SDR dongle present = false; - if(rtl_fm_init(frequency, 200000, 48000, output_thread_fn, NULL) < 0) { + if(rtl_fm_init(frequency, 200000, 48000, rtlOutputThreadFunc, &mOutputContext) < 0) { qDebug("%s: no RTL USB adapter?", Q_FUNC_INFO); } else { present = true; @@ -132,15 +127,59 @@ RtlFmRadioTunerControl::Private::Private(RtlFmRadioTunerControl *parent) }); } -void RtlFmRadioTunerControl::Private::output_thread_fn(int16_t *result, int result_len, void *ctx) +void RtlFmRadioTunerControl::Private::outputInit(void) { - if (!muted) - mRadioOutput->play((void*) result, result_len); + // Set up the format + QAudioFormat format; + format.setSampleRate(24000); + format.setChannelCount(2); + format.setSampleSize(16); + format.setCodec("audio/pcm"); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + + QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); + if (!info.isFormatSupported(format)) { + qWarning() << "Raw audio format not supported by backend, cannot play audio."; + return; + } + + // Create output + mAudioOutput = new QAudioOutput(format); + mAudioOutput->setCategory(QString("radio")); + + // Initialize context to connect RTL-SDR library to QAudioOutput, + // including output buffer and muted state + mOutputContext.buffer = new OutputBuffer(format, q); + mOutputContext.muted = false; +} + +void RtlFmRadioTunerControl::Private::outputStart(void) +{ + mOutputContext.buffer->start(); + mAudioOutput->start(mOutputContext.buffer); +} + +void RtlFmRadioTunerControl::Private::outputStop(void) +{ + mAudioOutput->stop(); + mOutputContext.buffer->stop(); +} + +void RtlFmRadioTunerControl::Private::rtlOutputThreadFunc(int16_t *result, int result_len, void *ctx) +{ + const char *p = (const char *) result; + OutputContext *context = reinterpret_cast<OutputContext*>(ctx); + + if (!context->muted) { + context->buffer->writeData(p, result_len * 2); + } } RtlFmRadioTunerControl::Private::~Private() { - delete mRadioOutput; + delete mAudioOutput; + delete mOutputContext.buffer; rtl_fm_cleanup(); } @@ -174,6 +213,8 @@ void RtlFmRadioTunerControl::setBand(QRadioTuner::Band band) return; d->band = band; emit bandChanged(band); +#else + Q_UNUSED(band); #endif } @@ -297,14 +338,14 @@ void RtlFmRadioTunerControl::setVolume(int volume) bool RtlFmRadioTunerControl::isMuted() const { - return d->muted; + return d->muted(); } void RtlFmRadioTunerControl::setMuted(bool muted) { - if (d->muted == muted) + if (d->muted() == muted) return; - d->muted = muted; + d->setMuted(muted); emit mutedChanged(muted); } @@ -366,6 +407,7 @@ void RtlFmRadioTunerControl::start() //rtl_fm_stop(); rtl_fm_start(); + d->outputStart(); d->state = QRadioTuner::ActiveState; emit stateChanged(d->state); qDebug() << "RtlFmRadioTunerControl::start - exit\n"; @@ -383,6 +425,7 @@ void RtlFmRadioTunerControl::stop() } rtl_fm_stop(); + d->outputStop(); d->state = QRadioTuner::StoppedState; emit stateChanged(d->state); qDebug() << "RtlFmRadioTunerControl::stop - exit\n"; |