Skip to content

Instantly share code, notes, and snippets.

@YtvwlD
Last active November 28, 2019 20:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save YtvwlD/fcb74d99d0afdb9bf0ffaaefb96d5094 to your computer and use it in GitHub Desktop.
Save YtvwlD/fcb74d99d0afdb9bf0ffaaefb96d5094 to your computer and use it in GitHub Desktop.
Stream the screen of your Android device to a Chromecast using only free software!

aosp2chromecast

Stream the screen of your Android device to a Chromecast using only free software!

tl;dr: This is just glue code combining ScreenStream, pychromecast and DashCast.

What you'll need

  1. an Android device (obviously)
  2. the app ScreenStream installed on this device
  3. a device with Python 3 installed - can be the same as your Android device (with eg. Termux) or your laptop or something
  4. pychromecast and this script installed on this device
  5. a Chromecast (obviously)
  6. a single network where all these devices are placed in (and are able to see one another - Zeroconf)

What you'll need to do

  1. open ScreenStream on your Android device
  2. start this script with python3 aosp2chromecast.py - if you're running this on a different device, you'll need to pass --url <the URL ScreenStream is displaying>
  3. press the play button in ScreenStream (you could have done this in the first step already)

More options are available (see -h), but this should be enough to get you started.

Be aware that your screen content is transmitted over the network without any encryption - only use this if you trust the network or don't have any sensitive content on your screen.

#!/usr/bin/env python3
from argparse import ArgumentParser, Namespace
import socket
from time import sleep
from typing import List, Optional, Type, TypeVar
from urllib.parse import urljoin
import pychromecast
from pychromecast.controllers.dashcast import DashCastController
T = TypeVar("T")
def parse_args() -> Namespace:
parser = ArgumentParser(description="stream the screen of your Android device to a Chromecast")
parser.add_argument("--url", type=str, help="the URL ScreenStream is displaying (only needed when the app is running on a different device than this script)") # TODO: type=url?
parser.add_argument("--pin", type=int, help="the PIN ScreenStream is displaying (if you do not specify this, you will be asked for it)")
parser.add_argument("--cast_name", type=str, help="the name of your Chromecast (if you do not specify this, you will be presented a list of available devices to select from)")
# TODO: --cast_ip?
args = parser.parse_args()
return args
def ask(what: str, choose_from: Optional[List] = None, type: Type[T] = int) -> T:
if choose_from is None:
while True:
inp = input(f"Please enter {what}: ")
try:
return type(inp)
except ValueError:
print(f"'{inp}' is not a valid {type.__name__}.")
else: # TODO: selection via arrow keys
assert type == int
print(f"Please select a {what} from the following options: (0-{len(choose_from)})")
for idx, name in enumerate(choose_from):
print(f"{idx}. {name}")
while True:
inp = input("> ")
try:
idx = int(inp)
except ValueError:
print(f"'{inp}' is not a valid int.")
else:
if 0 <= idx < len(choose_from):
return idx # correct, but mypy didn't notice
else:
print(f"'{inp}' is not in the range [0, {len(choose_from)-1}].")
def determine_url() -> str:
# Try to find our primary IP address.
# That is of course the one with which we would connect to Google.
# Also, just do IPv4 here.
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.connect(("8.8.8.8", 1)) # This doesn't have to work.
ip = sock.getsockname()[0]
sock.close()
# Just assume that ScreenStream listens on port 8080.
return f"http://{ip}:8080/"
def find_chromecast(name: Optional[str] = None) -> pychromecast.Chromecast:
casts = pychromecast.get_chromecasts()
if name:
for cc in casts:
if name == cc.device.friendly_name:
return cc
else:
print(f"Device {name} not found.")
return casts[ask("Chromecast", [cc.device.friendly_name for cc in casts])]
if __name__ == "__main__":
args = parse_args()
pin = args.pin or ask("PIN", type=int)
url_to_device = args.url or determine_url()
url = urljoin(url_to_device, f"/?pin={pin}")
cast = find_chromecast(args.cast_name)
print(f"Going to open {url} on {cast.device.friendly_name}.")
# TODO: Check whether this URL actually works.
cast.wait() # wait for connection
dc = DashCastController()
cast.register_handler(dc)
dc.load_url(url)
try:
while True:
sleep(1000)
except KeyboardInterrupt:
cast.quit_app()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment