CastMirror

CastMirror

Native Chromecast display mirroring.
Low latency. No Chrome.

CItestsC++20LinuxApache-2.0latency

CastMirror GTK app — Cast tab

What it is

CastMirror is a native C++20 sender for Google Cast display mirroring. It discovers devices on the LAN, captures the Linux desktop and system audio, encodes H.264 (libx264) and Opus, and streams Cast RTP/RTCP over UDP — the same media path Chrome uses for “Cast screen,” without embedding Chrome.

The shipping UI is a GTK 4 + libadwaita desktop app. A CLI is included.

What it is not

  • Not a Chrome / CEF wrapper
  • Not Sunshine or Moonlight (those are ~20–50 ms game streams; Cast keeps a playout delay, about 200 ms here)
  • Not an HLS/DASH “fling” to the Default Media Receiver
  • Not affiliated with Google. Chromecast, Google Cast, and Google TV are Google trademarks
  • app/winui/ is a blueprint, not the shipping Windows product

Official Cast sender SDKs cannot mirror a desktop. Chrome’s mirroring path is private as a product and open as a protocol. CastMirror implements that protocol as a LAN sender.

Features

  • One-click Cast to Chromecast, Google TV, and Cast TVs (or add a device by IP) with dynamic hardware model glyphs
  • Screen or window sharing — cast an entire monitor or pick a single application window with application icon resolution. On Wayland the system portal picker handles selection; on X11 CastMirror enumerates and captures windows directly with XComposite redirection
  • Quality presets Auto / High / Balanced / Smooth with an inline bitrate slider (1–25 Mbps) synchronized between Cast and Settings
  • Live studio controls — Freeze display and Mute TV audio on the fly with clean silence-frame injection
  • Real-time vector sparklines — Hardware-accelerated Cairo mini-charts for live FPS, bitrate, RTT, and packet loss
  • Host speakers mute while audio is mirrored; previous mute state is restored on Stop
  • Adaptive bitrate is always on: it holds your selected bitrate target, drops on congestion, and ramps back up aggressively once the link recovers
  • Appearance & Diagnostics — System / Light / Dark theme switcher and built-in hardware/network self-test wizard
  • AES-128-CTR per-frame media crypto as required by Cast Streaming
  • TLS control plane on port 8009
  • Stop budget under 500 ms (capture does not run except during a live session)

Quick start (Linux)

sudo apt update
sudo apt install -y build-essential cmake ninja-build pkg-config protobuf-compiler libprotobuf-dev \
libssl-dev libopus-dev libpulse-dev libx11-dev libxext-dev libxrandr-dev libxfixes-dev \
libxcomposite-dev libxdamage-dev \
libva-dev libavcodec-dev libswscale-dev libavutil-dev nlohmann-json3-dev libgtest-dev \
libgtk-4-dev libadwaita-1-dev
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
./build/app/castmirror-gui
./build/app/castmirror

Full package notes, firewall, and audio behavior: docs/building.md.

Usage

The GUI is split into four dedicated tabs:

1. Cast

Discover LAN receivers, select a monitor display or open application window, tune target bitrate, and start mirroring.

CastMirror — Cast tab

2. Live session

Real-time streaming pipeline visualization, hardware-accelerated Cairo vector sparkline charts (FPS, Bitrate, RTT, Packet Loss), dynamic adaptive ladder rungs, and live studio controls (Freeze display, Mute TV audio).

CastMirror — Live session tab

3. Settings

Configure video encoding presets, target playout buffer delay, host audio mute behavior, color scheme theme (System default / Light / Dark), and run hardware/network self-test diagnostics.

CastMirror — Settings tab

4. Logs

Live searchable diagnostic event logs with filter levels, quick copy, and open log directory actions.

CastMirror — Logs tab

CLI:

# Cast a full display
./build/app/castmirror --device 192.168.1.150 --display 0 --preset High
# List available windows, then cast one
./build/app/castmirror --list-windows
./build/app/castmirror --device 192.168.1.150 --window 12345
# Audio-only
./build/app/castmirror --device 192.168.1.150 --no-audio

Desktop launcher: app/io.github.vindeckyy.CastMirror.desktop.

Architecture

flowchart LR
X11[X11 screen/window capture] --> x264[libx264]
Portal[Wayland portal+PipeWire] --> x264
Pulse[Pulse/PipeWire monitor] --> Opus[Opus]
x264 --> AES[AES-128-CTR]
Opus --> AES
AES --> RTP[Cast RTP]
RTP --> UDP[UDP to device]
Device[Cast device] -->|RTCP CAST NACK PLI| Adapt[Adaptive controller]
Adapt --> x264
TLS[Cast V2 TLS 8009] --- Device
Loading

Details: docs/ARCHITECTURE.md, docs/protocol.md.

Compatibility

Chromecast 3rd gen, Ultra, Google TV / Streamer, and built-in Cast TVs. Nest Hub is 720p-class. Matrix and preset table: docs/COMPATIBILITY.md.

Project layout

CastMirror/
├── app/gui/ # Shipping GTK 4 + libadwaita UI
├── app/cli/ # Interactive / flag CLI
├── app/winui/ # Windows UI blueprint (not v1 shipping)
├── core/ # castcore C++20 library
├── tests/ # Google Test
├── tools/ # poc-control, poc-streaming, poc-encode, poc-join, fake-receiver
├── docs/ # Pages site + architecture / protocol / building
└── receiver-fallback/ # CAF research fallback, not the primary path

Development

cd build && ctest --output-on-failure
./tests/castmirror_tests
./tools/poc-encode
./tools/fake-receiver 28009 53533

See CONTRIBUTING.md. Historical lab notes: docs/TEST_REPORT.md.

Security

LAN-only. TLS to :8009. Media AES as the protocol requires. No cloud. Report privately: SECURITY.md.

License

Source in this repository is Apache License 2.0 — see LICENSE.

Binaries linked against GPL libx264 generally must be treated as GPL. Read NOTICE before you distribute builds.

Disclaimer

CastMirror is an independent project. It is not affiliated with, endorsed by, or sponsored by Google LLC. It speaks a Chromium-compatible Cast Streaming protocol; firmware app IDs can change.

About

Native Chromecast display mirroring for Linux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

CastMirror

CastMirror

Native Chromecast display mirroring.
Low latency. No Chrome.

CItestsC++20LinuxApache-2.0latency

CastMirror GTK app — Cast tab

What it is

CastMirror is a native C++20 sender for Google Cast display mirroring. It discovers devices on the LAN, captures the Linux desktop and system audio, encodes H.264 (libx264) and Opus, and streams Cast RTP/RTCP over UDP — the same media path Chrome uses for “Cast screen,” without embedding Chrome.

The shipping UI is a GTK 4 + libadwaita desktop app. A CLI is included.

What it is not

  • Not a Chrome / CEF wrapper
  • Not Sunshine or Moonlight (those are ~20–50 ms game streams; Cast keeps a playout delay, about 200 ms here)
  • Not an HLS/DASH “fling” to the Default Media Receiver
  • Not affiliated with Google. Chromecast, Google Cast, and Google TV are Google trademarks
  • app/winui/ is a blueprint, not the shipping Windows product

Official Cast sender SDKs cannot mirror a desktop. Chrome’s mirroring path is private as a product and open as a protocol. CastMirror implements that protocol as a LAN sender.

Features

  • One-click Cast to Chromecast, Google TV, and Cast TVs (or add a device by IP) with dynamic hardware model glyphs
  • Screen or window sharing — cast an entire monitor or pick a single application window with application icon resolution. On Wayland the system portal picker handles selection; on X11 CastMirror enumerates and captures windows directly with XComposite redirection
  • Quality presets Auto / High / Balanced / Smooth with an inline bitrate slider (1–25 Mbps) synchronized between Cast and Settings
  • Live studio controls — Freeze display and Mute TV audio on the fly with clean silence-frame injection
  • Real-time vector sparklines — Hardware-accelerated Cairo mini-charts for live FPS, bitrate, RTT, and packet loss
  • Host speakers mute while audio is mirrored; previous mute state is restored on Stop
  • Adaptive bitrate is always on: it holds your selected bitrate target, drops on congestion, and ramps back up aggressively once the link recovers
  • Appearance & Diagnostics — System / Light / Dark theme switcher and built-in hardware/network self-test wizard
  • AES-128-CTR per-frame media crypto as required by Cast Streaming
  • TLS control plane on port 8009
  • Stop budget under 500 ms (capture does not run except during a live session)

Quick start (Linux)

sudo apt update
sudo apt install -y build-essential cmake ninja-build pkg-config protobuf-compiler libprotobuf-dev \
libssl-dev libopus-dev libpulse-dev libx11-dev libxext-dev libxrandr-dev libxfixes-dev \
libxcomposite-dev libxdamage-dev \
libva-dev libavcodec-dev libswscale-dev libavutil-dev nlohmann-json3-dev libgtest-dev \
libgtk-4-dev libadwaita-1-dev
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
./build/app/castmirror-gui
./build/app/castmirror

Full package notes, firewall, and audio behavior: docs/building.md.

Usage

The GUI is split into four dedicated tabs:

1. Cast

Discover LAN receivers, select a monitor display or open application window, tune target bitrate, and start mirroring.

CastMirror — Cast tab

2. Live session

Real-time streaming pipeline visualization, hardware-accelerated Cairo vector sparkline charts (FPS, Bitrate, RTT, Packet Loss), dynamic adaptive ladder rungs, and live studio controls (Freeze display, Mute TV audio).

CastMirror — Live session tab

3. Settings

Configure video encoding presets, target playout buffer delay, host audio mute behavior, color scheme theme (System default / Light / Dark), and run hardware/network self-test diagnostics.

CastMirror — Settings tab

4. Logs

Live searchable diagnostic event logs with filter levels, quick copy, and open log directory actions.

CastMirror — Logs tab

CLI:

# Cast a full display
./build/app/castmirror --device 192.168.1.150 --display 0 --preset High
# List available windows, then cast one
./build/app/castmirror --list-windows
./build/app/castmirror --device 192.168.1.150 --window 12345
# Audio-only
./build/app/castmirror --device 192.168.1.150 --no-audio

Desktop launcher: app/io.github.vindeckyy.CastMirror.desktop.

Architecture

flowchart LR
X11[X11 screen/window capture] --> x264[libx264]
Portal[Wayland portal+PipeWire] --> x264
Pulse[Pulse/PipeWire monitor] --> Opus[Opus]
x264 --> AES[AES-128-CTR]
Opus --> AES
AES --> RTP[Cast RTP]
RTP --> UDP[UDP to device]
Device[Cast device] -->|RTCP CAST NACK PLI| Adapt[Adaptive controller]
Adapt --> x264
TLS[Cast V2 TLS 8009] --- Device
Loading

Details: docs/ARCHITECTURE.md, docs/protocol.md.

Compatibility

Chromecast 3rd gen, Ultra, Google TV / Streamer, and built-in Cast TVs. Nest Hub is 720p-class. Matrix and preset table: docs/COMPATIBILITY.md.

Project layout

CastMirror/
├── app/gui/ # Shipping GTK 4 + libadwaita UI
├── app/cli/ # Interactive / flag CLI
├── app/winui/ # Windows UI blueprint (not v1 shipping)
├── core/ # castcore C++20 library
├── tests/ # Google Test
├── tools/ # poc-control, poc-streaming, poc-encode, poc-join, fake-receiver
├── docs/ # Pages site + architecture / protocol / building
└── receiver-fallback/ # CAF research fallback, not the primary path

Development

cd build && ctest --output-on-failure
./tests/castmirror_tests
./tools/poc-encode
./tools/fake-receiver 28009 53533

See CONTRIBUTING.md. Historical lab notes: docs/TEST_REPORT.md.

Security

LAN-only. TLS to :8009. Media AES as the protocol requires. No cloud. Report privately: SECURITY.md.

License

Source in this repository is Apache License 2.0 — see LICENSE.

Binaries linked against GPL libx264 generally must be treated as GPL. Read NOTICE before you distribute builds.

Disclaimer

CastMirror is an independent project. It is not affiliated with, endorsed by, or sponsored by Google LLC. It speaks a Chromium-compatible Cast Streaming protocol; firmware app IDs can change.

About

Native Chromecast display mirroring for Linux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

