giuliomoro@132: /* giuliomoro@132: * ClockSynchronizer.cpp giuliomoro@132: * giuliomoro@132: * Created on: 26 Aug 2015 giuliomoro@132: * Author: giulio giuliomoro@132: */ giuliomoro@132: giuliomoro@132: #include "ClockSynchronizer.h" giuliomoro@132: giuliomoro@132: // declare static members giuliomoro@132: float ClockSynchronizer::targetSamplingRate; giuliomoro@132: float ClockSynchronizer::currentSamplingRate; giuliomoro@132: bool ClockSynchronizer::threadRunning; giuliomoro@132: int ClockSynchronizer::threadWasRunning; giuliomoro@132: bool ClockSynchronizer::staticConstructed=false; giuliomoro@132: AuxiliaryTask ClockSynchronizer::setClockTask; giuliomoro@132: giuliomoro@132: void ClockSynchronizer::staticConstructor(){ giuliomoro@132: int priority=90; giuliomoro@132: setClockTask=BeagleRT_createAuxiliaryTask(&ClockSynchronizer::setClock, priority, "setClockTask"); giuliomoro@132: threadRunning=false; giuliomoro@132: } giuliomoro@132: giuliomoro@132: void ClockSynchronizer::setClock(){ giuliomoro@132: rt_printf("Setting clock to %f\n",targetSamplingRate); giuliomoro@132: threadRunning=true; giuliomoro@132: //I2C magic giuliomoro@132: gAudioCodec->setAudioSamplingRate(targetSamplingRate); giuliomoro@132: threadRunning=false; giuliomoro@132: threadWasRunning=3; giuliomoro@132: rt_printf("Exiting thread\n"); giuliomoro@132: }; giuliomoro@132: giuliomoro@132: ClockSynchronizer::ClockSynchronizer() { giuliomoro@132: reset(); giuliomoro@132: } giuliomoro@132: giuliomoro@132: ClockSynchronizer::~ClockSynchronizer(){}; giuliomoro@132: giuliomoro@132: void ClockSynchronizer::setup(){ giuliomoro@132: if(staticConstructed==false) //This should be called in the constructor, but because of the current limitations of giuliomoro@132: // BeagleRT, it is here and setup() needs to be called in BeagleRT setup(); giuliomoro@132: staticConstructor(); giuliomoro@132: } giuliomoro@132: void ClockSynchronizer::reset(){ giuliomoro@132: localCounter=0; giuliomoro@132: remoteCounter=0; giuliomoro@132: lastTime=0; giuliomoro@132: localOffset=-1; giuliomoro@132: remoteOffset=-1; giuliomoro@132: timeOffset=-1; giuliomoro@132: currentSamplingRate=44100; giuliomoro@132: } giuliomoro@132: giuliomoro@132: void ClockSynchronizer::update(int aLocalCounter, int aRemoteCounter, RTIME aLastTime){ giuliomoro@132: if(threadRunning==true){ //do nothing if clock is being adjusted giuliomoro@132: rt_printf("do nothing if clock is being adjusted\n"); giuliomoro@132: return; giuliomoro@132: } giuliomoro@132: if(threadWasRunning > 0){ //reset variables after clock has been adjusted giuliomoro@132: threadWasRunning--; // wait a few calls to make sure the clock stabilizes giuliomoro@132: rt_printf("wait a few calls to make sure the clock stabilizes\n"); giuliomoro@132: return; giuliomoro@132: }/* giuliomoro@132: if(threadWasRunning==1){ giuliomoro@132: threadWasRunning=0; giuliomoro@132: // reset offsets after a correction giuliomoro@132: localOffset=aLocalCounter; giuliomoro@132: remoteOffset=aRemoteCounter; giuliomoro@132: timeOffset=aLastTime; giuliomoro@132: rt_printf("reset variables after clock has been adjusted\n"); giuliomoro@132: return; giuliomoro@132: }*/ giuliomoro@132: if (localOffset<=0 || remoteOffset<=0){ // probably this is the first run giuliomoro@132: localOffset=aLocalCounter; giuliomoro@132: remoteOffset=aRemoteCounter; giuliomoro@132: timeOffset=aLastTime; giuliomoro@132: rt_printf("First run of update(), localOffset: %d, remoteOffset: %d, timeOffset: %llu\n", giuliomoro@132: localOffset, remoteOffset, timeOffset); giuliomoro@132: return; giuliomoro@132: } giuliomoro@132: localCounter=aLocalCounter-localOffset; giuliomoro@132: remoteCounter=aRemoteCounter-remoteOffset; giuliomoro@132: lastTime=aLastTime-timeOffset; giuliomoro@132: if (localCounter<=0 || remoteCounter<=0 || timeOffset<=0) {// did anything wrong happened? giuliomoro@132: rt_printf("fourth\n"); giuliomoro@132: return; giuliomoro@132: } giuliomoro@132: // TODO: make sure we do not get actually adjust the clock too often (e.g.: limits on the timestamp) giuliomoro@132: // Should keep track of last time a change has been made, so that when a large compensation is needed giuliomoro@132: // (e.g.: as the program has just started), adjustClock() is called more frequently giuliomoro@132: // but gets called less often later. giuliomoro@132: // Should also try to avoid drastic correction after a while that the program giuliomoro@132: // has started, so to avoid glitches. But this can maybe be handled by the thread itself. giuliomoro@132: // TODO: should keep a log and maybe compensate for (and prevent) overshoot according to previous changes giuliomoro@132: rt_printf("lastTime: %llu, remoteCounter: %d\n", lastTime, remoteCounter); giuliomoro@132: giuliomoro@132: currentSamplingRate=gAudioCodec->getAudioSamplingRate(); giuliomoro@132: float T=1/currentSamplingRate; giuliomoro@132: int elapsedSamples=remoteCounter*(NetworkBuffer::bufferLength-NetworkBuffer::headerLength); giuliomoro@132: double expectedTimeUs=T*elapsedSamples*1000000; giuliomoro@132: double actualTimeUs=lastTime/1000.0; giuliomoro@132: targetSamplingRate=expectedTimeUs/actualTimeUs*currentSamplingRate; giuliomoro@132: // rt_printf("Fs: %f, expectedTimeUs: %f, lastTime: %ul\n", expectedTimeUs, lastTime); giuliomoro@132: rt_printf("Fs: %.1f, expectedTimeUs: %4.3f, actualTimeUs: %4.3f, targetFs_ %.3f\n", giuliomoro@132: gAudioCodec->getAudioSamplingRate(), expectedTimeUs/elapsedSamples, actualTimeUs/elapsedSamples, targetSamplingRate); giuliomoro@132: adjustClock(); giuliomoro@132: } giuliomoro@132: giuliomoro@132: void ClockSynchronizer::adjustClock(){ giuliomoro@132: if(currentSamplingRate!= targetSamplingRate){ //TODO: actually check that the difference is less than the quantization error in the PLL giuliomoro@132: BeagleRT_scheduleAuxiliaryTask(setClockTask); giuliomoro@132: } giuliomoro@132: }