summaryrefslogtreecommitdiffstats
path: root/rtlfmradiotunercontrol.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'rtlfmradiotunercontrol.cpp')
-rw-r--r--rtlfmradiotunercontrol.cpp113
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";