CastMirror

CastMirror

Native Chromecast display mirroring.
Low latency. No Chrome.

CItestsC++20LinuxApache-2.0latency

CastMirror GTK app — Cast tab

What it is

CastMirror is a native C++20 sender for Google Cast display mirroring. It discovers devices on the LAN, captures the Linux desktop and system audio, encodes H.264 (libx264) and Opus, and streams Cast RTP/RTCP over UDP — the same media path Chrome uses for “Cast screen,” without embedding Chrome.

The shipping UI is a GTK 4 + libadwaita desktop app. A CLI is included.

What it is not

  • Not a Chrome / CEF wrapper
  • Not Sunshine or Moonlight (those are ~20–50 ms game streams; Cast keeps a playout delay, about 200 ms here)
  • Not an HLS/DASH “fling” to the Default Media Receiver
  • Not affiliated with Google. Chromecast, Google Cast, and Google TV are Google trademarks
  • app/winui/ is a blueprint, not the shipping Windows product

Official Cast sender SDKs cannot mirror a desktop. Chrome’s mirroring path is private as a product and open as a protocol. CastMirror implements that protocol as a LAN sender.

Features

  • One-click Cast to Chromecast, Google TV, and Cast TVs (or add a device by IP) with dynamic hardware model glyphs
  • Screen or window sharing — cast an entire monitor or pick a single application window with application icon resolution. On Wayland the system portal picker handles selection; on X11 CastMirror enumerates and captures windows directly with XComposite redirection
  • Quality presets Auto / High / Balanced / Smooth with an inline bitrate slider (1–25 Mbps) synchronized between Cast and Settings
  • Live studio controls — Freeze display and Mute TV audio on the fly with clean silence-frame injection
  • Real-time vector sparklines — Hardware-accelerated Cairo mini-charts for live FPS, bitrate, RTT, and packet loss
  • Host speakers mute while audio is mirrored; previous mute state is restored on Stop
  • Adaptive bitrate is always on: it holds your selected bitrate target, drops on congestion, and ramps back up aggressively once the link recovers
  • Appearance & Diagnostics — System / Light / Dark theme switcher and built-in hardware/network self-test wizard
  • AES-128-CTR per-frame media crypto as required by Cast Streaming
  • TLS control plane on port 8009
  • Stop budget under 500 ms (capture does not run except during a live session)

Quick start (Linux)

sudo apt update
sudo apt install -y build-essential cmake ninja-build pkg-config protobuf-compiler libprotobuf-dev \
libssl-dev libopus-dev libpulse-dev libx11-dev libxext-dev libxrandr-dev libxfixes-dev \
libxcomposite-dev libxdamage-dev \
libva-dev libavcodec-dev libswscale-dev libavutil-dev nlohmann-json3-dev libgtest-dev \
libgtk-4-dev libadwaita-1-dev
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
./build/app/castmirror-gui
./build/app/castmirror

Full package notes, firewall, and audio behavior: docs/building.md.

Usage

The GUI is split into four dedicated tabs:

1. Cast

Discover LAN receivers, select a monitor display or open application window, tune target bitrate, and start mirroring.

CastMirror — Cast tab

2. Live session

Real-time streaming pipeline visualization, hardware-accelerated Cairo vector sparkline charts (FPS, Bitrate, RTT, Packet Loss), dynamic adaptive ladder rungs, and live studio controls (Freeze display, Mute TV audio).

CastMirror — Live session tab

3. Settings

Configure video encoding presets, target playout buffer delay, host audio mute behavior, color scheme theme (System default / Light / Dark), and run hardware/network self-test diagnostics.

CastMirror — Settings tab

4. Logs

Live searchable diagnostic event logs with filter levels, quick copy, and open log directory actions.

CastMirror — Logs tab

CLI:

# Cast a full display
./build/app/castmirror --device 192.168.1.150 --display 0 --preset High
# List available windows, then cast one
./build/app/castmirror --list-windows
./build/app/castmirror --device 192.168.1.150 --window 12345
# Audio-only
./build/app/castmirror --device 192.168.1.150 --no-audio

Desktop launcher: app/io.github.vindeckyy.CastMirror.desktop.

Architecture

flowchart LR
X11[X11 screen/window capture] --> x264[libx264]
Portal[Wayland portal+PipeWire] --> x264
Pulse[Pulse/PipeWire monitor] --> Opus[Opus]
x264 --> AES[AES-128-CTR]
Opus --> AES
AES --> RTP[Cast RTP]
RTP --> UDP[UDP to device]
Device[Cast device] -->|RTCP CAST NACK PLI| Adapt[Adaptive controller]
Adapt --> x264
TLS[Cast V2 TLS 8009] --- Device
Loading

Details: docs/ARCHITECTURE.md, docs/protocol.md.

Compatibility

Chromecast 3rd gen, Ultra, Google TV / Streamer, and built-in Cast TVs. Nest Hub is 720p-class. Matrix and preset table: docs/COMPATIBILITY.md.

Project layout

CastMirror/
├── app/gui/ # Shipping GTK 4 + libadwaita UI
├── app/cli/ # Interactive / flag CLI
├── app/winui/ # Windows UI blueprint (not v1 shipping)
├── core/ # castcore C++20 library
├── tests/ # Google Test
├── tools/ # poc-control, poc-streaming, poc-encode, poc-join, fake-receiver
├── docs/ # Pages site + architecture / protocol / building
└── receiver-fallback/ # CAF research fallback, not the primary path

Development

cd build && ctest --output-on-failure
./tests/castmirror_tests
./tools/poc-encode
./tools/fake-receiver 28009 53533

See CONTRIBUTING.md. Historical lab notes: docs/TEST_REPORT.md.

Security

LAN-only. TLS to :8009. Media AES as the protocol requires. No cloud. Report privately: SECURITY.md.

License

Source in this repository is Apache License 2.0 — see LICENSE.

Binaries linked against GPL libx264 generally must be treated as GPL. Read NOTICE before you distribute builds.

Disclaimer

CastMirror is an independent project. It is not affiliated with, endorsed by, or sponsored by Google LLC. It speaks a Chromium-compatible Cast Streaming protocol; firmware app IDs can change.

About

Native Chromecast display mirroring for Linux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

