| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
 | 
					
						
							|  |  |  | // written by Christian Daniel                                                   //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // 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 <http://www.gnu.org/licenses/>.          //
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <QTime>
 | 
					
						
							|  |  |  | #include "audio/audiofifo.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MIN(x, y) ((x) < (y) ? (x) : (y))
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AudioFifo::AudioFifo() : | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	m_fifo(0) | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	m_size = 0; | 
					
						
							|  |  |  | 	m_fill = 0; | 
					
						
							|  |  |  | 	m_head = 0; | 
					
						
							|  |  |  | 	m_tail = 0; | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	m_sampleSize = 0; | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AudioFifo::AudioFifo(uint sampleSize, uint numSamples) : | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	m_fifo(0) | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	create(sampleSize, numSamples); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AudioFifo::~AudioFifo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	if (m_fifo != 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		delete[] m_fifo; | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 		m_fifo = 0; | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_writeWaitCondition.wakeOne(); | 
					
						
							|  |  |  | 	m_readWaitCondition.wakeOne(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_size = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AudioFifo::setSize(uint sampleSize, uint numSamples) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return create(sampleSize, numSamples); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-24 00:51:27 +02:00
										 |  |  | uint AudioFifo::write(const quint8* data, uint numSamples, int timeout_ms) | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	QTime time; | 
					
						
							|  |  |  | 	uint total; | 
					
						
							|  |  |  | 	uint remaining; | 
					
						
							|  |  |  | 	uint copyLen; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	if(m_fifo == 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	time.start(); | 
					
						
							|  |  |  | 	m_mutex.lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-24 00:51:27 +02:00
										 |  |  | 	if(timeout_ms == 0) | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		total = MIN(numSamples, m_size - m_fill); | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		total = numSamples; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	remaining = total; | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	while (remaining > 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (isFull()) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2015-08-24 00:51:27 +02:00
										 |  |  | 			if (time.elapsed() < timeout_ms) | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				m_writeWaitLock.lock(); | 
					
						
							|  |  |  | 				m_mutex.unlock(); | 
					
						
							| 
									
										
										
										
											2015-08-24 00:51:27 +02:00
										 |  |  | 				int ms = timeout_ms - time.elapsed(); | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				if(ms < 1) | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 					ms = 1; | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				bool ok = m_writeWaitCondition.wait(&m_writeWaitLock, ms); | 
					
						
							|  |  |  | 				m_writeWaitLock.unlock(); | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				if(!ok) | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 					return total - remaining; | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				m_mutex.lock(); | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if(m_fifo == 0) | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 					m_mutex.unlock(); | 
					
						
							|  |  |  | 					return 0; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				m_mutex.unlock(); | 
					
						
							|  |  |  | 				return total - remaining; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		copyLen = MIN(remaining, m_size - m_fill); | 
					
						
							|  |  |  | 		copyLen = MIN(copyLen, m_size - m_tail); | 
					
						
							|  |  |  | 		memcpy(m_fifo + (m_tail * m_sampleSize), data, copyLen * m_sampleSize); | 
					
						
							|  |  |  | 		m_tail += copyLen; | 
					
						
							|  |  |  | 		m_tail %= m_size; | 
					
						
							|  |  |  | 		m_fill += copyLen; | 
					
						
							|  |  |  | 		data += copyLen * m_sampleSize; | 
					
						
							|  |  |  | 		remaining -= copyLen; | 
					
						
							|  |  |  | 		m_readWaitCondition.wakeOne(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_mutex.unlock(); | 
					
						
							|  |  |  | 	return total; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-24 00:51:27 +02:00
										 |  |  | uint AudioFifo::read(quint8* data, uint numSamples, int timeout_ms) | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	QTime time; | 
					
						
							|  |  |  | 	uint total; | 
					
						
							|  |  |  | 	uint remaining; | 
					
						
							|  |  |  | 	uint copyLen; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	if(m_fifo == 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	time.start(); | 
					
						
							|  |  |  | 	m_mutex.lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-24 00:51:27 +02:00
										 |  |  | 	if(timeout_ms == 0) | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		total = MIN(numSamples, m_fill); | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		total = numSamples; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	remaining = total; | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	while(remaining > 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if(isEmpty()) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2015-08-24 00:51:27 +02:00
										 |  |  | 			if(time.elapsed() < timeout_ms) | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				m_readWaitLock.lock(); | 
					
						
							|  |  |  | 				m_mutex.unlock(); | 
					
						
							| 
									
										
										
										
											2015-08-24 00:51:27 +02:00
										 |  |  | 				int ms = timeout_ms - time.elapsed(); | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				if(ms < 1) | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 					ms = 1; | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				bool ok = m_readWaitCondition.wait(&m_readWaitLock, ms); | 
					
						
							|  |  |  | 				m_readWaitLock.unlock(); | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				if(!ok) | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 					return total - remaining; | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				m_mutex.lock(); | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if(m_fifo == 0) | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 					m_mutex.unlock(); | 
					
						
							|  |  |  | 					return 0; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 				m_mutex.unlock(); | 
					
						
							|  |  |  | 				return total - remaining; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		copyLen = MIN(remaining, m_fill); | 
					
						
							|  |  |  | 		copyLen = MIN(copyLen, m_size - m_head); | 
					
						
							|  |  |  | 		memcpy(data, m_fifo + (m_head * m_sampleSize), copyLen * m_sampleSize); | 
					
						
							|  |  |  | 		m_head += copyLen; | 
					
						
							|  |  |  | 		m_head %= m_size; | 
					
						
							|  |  |  | 		m_fill -= copyLen; | 
					
						
							|  |  |  | 		data += copyLen * m_sampleSize; | 
					
						
							|  |  |  | 		remaining -= copyLen; | 
					
						
							|  |  |  | 		m_writeWaitCondition.wakeOne(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_mutex.unlock(); | 
					
						
							|  |  |  | 	return total; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint AudioFifo::drain(uint numSamples) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(numSamples > m_fill) | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		numSamples = m_fill; | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 	m_head = (m_head + numSamples) % m_size; | 
					
						
							|  |  |  | 	m_fill -= numSamples; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_writeWaitCondition.wakeOne(); | 
					
						
							|  |  |  | 	return numSamples; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioFifo::clear() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_fill = 0; | 
					
						
							|  |  |  | 	m_head = 0; | 
					
						
							|  |  |  | 	m_tail = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_writeWaitCondition.wakeOne(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AudioFifo::create(uint sampleSize, uint numSamples) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	if(m_fifo != 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		delete[] m_fifo; | 
					
						
							|  |  |  | 		m_fifo = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_sampleSize = sampleSize; | 
					
						
							|  |  |  | 	m_size = 0; | 
					
						
							|  |  |  | 	m_fill = 0; | 
					
						
							|  |  |  | 	m_head = 0; | 
					
						
							|  |  |  | 	m_tail = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-20 03:38:31 +02:00
										 |  |  | 	if((m_fifo = new qint8[numSamples * m_sampleSize]) == 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-05-18 16:52:39 +01:00
										 |  |  | 		qDebug("out of memory"); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_size = numSamples; | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } |