diff --git a/applications/gui/src/camera.hpp b/applications/gui/src/camera.hpp
index 7003f3c96a0264872b65ce4cba867959ba7c002a..d044151da12113c7eff28978c527b557d355bcc6 100644
--- a/applications/gui/src/camera.hpp
+++ b/applications/gui/src/camera.hpp
@@ -69,6 +69,8 @@ class Camera {
 
 	void draw(std::vector<ftl::rgbd::FrameSet*> &fss);
 
+	inline int64_t getFrameTimeMS() const { return int64_t(delta_ * 1000.0f); }
+
 	/**
 	 * @internal. Used to inform the camera if it is the active camera or not.
 	 */
diff --git a/applications/gui/src/src_window.cpp b/applications/gui/src/src_window.cpp
index 501f6d4f5939e07c23e289ceb55392f412ee8f75..5b6b84174cf8271ee2348988a0e6a9f6417ee427 100644
--- a/applications/gui/src/src_window.cpp
+++ b/applications/gui/src/src_window.cpp
@@ -110,8 +110,9 @@ SourceWindow::SourceWindow(ftl::gui::Screen *screen)
 
 	receiver_->onAudio([this](ftl::audio::FrameSet &fs) {
 		if (framesets_.size() == 0) return true;
-		//LOG(INFO) << "Audio delay required = " << (ts - frameset_.timestamp) << "ms";
-		speaker_->setDelay(fs.timestamp - framesets_[0]->timestamp + ftl::timer::getInterval());  // Add Xms for local render time
+		auto *c = screen_->activeCamera();
+		int64_t renddelay = (c) ? c->getFrameTimeMS() : 0;
+		speaker_->setDelay(fs.timestamp - framesets_[0]->timestamp + renddelay);  // Add Xms for local render time
 		speaker_->queue(fs.timestamp, fs.frames[0]);
 		return true;
 	});
diff --git a/components/audio/include/ftl/audio/buffer.hpp b/components/audio/include/ftl/audio/buffer.hpp
index fad4f447acde457619476602de88ded940bb2f4a..7d438320d3da0d92f6aa4b5efeb2cd0ec5c2cd80 100644
--- a/components/audio/include/ftl/audio/buffer.hpp
+++ b/components/audio/include/ftl/audio/buffer.hpp
@@ -2,6 +2,7 @@
 #define _FTL_AUDIO_BUFFER_HPP_
 
 #include <vector>
+#include <cmath>
 
 namespace ftl {
 namespace audio {
@@ -23,10 +24,19 @@ class Buffer {
 
 	void setDelay(float d) {
 		req_delay_ = d  * static_cast<float>(rate_);
+		// Big jumps should be instant
+		if (fabs(req_delay_ - cur_delay_) > 0.5f) {
+			//cur_delay_ = req_delay_;
+			reset();
+		}
 	}
 
 	float delay() const { return cur_delay_ / static_cast<float>(rate_); }
 
+	virtual void reset() {
+		cur_delay_ = req_delay_;
+	}
+
 	virtual int size() const=0;
 	virtual int frames() const=0;
 
@@ -86,6 +96,12 @@ class FixedBuffer : public ftl::audio::Buffer<T> {
 
 	void read(std::vector<T> &out, int frames) override;
 
+	void reset() override {
+		Buffer<T>::reset();
+		write_position_ = 0;
+		read_position_ = 0;
+	}
+
 	private:
 	int write_position_;
 	int read_position_;
diff --git a/components/audio/include/ftl/audio/source.hpp b/components/audio/include/ftl/audio/source.hpp
index 8b810e3e8bae58ba4cab89dfb3d432bc93607579..797aee1e9ac2288a93f60bd674e6003f84e0495c 100644
--- a/components/audio/include/ftl/audio/source.hpp
+++ b/components/audio/include/ftl/audio/source.hpp
@@ -43,6 +43,7 @@ class Source : public ftl::Configurable, public ftl::audio::Generator {
 
 	ftl::audio::Buffer<short> *buffer_;
 	int to_read_;
+	int64_t latency_;
 
 	ftl::audio::FrameSet frameset_;
 
diff --git a/components/audio/include/ftl/audio/speaker.hpp b/components/audio/include/ftl/audio/speaker.hpp
index ea6d6d92d9b11b580fc3de2dcd895ecaa2379ebf..f27795bf40c29577c7de8e46ab27414e8ba699a5 100644
--- a/components/audio/include/ftl/audio/speaker.hpp
+++ b/components/audio/include/ftl/audio/speaker.hpp
@@ -26,6 +26,7 @@ class Speaker : public ftl::Configurable {
 	ftl::audio::Buffer<short> *buffer_;
 	bool active_;
 	float extra_delay_;
+	int64_t latency_;
 
 	#ifdef HAVE_PORTAUDIO
 	PaStream *stream_;
diff --git a/components/audio/src/source.cpp b/components/audio/src/source.cpp
index 48d176eaab6e558e5d66a3bc388b330b8fdbd839..d30d2d045048b70928a6d4624bfe9396d451b2a2 100644
--- a/components/audio/src/source.cpp
+++ b/components/audio/src/source.cpp
@@ -89,6 +89,8 @@ Source::Source(nlohmann::json &config) : ftl::Configurable(config), buffer_(null
     inputParameters.suggestedLatency = (device >= 0) ? Pa_GetDeviceInfo(device)->defaultLowInputLatency : 0;
     inputParameters.hostApiSpecificStreamInfo = NULL;
 
+	latency_ = int64_t(inputParameters.suggestedLatency * 1000.0);
+
 	PaError err;
 
 	if (inputParameters.device >= 0) { 
@@ -147,7 +149,7 @@ Source::Source(nlohmann::json &config) : ftl::Configurable(config), buffer_(null
 	timer_main_ = ftl::timer::add(ftl::timer::kTimerMain, [this](int64_t ts) {
 
         // Remove one interval since the audio starts from the last frame
-		frameset_.timestamp = ts - ftl::timer::getInterval();
+		frameset_.timestamp = ts - ftl::timer::getInterval() + latency_;
 
 		frameset_.id = 0;
 		frameset_.count = 1;
diff --git a/components/audio/src/speaker.cpp b/components/audio/src/speaker.cpp
index f9ebd5d6e84451cdc61cb5aa4f48de1685328ad1..1e897f33b1d5e7a7dbd3a9d898c58bde985a9585 100644
--- a/components/audio/src/speaker.cpp
+++ b/components/audio/src/speaker.cpp
@@ -83,14 +83,25 @@ void Speaker::_open(int fsize, int sample, int channels) {
 		buffer_ = new ftl::audio::MonoBuffer16<2000>(sample);
 	}
 
+	PaStreamParameters outputParameters;
+    //bzero( &inputParameters, sizeof( inputParameters ) );
+    outputParameters.channelCount = channels;
+    outputParameters.device = Pa_GetDefaultOutputDevice();
+    outputParameters.sampleFormat = paInt16;
+    outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
+    outputParameters.hostApiSpecificStreamInfo = NULL;
+
+	//LOG(INFO) << "OUTPUT LATENCY: " << outputParameters.suggestedLatency;
+	latency_ = int64_t(outputParameters.suggestedLatency * 1000.0);
+
 	#ifdef HAVE_PORTAUDIO
-	auto err = Pa_OpenDefaultStream(
+	auto err = Pa_OpenStream(
 		&stream_,
-		0,
-		channels,
-		paInt16,
+		NULL,
+		&outputParameters,
 		sample,  // Sample rate
 		256,    // Size of single frame
+		paNoFlag,
 		(channels == 1) ? pa_speaker_callback<ftl::audio::MonoBuffer16<2000>> : pa_speaker_callback<ftl::audio::StereoBuffer16<2000>>,
 		this->buffer_
 	);
@@ -132,7 +143,11 @@ void Speaker::queue(int64_t ts, ftl::audio::Frame &frame) {
 }
 
 void Speaker::setDelay(int64_t ms) {
+	ms -= latency_;
 	float d = static_cast<float>(ms) / 1000.0f + extra_delay_;
-	if (d < 0.0f) d = 0.0f;  // Clamp to 0 delay (not ideal to be exactly 0)
-	if (buffer_) buffer_->setDelay(d);
+	if (d < 0.0f) d = 0.001f;  // Clamp to 0 delay (not ideal to be exactly 0)
+	if (buffer_) {
+		buffer_->setDelay(d);
+		//LOG(INFO) << "Audio delay: " << buffer_->delay();
+	}
 }
diff --git a/components/streams/src/netstream.cpp b/components/streams/src/netstream.cpp
index 54fc032074f25be186a8a20055f330f6968c7eac..0515b1e2fb3f79859c97a7476ba56d0f15f42cfd 100644
--- a/components/streams/src/netstream.cpp
+++ b/components/streams/src/netstream.cpp
@@ -17,7 +17,7 @@ using std::optional;
 
 static constexpr int kTallyScale = 10;
 
-Net::Net(nlohmann::json &config, ftl::net::Universe *net) : Stream(config), active_(false), net_(net) {
+Net::Net(nlohmann::json &config, ftl::net::Universe *net) : Stream(config), active_(false), net_(net), clock_adjust_(0) {
 	// TODO: Install "find_stream" binding if not installed...
 	if (!net_->isBound("find_stream")) {
 		net_->bind("find_stream", [this](const std::string &uri) -> optional<ftl::UUID> {
@@ -146,6 +146,7 @@ bool Net::begin() {
 		if (!active_) return;
 
 		StreamPacket spkt = spkt_raw;
+		spkt.timestamp -= clock_adjust_;
 		spkt.version = 4;
 
 		// Manage recuring requests
@@ -269,6 +270,27 @@ bool Net::_sendRequest(Channel c, uint8_t frameset, uint8_t frames, uint8_t coun
 
 	net_->send(peer_, uri_, (short)0, spkt, pkt);
 
+	if (true) {  // TODO: Not every time
+		auto start = std::chrono::high_resolution_clock::now();
+		int64_t mastertime;
+
+		try {
+			mastertime = net_->call<int64_t>(peer_, "__ping__");
+		} catch (...) {
+			LOG(ERROR) << "Ping failed";
+			// Reset time peer and remove timer
+			time_peer_ = ftl::UUID(0);
+			return false;
+		}
+
+		auto elapsed = std::chrono::high_resolution_clock::now() - start;
+		int64_t latency = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
+		clock_adjust_ = mastertime - (ftl::timer::get_time() + (latency/2));
+
+		if (clock_adjust_ > 0) {
+			LOG(INFO) << "Clock adjustment: " << clock_adjust_;
+		}
+	}
 	return true;
 }