CastMirror

CastMirror

Native Chromecast display mirroring.
Low latency. No Chrome.

CItestsC++20LinuxApache-2.0latency

CastMirror GTK app — Cast tab

What it is

CastMirror is a native C++20 sender for Google Cast display mirroring. It discovers devices on the LAN, captures the Linux desktop and system audio, encodes H.264 (libx264) and Opus, and streams Cast RTP/RTCP over UDP — the same media path Chrome uses for “Cast screen,” without embedding Chrome.

The shipping UI is a GTK 4 + libadwaita desktop app. A CLI is included.

What it is not

  • Not a Chrome / CEF wrapper
  • Not Sunshine or Moonlight (those are ~20–50 ms game streams; Cast keeps a playout delay, about 200 ms here)
  • Not an HLS/DASH “fling” to the Default Media Receiver
  • Not affiliated with Google. Chromecast, Google Cast, and Google TV are Google trademarks
  • app/winui/ is a blueprint, not the shipping Windows product

Official Cast sender SDKs cannot mirror a desktop. Chrome’s mirroring path is private as a product and open as a protocol. CastMirror implements that protocol as a LAN sender.

Features

  • One-click Cast to Chromecast, Google TV, and Cast TVs (or add a device by IP) with dynamic hardware model glyphs
  • Screen or window sharing — cast an entire monitor or pick a single application window with application icon resolution. On Wayland the system portal picker handles selection; on X11 CastMirror enumerates and captures windows directly with XComposite redirection
  • Quality presets Auto / High / Balanced / Smooth with an inline bitrate slider (1–25 Mbps) synchronized between Cast and Settings
  • Live studio controls — Freeze display and Mute TV audio on the fly with clean silence-frame injection
  • Real-time vector sparklines — Hardware-accelerated Cairo mini-charts for live FPS, bitrate, RTT, and packet loss
  • Host speakers mute while audio is mirrored; previous mute state is restored on Stop
  • Adaptive bitrate is always on: it holds your selected bitrate target, drops on congestion, and ramps back up aggressively once the link recovers
  • Appearance & Diagnostics — System / Light / Dark theme switcher and built-in hardware/network self-test wizard
  • AES-128-CTR per-frame media crypto as required by Cast Streaming
  • TLS control plane on port 8009
  • Stop budget under 500 ms (capture does not run except during a live session)

Quick start (Linux)

sudo apt update
sudo apt install -y build-essential cmake ninja-build pkg-config protobuf-compiler libprotobuf-dev \
libssl-dev libopus-dev libpulse-dev libx11-dev libxext-dev libxrandr-dev libxfixes-dev \
libxcomposite-dev libxdamage-dev \
libva-dev libavcodec-dev libswscale-dev libavutil-dev nlohmann-json3-dev libgtest-dev \
libgtk-4-dev libadwaita-1-dev
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
./build/app/castmirror-gui
./build/app/castmirror

Full package notes, firewall, and audio behavior: docs/building.md.

Usage

The GUI is split into four dedicated tabs:

1. Cast

Discover LAN receivers, select a monitor display or open application window, tune target bitrate, and start mirroring.

CastMirror — Cast tab

2. Live session

Real-time streaming pipeline visualization, hardware-accelerated Cairo vector sparkline charts (FPS, Bitrate, RTT, Packet Loss), dynamic adaptive ladder rungs, and live studio controls (Freeze display, Mute TV audio).

CastMirror — Live session tab

3. Settings

Configure video encoding presets, target playout buffer delay, host audio mute behavior, color scheme theme (System default / Light / Dark), and run hardware/network self-test diagnostics.

CastMirror — Settings tab

4. Logs

Live searchable diagnostic event logs with filter levels, quick copy, and open log directory actions.

CastMirror — Logs tab

CLI:

# Cast a full display
./build/app/castmirror --device 192.168.1.150 --display 0 --preset High
# List available windows, then cast one
./build/app/castmirror --list-windows
./build/app/castmirror --device 192.168.1.150 --window 12345
# Audio-only
./build/app/castmirror --device 192.168.1.150 --no-audio

Desktop launcher: app/io.github.vindeckyy.CastMirror.desktop.

Architecture

flowchart LR
X11[X11 screen/window capture] --> x264[libx264]
Portal[Wayland portal+PipeWire] --> x264
Pulse[Pulse/PipeWire monitor] --> Opus[Opus]
x264 --> AES[AES-128-CTR]
Opus --> AES
AES --> RTP[Cast RTP]
RTP --> UDP[UDP to device]
Device[Cast device] -->|RTCP CAST NACK PLI| Adapt[Adaptive controller]
Adapt --> x264
TLS[Cast V2 TLS 8009] --- Device
Loading

Details: docs/ARCHITECTURE.md, docs/protocol.md.

Compatibility

Chromecast 3rd gen, Ultra, Google TV / Streamer, and built-in Cast TVs. Nest Hub is 720p-class. Matrix and preset table: docs/COMPATIBILITY.md.

Project layout

CastMirror/
├── app/gui/ # Shipping GTK 4 + libadwaita UI
├── app/cli/ # Interactive / flag CLI
├── app/winui/ # Windows UI blueprint (not v1 shipping)
├── core/ # castcore C++20 library
├── tests/ # Google Test
├── tools/ # poc-control, poc-streaming, poc-encode, poc-join, fake-receiver
├── docs/ # Pages site + architecture / protocol / building
└── receiver-fallback/ # CAF research fallback, not the primary path

Development

cd build && ctest --output-on-failure
./tests/castmirror_tests
./tools/poc-encode
./tools/fake-receiver 28009 53533

See CONTRIBUTING.md. Historical lab notes: docs/TEST_REPORT.md.

Security

LAN-only. TLS to :8009. Media AES as the protocol requires. No cloud. Report privately: SECURITY.md.

License

Source in this repository is Apache License 2.0 — see LICENSE.

Binaries linked against GPL libx264 generally must be treated as GPL. Read NOTICE before you distribute builds.

Disclaimer

CastMirror is an independent project. It is not affiliated with, endorsed by, or sponsored by Google LLC. It speaks a Chromium-compatible Cast Streaming protocol; firmware app IDs can change.

About

Native Chromecast display mirroring for Linux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

CastMirror

CastMirror

Native Chromecast display mirroring.
Low latency. No Chrome.

CItestsC++20LinuxApache-2.0latency

CastMirror GTK app — Cast tab

What it is

CastMirror is a native C++20 sender for Google Cast display mirroring. It discovers devices on the LAN, captures the Linux desktop and system audio, encodes H.264 (libx264) and Opus, and streams Cast RTP/RTCP over UDP — the same media path Chrome uses for “Cast screen,” without embedding Chrome.

The shipping UI is a GTK 4 + libadwaita desktop app. A CLI is included.

What it is not

  • Not a Chrome / CEF wrapper
  • Not Sunshine or Moonlight (those are ~20–50 ms game streams; Cast keeps a playout delay, about 200 ms here)
  • Not an HLS/DASH “fling” to the Default Media Receiver
  • Not affiliated with Google. Chromecast, Google Cast, and Google TV are Google trademarks
  • app/winui/ is a blueprint, not the shipping Windows product

Official Cast sender SDKs cannot mirror a desktop. Chrome’s mirroring path is private as a product and open as a protocol. CastMirror implements that protocol as a LAN sender.

Features

  • One-click Cast to Chromecast, Google TV, and Cast TVs (or add a device by IP) with dynamic hardware model glyphs
  • Screen or window sharing — cast an entire monitor or pick a single application window with application icon resolution. On Wayland the system portal picker handles selection; on X11 CastMirror enumerates and captures windows directly with XComposite redirection
  • Quality presets Auto / High / Balanced / Smooth with an inline bitrate slider (1–25 Mbps) synchronized between Cast and Settings
  • Live studio controls — Freeze display and Mute TV audio on the fly with clean silence-frame injection
  • Real-time vector sparklines — Hardware-accelerated Cairo mini-charts for live FPS, bitrate, RTT, and packet loss
  • Host speakers mute while audio is mirrored; previous mute state is restored on Stop
  • Adaptive bitrate is always on: it holds your selected bitrate target, drops on congestion, and ramps back up aggressively once the link recovers
  • Appearance & Diagnostics — System / Light / Dark theme switcher and built-in hardware/network self-test wizard
  • AES-128-CTR per-frame media crypto as required by Cast Streaming
  • TLS control plane on port 8009
  • Stop budget under 500 ms (capture does not run except during a live session)

Quick start (Linux)

sudo apt update
sudo apt install -y build-essential cmake ninja-build pkg-config protobuf-compiler libprotobuf-dev \
libssl-dev libopus-dev libpulse-dev libx11-dev libxext-dev libxrandr-dev libxfixes-dev \
libxcomposite-dev libxdamage-dev \
libva-dev libavcodec-dev libswscale-dev libavutil-dev nlohmann-json3-dev libgtest-dev \
libgtk-4-dev libadwaita-1-dev
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
./build/app/castmirror-gui
./build/app/castmirror

Full package notes, firewall, and audio behavior: docs/building.md.

Usage

The GUI is split into four dedicated tabs:

1. Cast

Discover LAN receivers, select a monitor display or open application window, tune target bitrate, and start mirroring.

CastMirror — Cast tab

2. Live session

Real-time streaming pipeline visualization, hardware-accelerated Cairo vector sparkline charts (FPS, Bitrate, RTT, Packet Loss), dynamic adaptive ladder rungs, and live studio controls (Freeze display, Mute TV audio).

CastMirror — Live session tab

3. Settings

Configure video encoding presets, target playout buffer delay, host audio mute behavior, color scheme theme (System default / Light / Dark), and run hardware/network self-test diagnostics.

CastMirror — Settings tab

4. Logs

Live searchable diagnostic event logs with filter levels, quick copy, and open log directory actions.

CastMirror — Logs tab

CLI:

# Cast a full display
./build/app/castmirror --device 192.168.1.150 --display 0 --preset High
# List available windows, then cast one
./build/app/castmirror --list-windows
./build/app/castmirror --device 192.168.1.150 --window 12345
# Audio-only
./build/app/castmirror --device 192.168.1.150 --no-audio

Desktop launcher: app/io.github.vindeckyy.CastMirror.desktop.

Architecture

flowchart LR
X11[X11 screen/window capture] --> x264[libx264]
Portal[Wayland portal+PipeWire] --> x264
Pulse[Pulse/PipeWire monitor] --> Opus[Opus]
x264 --> AES[AES-128-CTR]
Opus --> AES
AES --> RTP[Cast RTP]
RTP --> UDP[UDP to device]
Device[Cast device] -->|RTCP CAST NACK PLI| Adapt[Adaptive controller]
Adapt --> x264
TLS[Cast V2 TLS 8009] --- Device
Loading

Details: docs/ARCHITECTURE.md, docs/protocol.md.

Compatibility

Chromecast 3rd gen, Ultra, Google TV / Streamer, and built-in Cast TVs. Nest Hub is 720p-class. Matrix and preset table: docs/COMPATIBILITY.md.

Project layout

CastMirror/
├── app/gui/ # Shipping GTK 4 + libadwaita UI
├── app/cli/ # Interactive / flag CLI
├── app/winui/ # Windows UI blueprint (not v1 shipping)
├── core/ # castcore C++20 library
├── tests/ # Google Test
├── tools/ # poc-control, poc-streaming, poc-encode, poc-join, fake-receiver
├── docs/ # Pages site + architecture / protocol / building
└── receiver-fallback/ # CAF research fallback, not the primary path

Development

cd build && ctest --output-on-failure
./tests/castmirror_tests
./tools/poc-encode
./tools/fake-receiver 28009 53533

See CONTRIBUTING.md. Historical lab notes: docs/TEST_REPORT.md.

Security

LAN-only. TLS to :8009. Media AES as the protocol requires. No cloud. Report privately: SECURITY.md.

License

Source in this repository is Apache License 2.0 — see LICENSE.

Binaries linked against GPL libx264 generally must be treated as GPL. Read NOTICE before you distribute builds.

Disclaimer

CastMirror is an independent project. It is not affiliated with, endorsed by, or sponsored by Google LLC. It speaks a Chromium-compatible Cast Streaming protocol; firmware app IDs can change.

About

Native Chromecast display mirroring for Linux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

CastMirror

CastMirror

Native Chromecast display mirroring.
Low latency. No Chrome.

CItestsC++20LinuxApache-2.0latency

CastMirror GTK app — Cast tab

What it is

CastMirror is a native C++20 sender for Google Cast display mirroring. It discovers devices on the LAN, captures the Linux desktop and system audio, encodes H.264 (libx264) and Opus, and streams Cast RTP/RTCP over UDP — the same media path Chrome uses for “Cast screen,” without embedding Chrome.

The shipping UI is a GTK 4 + libadwaita desktop app. A CLI is included.

What it is not

  • Not a Chrome / CEF wrapper
  • Not Sunshine or Moonlight (those are ~20–50 ms game streams; Cast keeps a playout delay, about 200 ms here)
  • Not an HLS/DASH “fling” to the Default Media Receiver
  • Not affiliated with Google. Chromecast, Google Cast, and Google TV are Google trademarks
  • app/winui/ is a blueprint, not the shipping Windows product

Official Cast sender SDKs cannot mirror a desktop. Chrome’s mirroring path is private as a product and open as a protocol. CastMirror implements that protocol as a LAN sender.

Features

  • One-click Cast to Chromecast, Google TV, and Cast TVs (or add a device by IP) with dynamic hardware model glyphs
  • Screen or window sharing — cast an entire monitor or pick a single application window with application icon resolution. On Wayland the system portal picker handles selection; on X11 CastMirror enumerates and captures windows directly with XComposite redirection
  • Quality presets Auto / High / Balanced / Smooth with an inline bitrate slider (1–25 Mbps) synchronized between Cast and Settings
  • Live studio controls — Freeze display and Mute TV audio on the fly with clean silence-frame injection
  • Real-time vector sparklines — Hardware-accelerated Cairo mini-charts for live FPS, bitrate, RTT, and packet loss
  • Host speakers mute while audio is mirrored; previous mute state is restored on Stop
  • Adaptive bitrate is always on: it holds your selected bitrate target, drops on congestion, and ramps back up aggressively once the link recovers
  • Appearance & Diagnostics — System / Light / Dark theme switcher and built-in hardware/network self-test wizard
  • AES-128-CTR per-frame media crypto as required by Cast Streaming
  • TLS control plane on port 8009
  • Stop budget under 500 ms (capture does not run except during a live session)

Quick start (Linux)

sudo apt update
sudo apt install -y build-essential cmake ninja-build pkg-config protobuf-compiler libprotobuf-dev \
libssl-dev libopus-dev libpulse-dev libx11-dev libxext-dev libxrandr-dev libxfixes-dev \
libxcomposite-dev libxdamage-dev \
libva-dev libavcodec-dev libswscale-dev libavutil-dev nlohmann-json3-dev libgtest-dev \
libgtk-4-dev libadwaita-1-dev
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
./build/app/castmirror-gui
./build/app/castmirror

Full package notes, firewall, and audio behavior: docs/building.md.

Usage

The GUI is split into four dedicated tabs:

1. Cast

Discover LAN receivers, select a monitor display or open application window, tune target bitrate, and start mirroring.

CastMirror — Cast tab

2. Live session

Real-time streaming pipeline visualization, hardware-accelerated Cairo vector sparkline charts (FPS, Bitrate, RTT, Packet Loss), dynamic adaptive ladder rungs, and live studio controls (Freeze display, Mute TV audio).

CastMirror — Live session tab

3. Settings

Configure video encoding presets, target playout buffer delay, host audio mute behavior, color scheme theme (System default / Light / Dark), and run hardware/network self-test diagnostics.

CastMirror — Settings tab

4. Logs

Live searchable diagnostic event logs with filter levels, quick copy, and open log directory actions.

CastMirror — Logs tab

CLI:

# Cast a full display
./build/app/castmirror --device 192.168.1.150 --display 0 --preset High
# List available windows, then cast one
./build/app/castmirror --list-windows
./build/app/castmirror --device 192.168.1.150 --window 12345
# Audio-only
./build/app/castmirror --device 192.168.1.150 --no-audio

Desktop launcher: app/io.github.vindeckyy.CastMirror.desktop.

Architecture

flowchart LR
X11[X11 screen/window capture] --> x264[libx264]
Portal[Wayland portal+PipeWire] --> x264
Pulse[Pulse/PipeWire monitor] --> Opus[Opus]
x264 --> AES[AES-128-CTR]
Opus --> AES
AES --> RTP[Cast RTP]
RTP --> UDP[UDP to device]
Device[Cast device] -->|RTCP CAST NACK PLI| Adapt[Adaptive controller]
Adapt --> x264
TLS[Cast V2 TLS 8009] --- Device
Loading

Details: docs/ARCHITECTURE.md, docs/protocol.md.

Compatibility

Chromecast 3rd gen, Ultra, Google TV / Streamer, and built-in Cast TVs. Nest Hub is 720p-class. Matrix and preset table: docs/COMPATIBILITY.md.

Project layout

CastMirror/
├── app/gui/ # Shipping GTK 4 + libadwaita UI
├── app/cli/ # Interactive / flag CLI
├── app/winui/ # Windows UI blueprint (not v1 shipping)
├── core/ # castcore C++20 library
├── tests/ # Google Test
├── tools/ # poc-control, poc-streaming, poc-encode, poc-join, fake-receiver
├── docs/ # Pages site + architecture / protocol / building
└── receiver-fallback/ # CAF research fallback, not the primary path

Development

cd build && ctest --output-on-failure
./tests/castmirror_tests
./tools/poc-encode
./tools/fake-receiver 28009 53533

See CONTRIBUTING.md. Historical lab notes: docs/TEST_REPORT.md.

Security

LAN-only. TLS to :8009. Media AES as the protocol requires. No cloud. Report privately: SECURITY.md.

License

Source in this repository is Apache License 2.0 — see LICENSE.

Binaries linked against GPL libx264 generally must be treated as GPL. Read NOTICE before you distribute builds.

Disclaimer

CastMirror is an independent project. It is not affiliated with, endorsed by, or sponsored by Google LLC. It speaks a Chromium-compatible Cast Streaming protocol; firmware app IDs can change.

About

Native Chromecast display mirroring for Linux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

CastMirror

CastMirror

Native Chromecast display mirroring.
Low latency. No Chrome.

CItestsC++20LinuxApache-2.0latency

CastMirror GTK app — Cast tab

What it is

CastMirror is a native C++20 sender for Google Cast display mirroring. It discovers devices on the LAN, captures the Linux desktop and system audio, encodes H.264 (libx264) and Opus, and streams Cast RTP/RTCP over UDP — the same media path Chrome uses for “Cast screen,” without embedding Chrome.

The shipping UI is a GTK 4 + libadwaita desktop app. A CLI is included.

What it is not

  • Not a Chrome / CEF wrapper
  • Not Sunshine or Moonlight (those are ~20–50 ms game streams; Cast keeps a playout delay, about 200 ms here)
  • Not an HLS/DASH “fling” to the Default Media Receiver
  • Not affiliated with Google. Chromecast, Google Cast, and Google TV are Google trademarks
  • app/winui/ is a blueprint, not the shipping Windows product

Official Cast sender SDKs cannot mirror a desktop. Chrome’s mirroring path is private as a product and open as a protocol. CastMirror implements that protocol as a LAN sender.

Features

  • One-click Cast to Chromecast, Google TV, and Cast TVs (or add a device by IP) with dynamic hardware model glyphs
  • Screen or window sharing — cast an entire monitor or pick a single application window with application icon resolution. On Wayland the system portal picker handles selection; on X11 CastMirror enumerates and captures windows directly with XComposite redirection
  • Quality presets Auto / High / Balanced / Smooth with an inline bitrate slider (1–25 Mbps) synchronized between Cast and Settings
  • Live studio controls — Freeze display and Mute TV audio on the fly with clean silence-frame injection
  • Real-time vector sparklines — Hardware-accelerated Cairo mini-charts for live FPS, bitrate, RTT, and packet loss
  • Host speakers mute while audio is mirrored; previous mute state is restored on Stop
  • Adaptive bitrate is always on: it holds your selected bitrate target, drops on congestion, and ramps back up aggressively once the link recovers
  • Appearance & Diagnostics — System / Light / Dark theme switcher and built-in hardware/network self-test wizard
  • AES-128-CTR per-frame media crypto as required by Cast Streaming
  • TLS control plane on port 8009
  • Stop budget under 500 ms (capture does not run except during a live session)

Quick start (Linux)

sudo apt update
sudo apt install -y build-essential cmake ninja-build pkg-config protobuf-compiler libprotobuf-dev \
libssl-dev libopus-dev libpulse-dev libx11-dev libxext-dev libxrandr-dev libxfixes-dev \
libxcomposite-dev libxdamage-dev \
libva-dev libavcodec-dev libswscale-dev libavutil-dev nlohmann-json3-dev libgtest-dev \
libgtk-4-dev libadwaita-1-dev
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
./build/app/castmirror-gui
./build/app/castmirror

Full package notes, firewall, and audio behavior: docs/building.md.

Usage

The GUI is split into four dedicated tabs:

1. Cast

Discover LAN receivers, select a monitor display or open application window, tune target bitrate, and start mirroring.

CastMirror — Cast tab

2. Live session

Real-time streaming pipeline visualization, hardware-accelerated Cairo vector sparkline charts (FPS, Bitrate, RTT, Packet Loss), dynamic adaptive ladder rungs, and live studio controls (Freeze display, Mute TV audio).

CastMirror — Live session tab

3. Settings

Configure video encoding presets, target playout buffer delay, host audio mute behavior, color scheme theme (System default / Light / Dark), and run hardware/network self-test diagnostics.

CastMirror — Settings tab

4. Logs

Live searchable diagnostic event logs with filter levels, quick copy, and open log directory actions.

CastMirror — Logs tab

CLI:

# Cast a full display
./build/app/castmirror --device 192.168.1.150 --display 0 --preset High
# List available windows, then cast one
./build/app/castmirror --list-windows
./build/app/castmirror --device 192.168.1.150 --window 12345
# Audio-only
./build/app/castmirror --device 192.168.1.150 --no-audio

Desktop launcher: app/io.github.vindeckyy.CastMirror.desktop.

Architecture

flowchart LR
X11[X11 screen/window capture] --> x264[libx264]
Portal[Wayland portal+PipeWire] --> x264
Pulse[Pulse/PipeWire monitor] --> Opus[Opus]
x264 --> AES[AES-128-CTR]
Opus --> AES
AES --> RTP[Cast RTP]
RTP --> UDP[UDP to device]
Device[Cast device] -->|RTCP CAST NACK PLI| Adapt[Adaptive controller]
Adapt --> x264
TLS[Cast V2 TLS 8009] --- Device
Loading

Details: docs/ARCHITECTURE.md, docs/protocol.md.

Compatibility

Chromecast 3rd gen, Ultra, Google TV / Streamer, and built-in Cast TVs. Nest Hub is 720p-class. Matrix and preset table: docs/COMPATIBILITY.md.

Project layout

CastMirror/
├── app/gui/ # Shipping GTK 4 + libadwaita UI
├── app/cli/ # Interactive / flag CLI
├── app/winui/ # Windows UI blueprint (not v1 shipping)
├── core/ # castcore C++20 library
├── tests/ # Google Test
├── tools/ # poc-control, poc-streaming, poc-encode, poc-join, fake-receiver
├── docs/ # Pages site + architecture / protocol / building
└── receiver-fallback/ # CAF research fallback, not the primary path

Development

cd build && ctest --output-on-failure
./tests/castmirror_tests
./tools/poc-encode
./tools/fake-receiver 28009 53533

See CONTRIBUTING.md. Historical lab notes: docs/TEST_REPORT.md.

Security

LAN-only. TLS to :8009. Media AES as the protocol requires. No cloud. Report privately: SECURITY.md.

License

Source in this repository is Apache License 2.0 — see LICENSE.

Binaries linked against GPL libx264 generally must be treated as GPL. Read NOTICE before you distribute builds.

Disclaimer

CastMirror is an independent project. It is not affiliated with, endorsed by, or sponsored by Google LLC. It speaks a Chromium-compatible Cast Streaming protocol; firmware app IDs can change.

About

Native Chromecast display mirroring for Linux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

