annotate core/ClockSynchronizer.cpp @ 133:04b1678614c9 scope-refactoring

Using moving average for clock detection during synchronization seems to be working better but audio gets worse and worse
author Giulio Moro <giuliomoro@yahoo.it>
date Thu, 27 Aug 2015 03:33:32 +0100
parents e24c531220ee
children
rev   line source
giuliomoro@132 1 /*
giuliomoro@132 2 * ClockSynchronizer.cpp
giuliomoro@132 3 *
giuliomoro@132 4 * Created on: 26 Aug 2015
giuliomoro@132 5 * Author: giulio
giuliomoro@132 6 */
giuliomoro@132 7
giuliomoro@132 8 #include "ClockSynchronizer.h"
giuliomoro@132 9
giuliomoro@132 10 // declare static members
giuliomoro@132 11 float ClockSynchronizer::targetSamplingRate;
giuliomoro@132 12 float ClockSynchronizer::currentSamplingRate;
giuliomoro@132 13 bool ClockSynchronizer::threadRunning;
giuliomoro@132 14 int ClockSynchronizer::threadWasRunning;
giuliomoro@132 15 bool ClockSynchronizer::staticConstructed=false;
giuliomoro@132 16 AuxiliaryTask ClockSynchronizer::setClockTask;
giuliomoro@132 17
giuliomoro@132 18 void ClockSynchronizer::staticConstructor(){
giuliomoro@132 19 int priority=90;
giuliomoro@132 20 setClockTask=BeagleRT_createAuxiliaryTask(&ClockSynchronizer::setClock, priority, "setClockTask");
giuliomoro@132 21 threadRunning=false;
giuliomoro@132 22 }
giuliomoro@132 23
giuliomoro@132 24 void ClockSynchronizer::setClock(){
giuliomoro@133 25 // rt_printf("Setting clock to %f\n",targetSamplingRate);
giuliomoro@132 26 threadRunning=true;
giuliomoro@132 27 //I2C magic
giuliomoro@132 28 gAudioCodec->setAudioSamplingRate(targetSamplingRate);
giuliomoro@132 29 threadRunning=false;
giuliomoro@133 30 threadWasRunning=1;
giuliomoro@133 31 // rt_printf("Exiting thread\n");
giuliomoro@132 32 };
giuliomoro@132 33
giuliomoro@132 34 ClockSynchronizer::ClockSynchronizer() {
giuliomoro@132 35 reset();
giuliomoro@132 36 }
giuliomoro@132 37
giuliomoro@132 38 ClockSynchronizer::~ClockSynchronizer(){};
giuliomoro@132 39
giuliomoro@132 40 void ClockSynchronizer::setup(){
giuliomoro@132 41 if(staticConstructed==false) //This should be called in the constructor, but because of the current limitations of
giuliomoro@132 42 // BeagleRT, it is here and setup() needs to be called in BeagleRT setup();
giuliomoro@132 43 staticConstructor();
giuliomoro@132 44 }
giuliomoro@132 45 void ClockSynchronizer::reset(){
giuliomoro@132 46 localCounter=0;
giuliomoro@132 47 remoteCounter=0;
giuliomoro@132 48 lastTime=0;
giuliomoro@132 49 localOffset=-1;
giuliomoro@132 50 remoteOffset=-1;
giuliomoro@132 51 timeOffset=-1;
giuliomoro@132 52 currentSamplingRate=44100;
giuliomoro@132 53 }
giuliomoro@132 54
giuliomoro@132 55 void ClockSynchronizer::update(int aLocalCounter, int aRemoteCounter, RTIME aLastTime){
giuliomoro@132 56 if(threadRunning==true){ //do nothing if clock is being adjusted
giuliomoro@132 57 rt_printf("do nothing if clock is being adjusted\n");
giuliomoro@132 58 return;
giuliomoro@132 59 }
giuliomoro@132 60 if(threadWasRunning > 0){ //reset variables after clock has been adjusted
giuliomoro@132 61 threadWasRunning--; // wait a few calls to make sure the clock stabilizes
giuliomoro@132 62 rt_printf("wait a few calls to make sure the clock stabilizes\n");
giuliomoro@132 63 return;
giuliomoro@132 64 }/*
giuliomoro@132 65 if(threadWasRunning==1){
giuliomoro@132 66 threadWasRunning=0;
giuliomoro@132 67 // reset offsets after a correction
giuliomoro@132 68 localOffset=aLocalCounter;
giuliomoro@132 69 remoteOffset=aRemoteCounter;
giuliomoro@132 70 timeOffset=aLastTime;
giuliomoro@132 71 rt_printf("reset variables after clock has been adjusted\n");
giuliomoro@132 72 return;
giuliomoro@132 73 }*/
giuliomoro@132 74 if (localOffset<=0 || remoteOffset<=0){ // probably this is the first run
giuliomoro@132 75 localOffset=aLocalCounter;
giuliomoro@132 76 remoteOffset=aRemoteCounter;
giuliomoro@132 77 timeOffset=aLastTime;
giuliomoro@132 78 rt_printf("First run of update(), localOffset: %d, remoteOffset: %d, timeOffset: %llu\n",
giuliomoro@132 79 localOffset, remoteOffset, timeOffset);
giuliomoro@132 80 return;
giuliomoro@132 81 }
giuliomoro@132 82 localCounter=aLocalCounter-localOffset;
giuliomoro@132 83 remoteCounter=aRemoteCounter-remoteOffset;
giuliomoro@132 84 lastTime=aLastTime-timeOffset;
giuliomoro@132 85 if (localCounter<=0 || remoteCounter<=0 || timeOffset<=0) {// did anything wrong happened?
giuliomoro@132 86 rt_printf("fourth\n");
giuliomoro@132 87 return;
giuliomoro@132 88 }
giuliomoro@132 89 // TODO: make sure we do not get actually adjust the clock too often (e.g.: limits on the timestamp)
giuliomoro@132 90 // Should keep track of last time a change has been made, so that when a large compensation is needed
giuliomoro@132 91 // (e.g.: as the program has just started), adjustClock() is called more frequently
giuliomoro@132 92 // but gets called less often later.
giuliomoro@132 93 // Should also try to avoid drastic correction after a while that the program
giuliomoro@132 94 // has started, so to avoid glitches. But this can maybe be handled by the thread itself.
giuliomoro@132 95 // TODO: should keep a log and maybe compensate for (and prevent) overshoot according to previous changes
giuliomoro@133 96 static RTIME lastlastTime=0;
giuliomoro@133 97 // rt_printf("interval: %f, \n",(double)(remoteCounter*300.0)/lastTime*1000000000.0);
giuliomoro@133 98 lastlastTime=lastTime;
giuliomoro@132 99 currentSamplingRate=gAudioCodec->getAudioSamplingRate();
giuliomoro@132 100 float T=1/currentSamplingRate;
giuliomoro@132 101 int elapsedSamples=remoteCounter*(NetworkBuffer::bufferLength-NetworkBuffer::headerLength);
giuliomoro@132 102 double expectedTimeUs=T*elapsedSamples*1000000;
giuliomoro@133 103 double actualTimeS=lastTime/1000000000.0;
giuliomoro@132 104 double actualTimeUs=lastTime/1000.0;
giuliomoro@133 105 static float averageBuffer[101]={0};
giuliomoro@133 106 static int averageBufferPointer=0;
giuliomoro@133 107 static float average=0;
giuliomoro@133 108 static int bufferFull=0;
giuliomoro@133 109 average-=averageBuffer[averageBufferPointer];
giuliomoro@133 110 averageBuffer[averageBufferPointer]=elapsedSamples/actualTimeS;
giuliomoro@133 111 average+=averageBuffer[averageBufferPointer];
giuliomoro@133 112 averageBufferPointer++;
giuliomoro@133 113 if(averageBufferPointer==101){
giuliomoro@133 114 averageBufferPointer=0;
giuliomoro@133 115 bufferFull++;
giuliomoro@133 116 }
giuliomoro@133 117
giuliomoro@132 118 // rt_printf("Fs: %f, expectedTimeUs: %f, lastTime: %ul\n", expectedTimeUs, lastTime);
giuliomoro@133 119 // rt_printf("Fs: %.1f, actualTimeS: %4.6f, targetFs_ %.3f\n",
giuliomoro@133 120 if((averageBufferPointer&3)==0){
giuliomoro@133 121 static float oldTargetSamplingRate=0;
giuliomoro@133 122 targetSamplingRate=average/101;
giuliomoro@133 123 if(bufferFull>=3 && fabsf(targetSamplingRate-oldTargetSamplingRate) < 1){
giuliomoro@133 124 rt_printf("%.1f, %4.6f, %.3f;\n",
giuliomoro@133 125 gAudioCodec->getAudioSamplingRate(), actualTimeS, targetSamplingRate, targetSamplingRate-oldTargetSamplingRate);
giuliomoro@133 126 adjustClock();
giuliomoro@133 127 }
giuliomoro@133 128 oldTargetSamplingRate=targetSamplingRate;
giuliomoro@133 129 }
giuliomoro@132 130 }
giuliomoro@132 131
giuliomoro@132 132 void ClockSynchronizer::adjustClock(){
giuliomoro@133 133 if(fabsf(currentSamplingRate-targetSamplingRate)>0.7){ //TODO: actually check that the difference is less than the quantization error in the PLL
giuliomoro@132 134 BeagleRT_scheduleAuxiliaryTask(setClockTask);
giuliomoro@132 135 }
giuliomoro@132 136 }