diff --git a/CMakeLists.txt b/CMakeLists.txt
index db8215811..c7639a793 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -94,6 +94,7 @@ set(sdrbase_SOURCES
sdrbase/audio/audiodeviceinfo.cpp
sdrbase/audio/audiofifo.cpp
sdrbase/audio/audiooutput.cpp
+ sdrbase/audio/audioinput.cpp
sdrbase/dsp/afsquelch.cpp
sdrbase/dsp/agc.cpp
@@ -185,6 +186,7 @@ set(sdrbase_HEADERS
sdrbase/audio/audiodeviceinfo.h
sdrbase/audio/audiofifo.h
sdrbase/audio/audiooutput.h
+ sdrbase/audio/audioinput.h
sdrbase/dsp/afsquelch.h
sdrbase/dsp/downchannelizer.h
diff --git a/sdrbase/audio/audioinput.cpp b/sdrbase/audio/audioinput.cpp
new file mode 100644
index 000000000..2476d779a
--- /dev/null
+++ b/sdrbase/audio/audioinput.cpp
@@ -0,0 +1,183 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 Edouard Griffiths, F4EXB //
+// //
+// 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 as version 3 of the License, or //
+// //
+// 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 V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include
+#include "audio/audioinput.h"
+#include "audio/audiofifo.h"
+
+AudioInput::AudioInput() :
+ m_mutex(),
+ m_audioInput(0),
+ m_audioUsageCount(0),
+ m_onExit(false),
+ m_audioFifos()
+{
+}
+
+AudioInput::~AudioInput()
+{
+ stop();
+
+ QMutexLocker mutexLocker(&m_mutex);
+
+ for (AudioFifos::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it)
+ {
+ delete *it;
+ }
+
+ m_audioFifos.clear();
+}
+
+bool AudioInput::start(int device, int rate)
+{
+ QMutexLocker mutexLocker(&m_mutex);
+
+ if (m_audioUsageCount == 0)
+ {
+ QAudioDeviceInfo devInfo;
+
+ if (device < 0)
+ {
+ devInfo = QAudioDeviceInfo::defaultInputDevice();
+ qWarning("AudioInput::start: using default device %s", qPrintable(devInfo.defaultInputDevice().deviceName()));
+ }
+ else
+ {
+ QList devicesInfo = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
+
+ if (device < devicesInfo.size())
+ {
+ devInfo = devicesInfo[device];
+ qWarning("AudioInput::start: using audio device #%d: %s", device, qPrintable(devInfo.defaultInputDevice().deviceName()));
+ }
+ else
+ {
+ devInfo = QAudioDeviceInfo::defaultInputDevice();
+ qWarning("AudioInput::start: audio device #%d does not exist. Using default device %s", device, qPrintable(devInfo.defaultInputDevice().deviceName()));
+ }
+ }
+
+ //QAudioDeviceInfo devInfo(QAudioDeviceInfo::defaultOutputDevice());
+
+ m_audioFormat.setSampleRate(rate);
+ m_audioFormat.setChannelCount(2);
+ m_audioFormat.setSampleSize(16);
+ m_audioFormat.setCodec("audio/pcm");
+ m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);
+ m_audioFormat.setSampleType(QAudioFormat::SignedInt);
+
+ if (!devInfo.isFormatSupported(m_audioFormat))
+ {
+ m_audioFormat = devInfo.nearestFormat(m_audioFormat);
+ qWarning("AudioInput::start: %d Hz S16_LE audio format not supported. New rate: %d", rate, m_audioFormat.sampleRate());
+ }
+
+ if (m_audioFormat.sampleSize() != 16)
+ {
+ qWarning("AudioInput::start: Audio device ( %s ) failed", qPrintable(devInfo.defaultInputDevice().deviceName()));
+ return false;
+ }
+
+ m_audioInput = new QAudioInput(devInfo, m_audioFormat);
+
+ QIODevice::open(QIODevice::ReadOnly);
+
+ m_audioInput->start(this);
+
+ if (m_audioInput->state() != QAudio::ActiveState)
+ {
+ qWarning("AudioInput::start: cannot start");
+ }
+ }
+
+ m_audioUsageCount++;
+
+ return true;
+}
+
+void AudioInput::stop()
+{
+ qDebug("AudioInput::stop");
+
+ QMutexLocker mutexLocker(&m_mutex);
+
+ if (m_audioUsageCount > 0)
+ {
+ m_audioUsageCount--;
+
+ if (m_audioUsageCount == 0)
+ {
+ QIODevice::close();
+
+ if (!m_onExit) {
+ delete m_audioInput;
+ }
+ }
+ }
+}
+
+void AudioInput::addFifo(AudioFifo* audioFifo)
+{
+ QMutexLocker mutexLocker(&m_mutex);
+
+ m_audioFifos.push_back(audioFifo);
+}
+
+void AudioInput::removeFifo(AudioFifo* audioFifo)
+{
+ QMutexLocker mutexLocker(&m_mutex);
+
+ m_audioFifos.remove(audioFifo);
+}
+
+qint64 AudioInput::readData(char* data, qint64 maxLen)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(maxLen);
+ return 0;
+}
+
+qint64 AudioInput::writeData(const char *data, qint64 len)
+{
+ // @TODO: Study this mutex on OSX, for now deadlocks possible
+#ifndef __APPLE__
+ QMutexLocker mutexLocker(&m_mutex);
+#endif
+
+ if ((m_audioFormat.sampleSize() != 16)
+ || (m_audioFormat.sampleType() != QAudioFormat::SignedInt)
+ || (m_audioFormat.byteOrder() != QAudioFormat::LittleEndian))
+ {
+ qCritical("AudioInput::writeData: invalid format not S16LE");
+ return 0;
+ }
+
+ if (m_audioFormat.channelCount() != 2) {
+ qCritical("AudioInput::writeData: invalid format not stereo");
+ return 0;
+ }
+
+ for (AudioFifos::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it)
+ {
+ (*it)->write(reinterpret_cast(data), len/4, 10);
+ }
+
+ return len;
+}
+
diff --git a/sdrbase/audio/audioinput.h b/sdrbase/audio/audioinput.h
new file mode 100644
index 000000000..196ae0459
--- /dev/null
+++ b/sdrbase/audio/audioinput.h
@@ -0,0 +1,67 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 Edouard Griffiths, F4EXB //
+// //
+// 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 as version 3 of the License, or //
+// //
+// 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 V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SDRBASE_AUDIO_AUDIOINPUT_H_
+#define SDRBASE_AUDIO_AUDIOINPUT_H_
+
+#include
+#include
+#include
+#include
+#include
+#include "util/export.h"
+
+class QAudioInput;
+class AudioFifo;
+class AudioOutputPipe;
+
+
+class SDRANGEL_API AudioInput : public QIODevice {
+public:
+ AudioInput();
+ virtual ~AudioInput();
+
+ bool start(int device, int rate);
+ void stop();
+
+ void addFifo(AudioFifo* audioFifo);
+ void removeFifo(AudioFifo* audioFifo);
+
+ uint getRate() const { return m_audioFormat.sampleRate(); }
+ void setOnExit(bool onExit) { m_onExit = onExit; }
+
+private:
+ QMutex m_mutex;
+ QAudioInput* m_audioInput;
+ uint m_audioUsageCount;
+ bool m_onExit;
+
+ typedef std::list AudioFifos;
+ AudioFifos m_audioFifos;
+ std::vector m_mixBuffer;
+
+ QAudioFormat m_audioFormat;
+
+ //virtual bool open(OpenMode mode);
+ virtual qint64 readData(char* data, qint64 maxLen);
+ virtual qint64 writeData(const char* data, qint64 len);
+
+ friend class AudioOutputPipe;
+};
+
+
+
+#endif /* SDRBASE_AUDIO_AUDIOINPUT_H_ */
diff --git a/sdrbase/sdrbase.pro b/sdrbase/sdrbase.pro
index 10bce8e2c..b62db5bce 100644
--- a/sdrbase/sdrbase.pro
+++ b/sdrbase/sdrbase.pro
@@ -34,6 +34,7 @@ SOURCES += mainwindow.cpp\
audio/audiodeviceinfo.cpp\
audio/audiofifo.cpp\
audio/audiooutput.cpp\
+ audio/audioinput.cpp\
device/devicesourceapi.cpp\
device/devicesinkapi.cpp\
dsp/afsquelch.cpp\
@@ -116,6 +117,7 @@ HEADERS += mainwindow.h\
audio/audiodeviceinfo.h\
audio/audiofifo.h\
audio/audiooutput.h\
+ audio/audioinput.h\
device/devicesourceapi.h\
device/devicesinkapi.h\
dsp/afsquelch.h\