120 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			120 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | #include "AudioDecoder.h"
 | ||
|  | 
 | ||
|  | AudioDecoder::AudioDecoder(QObject *parent) : | ||
|  |     QIODevice(parent), | ||
|  |     m_state { AudioDecoder::Stopped }, | ||
|  |     m_input { &m_data, this }, | ||
|  |     m_output { &m_data, this }, | ||
|  |     m_init { false }, | ||
|  |     m_isDecodingFinished { false } | ||
|  | { | ||
|  |     setOpenMode(QIODevice::ReadOnly); | ||
|  | 
 | ||
|  |     m_decoder = new QAudioDecoder(this); | ||
|  |     connect(m_decoder, &QAudioDecoder::bufferReady, this, &AudioDecoder::bufferReady); | ||
|  |     connect(m_decoder, static_cast<void(QAudioDecoder::*)(QAudioDecoder::Error)>(&QAudioDecoder::error), this, &AudioDecoder::errored); | ||
|  |     connect(m_decoder, &QAudioDecoder::finished, this, &AudioDecoder::finished); | ||
|  | } | ||
|  | 
 | ||
|  | AudioDecoder::~AudioDecoder(){ | ||
|  |     stop(); | ||
|  | } | ||
|  | 
 | ||
|  | // initialize an audio device
 | ||
|  | void AudioDecoder::init(const QAudioFormat &format) { | ||
|  |     m_decoder->setAudioFormat(format); | ||
|  | 
 | ||
|  |     if (!m_output.open(QIODevice::ReadOnly) || !m_input.open(QIODevice::WriteOnly)){ | ||
|  |         m_init = false; | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     m_init = true; | ||
|  |     emit initialized(); | ||
|  | } | ||
|  | 
 | ||
|  | // play an audio file
 | ||
|  | void AudioDecoder::start(const QString &filePath){ | ||
|  |     if(!m_init){ | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     if(m_state == AudioDecoder::Decoding){ | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     m_state = AudioDecoder::Decoding; | ||
|  |     m_decoder->setSourceFilename(filePath); | ||
|  |     m_decoder->start(); | ||
|  | } | ||
|  | 
 | ||
|  | // Stop playing audio
 | ||
|  | void AudioDecoder::stop() { | ||
|  |     m_state = AudioDecoder::Stopped; | ||
|  |     m_decoder->stop(); | ||
|  |     m_data.clear(); | ||
|  |     m_isDecodingFinished = false; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // io device, read into buffer.
 | ||
|  | qint64 AudioDecoder::readData(char* data, qint64 maxlen) { | ||
|  |     memset(data, 0, maxlen); | ||
|  | 
 | ||
|  |     if (m_state == AudioDecoder::Decoding){ | ||
|  |         m_output.read(data, maxlen); | ||
|  | 
 | ||
|  |         // Emulate QAudioProbe behaviour for audio data that is sent to output device
 | ||
|  |         if (maxlen > 0){ | ||
|  |             QByteArray buff(data, maxlen); | ||
|  |             emit newData(buff); | ||
|  |         } | ||
|  | 
 | ||
|  |         // Is finish of file
 | ||
|  |         if (atEnd()){ | ||
|  |             stop(); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return maxlen; | ||
|  | } | ||
|  | 
 | ||
|  | // io device, unused.
 | ||
|  | qint64 AudioDecoder::writeData(const char* data, qint64 len) { | ||
|  |     Q_UNUSED(data); | ||
|  |     Q_UNUSED(len); | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | // io device, at end of device
 | ||
|  | bool AudioDecoder::atEnd() const { | ||
|  |     bool value = m_output.size() | ||
|  |         && m_output.atEnd() | ||
|  |         && m_isDecodingFinished; | ||
|  |     return value; | ||
|  | } | ||
|  | 
 | ||
|  | // handle buffered data ready
 | ||
|  | void AudioDecoder::bufferReady() { | ||
|  |     const QAudioBuffer &buffer = m_decoder->read(); | ||
|  |     if(!buffer.isValid()){ | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     const int length = buffer.byteCount(); | ||
|  |     const char *data = buffer.constData<char>(); | ||
|  | 
 | ||
|  |     m_input.write(data, length); | ||
|  | } | ||
|  | 
 | ||
|  | // handle buffered data decoding is finished
 | ||
|  | void AudioDecoder::finished() { | ||
|  |     m_isDecodingFinished = true; | ||
|  | } | ||
|  | 
 | ||
|  | // handle buffered data decoding error
 | ||
|  | void AudioDecoder::errored(QAudioDecoder::Error /*error*/) { | ||
|  |     stop(); | ||
|  | } |