| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							| 
									
										
										
										
											2023-11-18 10:07:41 +01:00
										 |  |  | // Copyright (C) 2016-2021 Edouard Griffiths, F4EXB <f4exb06@gmail.com>          //
 | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // 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                  //
 | 
					
						
							| 
									
										
										
										
											2019-04-11 06:57:41 +02:00
										 |  |  | // (at your option) any later version.                                           //
 | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // 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 <QDebug>
 | 
					
						
							|  |  |  | #include <cstring>
 | 
					
						
							|  |  |  | #include <cmath>
 | 
					
						
							| 
									
										
										
										
											2018-02-24 10:29:27 +01:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2016-07-24 19:50:51 +02:00
										 |  |  | #include <boost/crc.hpp>
 | 
					
						
							|  |  |  | #include <boost/cstdint.hpp>
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  | #include "remoteinputbuffer.h"
 | 
					
						
							| 
									
										
										
										
											2016-07-24 19:50:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  | RemoteInputBuffer::RemoteInputBuffer() : | 
					
						
							| 
									
										
										
										
											2020-06-28 07:19:20 +02:00
										 |  |  |         m_decoderSlots(nullptr), | 
					
						
							|  |  |  |         m_frames(nullptr), | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |         m_curNbBlocks(0), | 
					
						
							| 
									
										
										
										
											2016-07-18 00:39:35 +02:00
										 |  |  |         m_minNbBlocks(256), | 
					
						
							| 
									
										
										
										
											2017-05-25 20:13:34 +02:00
										 |  |  |         m_curOriginalBlocks(0), | 
					
						
							| 
									
										
										
										
											2016-07-27 18:49:17 +02:00
										 |  |  |         m_minOriginalBlocks(128), | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |         m_curNbRecovery(0), | 
					
						
							| 
									
										
										
										
											2016-07-18 00:39:35 +02:00
										 |  |  |         m_maxNbRecovery(0), | 
					
						
							|  |  |  |         m_framesDecoded(true), | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |         m_readIndex(0), | 
					
						
							|  |  |  |         m_readBuffer(0), | 
					
						
							|  |  |  |         m_readSize(0), | 
					
						
							| 
									
										
										
										
											2016-07-13 03:31:19 +02:00
										 |  |  |         m_bufferLenSec(0.0f), | 
					
						
							| 
									
										
										
										
											2017-05-25 20:13:34 +02:00
										 |  |  |         m_nbReads(0), | 
					
						
							|  |  |  |         m_nbWrites(0), | 
					
						
							|  |  |  |         m_balCorrection(0), | 
					
						
							|  |  |  | 	    m_balCorrLimit(0) | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	m_currentMeta.init(); | 
					
						
							| 
									
										
										
										
											2020-06-28 07:19:20 +02:00
										 |  |  |     setNbDecoderSlots(16); | 
					
						
							| 
									
										
										
										
											2020-11-14 22:40:22 +01:00
										 |  |  |     m_decoderIndexHead = m_nbDecoderSlots/2; | 
					
						
							| 
									
										
										
										
											2016-07-24 12:53:39 +02:00
										 |  |  | 	m_tvOut_sec = 0; | 
					
						
							|  |  |  | 	m_tvOut_usec = 0; | 
					
						
							| 
									
										
										
										
											2016-07-13 03:31:19 +02:00
										 |  |  | 	m_readNbBytes = 1; | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |     m_paramsCM256.BlockBytes = sizeof(RemoteProtectedBlock); // never changes
 | 
					
						
							|  |  |  |     m_paramsCM256.OriginalCount = RemoteNbOrginalBlocks;  // never changes
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-23 19:59:42 +02:00
										 |  |  |     if (!m_cm256.isInitialized()) { | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |         m_cm256_OK = false; | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  |         qDebug() << "RemoteInputBuffer::RemoteInputBuffer: cannot initialize CM256 library"; | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         m_cm256_OK = true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-02-24 10:29:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-28 06:56:21 +02:00
										 |  |  |     std::fill(m_decoderSlots, m_decoderSlots + m_nbDecoderSlots, DecoderSlot()); | 
					
						
							|  |  |  |     std::fill(m_frames, m_frames + m_nbDecoderSlots, BufferFrame()); | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  | RemoteInputBuffer::~RemoteInputBuffer() | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (m_readBuffer) { | 
					
						
							|  |  |  | 		delete[] m_readBuffer; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-28 07:19:20 +02:00
										 |  |  |     if (m_decoderSlots) { | 
					
						
							|  |  |  |         delete[] m_decoderSlots; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m_frames) { | 
					
						
							|  |  |  |         delete[] m_frames; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteInputBuffer::setNbDecoderSlots(int nbDecoderSlots) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_nbDecoderSlots = nbDecoderSlots; | 
					
						
							|  |  |  |     m_framesSize = m_nbDecoderSlots * (RemoteNbOrginalBlocks - 1) * RemoteNbBytesPerBlock; | 
					
						
							|  |  |  |   	m_framesNbBytes = m_nbDecoderSlots * sizeof(BufferFrame); | 
					
						
							|  |  |  |     m_wrDeltaEstimate = m_framesNbBytes / 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (m_decoderSlots) { | 
					
						
							|  |  |  |         delete[] m_decoderSlots; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m_frames) { | 
					
						
							|  |  |  |         delete[] m_frames; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_decoderSlots = new DecoderSlot[m_nbDecoderSlots]; | 
					
						
							|  |  |  |     m_frames = new BufferFrame[m_nbDecoderSlots]; | 
					
						
							|  |  |  |     m_frameHead = -1; | 
					
						
							| 
									
										
										
										
											2021-12-26 11:55:16 +01:00
										 |  |  |     initReadIndex(); | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-28 08:17:39 +02:00
										 |  |  | void RemoteInputBuffer::setBufferLenSec(const RemoteMetaDataFEC& metaData) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_bufferLenSec = (float) m_framesNbBytes / (float) (metaData.m_sampleRate * metaData.m_sampleBytes * 2); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  | void RemoteInputBuffer::initDecodeAllSlots() | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-28 06:56:21 +02:00
										 |  |  |     for (int i = 0; i < m_nbDecoderSlots; i++) | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         m_decoderSlots[i].m_blockCount = 0; | 
					
						
							| 
									
										
										
										
											2016-07-07 03:49:47 +02:00
										 |  |  |         m_decoderSlots[i].m_originalCount = 0; | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |         m_decoderSlots[i].m_recoveryCount = 0; | 
					
						
							|  |  |  |         m_decoderSlots[i].m_decoded = false; | 
					
						
							| 
									
										
										
										
											2016-06-23 00:58:07 +02:00
										 |  |  |         m_decoderSlots[i].m_metaRetrieved = false; | 
					
						
							| 
									
										
										
										
											2016-07-28 17:09:15 +02:00
										 |  |  |         resetOriginalBlocks(i); | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |         memset((void *) m_decoderSlots[i].m_recoveryBlocks, 0, RemoteNbOrginalBlocks * sizeof(RemoteProtectedBlock)); | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  | void RemoteInputBuffer::initDecodeSlot(int slotIndex) | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     // collect stats before voiding the slot
 | 
					
						
							| 
									
										
										
										
											2016-07-18 00:39:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |     m_curNbBlocks = m_decoderSlots[slotIndex].m_blockCount; | 
					
						
							| 
									
										
										
										
											2016-07-27 18:49:17 +02:00
										 |  |  |     m_curOriginalBlocks = m_decoderSlots[slotIndex].m_originalCount; | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |     m_curNbRecovery = m_decoderSlots[slotIndex].m_recoveryCount; | 
					
						
							|  |  |  |     m_avgNbBlocks(m_curNbBlocks); | 
					
						
							| 
									
										
										
										
											2016-07-27 18:49:17 +02:00
										 |  |  |     m_avgOrigBlocks(m_curOriginalBlocks); | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |     m_avgNbRecovery(m_curNbRecovery); | 
					
						
							| 
									
										
										
										
											2016-07-18 00:39:35 +02:00
										 |  |  |     m_framesDecoded = m_framesDecoded && m_decoderSlots[slotIndex].m_decoded; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (m_curNbBlocks < m_minNbBlocks) { | 
					
						
							|  |  |  |         m_minNbBlocks = m_curNbBlocks; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-27 18:49:17 +02:00
										 |  |  |     if (m_curOriginalBlocks < m_minOriginalBlocks) { | 
					
						
							|  |  |  |         m_minOriginalBlocks = m_curOriginalBlocks; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-18 00:39:35 +02:00
										 |  |  |     if (m_curNbRecovery > m_maxNbRecovery) { | 
					
						
							|  |  |  |         m_maxNbRecovery = m_curNbRecovery; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |     // void the slot
 | 
					
						
							| 
									
										
										
										
											2016-07-18 00:39:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |     m_decoderSlots[slotIndex].m_blockCount = 0; | 
					
						
							|  |  |  |     m_decoderSlots[slotIndex].m_originalCount = 0; | 
					
						
							|  |  |  |     m_decoderSlots[slotIndex].m_recoveryCount = 0; | 
					
						
							|  |  |  |     m_decoderSlots[slotIndex].m_decoded = false; | 
					
						
							|  |  |  |     m_decoderSlots[slotIndex].m_metaRetrieved = false; | 
					
						
							| 
									
										
										
										
											2016-07-28 17:09:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     resetOriginalBlocks(slotIndex); | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |     memset((void *) m_decoderSlots[slotIndex].m_recoveryBlocks, 0, RemoteNbOrginalBlocks * sizeof(RemoteProtectedBlock)); | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  | void RemoteInputBuffer::initReadIndex() | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-28 06:56:21 +02:00
										 |  |  |     m_readIndex = ((m_decoderIndexHead + (m_nbDecoderSlots/2)) % m_nbDecoderSlots) * sizeof(BufferFrame); | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |     m_wrDeltaEstimate = m_framesNbBytes / 2; | 
					
						
							| 
									
										
										
										
											2016-07-13 03:31:19 +02:00
										 |  |  |     m_nbReads = 0; | 
					
						
							|  |  |  |     m_nbWrites = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  | void RemoteInputBuffer::rwCorrectionEstimate(int slotIndex) | 
					
						
							| 
									
										
										
										
											2016-07-13 03:31:19 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (m_nbReads >= 40) // check every ~1s as tick is ~50ms
 | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2020-06-28 06:56:21 +02:00
										 |  |  | 		int targetPivotSlot = (slotIndex + (m_nbDecoderSlots/2))  % m_nbDecoderSlots; // slot at half buffer opposite of current write slot
 | 
					
						
							| 
									
										
										
										
											2016-07-13 03:31:19 +02:00
										 |  |  | 		int targetPivotIndex = targetPivotSlot * sizeof(BufferFrame);             // buffer index corresponding to start of above slot
 | 
					
						
							| 
									
										
										
										
											2020-06-28 06:56:21 +02:00
										 |  |  | 		int normalizedReadIndex = (m_readIndex < targetPivotIndex ? m_readIndex + m_nbDecoderSlots * sizeof(BufferFrame) :  m_readIndex) | 
					
						
							| 
									
										
										
										
											2016-07-13 03:31:19 +02:00
										 |  |  | 				- (targetPivotSlot * sizeof(BufferFrame)); // normalize read index so it is positive and zero at start of pivot slot
 | 
					
						
							|  |  |  | 		int dBytes; | 
					
						
							|  |  |  |         int rwDelta = (m_nbReads * m_readNbBytes) - (m_nbWrites * sizeof(BufferFrame)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-28 06:56:21 +02:00
										 |  |  | 		if (normalizedReadIndex < (m_nbDecoderSlots/ 2) * (int) sizeof(BufferFrame)) // read leads
 | 
					
						
							| 
									
										
										
										
											2016-07-13 03:31:19 +02:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			dBytes = - normalizedReadIndex - rwDelta; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else // read lags
 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2020-06-28 06:56:21 +02:00
										 |  |  |             int bufSize = (m_nbDecoderSlots * sizeof(BufferFrame)); | 
					
						
							| 
									
										
										
										
											2019-04-28 22:05:54 +02:00
										 |  |  | 			dBytes = bufSize - normalizedReadIndex - rwDelta; | 
					
						
							| 
									
										
										
										
											2016-07-13 03:31:19 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-28 22:05:54 +02:00
										 |  |  |          // calculate exponential moving average on floating point for better accuracy (was int)
 | 
					
						
							|  |  |  |         double newCorrection = ((double) dBytes) / (((int) m_currentMeta.m_sampleBytes) * 2 * m_nbReads); | 
					
						
							|  |  |  |         m_balCorrection = 0.25*m_balCorrection + 0.75*newCorrection; // exponential average with alpha = 0.75 (original is wrong)
 | 
					
						
							|  |  |  |         //m_balCorrection = (m_balCorrection / 4) + (dBytes / (int) (m_currentMeta.m_sampleBytes * 2 * m_nbReads)); // correction is in number of samples. Alpha = 0.25
 | 
					
						
							| 
									
										
										
										
											2016-07-13 03:31:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (m_balCorrection < -m_balCorrLimit) { | 
					
						
							|  |  |  |             m_balCorrection = -m_balCorrLimit; | 
					
						
							|  |  |  |         } else if (m_balCorrection > m_balCorrLimit) { | 
					
						
							|  |  |  |             m_balCorrection = m_balCorrLimit; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    m_nbReads = 0; | 
					
						
							|  |  |  | 	    m_nbWrites = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  | void RemoteInputBuffer::checkSlotData(int slotIndex) | 
					
						
							| 
									
										
										
										
											2016-07-06 02:54:01 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-12 08:52:38 +02:00
										 |  |  |     int pseudoWriteIndex = slotIndex * sizeof(BufferFrame); | 
					
						
							|  |  |  |     m_wrDeltaEstimate = pseudoWriteIndex - m_readIndex; | 
					
						
							| 
									
										
										
										
											2020-06-28 06:56:21 +02:00
										 |  |  |     int rwDelayBytes = (m_wrDeltaEstimate > 0 ? m_wrDeltaEstimate : sizeof(BufferFrame) * m_nbDecoderSlots + m_wrDeltaEstimate); | 
					
						
							| 
									
										
										
										
											2016-07-24 12:53:39 +02:00
										 |  |  |     int sampleRate = m_currentMeta.m_sampleRate; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (sampleRate > 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int64_t ts = m_currentMeta.m_tv_sec * 1000000LL + m_currentMeta.m_tv_usec; | 
					
						
							| 
									
										
										
										
											2018-09-09 22:35:25 +02:00
										 |  |  |         ts -= (rwDelayBytes * 1000000LL) / (sampleRate * 2 * m_currentMeta.m_sampleBytes); | 
					
						
							| 
									
										
										
										
											2016-07-24 12:53:39 +02:00
										 |  |  |         m_tvOut_sec = ts / 1000000LL; | 
					
						
							|  |  |  |         m_tvOut_usec = ts - (m_tvOut_sec * 1000000LL); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-06 02:54:01 +02:00
										 |  |  |     if (!m_decoderSlots[slotIndex].m_decoded) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  |         qDebug() << "RemoteInputBuffer::checkSlotData: incomplete frame:" | 
					
						
							| 
									
										
										
										
											2018-09-13 14:58:35 +02:00
										 |  |  |                 << " slotIndex: " << slotIndex | 
					
						
							| 
									
										
										
										
											2016-07-06 02:54:01 +02:00
										 |  |  |                 << " m_blockCount: " << m_decoderSlots[slotIndex].m_blockCount | 
					
						
							|  |  |  |                 << " m_recoveryCount: " << m_decoderSlots[slotIndex].m_recoveryCount; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  | void RemoteInputBuffer::writeData(char *array) | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |     RemoteSuperBlock *superBlock = (RemoteSuperBlock *) array; | 
					
						
							| 
									
										
										
										
											2018-09-13 09:18:58 +02:00
										 |  |  |     int frameIndex = superBlock->m_header.m_frameIndex; | 
					
						
							| 
									
										
										
										
											2020-06-28 06:56:21 +02:00
										 |  |  |     int decoderIndex = frameIndex % m_nbDecoderSlots; | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |     // frame break
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |     if (m_frameHead == -1) // initial state
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         m_decoderIndexHead = decoderIndex; // new decoder slot head
 | 
					
						
							|  |  |  |         m_frameHead = frameIndex; | 
					
						
							|  |  |  |         initReadIndex(); // reset read index
 | 
					
						
							|  |  |  |         initDecodeAllSlots(); // initialize all slots
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (m_frameHead != frameIndex) // frame break => new frame starts
 | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |         m_decoderIndexHead = decoderIndex; // new decoder slot head
 | 
					
						
							|  |  |  |         m_frameHead = frameIndex;          // new frame head
 | 
					
						
							|  |  |  |         checkSlotData(decoderIndex);       // check slot before re-init
 | 
					
						
							|  |  |  |         rwCorrectionEstimate(decoderIndex); | 
					
						
							| 
									
										
										
										
											2019-04-28 21:22:48 +02:00
										 |  |  |         m_nbWrites++; | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |         initDecodeSlot(decoderIndex);      // collect stats and re-initialize current slot
 | 
					
						
							| 
									
										
										
										
											2016-07-15 19:44:02 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |     // Block processing
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |     if (m_decoderSlots[decoderIndex].m_blockCount < RemoteNbOrginalBlocks) // not enough blocks to decode -> store data
 | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-09-13 09:18:58 +02:00
										 |  |  |         int blockIndex = superBlock->m_header.m_blockIndex; | 
					
						
							| 
									
										
										
										
											2016-07-07 03:49:47 +02:00
										 |  |  |         int blockCount = m_decoderSlots[decoderIndex].m_blockCount; | 
					
						
							|  |  |  |         int recoveryCount = m_decoderSlots[decoderIndex].m_recoveryCount; | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |         m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[blockCount].Index = blockIndex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (blockIndex == 0) // first block with meta
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             m_decoderSlots[decoderIndex].m_metaRetrieved = true; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |         if (blockIndex < RemoteNbOrginalBlocks) // original data
 | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-09-13 09:18:58 +02:00
										 |  |  |             m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[blockCount].Block = (void *) storeOriginalBlock(decoderIndex, blockIndex, superBlock->m_protectedBlock); | 
					
						
							| 
									
										
										
										
											2016-07-07 03:49:47 +02:00
										 |  |  |             m_decoderSlots[decoderIndex].m_originalCount++; | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         else // recovery data
 | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-09-13 09:18:58 +02:00
										 |  |  |             m_decoderSlots[decoderIndex].m_recoveryBlocks[recoveryCount] = superBlock->m_protectedBlock; | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |             m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[blockCount].Block = (void *) &m_decoderSlots[decoderIndex].m_recoveryBlocks[recoveryCount]; | 
					
						
							|  |  |  |             m_decoderSlots[decoderIndex].m_recoveryCount++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-07-07 03:49:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-15 19:44:02 +02:00
										 |  |  |     m_decoderSlots[decoderIndex].m_blockCount++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |     if (m_decoderSlots[decoderIndex].m_blockCount == RemoteNbOrginalBlocks) // ready to decode
 | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-07-07 03:49:47 +02:00
										 |  |  |         m_decoderSlots[decoderIndex].m_decoded = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |         if (m_cm256_OK && (m_decoderSlots[decoderIndex].m_recoveryCount > 0)) // recovery data used => need to decode FEC
 | 
					
						
							| 
									
										
										
										
											2016-07-15 19:44:02 +02:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |             m_paramsCM256.BlockBytes = sizeof(RemoteProtectedBlock); // never changes
 | 
					
						
							|  |  |  |             m_paramsCM256.OriginalCount = RemoteNbOrginalBlocks;  // never changes
 | 
					
						
							| 
									
										
										
										
											2016-07-15 19:44:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |             if (m_decoderSlots[decoderIndex].m_metaRetrieved) { | 
					
						
							|  |  |  |                 m_paramsCM256.RecoveryCount = m_currentMeta.m_nbFECBlocks; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 m_paramsCM256.RecoveryCount = m_decoderSlots[decoderIndex].m_recoveryCount; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-23 19:59:42 +02:00
										 |  |  |             if (m_cm256.cm256_decode(m_paramsCM256, m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks)) // CM256 decode
 | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  |                 qDebug() << "RemoteInputBuffer::writeData: decode CM256 error:" | 
					
						
							| 
									
										
										
										
											2018-09-13 14:58:35 +02:00
										 |  |  |                         << " decoderIndex: " << decoderIndex | 
					
						
							|  |  |  |                         << " m_blockCount: " << m_decoderSlots[decoderIndex].m_blockCount | 
					
						
							| 
									
										
										
										
											2016-07-07 03:49:47 +02:00
										 |  |  |                         << " m_originalCount: " << m_decoderSlots[decoderIndex].m_originalCount | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |                         << " m_recoveryCount: " << m_decoderSlots[decoderIndex].m_recoveryCount; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |             else | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  |                 qDebug() << "RemoteInputBuffer::writeData: decode CM256 success:" | 
					
						
							| 
									
										
										
										
											2018-09-13 14:58:35 +02:00
										 |  |  |                         << " decoderIndex: " << decoderIndex | 
					
						
							|  |  |  |                         << " m_blockCount: " << m_decoderSlots[decoderIndex].m_blockCount | 
					
						
							| 
									
										
										
										
											2016-07-07 03:49:47 +02:00
										 |  |  |                         << " m_originalCount: " << m_decoderSlots[decoderIndex].m_originalCount | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |                         << " m_recoveryCount: " << m_decoderSlots[decoderIndex].m_recoveryCount; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |                 for (int ir = 0; ir < m_decoderSlots[decoderIndex].m_recoveryCount; ir++) // restore missing blocks
 | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |                 { | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |                     int recoveryIndex = RemoteNbOrginalBlocks - m_decoderSlots[decoderIndex].m_recoveryCount + ir; | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |                     int blockIndex = m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[recoveryIndex].Index; | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |                     RemoteProtectedBlock *recoveredBlock = (RemoteProtectedBlock *) m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[recoveryIndex].Block; | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |                     if (blockIndex == 0) // first block with meta
 | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |                     { | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |                         RemoteMetaDataFEC *metaData = (RemoteMetaDataFEC *) recoveredBlock; | 
					
						
							| 
									
										
										
										
											2016-07-24 19:50:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                         boost::crc_32_type crc32; | 
					
						
							| 
									
										
										
										
											2019-04-26 02:50:02 +02:00
										 |  |  |                         crc32.process_bytes(metaData, sizeof(RemoteMetaDataFEC)-4); | 
					
						
							| 
									
										
										
										
											2016-07-24 19:50:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                         if (crc32.checksum() == metaData->m_crc32) | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             m_decoderSlots[decoderIndex].m_metaRetrieved = true; | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  |                             printMeta("RemoteInputBuffer::writeData: recovered meta", metaData); | 
					
						
							| 
									
										
										
										
											2016-07-24 19:50:51 +02:00
										 |  |  |                         } | 
					
						
							|  |  |  |                         else | 
					
						
							|  |  |  |                         { | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  |                             qDebug() << "RemoteInputBuffer::writeData: recovered meta: invalid CRC32"; | 
					
						
							| 
									
										
										
										
											2016-07-24 19:50:51 +02:00
										 |  |  |                         } | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-28 17:09:15 +02:00
										 |  |  |                     storeOriginalBlock(decoderIndex, blockIndex, *recoveredBlock); | 
					
						
							| 
									
										
										
										
											2016-07-20 08:54:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  |                     qDebug() << "RemoteInputBuffer::writeData: recovered block #" << blockIndex; | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |                 } // restore missing blocks
 | 
					
						
							|  |  |  |             } // CM256 decode
 | 
					
						
							| 
									
										
										
										
											2018-09-13 14:58:35 +02:00
										 |  |  |         } // recovery
 | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |         if (m_decoderSlots[decoderIndex].m_metaRetrieved) // block zero with its meta data has been received
 | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  |             RemoteMetaDataFEC *metaData = getMetaData(decoderIndex); | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (!(*metaData == m_currentMeta)) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2018-09-13 14:58:35 +02:00
										 |  |  |                 uint32_t sampleRate =  metaData->m_sampleRate; | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-13 14:58:35 +02:00
										 |  |  |                 if (sampleRate != 0) | 
					
						
							|  |  |  |                 { | 
					
						
							| 
									
										
										
										
											2020-06-28 08:17:39 +02:00
										 |  |  |                     setBufferLenSec(*metaData); | 
					
						
							| 
									
										
										
										
											2019-04-30 08:43:55 +02:00
										 |  |  |                     m_balCorrLimit = sampleRate / 400; // +/- 5% correction max per read
 | 
					
						
							| 
									
										
										
										
											2018-09-13 14:58:35 +02:00
										 |  |  |                     m_readNbBytes = (sampleRate * metaData->m_sampleBytes * 2) / 20; | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  |                 printMeta("RemoteInputBuffer::writeData: new meta", metaData); // print for change other than timestamp
 | 
					
						
							| 
									
										
										
										
											2016-07-17 23:33:50 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             m_currentMeta = *metaData; // renew current meta
 | 
					
						
							|  |  |  |         } // check block 0
 | 
					
						
							|  |  |  |     } // decode
 | 
					
						
							| 
									
										
										
										
											2016-07-07 02:36:44 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  | uint8_t *RemoteInputBuffer::readData(int32_t length) | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |     uint8_t *buffer = (uint8_t *) m_frames; | 
					
						
							|  |  |  |     uint32_t readIndex = m_readIndex; | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 03:31:19 +02:00
										 |  |  |     m_nbReads++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-11 14:32:10 +01:00
										 |  |  |     // SEGFAULT FIX: arbitratily truncate so that it does not exceed buffer length
 | 
					
						
							| 
									
										
										
										
											2020-06-28 06:56:21 +02:00
										 |  |  |     if (length > m_framesSize) { | 
					
						
							|  |  |  |         length = m_framesSize; | 
					
						
							| 
									
										
										
										
											2016-12-11 14:32:10 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |     if (m_readIndex + length < m_framesNbBytes) // ends before buffer bound
 | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |         m_readIndex += length; | 
					
						
							|  |  |  |         return &buffer[readIndex]; | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |     else if (m_readIndex + length == m_framesNbBytes) // ends at buffer bound
 | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |         m_readIndex = 0; | 
					
						
							|  |  |  |         return &buffer[readIndex]; | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |     else // ends after buffer bound
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (length > m_readSize) // reallocate composition buffer if necessary
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (m_readBuffer) { | 
					
						
							|  |  |  |                 delete[] m_readBuffer; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |             m_readBuffer = new uint8_t[length]; | 
					
						
							|  |  |  |             m_readSize = length; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-14 22:25:40 +01:00
										 |  |  |         if (m_readBuffer) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             std::memcpy((void *) m_readBuffer, (const void *) &buffer[m_readIndex], m_framesNbBytes - m_readIndex); // copy end of buffer
 | 
					
						
							|  |  |  |             length -= m_framesNbBytes - m_readIndex; | 
					
						
							|  |  |  |             std::memcpy((void *) &m_readBuffer[m_framesNbBytes - m_readIndex], (const void *) buffer, length); // copy start of buffer
 | 
					
						
							|  |  |  |             m_readIndex = length; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |         return m_readBuffer; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:26:26 +01:00
										 |  |  | void RemoteInputBuffer::printMeta(const QString& header, RemoteMetaDataFEC *metaData) | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	qDebug() << header << ": " | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |             << "|" << metaData->m_centerFrequency | 
					
						
							|  |  |  |             << ":" << metaData->m_sampleRate | 
					
						
							|  |  |  |             << ":" << (int) (metaData->m_sampleBytes & 0xF) | 
					
						
							|  |  |  |             << ":" << (int) metaData->m_sampleBits | 
					
						
							|  |  |  |             << ":" << (int) metaData->m_nbOriginalBlocks | 
					
						
							|  |  |  |             << ":" << (int) metaData->m_nbFECBlocks | 
					
						
							| 
									
										
										
										
											2021-12-23 16:27:19 +01:00
										 |  |  |             << "|" << metaData->m_deviceIndex | 
					
						
							|  |  |  |             << ":" << metaData->m_channelIndex | 
					
						
							| 
									
										
										
										
											2016-06-20 00:45:24 +02:00
										 |  |  |             << "|" << metaData->m_tv_sec | 
					
						
							|  |  |  |             << ":" << metaData->m_tv_usec | 
					
						
							|  |  |  |             << "|"; | 
					
						
							| 
									
										
										
										
											2016-06-19 09:56:49 +02:00
										 |  |  | } |