diff --git a/applications/vision/src/main.cpp b/applications/vision/src/main.cpp
index a2dd5e1c044e0f26c69d0afabc2cf059767f3494..d077c5313744e5f2f42c3d33784b5f0a2094555b 100644
--- a/applications/vision/src/main.cpp
+++ b/applications/vision/src/main.cpp
@@ -160,12 +160,16 @@ static void run(ftl::Configurable *root) {
 
 	// Send channels on flush
 	auto flushhandle = pool.onFlushSet([sender](ftl::data::FrameSet &fs, ftl::codecs::Channel c) {
-		// TODO: Check the channel to see if it should be sent or not
-		switch (c) {
-		case Channel::Colour	:
-		//case Channel::Colour2	:
-		case Channel::Depth		: sender->post(fs, c); break;
-		default: break;
+		if ((int)c >= 64) sender->post(fs, c);
+		else {
+			switch (c) {
+			case Channel::AudioStereo	:
+			case Channel::AudioMono		:
+			case Channel::Colour		:
+			case Channel::Colour2		:
+			case Channel::Depth			: sender->post(fs, c); break;
+			default: break;
+			}
 		}
 		return true;
 	});
diff --git a/components/structures/include/ftl/data/new_frame.hpp b/components/structures/include/ftl/data/new_frame.hpp
index e925b95a8811d6d4cc106cd388f983c6859b6bba..a0488cadbd61dc1b59804cc7fe196e2d84a26a1e 100644
--- a/components/structures/include/ftl/data/new_frame.hpp
+++ b/components/structures/include/ftl/data/new_frame.hpp
@@ -138,6 +138,22 @@ class Frame {
 
 	inline bool hasOwn(ftl::codecs::Channel c) const;
 
+	/**
+	 * Is the channel potentially available if requested via a stream. Not all
+	 * channels are encoded and transmitted, but must be requested. This
+	 * indicates if such a request can be fullfilled.
+	 */
+	inline bool available(ftl::codecs::Channel c) const;
+
+	std::unordered_set<ftl::codecs::Channel> available() const;
+
+	bool availableAll(const std::unordered_set<ftl::codecs::Channel> &cs) const;
+
+	/**
+	 * Used by a receiver to mark potential availability.
+	 */
+	inline void markAvailable(ftl::codecs::Channel c);
+
 	inline bool changed(ftl::codecs::Channel c) const;
 
 	inline bool readonly(ftl::codecs::Channel c) const;
@@ -335,6 +351,7 @@ class Frame {
 	Session *parent_;
 	FrameStatus status_;
 	FrameMode mode_ = FrameMode::PRIMARY;
+	uint64_t available_ = 0;
 
 	inline void restart(int64_t ts) {
 		timestamp_ = ts;
@@ -427,6 +444,15 @@ bool ftl::data::Frame::hasOwn(ftl::codecs::Channel c) const {
 	return (i != data_.end() && i->second.status != ftl::data::ChannelStatus::INVALID);
 }
 
+bool ftl::data::Frame::available(ftl::codecs::Channel c) const {
+	const int ic = static_cast<int>(c);
+	return (ic >= 64) ? has(c) : (0x1ull << ic) & available_;
+}
+
+void ftl::data::Frame::markAvailable(ftl::codecs::Channel c) {
+	if ((int)c < 64) available_ |= (0x1ull << (int)c);
+}
+
 bool ftl::data::Frame::changed(ftl::codecs::Channel c) const {
 	return changed_.find(c) != changed_.end();
 }
diff --git a/components/structures/src/new_frame.cpp b/components/structures/src/new_frame.cpp
index 3181e31eef4e39d6965ba2ab2cd43f296bd1c96a..bcbc96d21feaf71823e5d5b26f21856a74134b9b 100644
--- a/components/structures/src/new_frame.cpp
+++ b/components/structures/src/new_frame.cpp
@@ -89,6 +89,14 @@ bool ftl::data::Frame::has(ftl::codecs::Channel c) const {
 	}
 }
 
+bool ftl::data::Frame::availableAll(const std::unordered_set<ftl::codecs::Channel> &cs) const {
+	bool result = true;
+	for (auto c : cs) {
+		result &= available(c);
+	}
+	return result;
+}
+
 void ftl::data::Frame::remove(ftl::codecs::Channel c) {
 	const auto &i = data_.find(c);
 	if (i != data_.end()) {
@@ -343,12 +351,14 @@ void Frame::reset() {
 	changed_.clear();
 	status_ = FrameStatus::CREATED;
 	mode_ = FrameMode::PRIMARY;
+	available_ = 0;
 }
 
 void Frame::hardReset() {
 	status_ = FrameStatus::CREATED;
 	changed_.clear();
 	data_.clear();
+	available_ = 0;
 }
 
 Frame Frame::response() {