mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	Audio output device recording: implementation (1)
This commit is contained in:
		
							parent
							
								
									e89331f58f
								
							
						
					
					
						commit
						4a383e439b
					
				| @ -641,6 +641,9 @@ void AudioDeviceManager::setOutputDeviceInfo(int outputDeviceIndex, const Output | ||||
|     audioOutput->setUdpChannelMode(deviceInfo.udpChannelMode); | ||||
|     audioOutput->setUdpChannelFormat(deviceInfo.udpChannelCodec, deviceInfo.udpChannelMode == AudioOutputDevice::UDPChannelStereo, deviceInfo.sampleRate); | ||||
|     audioOutput->setUdpDecimation(deviceInfo.udpDecimationFactor); | ||||
|     audioOutput->setFileRecordName(deviceInfo.fileRecordName); | ||||
|     audioOutput->setRecordToFile(deviceInfo.recordToFile); | ||||
|     audioOutput->setRecordSilenceTime(deviceInfo.recordSilenceTime); | ||||
| 
 | ||||
|     qDebug("AudioDeviceManager::setOutputDeviceInfo: index: %d device: %s updated", | ||||
|             outputDeviceIndex, qPrintable(deviceName)); | ||||
|  | ||||
| @ -23,16 +23,22 @@ | ||||
| #include "audiooutputdevice.h" | ||||
| #include "audiofifo.h" | ||||
| #include "audionetsink.h" | ||||
| #include "dsp/wavfilerecord.h" | ||||
| 
 | ||||
| AudioOutputDevice::AudioOutputDevice() : | ||||
| 	m_audioOutput(0), | ||||
| 	m_audioNetSink(0), | ||||
| 	m_audioOutput(nullptr), | ||||
| 	m_audioNetSink(nullptr), | ||||
|     m_wavFileRecord(nullptr), | ||||
|     m_copyAudioToUdp(false), | ||||
| 	m_udpChannelMode(UDPChannelLeft), | ||||
| 	m_udpChannelCodec(UDPCodecL16), | ||||
| 	m_audioUsageCount(0), | ||||
| 	m_onExit(false), | ||||
| 	m_volume(1.0), | ||||
|     m_recordToFile(false), | ||||
|     m_recordSilenceTime(0), | ||||
|     m_recordSilenceNbSamples(0), | ||||
|     m_recordSilenceCount(0), | ||||
| 	m_audioFifos() | ||||
| { | ||||
| } | ||||
| @ -114,14 +120,15 @@ bool AudioOutputDevice::start(int device, int rate) | ||||
| 
 | ||||
|         m_audioOutput = new QAudioOutput(devInfo, m_audioFormat); | ||||
|         m_audioNetSink = new AudioNetSink(0, m_audioFormat.sampleRate(), false); | ||||
|         m_wavFileRecord = new WavFileRecord(m_audioFormat.sampleRate()); | ||||
| 		m_audioOutput->setVolume(m_volume); | ||||
|         m_recordSilenceNbSamples = (m_recordSilenceTime * m_audioFormat.sampleRate()) / 10; // time in 100'ś ms
 | ||||
| 
 | ||||
|         QIODevice::open(QIODevice::ReadOnly); | ||||
| 
 | ||||
|         m_audioOutput->start(this); | ||||
| 
 | ||||
|         if (m_audioOutput->state() != QAudio::ActiveState) | ||||
|         { | ||||
|         if (m_audioOutput->state() != QAudio::ActiveState) { | ||||
|             qWarning("AudioOutputDevice::start: cannot start"); | ||||
|         } | ||||
| //	}
 | ||||
| @ -139,8 +146,11 @@ void AudioOutputDevice::stop() | ||||
|     m_audioOutput->stop(); | ||||
|     QIODevice::close(); | ||||
|     delete m_audioNetSink; | ||||
|     m_audioNetSink = 0; | ||||
|     m_audioNetSink = nullptr; | ||||
|     delete m_wavFileRecord; | ||||
|     m_wavFileRecord = nullptr; | ||||
|     delete m_audioOutput; | ||||
|     m_audioOutput = nullptr; | ||||
| 
 | ||||
| //    if (m_audioUsageCount > 0)
 | ||||
| //    {
 | ||||
| @ -161,14 +171,12 @@ void AudioOutputDevice::stop() | ||||
| void AudioOutputDevice::addFifo(AudioFifo* audioFifo) | ||||
| { | ||||
| 	QMutexLocker mutexLocker(&m_mutex); | ||||
| 
 | ||||
| 	m_audioFifos.push_back(audioFifo); | ||||
| } | ||||
| 
 | ||||
| void AudioOutputDevice::removeFifo(AudioFifo* audioFifo) | ||||
| { | ||||
| 	QMutexLocker mutexLocker(&m_mutex); | ||||
| 
 | ||||
| 	m_audioFifos.remove(audioFifo); | ||||
| } | ||||
| 
 | ||||
| @ -219,6 +227,63 @@ void AudioOutputDevice::setUdpDecimation(uint32_t decimation) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void AudioOutputDevice::setFileRecordName(const QString& fileRecordName) | ||||
| { | ||||
|     if (!m_wavFileRecord) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     QStringList dotBreakout = fileRecordName.split(QLatin1Char('.')); | ||||
| 
 | ||||
|     if (dotBreakout.size() > 1) { | ||||
|         QString extension = dotBreakout.last(); | ||||
| 
 | ||||
|         if (extension != "wav") { | ||||
|             dotBreakout.last() = "wav"; | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         dotBreakout.append("wav"); | ||||
|     } | ||||
| 
 | ||||
|     QString newFileRecordName = dotBreakout.join(QLatin1Char('.')); | ||||
|     QString fileBase; | ||||
|     FileRecordInterface::guessTypeFromFileName(newFileRecordName, fileBase); | ||||
|     qDebug("AudioOutputDevice::setFileRecordName: newFileRecordName: %s fileBase: %s", qPrintable(newFileRecordName), qPrintable(fileBase)); | ||||
|     m_wavFileRecord->setFileName(fileBase); | ||||
| } | ||||
| 
 | ||||
| void AudioOutputDevice::setRecordToFile(bool recordToFile) | ||||
| { | ||||
|     if (!m_wavFileRecord) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (recordToFile) | ||||
|     { | ||||
|         if (!m_wavFileRecord->isRecording()) { | ||||
|             m_wavFileRecord->startRecording(); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         if (m_wavFileRecord->isRecording()) { | ||||
|             m_wavFileRecord->stopRecording(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     m_recordToFile = recordToFile; | ||||
|     m_recordSilenceCount = 0; | ||||
| } | ||||
| 
 | ||||
| void AudioOutputDevice::setRecordSilenceTime(int recordSilenceTime) | ||||
| { | ||||
|     m_recordSilenceNbSamples = (recordSilenceTime * m_audioFormat.sampleRate()) / 10; // time in 100'ś ms
 | ||||
|     m_recordSilenceCount = 0; | ||||
|     m_recordSilenceTime = recordSilenceTime; | ||||
| } | ||||
| 
 | ||||
| qint64 AudioOutputDevice::readData(char* data, qint64 maxLen) | ||||
| { | ||||
|     //qDebug("AudioOutputDevice::readData: %lld", maxLen);
 | ||||
| @ -331,6 +396,36 @@ qint64 AudioOutputDevice::readData(char* data, qint64 maxLen) | ||||
| 	            break; | ||||
| 	        } | ||||
| 		} | ||||
| 
 | ||||
|         if ((m_recordToFile) && (m_wavFileRecord)) | ||||
|         { | ||||
|             if ((sr == 0) && (sl == 0)) | ||||
|             { | ||||
|                 if (m_recordSilenceNbSamples <= 0) | ||||
|                 { | ||||
|                     m_wavFileRecord->write(sl, sr); | ||||
|                     m_recordSilenceCount = 0; | ||||
|                 } | ||||
|                 else if (m_recordSilenceCount < m_recordSilenceNbSamples) | ||||
|                 { | ||||
|                     m_wavFileRecord->write(sl, sr); | ||||
|                     m_recordSilenceCount++; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     m_wavFileRecord->stopRecording(); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (!m_wavFileRecord->isRecording()) { | ||||
|                     m_wavFileRecord->startRecording(); | ||||
|                 } | ||||
| 
 | ||||
|                 m_wavFileRecord->write(sl, sr); | ||||
|                 m_recordSilenceCount = 0; | ||||
|             } | ||||
|         } | ||||
| 	} | ||||
| 
 | ||||
| 	return samplesPerBuffer * 4; | ||||
|  | ||||
| @ -31,6 +31,7 @@ class QAudioOutput; | ||||
| class AudioFifo; | ||||
| class AudioOutputPipe; | ||||
| class AudioNetSink; | ||||
| class WavFileRecord; | ||||
| 
 | ||||
| class SDRBASE_API AudioOutputDevice : QIODevice { | ||||
| public: | ||||
| @ -72,17 +73,26 @@ public: | ||||
| 	void setUdpChannelFormat(UDPChannelCodec udpChannelCodec, bool stereo, int sampleRate); | ||||
| 	void setUdpDecimation(uint32_t decimation); | ||||
| 	void setVolume(float volume); | ||||
|     void setFileRecordName(const QString& fileRecordName); | ||||
|     void setRecordToFile(bool recordToFile); | ||||
|     void setRecordSilenceTime(int recordSilenceTime); | ||||
| 
 | ||||
| private: | ||||
| 	QRecursiveMutex m_mutex; | ||||
| 	QAudioOutput* m_audioOutput; | ||||
| 	AudioNetSink* m_audioNetSink; | ||||
|     WavFileRecord* m_wavFileRecord; | ||||
| 	bool m_copyAudioToUdp; | ||||
| 	UDPChannelMode m_udpChannelMode; | ||||
| 	UDPChannelCodec m_udpChannelCodec; | ||||
| 	uint m_audioUsageCount; | ||||
| 	bool m_onExit; | ||||
| 	float m_volume; | ||||
|     QString m_fileRecordName; | ||||
|     bool m_recordToFile; | ||||
|     int m_recordSilenceTime; | ||||
|     int m_recordSilenceNbSamples; | ||||
|     int m_recordSilenceCount; | ||||
| 
 | ||||
| 	std::list<AudioFifo*> m_audioFifos; | ||||
| 	std::vector<qint32> m_mixBuffer; | ||||
|  | ||||
| @ -111,6 +111,19 @@ void WavFileRecord::feed(const SampleVector::const_iterator& begin, const Sample | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void WavFileRecord::write(qint16 lSample, qint16 rSample) | ||||
| { | ||||
|     if (m_recordStart) | ||||
|     { | ||||
|         writeHeader(); | ||||
|         m_recordStart = false; | ||||
|     } | ||||
| 
 | ||||
|     m_sampleFile.write(reinterpret_cast<const char*>(&lSample), 2); | ||||
|     m_sampleFile.write(reinterpret_cast<const char*>(&rSample), 2); | ||||
|     m_byteCount += 4; | ||||
| } | ||||
| 
 | ||||
| void WavFileRecord::start() | ||||
| { | ||||
| } | ||||
|  | ||||
| @ -97,6 +97,7 @@ public: | ||||
|     void genUniqueFileName(uint deviceUID, int istream = -1); | ||||
| 
 | ||||
|     virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly) override; | ||||
|     void write(qint16 lSample, qint16 rSample); //!< write a single sample
 | ||||
|     virtual void start() override; | ||||
|     virtual void stop() override; | ||||
|     virtual bool handleMessage(const Message& message) override; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user