CastMirror

CastMirror

Native Chromecast display mirroring.
Low latency. No Chrome.

CItestsC++20LinuxApache-2.0latency

CastMirror GTK app — Cast tab

What it is

CastMirror is a native C++20 sender for Google Cast display mirroring. It discovers devices on the LAN, captures the Linux desktop and system audio, encodes H.264 (libx264) and Opus, and streams Cast RTP/RTCP over UDP — the same media path Chrome uses for “Cast screen,” without embedding Chrome.

The shipping UI is a GTK 4 + libadwaita desktop app. A CLI is included.

What it is not

  • Not a Chrome / CEF wrapper
  • Not Sunshine or Moonlight (those are ~20–50 ms game streams; Cast keeps a playout delay, about 200 ms here)
  • Not an HLS/DASH “fling” to the Default Media Receiver
  • Not affiliated with Google. Chromecast, Google Cast, and Google TV are Google trademarks
  • app/winui/ is a blueprint, not the shipping Windows product

Official Cast sender SDKs cannot mirror a desktop. Chrome’s mirroring path is private as a product and open as a protocol. CastMirror implements that protocol as a LAN sender.

Features

  • One-click Cast to Chromecast, Google TV, and Cast TVs (or add a device by IP) with dynamic hardware model glyphs
  • Screen or window sharing — cast an entire monitor or pick a single application window with application icon resolution. On Wayland the system portal picker handles selection; on X11 CastMirror enumerates and captures windows directly with XComposite redirection
  • Quality presets Auto / High / Balanced / Smooth with an inline bitrate slider (1–25 Mbps) synchronized between Cast and Settings
  • Live studio controls — Freeze display and Mute TV audio on the fly with clean silence-frame injection
  • Real-time vector sparklines — Hardware-accelerated Cairo mini-charts for live FPS, bitrate, RTT, and packet loss
  • Host speakers mute while audio is mirrored; previous mute state is restored on Stop
  • Adaptive bitrate is always on: it holds your selected bitrate target, drops on congestion, and ramps back up aggressively once the link recovers
  • Appearance & Diagnostics — System / Light / Dark theme switcher and built-in hardware/network self-test wizard
  • AES-128-CTR per-frame media crypto as required by Cast Streaming
  • TLS control plane on port 8009
  • Stop budget under 500 ms (capture does not run except during a live session)

Quick start (Linux)

sudo apt update
sudo apt install -y build-essential cmake ninja-build pkg-config protobuf-compiler libprotobuf-dev \
libssl-dev libopus-dev libpulse-dev libx11-dev libxext-dev libxrandr-dev libxfixes-dev \
libxcomposite-dev libxdamage-dev \
libva-dev libavcodec-dev libswscale-dev libavutil-dev nlohmann-json3-dev libgtest-dev \
libgtk-4-dev libadwaita-1-dev
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
./build/app/castmirror-gui
./build/app/castmirror

Full package notes, firewall, and audio behavior: docs/building.md.

Usage

The GUI is split into four dedicated tabs:

1. Cast

Discover LAN receivers, select a monitor display or open application window, tune target bitrate, and start mirroring.

CastMirror — Cast tab

2. Live session

Real-time streaming pipeline visualization, hardware-accelerated Cairo vector sparkline charts (FPS, Bitrate, RTT, Packet Loss), dynamic adaptive ladder rungs, and live studio controls (Freeze display, Mute TV audio).

CastMirror — Live session tab

3. Settings

Configure video encoding presets, target playout buffer delay, host audio mute behavior, color scheme theme (System default / Light / Dark), and run hardware/network self-test diagnostics.

CastMirror — Settings tab

4. Logs

Live searchable diagnostic event logs with filter levels, quick copy, and open log directory actions.

CastMirror — Logs tab

CLI:

# Cast a full display
./build/app/castmirror --device 192.168.1.150 --display 0 --preset High
# List available windows, then cast one
./build/app/castmirror --list-windows
./build/app/castmirror --device 192.168.1.150 --window 12345
# Audio-only
./build/app/castmirror --device 192.168.1.150 --no-audio

Desktop launcher: app/io.github.vindeckyy.CastMirror.desktop.

Architecture

flowchart LR
X11[X11 screen/window capture] --> x264[libx264]
Portal[Wayland portal+PipeWire] --> x264
Pulse[Pulse/PipeWire monitor] --> Opus[Opus]
x264 --> AES[AES-128-CTR]
Opus --> AES
AES --> RTP[Cast RTP]
RTP --> UDP[UDP to device]
Device[Cast device] -->|RTCP CAST NACK PLI| Adapt[Adaptive controller]
Adapt --> x264
TLS[Cast V2 TLS 8009] --- Device
Loading

Details: docs/ARCHITECTURE.md, docs/protocol.md.

Compatibility

Chromecast 3rd gen, Ultra, Google TV / Streamer, and built-in Cast TVs. Nest Hub is 720p-class. Matrix and preset table: docs/COMPATIBILITY.md.

Project layout

CastMirror/
├── app/gui/ # Shipping GTK 4 + libadwaita UI
├── app/cli/ # Interactive / flag CLI
├── app/winui/ # Windows UI blueprint (not v1 shipping)
├── core/ # castcore C++20 library
├── tests/ # Google Test
├── tools/ # poc-control, poc-streaming, poc-encode, poc-join, fake-receiver
├── docs/ # Pages site + architecture / protocol / building
└── receiver-fallback/ # CAF research fallback, not the primary path

Development

cd build && ctest --output-on-failure
./tests/castmirror_tests
./tools/poc-encode
./tools/fake-receiver 28009 53533

See CONTRIBUTING.md. Historical lab notes: docs/TEST_REPORT.md.

Security

LAN-only. TLS to :8009. Media AES as the protocol requires. No cloud. Report privately: SECURITY.md.

License

Source in this repository is Apache License 2.0 — see LICENSE.

Binaries linked against GPL libx264 generally must be treated as GPL. Read NOTICE before you distribute builds.

Disclaimer

CastMirror is an independent project. It is not affiliated with, endorsed by, or sponsored by Google LLC. It speaks a Chromium-compatible Cast Streaming protocol; firmware app IDs can change.

About

Native Chromecast display mirroring for Linux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages