Screen Cast: Chromecast

Hi everyone.
Recently I bought a Tablet and i put on it Fedora with KDE, I came from Galaxy Tab so one of the functions that i miss is the ability to cast the screen from the tablet to a Chromecast device, the problem is that there is not and easy way to cast my screen using wayland on KDE, i found a workaround to cast videos or images using a Brave or VLC, but sometimes i want to cast an application so i need to cast my screen or at least the application window.

I’m a Software Engineer but mostly focused on web development and backend, however I decided to work on this feature with my few knowledge about wayand and kde development, my idea is first, create a service to interact with chromecast protocol(find, devices, stream media, etc…) and second, create a KDE plasmoid for interacting with this service with he ability to cast my screen or a window .

I’m using python right now because it’s the easier way to interact with chromecast that i found but i’m open to alternatives.

here’s my progress:

I wrote a simple script with Python, my idea was use ffmpeg for creating a stream of my screen and cast to an specific chromecast device, it’s not working because the ffmpeg show errors when i try to cast the screen on wayland but the chromecast functions are working: find devices and cast media to those devices.
Here’s my script, it’s only depends on pychromecast pip package:

import pychromecast
import time
import subprocess
import os
from pychromecast.controllers.media import MediaController

def find_chromecasts():
    print("Searching Chromecast devices...")
    chromecasts, browser = pychromecast.get_chromecasts()
    if not chromecasts:
        print("Not found.")
        return None

    print("Chromecast devices availble:")
    for i, cc in enumerate(chromecasts):
        print(f"{i}: {cc.cast_info.friendly_name}")

    selection = int(input("Select Chromecast device: "))
    cast = chromecasts[selection]
    print(f"Connected to {cast.cast_info.friendly_name}")
    cast.wait()
    return cast

def get_displays():
    displays = []
    xrandr_output = subprocess.check_output(["xrandr", "--listmonitors"]).decode()
    for line in xrandr_output.split('\n')[1:]:  # Skip the first line
        if line.strip():
            displays.append(line.split()[-1])
    return displays

def select_display():
    displays = get_displays()
    print("Displays disponibles:")
    for i, display in enumerate(displays):
        print(f"{i}: {display}")
    selection = int(input("Select display: "))
    return displays[selection]

def get_display_resolution(display):
    xrandr_output = subprocess.check_output(["xrandr", "--query"]).decode()
    for line in xrandr_output.split('\n'):
        if display in line and "connected" in line:
            resolution = line.split()[2].split('+')[0]
            return resolution
    return "1920x1080"  # Default resolution if not found

def start_ffmpeg_stream(cast, display):
    ip = cast.cast_info.host
    port = cast.cast_info.port
    resolution = get_display_resolution(display)
    print("Casting to: ", ip)
    ffmpeg_command = [
        "ffmpeg",
        "-f", "x11grab",
        "-r", "60",
        "-s", resolution,
        "-i", f"{os.environ['DISPLAY']}.0+{display}",
        "-vcodec", "libx264",
        "-preset", "ultrafast",
        "-tune", "zerolatency",
        "-maxrate", "5000k",
        "-bufsize", "10000k",
        "-f", "matroska",
        f"tcp://{ip}:{port}"
    ]

    print("starting transmission with ffmpeg...")
    return subprocess.Popen(ffmpeg_command)

def stream_to_chromecast(cast, display):
    mc = cast.media_controller

    print(f"Setting transmission to {cast.cast_info.friendly_name}")
    stream_url = f"tcp://{cast.cast_info.host}:8009"

    ffmpeg_process = start_ffmpeg_stream(cast, display)

    print("Starting Chromecast transmission...")
    mc.play_media(stream_url, 'video/mp4')
    mc.block_until_active()

    print("Play started. Press Ctrl+C To stop.")
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("Stoping transmission...")
        mc.stop()
        cast.quit_app()
        ffmpeg_process.terminate()
        ffmpeg_process.wait()

if __name__ == "__main__":
    cast = find_chromecasts()
    if cast:
        display = select_display()
        stream_to_chromecast(cast, display)

Currently I’m looking for a better way to cast the screen on wayland, so any help is welcome, also i have no idea how to develop the cast widget, I’m focused right now on the functionality so any advice is welcome to.

Also here’s mockup of the plasmoid:

Any help or advice is welcome, thanks for reading.

1 Like