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

推荐订阅源

Vercel News
Vercel News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Apple Machine Learning Research
Apple Machine Learning Research
T
Tailwind CSS Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
V
V2EX
量子位
Last Week in AI
Last Week in AI
Jina AI
Jina AI
博客园 - 【当耐特】
爱范儿
爱范儿
宝玉的分享
宝玉的分享
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Hugging Face - Blog
Hugging Face - Blog
博客园 - 三生石上(FineUI控件)
有赞技术团队
有赞技术团队
小众软件
小众软件
IT之家
IT之家
博客园_首页
博客园 - 聂微东
S
SegmentFault 最新的问题
阮一峰的网络日志
阮一峰的网络日志
博客园 - 叶小钗

Morten Linderud

Resigning from Arch Linux 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
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