mirror of
				https://github.com/ShaYmez/MMDVM_CM.git
				synced 2025-11-03 20:50:21 -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;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |