惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cloudbric
Cloudbric
有赞技术团队
有赞技术团队
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
Threat Research - Cisco Blogs
L
LangChain Blog
Simon Willison's Weblog
Simon Willison's Weblog
Project Zero
Project Zero
Latest news
Latest news
S
Schneier on Security
Cisco Talos Blog
Cisco Talos Blog
MyScale Blog
MyScale Blog
C
Check Point Blog
IT之家
IT之家
P
Palo Alto Networks Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
CERT Recently Published Vulnerability Notes
Scott Helme
Scott Helme
The Hacker News
The Hacker News
C
CXSECURITY Database RSS Feed - CXSecurity.com
G
Google Developers Blog
T
Tor Project blog
T
Threatpost
D
DataBreaches.Net
博客园 - 【当耐特】
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Troy Hunt's Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Vercel News
Vercel News
云风的 BLOG
云风的 BLOG
NISL@THU
NISL@THU
P
Privacy & Cybersecurity Law Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Cisco Blogs
博客园_首页
S
Securelist
T
The Exploit Database - CXSecurity.com
Last Week in AI
Last Week in AI
量子位
U
Unit 42
Know Your Adversary
Know Your Adversary
Hugging Face - Blog
Hugging Face - Blog
S
Security Affairs
Google Online Security Blog
Google Online Security Blog
Hacker News: Ask HN
Hacker News: Ask HN
Webroot Blog
Webroot Blog
S
SegmentFault 最新的问题
Engineering at Meta
Engineering at Meta
N
News and Events Feed by Topic
P
Proofpoint News Feed
阮一峰的网络日志
阮一峰的网络日志

Morten Linderud

ACME device attestation, smallstep and pkcs11: attezt Personal infrastructure setup 2026 Self-hosting DNS for no fun, but a little profit! Easter hack: terraform-provider-openwrt SSH CA with device and identity attestation: ssh-tpm-ca-authority NixOS is not reproducible Store ssh keys inside the TPM: ssh-tpm-agent Store age identities inside the TPM: age-plugin-tpm Golang crypto/ecdh and the TPM My FOSS work update coredumpctl, delve and debug packages for Go Monitoring the kernel.org Transparency Log for a year Streaming the Steam Deck to OBS mkinitcpio v31 and UEFI stubs FOSS Activities in April 2021 FOSS Activities in March 2021 Simplifying and securing the boot process FOSS Activities in February 2021 FOSS Activities in January 2021 FOSS Activities in December 2020 Kubernetes in Arch Linux FOSS Activities in November 2020 PAM Bypass: when null(is not)ok FOSS Activities in October 2020 Improving the Secure Boot user experience Packaging LXD for Arch Linux Reproducible Arch Linux Packages Mailpile, sendmail and procmail The State of Hy Morten Linderud
Stream to chromecast with resolved, vlc and bash
Morten Linderud · 2024-01-07 · via Morten Linderud

Chromecast is one of those devices I just generally use a lot. They are small practical and enables me to stream video or music to my TV from multiple devices. But it also requires you to have a supported browser or video player. This is obviously a bit boring.

There has been multiple command line chromecast streamers through the years. But their ffmpeg usage has been shoddy at best with no hardware decoding support and usually quite bad implementations.

Instead of using these tools I have wound up with two bash scripts that pipes together a command line program to stream towards chromecasts and it works surprisingly well.

The first part of this is how we stream towards the chromecast. This is easily solveable with vlc luckily. You can just open vlc file://...., select Playback -> Renderer and generally find the correct chromecast there. But this is boring. We have to manually open the GUI and select the device!

I can peak into the app on my phone and learn that the local IP of my chromecast is 192.168.1.231. With clvc you can also pass sout and sout-chromecast-ip to auto-start a headless VLC players that will connect towards your chromecast.

IP="192.168.1.231"
cvlc --sout "#chromecast" --sout-chromecast-ip="$IP" "file://...."

This works really well on it’s own. You can also pipe yt-dlp into clvc and support most media websites like youtube or twitch. This allows you to quickly write up some scripts to stream from these sites and is fairly flexible.

IP="192.168.1.231"
yt-dlp "https://twitch.tv/sovietwomble" -o - | \
cvlc --sout "#chromecast" --sout-chromecast-ip="$IP" -

There is one issue though, that IP is not static. If the chromecast reconnects to the network it might change it’s IP, and I’m never going to bother setting a static device.

Luckily chromecast announces itself over DNS Service Discovery which allows devices to announce themself over the network through DNS names. To query for these devices we will be using systemd-resolved and resolvectl. You can probably use another DNS query tool, but systemd-resolved also supports mDNS which is useful for finding services on the network.

First you need to enable systemd-resolved through systemctl enable --now systemd-resolved. Your mileage might wary but in some distributions this comes enabled by default. It’s also important to note that you don’t need to make resolved your default stub resolver for any of this to work.

If you do read the resolvctl(1) man page you will see it has native support for dns-sd through resolvectl service.

$ resolvectl service _googlecast._tcp local

However I have not gotten this to work as it seems like it will try to send a combined DNS query to your network DNS resolver, and this doesn’t seem supported depending on the router you have. So we have to implement this ourself. So we will be using the PTR+SRV+TXT process as outlined in RFC6763.

To find available chromecasts on the network we’ll first query for PTR records on _googlecast._tcp.local.

$ resolvectl --type=PTR query _googlecast._tcp.local
_googlecast._tcp.local IN PTR Chromecast-Ultra-13ccb56dd0ea6ce65dbe15b39c573856._googlecast._tcp.local

Here I see one Chromecast. Then we need to query for the service record it self, SRV is defined as part of RFC2782.

$ resolvectl --type=SRV query Chromecast-Ultra-13ccb56dd0ea6ce65dbe15b39c573856._googlecast._tcp.local
Chromecast-Ultra-13ccb56dd0ea6ce65dbe15b39c573856._googlecast._tcp.local IN SRV 0 0 8009 13ccb56d-d0ea-6ce6-5dbe-15b39c573856.local

And finally we can just query the TXT record of the service for the IP of the device itself, which is the correct IP we started out with :)!

$ resolvectl query 13ccb56d-d0ea-6ce6-5dbe-15b39c573856.local
192.168.1.231

To make this easier in the future we can easily parse this space limited output with read in a bash script1.

$ ~/.local/bin/dns-sd
#!/usr/bin/bash
set -e
read -r _ _ _ ptr _ < <(resolvectl --type=PTR query "$1")
read -r _ _ _ _ _ _ srv _ < <(resolvectl --type=SRV query "$ptr")
read -r _ ip _ < <(resolvectl query "$srv")
printf "$ip"

And we can make our chromecast script as well which calls dns-sd.

$ ~/.local/bin/chromecast
#!/usr/bin/bash
IP="$(dns-sd _googlecast._tcp.local)"
echo "Using $IP"
yt-dlp "$1" -o - | cvlc --sout "#chromecast" --sout-chromecast-ip="$IP" -

With this we have a neat way to stream web content to our chromecast without having to go through a GUI.

Bonus content: qutebrowser

If you, like me, enjoy qutebrowser but find the lack of chromecast support annoying we can resolve that with the script above.

We’ll use the current chromecast script from qutebrowser:

https://github.com/qutebrowser/qutebrowser/blob/main/misc/userscripts/cast

And apply the diff here, which just removes code we don’t really need.

diff --git a/misc/userscripts/cast b/misc/userscripts/cast
index ec703d5fb..57c8f95f9 100755
--- a/misc/userscripts/cast
+++ b/misc/userscripts/cast
@@ -139,37 +139,6 @@ printjs() {
 }
 echo "jseval -q $(printjs)" >> "$QUTE_FIFO"

-tmpdir=$(mktemp -d)
-file_to_cast=${tmpdir}/qutecast
-cast_program=$(command -v castnow)
-
-# pick a ytdl program
-for p in "$QUTE_CAST_YTDL_PROGRAM" yt-dlp youtube-dl; do
-    ytdl_program=$(command -v -- "$p")
-    [ "$ytdl_program" == "" ] || break
-done
-
-if [[ "${cast_program}" == "" ]]; then
-    msg error "castnow can't be found"
-    exit 1
-fi
-if [[ "${ytdl_program}" == "" ]]; then
-    msg error "youtube-dl or a drop-in replacement can't be found in PATH, and no installed program " \
-        "specified in QUTE_CAST_YTDL_PROGRAM (currently \"$QUTE_CAST_YTDL_PROGRAM\")"
-    exit 1
-fi
-
-# kill any running instance of castnow
-pkill -f -- "${cast_program}"
-
-# start youtube download in stream mode (-o -) into temporary file
-"${ytdl_program}" -qo - "$1" > "${file_to_cast}" &
-ytdl_pid=$!
-
+pkill -f -- chromecast
 msg info "Casting $1" >> "$QUTE_FIFO"
-# start castnow in stream mode to cast on ChromeCast
-tail -F "${file_to_cast}" | ${cast_program} -
-
-# cleanup remaining background process and file on disk
-kill ${ytdl_pid}
-rm -rf "${tmpdir}"
+chromecast "$1"

Then add a keybind into config.py.

config.bind(',c', 'spawn --userscript cast')

Ta-da, chromecast support with our script.

Back to posts