| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // 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                  //
 | 
					
						
							| 
									
										
										
										
											2019-04-11 14:32:15 +02:00
										 |  |  | // (at your option) any later version.                                           //
 | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // 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 <http://www.gnu.org/licenses/>.          //
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <QAudioFormat>
 | 
					
						
							|  |  |  | #include <QAudioDeviceInfo>
 | 
					
						
							|  |  |  | #include <QAudioInput>
 | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  | #include "audio/audioinputdevice.h"
 | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | #include "audio/audiofifo.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  | AudioInputDevice::AudioInputDevice() : | 
					
						
							| 
									
										
										
										
											2018-01-06 06:12:30 +01:00
										 |  |  | 	m_mutex(QMutex::Recursive), | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | 	m_audioInput(0), | 
					
						
							|  |  |  | 	m_audioUsageCount(0), | 
					
						
							|  |  |  | 	m_onExit(false), | 
					
						
							| 
									
										
										
										
											2017-01-06 15:28:01 +01:00
										 |  |  | 	m_volume(0.5f), | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | 	m_audioFifos() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  | AudioInputDevice::~AudioInputDevice() | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	stop(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-24 04:18:58 +01:00
										 |  |  | 	for (std::list<AudioFifo*>::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it) | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		delete *it; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_audioFifos.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  | bool AudioInputDevice::start(int device, int rate) | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (m_audioUsageCount == 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-01-06 06:12:30 +01:00
										 |  |  |         QMutexLocker mutexLocker(&m_mutex); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  |         QAudioDeviceInfo devInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (device < 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             devInfo = QAudioDeviceInfo::defaultInputDevice(); | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  |             qWarning("AudioInputDevice::start: using default device %s", qPrintable(devInfo.defaultInputDevice().deviceName())); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             QList<QAudioDeviceInfo> devicesInfo = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (device < devicesInfo.size()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 devInfo = devicesInfo[device]; | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  |                 qWarning("AudioInputDevice::start: using audio device #%d: %s", device, qPrintable(devInfo.deviceName())); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 devInfo = QAudioDeviceInfo::defaultInputDevice(); | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  |                 qWarning("AudioInputDevice::start: audio device #%d does not exist. Using default device %s", device, qPrintable(devInfo.deviceName())); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //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); | 
					
						
							| 
									
										
										
										
											2018-11-19 02:33:44 +01:00
										 |  |  |         m_audioFormat.setSampleType(QAudioFormat::SignedInt); // Unknown, SignedInt, UnSignedInt, Float
 | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (!devInfo.isFormatSupported(m_audioFormat)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             m_audioFormat = devInfo.nearestFormat(m_audioFormat); | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  |             qWarning("AudioInputDevice::start: %d Hz S16_LE audio format not supported. Nearest is sampleRate: %d channelCount: %d sampleSize: %d sampleType: %d", | 
					
						
							| 
									
										
										
										
											2018-11-19 02:33:44 +01:00
										 |  |  |                     rate, m_audioFormat.sampleRate(), m_audioFormat.channelCount(), m_audioFormat.sampleSize(), (int) m_audioFormat.sampleType()); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-08-06 02:26:34 +02:00
										 |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  |             qInfo("AudioInputDevice::start: audio format OK"); | 
					
						
							| 
									
										
										
										
											2017-08-06 02:26:34 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (m_audioFormat.sampleSize() != 16) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  |             qWarning("AudioInputDevice::start: Audio device '%s' failed", qPrintable(devInfo.defaultInputDevice().deviceName())); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         m_audioInput = new QAudioInput(devInfo, m_audioFormat); | 
					
						
							| 
									
										
										
										
											2017-01-06 15:28:01 +01:00
										 |  |  |         m_audioInput->setVolume(m_volume); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         QIODevice::open(QIODevice::ReadWrite); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         m_audioInput->start(this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (m_audioInput->state() != QAudio::ActiveState) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  |             qWarning("AudioInputDevice::start: cannot start"); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_audioUsageCount++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  | void AudioInputDevice::stop() | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  |     qDebug("AudioInputDevice::stop"); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (m_audioUsageCount > 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         m_audioUsageCount--; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (m_audioUsageCount == 0) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  |             qDebug("AudioInputDevice::stop: effectively close QIODevice"); | 
					
						
							| 
									
										
										
										
											2018-01-06 06:12:30 +01:00
										 |  |  |             QMutexLocker mutexLocker(&m_mutex); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  |             QIODevice::close(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!m_onExit) { | 
					
						
							|  |  |  |                 delete m_audioInput; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  | void AudioInputDevice::addFifo(AudioFifo* audioFifo) | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_audioFifos.push_back(audioFifo); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  | void AudioInputDevice::removeFifo(AudioFifo* audioFifo) | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_audioFifos.remove(audioFifo); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  | qint64 AudioInputDevice::readData(char* data, qint64 maxLen) | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	Q_UNUSED(data); | 
					
						
							|  |  |  | 	Q_UNUSED(maxLen); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  | qint64 AudioInputDevice::writeData(const char *data, qint64 len) | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     // Study this mutex on OSX, for now deadlocks possible
 | 
					
						
							|  |  |  |     // Removed as it may indeed cause lockups and is in fact useless.
 | 
					
						
							|  |  |  | //#ifndef __APPLE__
 | 
					
						
							|  |  |  | //    QMutexLocker mutexLocker(&m_mutex);
 | 
					
						
							|  |  |  | //#endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((m_audioFormat.sampleSize() != 16) | 
					
						
							|  |  |  |     		|| (m_audioFormat.sampleType() != QAudioFormat::SignedInt) | 
					
						
							|  |  |  | 			|| (m_audioFormat.byteOrder() != QAudioFormat::LittleEndian)) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  |     	qCritical("AudioInputDevice::writeData: invalid format not S16LE"); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  |     	return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (m_audioFormat.channelCount() != 2) { | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  |     	qCritical("AudioInputDevice::writeData: invalid format not stereo"); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  |     	return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-24 04:18:58 +01:00
										 |  |  | 	for (std::list<AudioFifo*>::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it) | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-09-12 15:30:53 +02:00
										 |  |  | 		(*it)->write(reinterpret_cast<const quint8*>(data), len/4); | 
					
						
							| 
									
										
										
										
											2016-12-25 20:04:19 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return len; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 20:30:34 +01:00
										 |  |  | void AudioInputDevice::setVolume(float volume) | 
					
						
							| 
									
										
										
										
											2020-11-09 15:52:25 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     m_volume = volume; | 
					
						
							|  |  |  |     if (m_audioInput != nullptr) | 
					
						
							|  |  |  |          m_audioInput->setVolume(m_volume); | 
					
						
							|  |  |  | } |