diff --git a/components/rgbd-sources/include/ftl/rgbd_streamer.hpp b/components/rgbd-sources/include/ftl/rgbd_streamer.hpp
index 98409b79a19dad864128bc41037be73b87980786..8eb7460c77d41415a2a2051a7593597037119c52 100644
--- a/components/rgbd-sources/include/ftl/rgbd_streamer.hpp
+++ b/components/rgbd-sources/include/ftl/rgbd_streamer.hpp
@@ -49,7 +49,7 @@ class Streamer : public ftl::Configurable {
 	void remove(RGBDSource *);
 	void remove(const std::string &);
 
-	void run();
+	void run(bool block=false);
 	void stop();
 
 	RGBDSource *get(const std::string &uri);
diff --git a/components/rgbd-sources/src/rgbd_streamer.cpp b/components/rgbd-sources/src/rgbd_streamer.cpp
index 6048df87b0d16b0ecd529018605fff9977c0ccad..b4e256169d598587a637e35624750d8ed3370f90 100644
--- a/components/rgbd-sources/src/rgbd_streamer.cpp
+++ b/components/rgbd-sources/src/rgbd_streamer.cpp
@@ -83,7 +83,7 @@ void Streamer::add(RGBDSource *src) {
 	sources_[src->getURI()] = s;
 }
 
-void Streamer::_addClient(const string &source, int N, int rate, const UUID &peer, const string &dest) {
+void Streamer::_addClient(const string &source, int N, int rate, const ftl::UUID &peer, const string &dest) {
 	shared_lock<shared_mutex> slk(mutex_);
 	if (sources_.find(source) == sources_.end()) return;
 
@@ -113,19 +113,37 @@ void Streamer::stop() {
 	active_ = false;
 }
 
-void Streamer::run() {
+void Streamer::run(bool block) {
 	active_ = true;
 
-	// Create thread job for frame ticking
-	pool_.push([this](int id) {
+	if (block) {
 		while (active_) {
+			double wait = 1.0f / 25.0f;
+			auto start = std::chrono::high_resolution_clock::now();
 			// Create frame jobs at correct FPS interval
 			_schedule();
 
-			// TODO Proper time control
-			sleep_for(milliseconds(40));
+			std::chrono::duration<double> elapsed =
+				std::chrono::high_resolution_clock::now() - start;
+
+			sleep_for(milliseconds((long long)((wait - elapsed.count()) * 1000.0f)));
 		}
-	});
+	} else {
+		// Create thread job for frame ticking
+		pool_.push([this](int id) {
+			while (active_) {
+				double wait = 1.0f / 25.0f;
+				auto start = std::chrono::high_resolution_clock::now();
+				// Create frame jobs at correct FPS interval
+				_schedule();
+
+				std::chrono::duration<double> elapsed =
+					std::chrono::high_resolution_clock::now() - start;
+
+				sleep_for(milliseconds((long long)((wait - elapsed.count()) * 1000.0f)));
+			}
+		});
+	}
 }
 
 void Streamer::_swap(StreamSource &src) {