SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
audioinput.cpp
Go to the documentation of this file.
1 // Copyright (C) 2016 Edouard Griffiths, F4EXB //
3 // //
4 // This program is free software; you can redistribute it and/or modify //
5 // it under the terms of the GNU General Public License as published by //
6 // the Free Software Foundation as version 3 of the License, or //
7 // (at your option) any later version. //
8 // //
9 // This program is distributed in the hope that it will be useful, //
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
12 // GNU General Public License V3 for more details. //
13 // //
14 // You should have received a copy of the GNU General Public License //
15 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
17 
18 #include <string.h>
19 #include <QAudioFormat>
20 #include <QAudioDeviceInfo>
21 #include <QAudioInput>
22 #include "audio/audioinput.h"
23 #include "audio/audiofifo.h"
24 
26  m_mutex(QMutex::Recursive),
27  m_audioInput(0),
28  m_audioUsageCount(0),
29  m_onExit(false),
30  m_volume(0.5f),
31  m_audioFifos()
32 {
33 }
34 
36 {
37  stop();
38 
39  QMutexLocker mutexLocker(&m_mutex);
40 
41  for (std::list<AudioFifo*>::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it)
42  {
43  delete *it;
44  }
45 
46  m_audioFifos.clear();
47 }
48 
49 bool AudioInput::start(int device, int rate)
50 {
51  if (m_audioUsageCount == 0)
52  {
53  QMutexLocker mutexLocker(&m_mutex);
54  QAudioDeviceInfo devInfo;
55 
56  if (device < 0)
57  {
58  devInfo = QAudioDeviceInfo::defaultInputDevice();
59  qWarning("AudioInput::start: using default device %s", qPrintable(devInfo.defaultInputDevice().deviceName()));
60  }
61  else
62  {
63  QList<QAudioDeviceInfo> devicesInfo = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
64 
65  if (device < devicesInfo.size())
66  {
67  devInfo = devicesInfo[device];
68  qWarning("AudioInput::start: using audio device #%d: %s", device, qPrintable(devInfo.deviceName()));
69  }
70  else
71  {
72  devInfo = QAudioDeviceInfo::defaultInputDevice();
73  qWarning("AudioInput::start: audio device #%d does not exist. Using default device %s", device, qPrintable(devInfo.deviceName()));
74  }
75  }
76 
77  //QAudioDeviceInfo devInfo(QAudioDeviceInfo::defaultOutputDevice());
78 
79  m_audioFormat.setSampleRate(rate);
80  m_audioFormat.setChannelCount(2);
81  m_audioFormat.setSampleSize(16);
82  m_audioFormat.setCodec("audio/pcm");
83  m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);
84  m_audioFormat.setSampleType(QAudioFormat::SignedInt); // Unknown, SignedInt, UnSignedInt, Float
85 
86  if (!devInfo.isFormatSupported(m_audioFormat))
87  {
88  m_audioFormat = devInfo.nearestFormat(m_audioFormat);
89  qWarning("AudioInput::start: %d Hz S16_LE audio format not supported. Nearest is sampleRate: %d channelCount: %d sampleSize: %d sampleType: %d",
90  rate, m_audioFormat.sampleRate(), m_audioFormat.channelCount(), m_audioFormat.sampleSize(), (int) m_audioFormat.sampleType());
91  }
92  else
93  {
94  qInfo("AudioInput::start: audio format OK");
95  }
96 
97  if (m_audioFormat.sampleSize() != 16)
98  {
99  qWarning("AudioInput::start: Audio device '%s' failed", qPrintable(devInfo.defaultInputDevice().deviceName()));
100  return false;
101  }
102 
103  m_audioInput = new QAudioInput(devInfo, m_audioFormat);
104  m_audioInput->setVolume(m_volume);
105 
106  QIODevice::open(QIODevice::ReadWrite);
107 
108  m_audioInput->start(this);
109 
110  if (m_audioInput->state() != QAudio::ActiveState)
111  {
112  qWarning("AudioInput::start: cannot start");
113  }
114  }
115 
117 
118  return true;
119 }
120 
122 {
123  qDebug("AudioInput::stop");
124 
125  if (m_audioUsageCount > 0)
126  {
128 
129  if (m_audioUsageCount == 0)
130  {
131  qDebug("AudioInput::stop: effectively close QIODevice");
132  QMutexLocker mutexLocker(&m_mutex);
133  QIODevice::close();
134 
135  if (!m_onExit) {
136  delete m_audioInput;
137  }
138  }
139  }
140 }
141 
143 {
144  QMutexLocker mutexLocker(&m_mutex);
145 
146  m_audioFifos.push_back(audioFifo);
147 }
148 
150 {
151  QMutexLocker mutexLocker(&m_mutex);
152 
153  m_audioFifos.remove(audioFifo);
154 }
155 
156 qint64 AudioInput::readData(char* data, qint64 maxLen)
157 {
158  Q_UNUSED(data);
159  Q_UNUSED(maxLen);
160  return 0;
161 }
162 
163 qint64 AudioInput::writeData(const char *data, qint64 len)
164 {
165  // Study this mutex on OSX, for now deadlocks possible
166  // Removed as it may indeed cause lockups and is in fact useless.
167 //#ifndef __APPLE__
168 // QMutexLocker mutexLocker(&m_mutex);
169 //#endif
170 
171  if ((m_audioFormat.sampleSize() != 16)
172  || (m_audioFormat.sampleType() != QAudioFormat::SignedInt)
173  || (m_audioFormat.byteOrder() != QAudioFormat::LittleEndian))
174  {
175  qCritical("AudioInput::writeData: invalid format not S16LE");
176  return 0;
177  }
178 
179  if (m_audioFormat.channelCount() != 2) {
180  qCritical("AudioInput::writeData: invalid format not stereo");
181  return 0;
182  }
183 
184  for (std::list<AudioFifo*>::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it)
185  {
186  (*it)->write(reinterpret_cast<const quint8*>(data), len/4);
187  }
188 
189  return len;
190 }
191 
uint m_audioUsageCount
Definition: audioinput.h:52
virtual ~AudioInput()
Definition: audioinput.cpp:35
float m_volume
Definition: audioinput.h:54
std::list< AudioFifo * > m_audioFifos
Definition: audioinput.h:56
QMutex m_mutex
Definition: audioinput.h:50
bool m_onExit
Definition: audioinput.h:53
QAudioFormat m_audioFormat
Definition: audioinput.h:59
bool start(int device, int rate)
Definition: audioinput.cpp:49
QAudioInput * m_audioInput
Definition: audioinput.h:51
void removeFifo(AudioFifo *audioFifo)
Definition: audioinput.cpp:149
void stop()
Definition: audioinput.cpp:121
virtual qint64 writeData(const char *data, qint64 len)
Definition: audioinput.cpp:163
virtual qint64 readData(char *data, qint64 maxLen)
Definition: audioinput.cpp:156
void addFifo(AudioFifo *audioFifo)
Definition: audioinput.cpp:142