diff --git a/applications/gui/src/screen.cpp b/applications/gui/src/screen.cpp
index ea32b222b76510361ce946e25ba1af9af8d4ba22..5ad79c9729dc8ddd263207ec303c277da2296277 100644
--- a/applications/gui/src/screen.cpp
+++ b/applications/gui/src/screen.cpp
@@ -612,7 +612,7 @@ void ftl::gui::Screen::draw(NVGcontext *ctx) {
 		msg = string("Frame rate: ") + std::to_string((int)stats.fps);
 		nvgText(ctx, screenSize[0]-10, 20, msg.c_str(), NULL);
 		msg = string("Latency: ") + std::to_string((int)stats.latency) + string("ms");
-		nvgText(ctx, screenSize[0]-10, 40, msg.c_str(), NULL);	
+		//nvgText(ctx, screenSize[0]-10, 40, msg.c_str(), NULL);	
 
 		msg = string("Bitrate: ") + to_string_with_precision(stats.bitrate, 2) + string("Mbps");
 		nvgText(ctx, screenSize[0]-10, 60, msg.c_str(), NULL);
diff --git a/applications/gui/src/src_window.cpp b/applications/gui/src/src_window.cpp
index 23e774f6430d242d933fed5fdbf73fa945965e3f..405c4ee448560a162252fee9da5bf4e6911e81aa 100644
--- a/applications/gui/src/src_window.cpp
+++ b/applications/gui/src/src_window.cpp
@@ -202,7 +202,10 @@ bool SourceWindow::_processFrameset(ftl::rgbd::FrameSet &fs, bool fromstream) {
 	}
 
 	// Make sure there are enough framesets allocated
-	_checkFrameSets(fs.id);
+	{
+		UNIQUE_LOCK(mutex_, lk);
+		_checkFrameSets(fs.id);
+	}
 
 	if (!paused_) {
 		if (!fs.test(ftl::data::FSFlag::PARTIAL) || !screen_->root()->value("drop_partial_framesets", false)) { 
@@ -229,7 +232,10 @@ bool SourceWindow::_processFrameset(ftl::rgbd::FrameSet &fs, bool fromstream) {
 	}
 
 	const auto *cstream = interceptor_;
-	_createDefaultCameras(*framesets_[fs.id], true);  // cstream->available(fs.id).has(Channel::Depth)
+	{
+		UNIQUE_LOCK(mutex_, lk);
+		_createDefaultCameras(*framesets_[fs.id], true);  // cstream->available(fs.id).has(Channel::Depth)
+	}
 
 	//LOG(INFO) << "Channels = " << (unsigned int)cstream->available(fs.id);
 
diff --git a/applications/vision/src/main.cpp b/applications/vision/src/main.cpp
index e6086797379c8be213b65f4a9505b04d6f437681..06c352b25b6cbac045bafa8e3e96bb49ca93abd9 100644
--- a/applications/vision/src/main.cpp
+++ b/applications/vision/src/main.cpp
@@ -53,10 +53,62 @@ using json = nlohmann::json;
 
 static void run(ftl::Configurable *root) {
 	Universe *net = ftl::create<Universe>(root, "net");
-	ftl::ctrl::Master ctrl(root, net);
 
 	ftl::timer::setHighPrecision(true);
 
+	if (root->value("time_master", false)) {
+		net->bind("time_master", [net]() {
+			return net->id();
+		});
+		LOG(INFO) << "Becoming a time master";
+	}
+
+	if (root->get<string>("time_peer")) {
+		if (!net->connect(*root->get<string>("time_peer"))->waitConnection()) {
+			LOG(ERROR) << "Could not connect to time master";
+		} else {
+			LOG(INFO) << "Connected to time master";
+		}
+	}
+
+	auto opt_time_master = net->findOne<ftl::UUID>(string("time_master"));
+	ftl::UUID time_peer(0);
+	if (opt_time_master) {
+		time_peer = *opt_time_master;
+		LOG(INFO) << "Found a time master: " << time_peer.to_string();
+	}
+	int sync_counter = 0;
+
+	ftl::ctrl::Master ctrl(root, net);
+
+	// Sync clocks!
+	ftl::timer::add(ftl::timer::kTimerMain, [&time_peer,&sync_counter,net](int64_t ts) {
+		if (sync_counter-- <= 0 && time_peer != ftl::UUID(0) ) {
+			sync_counter = 20;
+			auto start = std::chrono::high_resolution_clock::now();
+			int64_t now = ftl::timer::get_time();
+
+			try {
+				net->asyncCall<int64_t>(time_peer, "__ping__", [start](const int64_t &mastertime) {
+					auto elapsed = std::chrono::high_resolution_clock::now() - start;
+					int64_t latency = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
+					auto clock_adjust = mastertime + ((latency+500)/2000) - ftl::timer::get_time();
+
+					//LOG(INFO) << "LATENCY: " << float(latency)/1000.0f << "ms";
+
+					if (clock_adjust != 0) {
+						LOG(INFO) << "Clock adjustment: " << clock_adjust << ", latency=" << float(latency)/1000.0f << "ms";
+						ftl::timer::setClockAdjustment(clock_adjust);
+					}		
+				});
+			} catch (const std::exception &e) {
+				LOG(ERROR) << "Ping failed, could not time sync: " << e.what();
+				return true;
+			}
+		}
+		return true;
+	});
+
 	auto paths = root->get<vector<string>>("paths");
 	string file = "";
 	if (paths && (*paths).size() > 0) file = (*paths)[(*paths).size()-1];
diff --git a/components/streams/src/netstream.cpp b/components/streams/src/netstream.cpp
index 4969489908d95598af837e0a4468aac14ff66c12..21c1542a7534e9ffd20531d6df45d430b0611ebc 100644
--- a/components/streams/src/netstream.cpp
+++ b/components/streams/src/netstream.cpp
@@ -348,39 +348,10 @@ bool Net::_processRequest(ftl::net::Peer &p, const ftl::codecs::Packet &pkt) {
 		}
 
 		// First connected peer (or reconnecting peer) becomes a time server
-		if (time_peer_ == ftl::UUID(0)) {
+		/*if (time_peer_ == ftl::UUID(0)) {
 			time_peer_ = p.id();
 			DLOG(INFO) << "Adding time peer";
-		}
-	}
-
-	// Sync clocks!
-	if (ftl::timer::isClockSlave() && p.id() == time_peer_) {
-		auto start = std::chrono::high_resolution_clock::now();
-		int64_t now = ftl::timer::get_time();
-		if (last_ping_ < now-500) {
-			last_ping_ = now;
-
-			try {
-				net_->asyncCall<int64_t>(time_peer_, "__ping__", [this, start](const int64_t &mastertime) {
-					auto elapsed = std::chrono::high_resolution_clock::now() - start;
-					int64_t latency = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
-					auto clock_adjust = mastertime - (ftl::timer::get_time() + (latency/2));
-
-					if (clock_adjust != 0) {
-						LOG(INFO) << "Clock adjustment: " << clock_adjust << ", latency=" << latency/2;
-						//LOG(INFO) << "Latency: " << (latency / 2);
-						//LOG(INFO) << "Local: " << std::chrono::time_point_cast<std::chrono::milliseconds>(start).time_since_epoch().count() << ", master: " << mastertime;
-						ftl::timer::setClockAdjustment(clock_adjust);
-					}		
-				});
-			} catch (...) {
-				LOG(ERROR) << "Ping failed";
-				// Reset time peer and remove timer
-				time_peer_ = ftl::UUID(0);
-				return false;
-			}
-		}
+		}*/
 	}
 
 	return false;