mirror of
				https://github.com/ShaYmez/MMDVM_CM.git
				synced 2025-11-03 12:40:28 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			160 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
*   Copyright (C) 2018 by Jonathan Naylor G4KLX
 | 
						|
*
 | 
						|
*   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; either version 2 of the License, or
 | 
						|
*   (at your option) any later version.
 | 
						|
*
 | 
						|
*   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 for more details.
 | 
						|
*
 | 
						|
*   You should have received a copy of the GNU General Public License
 | 
						|
*   along with this program; if not, write to the Free Software
 | 
						|
*   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
						|
*/
 | 
						|
 | 
						|
#include "DelayBuffer.h"
 | 
						|
#include "DMRDefines.h"
 | 
						|
 | 
						|
#include "Log.h"
 | 
						|
 | 
						|
#include <cstdio>
 | 
						|
#include <cassert>
 | 
						|
#include <cstring>
 | 
						|
 | 
						|
CDelayBuffer::CDelayBuffer(const std::string& name, unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, bool debug) :
 | 
						|
m_name(name),
 | 
						|
m_blockSize(blockSize),
 | 
						|
m_blockTime(blockTime),
 | 
						|
m_debug(debug),
 | 
						|
m_timer(1000U, 0U, jitterTime),
 | 
						|
m_stopWatch(),
 | 
						|
m_running(false),
 | 
						|
m_buffer(5000U, name.c_str()),
 | 
						|
m_outputCount(0U),
 | 
						|
m_lastData(NULL),
 | 
						|
m_lastDataLength(0U),
 | 
						|
m_lastDataValid(false)
 | 
						|
{
 | 
						|
	assert(blockSize > 0U);
 | 
						|
	assert(blockTime > 0U);
 | 
						|
	assert(jitterTime > 0U);
 | 
						|
 | 
						|
	m_lastData = new unsigned char[m_blockSize];
 | 
						|
 | 
						|
	reset();
 | 
						|
}
 | 
						|
 | 
						|
CDelayBuffer::~CDelayBuffer()
 | 
						|
{
 | 
						|
	delete[] m_lastData;
 | 
						|
}
 | 
						|
 | 
						|
bool CDelayBuffer::addData(const unsigned char* data, unsigned int length)
 | 
						|
{
 | 
						|
	assert(data != NULL);
 | 
						|
	assert(length > 0U);
 | 
						|
	assert(length == m_blockSize);
 | 
						|
 | 
						|
	if (m_debug)
 | 
						|
		LogDebug("%s, DelayBuffer: appending data", m_name.c_str());
 | 
						|
 | 
						|
	m_buffer.addData(data, length);
 | 
						|
 | 
						|
	if (!m_timer.isRunning()) {
 | 
						|
		if (m_debug)
 | 
						|
			LogDebug("%s, DelayBuffer: starting the timer from append", m_name.c_str());
 | 
						|
		m_timer.start();
 | 
						|
	}
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
B_STATUS CDelayBuffer::getData(unsigned char* data, unsigned int& length)
 | 
						|
{
 | 
						|
	assert(data != NULL);
 | 
						|
 | 
						|
	if (!m_running)
 | 
						|
		return BS_NO_DATA;
 | 
						|
 | 
						|
	unsigned int needed = m_stopWatch.elapsed() / m_blockTime + 2U;
 | 
						|
	if (needed <= m_outputCount)
 | 
						|
		return BS_NO_DATA;
 | 
						|
 | 
						|
	if (!m_buffer.isEmpty()) {
 | 
						|
		if (m_debug)
 | 
						|
			LogDebug("%s, DelayBuffer: returning data, elapsed=%ums", m_name.c_str(), m_stopWatch.elapsed());
 | 
						|
 | 
						|
		if (m_buffer.getData(data, m_blockSize)) {
 | 
						|
			length = m_blockSize;
 | 
						|
 | 
						|
			// Save this data in case no more data is available next time
 | 
						|
			::memcpy(m_lastData, data, length);
 | 
						|
			m_lastDataLength = length;
 | 
						|
			m_lastDataValid = true;
 | 
						|
 | 
						|
			m_outputCount++;
 | 
						|
 | 
						|
			return BS_DATA;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (m_debug)
 | 
						|
		LogDebug("%s, DelayBuffer: no data available, elapsed=%ums", m_name.c_str(), m_stopWatch.elapsed());
 | 
						|
 | 
						|
	// Return the last data frame if we have it
 | 
						|
	if (m_lastDataLength > 0U) {
 | 
						|
		if(m_lastDataValid) {
 | 
						|
			if (m_debug)
 | 
						|
				LogDebug("%s, DelayBuffer: returning the last received frame", m_name.c_str());
 | 
						|
			// Copy last valid data
 | 
						|
			::memcpy(data, m_lastData, m_lastDataLength);
 | 
						|
		} else {
 | 
						|
			if (m_debug)
 | 
						|
				LogDebug("%s, DelayBuffer: returning a silence frame", m_name.c_str());
 | 
						|
			// Copy last network header data
 | 
						|
			::memcpy(data, m_lastData, 20U);
 | 
						|
			// We only need to copy silence AMBE data, don't care about LC data for next YSF conversion stage
 | 
						|
			::memcpy(data + 20U, DMR_SILENCE_DATA, 33U);
 | 
						|
			data[53U] = 0U;
 | 
						|
			data[54U] = 0U; 
 | 
						|
		}
 | 
						|
 | 
						|
		m_lastDataValid = false;
 | 
						|
		length = m_lastDataLength;
 | 
						|
 | 
						|
		m_outputCount++;
 | 
						|
 | 
						|
		return BS_MISSING;
 | 
						|
	}
 | 
						|
 | 
						|
	return BS_NO_DATA;
 | 
						|
}
 | 
						|
 | 
						|
void CDelayBuffer::reset()
 | 
						|
{
 | 
						|
	m_buffer.clear();
 | 
						|
 | 
						|
	m_lastDataLength = 0U;
 | 
						|
 | 
						|
	m_outputCount = 0U;
 | 
						|
 | 
						|
	m_timer.stop();
 | 
						|
 | 
						|
	m_running = false;
 | 
						|
}
 | 
						|
 | 
						|
void CDelayBuffer::clock(unsigned int ms)
 | 
						|
{
 | 
						|
	m_timer.clock(ms);
 | 
						|
	if (m_timer.isRunning() && m_timer.hasExpired()) {
 | 
						|
		if (!m_running) {
 | 
						|
			m_stopWatch.start();
 | 
						|
			m_running = true;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |