@@ -187,7 +187,7 @@ void SyncStream::reset (String mainStreamKey)
187187 latestSyncSampleNumber = 0 ;
188188 latestGlobalSyncTime = 0.0 ;
189189 latestSyncMillis = -1 ;
190-
190+
191191 // Reset Harp detection state
192192 harpState = HarpDetectionState::IDLE;
193193 completedBarcodes.clear ();
@@ -211,10 +211,21 @@ void SyncStream::reset (String mainStreamKey)
211211 }
212212 else
213213 {
214- actualSampleRate = -1.0 ;
215- globalStartTime = 0.0 ;
216214 overrideHardwareTimestamps = syncLine > -1 ; // override hardware timestamps for other streams if sync line is set
217- isSynchronized = generatesTimestamps && !overrideHardwareTimestamps; // if the stream generates its own timestamps, it is synchronized unless it overrides hardware timestamps
215+
216+ if (generatesTimestamps && ! overrideHardwareTimestamps)
217+ {
218+ // if the stream generates its own timestamps, it is synchronized unless it overrides hardware timestamps
219+ actualSampleRate = expectedSampleRate;
220+ isSynchronized = true ;
221+ }
222+ else
223+ {
224+ actualSampleRate = -1.0 ;
225+ isSynchronized = false ;
226+ }
227+
228+ globalStartTime = 0.0 ;
218229 }
219230}
220231
@@ -260,6 +271,43 @@ void SyncStream::addEvent (int64 sampleNumber, bool state)
260271 }
261272}
262273
274+ void SyncStream::setHardwareTimestamp (int64 sampleNumber, double timestamp)
275+ {
276+
277+ if (generatesTimestamps && ! overrideHardwareTimestamps)
278+ {
279+ latestSyncSampleNumber = sampleNumber;
280+ latestGlobalSyncTime = timestamp;
281+
282+ if (! baselineMatchingPulse.complete )
283+ {
284+ baselineMatchingPulse.localSampleNumber = sampleNumber;
285+ baselineMatchingPulse.globalTimestamp = timestamp;
286+ baselineMatchingPulse.complete = true ;
287+
288+ actualSampleRate = expectedSampleRate; // safe initial
289+ globalStartTime = timestamp - (double (sampleNumber) / expectedSampleRate);
290+ latestSyncMillis = Time::currentTimeMillis ();
291+ return ;
292+ }
293+
294+ double dt = timestamp - baselineMatchingPulse.globalTimestamp ;
295+ int64 ds = sampleNumber - baselineMatchingPulse.localSampleNumber ;
296+
297+ if (dt <= 1e-6 || ds <= 0 )
298+ return ;
299+
300+ double estimated = double (ds) / dt;
301+
302+ if (std::abs (estimated - expectedSampleRate) / expectedSampleRate < 0.01 )
303+ {
304+ actualSampleRate = estimated;
305+ latestSyncMillis = Time::currentTimeMillis ();
306+ }
307+ }
308+
309+ }
310+
263311double SyncStream::getLatestSyncTime ()
264312{
265313 // LOGC ("Getting latest sync time for stream ", streamKey, "...");
@@ -281,16 +329,26 @@ double SyncStream::getLatestSyncTime()
281329
282330double SyncStream::getSyncAccuracy ()
283331{
332+
333+ if (generatesTimestamps && ! overrideHardwareTimestamps)
334+ return 0.0 ; // or compute error vs. expectedSampleRate drift
335+
284336 if (pulses.size () > 0 )
285337 {
286338
287- // LOGD ("Sync accuracy for stream ", streamKey);
339+ // if (!isMainStream)
340+ // {
341+ // LOGC ("Sync accuracy for stream ", streamKey);
342+
343+ // LOGC ("latestSyncSampleNumber: ", latestSyncSampleNumber);
344+ // LOGC ("latestGlobalSyncTime: ", latestGlobalSyncTime);
345+ // LOGC ("globalStartTime: ", globalStartTime);
346+ // LOGC ("actualSampleRate: ", actualSampleRate);
347+ // LOGC ("baselineMatchingPulse.globalTimestamp: ", baselineMatchingPulse.globalTimestamp);
348+ // LOGC ("baselineMatchingPulse.localSampleNumber: ", baselineMatchingPulse.localSampleNumber);
349+ // LOGC (" ");
350+ // }
288351
289- // LOGD ("latestSyncSampleNumber: ", latestSyncSampleNumber);
290- // LOGD ("latestGlobalSyncTime: ", latestGlobalSyncTime);
291- // LOGD ("globalStartTime: ", globalStartTime);
292- // LOGD ("actualSampleRate: ", actualSampleRate);
293- // LOGD ("baselineMatchingPulse.globalTimestamp: ", baselineMatchingPulse.globalTimestamp);
294352
295353 // NEW CALCULATION:
296354 double estimatedGlobalTime = double (latestSyncSampleNumber - baselineMatchingPulse.localSampleNumber )
@@ -309,8 +367,8 @@ double SyncStream::getSyncAccuracy()
309367
310368void SyncStream::syncWith (const SyncStream* mainStream)
311369{
312- // LOGD ("Synchronizing ", streamKey, " with ", mainStream->streamKey, "...");
313- // LOGD ("Expected sample rate: ", expectedSampleRate);
370+ // LOGC ("Synchronizing ", streamKey, " with ", mainStream->streamKey, "...");
371+ // LOGC ("Expected sample rate: ", expectedSampleRate);
314372
315373 if (mainStream->pulses .size () < 2 || pulses.size () < 2 )
316374 {
@@ -333,20 +391,19 @@ void SyncStream::syncWith (const SyncStream* mainStream)
333391 {
334392 if (comparePulses (pulse, mainPulse)) // putative match
335393 {
336- if (pulses.size () > localIndex + 3 && mainStream->pulses .size () > index + 3 )
394+ if (pulses.size () > localIndex + 2 && mainStream->pulses .size () > index + 2 )
337395 {
338- // previous three pulses also match
396+ // previous two pulses also match
339397 if (comparePulses (pulses[localIndex + 1 ], mainStream->pulses [index + 1 ])
340- && comparePulses (pulses[localIndex + 2 ], mainStream->pulses [index + 2 ])
341- && comparePulses (pulses[localIndex + 3 ], mainStream->pulses [index + 3 ]))
398+ && comparePulses (pulses[localIndex + 2 ], mainStream->pulses [index + 2 ]))
342399 {
343400 pulse.matchingPulseIndex = index;
344401 pulse.globalTimestamp = mainPulse.localTimestamp ;
345402 latestSyncSampleNumber = pulse.localSampleNumber ;
346403 latestGlobalSyncTime = pulse.globalTimestamp ;
347404 latestSyncMillis = pulse.computerTimeMillis ;
348- // LOGD ("Pulse at ", pulse.localTimestamp, " matches with 4 main pulses at ", index);
349- // LOGD ("latestSyncSampleNumber: ", latestSyncSampleNumber, ", latestGlobalSyncTime: ", latestGlobalSyncTime);
405+ // LOGC ("Pulse at ", pulse.localTimestamp, " matches with 3 main pulses at ", index);
406+ // LOGC ("latestSyncSampleNumber: ", latestSyncSampleNumber, ", latestGlobalSyncTime: ", latestGlobalSyncTime);
350407
351408
352409 if (baselineMatchingPulse.complete == false )
@@ -456,7 +513,9 @@ void SyncStream::syncWith (const SyncStream* mainStream)
456513
457514 {
458515 globalStartTime = estimatedGlobalStartTime;
516+
459517 isSynchronized = true ;
518+
460519 }
461520 }
462521 else
@@ -603,11 +662,15 @@ void SyncStream::attemptBarcodeDecoding()
603662 // decode last barcode
604663 if (harpDecoder.decodeBarcode (completedBarcodes.back (), expectedSampleRate))
605664 {
606- // LOGD ("Successful decoding...setting isHarpStream to true.");
607- isHarpStream = true ;
608- isSynchronized = true ;
609665
610-
666+ if (!isHarpStream)
667+ {
668+ LOGD (" Successful decoding...setting isHarpStream to true." );
669+ isHarpStream = true ;
670+ isSynchronized = false ;
671+
672+ }
673+
611674 // Validate timing
612675 if (!validateBarcodeTimestamp (completedBarcodes.back ()))
613676 {
@@ -648,12 +711,12 @@ void SyncStream::syncWithHarp()
648711
649712 if (std::abs (estimatedSampleRate - expectedSampleRate) / expectedSampleRate < 0.05 )
650713 {
651- LOGC (streamKey, " total barcodes = " , completedBarcodes.size (), " ; estimated sample rate: " , estimatedSampleRate);
714+ // LOGC (streamKey, " total barcodes = ", completedBarcodes.size(), "; estimated sample rate: ", estimatedSampleRate);
652715 actualSampleRate = estimatedSampleRate;
653716
654717 // Calculate global start time
655718 // LOGD ("Estimated global start time: ", double (firstBarcode.encodedTime) - firstBarcode.localStartTimestamp);
656- globalStartTime = (double (firstBarcode.encodedTime ) - firstBarcode.localStartTimestamp ) / 1000 ;
719+ globalStartTime = (double (firstBarcode.encodedTime ) - firstBarcode.localStartTimestamp ) / 1000 ; // divide by 1000 so that time appears in seconds in the stream info view
657720 baselineMatchingPulse.globalTimestamp = double (firstBarcode.encodedTime );
658721 baselineMatchingPulse.localSampleNumber = firstBarcode.localStartSample ;
659722 latestSyncSampleNumber = lastBarcode.barcodeEvents .front ().first ;
@@ -666,7 +729,7 @@ void SyncStream::syncWithHarp()
666729 }
667730 else
668731 {
669- LOGC (streamKey, " estimated sample rate out of range; clearing Harp barcodes." );
732+ LOGD (streamKey, " estimated sample rate out of range; clearing Harp barcodes." );
670733 isSynchronized = false ;
671734 completedBarcodes.clear ();
672735 }
@@ -796,6 +859,14 @@ void Synchronizer::addEvent (String streamKey,
796859 }
797860}
798861
862+
863+ void Synchronizer::setHardwareTimestamp (int64 sampleNumber, double timestamp, String streamKey)
864+ {
865+ const ScopedLock sl (synchronizerLock);
866+ streams[streamKey]->setHardwareTimestamp (sampleNumber, timestamp);
867+ }
868+
869+
799870double Synchronizer::convertSampleNumberToTimestamp (String streamKey, int64 sampleNumber)
800871{
801872 if (streams[streamKey]->isSynchronized )
@@ -889,7 +960,12 @@ SyncStatus Synchronizer::getStatus (String streamKey)
889960 return SyncStatus::HARDWARE_SYNCED;
890961
891962 if (streams[streamKey]->isHarpStream )
892- return SyncStatus::HARP_CLOCK;
963+ {
964+ if (isStreamSynced (streamKey))
965+ return SyncStatus::HARP_CLOCK;
966+ else
967+ return SyncStatus::HARP_DETECTING;
968+ }
893969
894970 if (isStreamSynced (streamKey))
895971 return SyncStatus::SYNCED;
0 commit comments