<div align="center" style="display: inline">
    <img src="https://gitlab.com/spease/IronCast/-/raw/master/ironcast/img/icon.png">
</div>

# IronCast

>A well-seasoned streaming ecosystem.

IronCast was born from a desire to replace cloud-based intrusive stream sticks with a open source, privacy-focused, entirely local alternative- while keeping the simplicity, ease of use, and light-weight interface. 

Streaming to your TV should be no more complicated that clicking 'share to screen.' 

## Install

These instruction are for the Raspberry Pi 4. IronCast is currently in a beta state, and is rapidly changing faster than PyPi is updated- you may be better served installing it by cloning the repo and installing it via `pip update -e .` instead of the last step.

```shell
$ # Install dependencies.
$ sudo apt install libcec-dev build-essential python3-dev libgl1 libglx-mesa0 libmtdev1 libgles2-mesa-dev
$ pip install --upgrade pip # Upgrade pip
$ python3 -m venv env  # Set up virtual environment
$ . env/bin/activate  # Activate virtual environment
$ pip install ironcast  # Install IronCast
```

## Server Usage

```shell
$ start-ironcast
```

This will start up IronCast and make it ready to receive streaming requests delivered from a DLNA Media Controller, such as BubbleUPnP.

## Client Usage

Once you open your DLNA client, you should see a place to choose a renderer. At that point, you should see your IronCast. Its name will be the title-cased hostname of the server it's running on, with any hyphens replaced with spaces.

For example, if the hostname of your Raspberry Pi is `living-room-ironcast`, then it will show up as a renderer as "Living Room IronCast."

Most DLNA Media Controllers, such as BubbleUPnP, will then make that renderer available in the 'share' dialog of media players. You can, for example, open up YouTube, click the 'Share' icon, and 'Share to Living Room IronCast' will be an available target.

## Contributing

To submit a contribution to IronCast, fork the repo and create a development/feature branch. Submit a pull request for your addition.

Code contributions must not reduce the pylint score, must be isorted, and must have had black run on it.

`pip install -e .` and `pip install -e .[dev]` can be used to pip install a local git repo, instead of the production version on PyPi.

## To-do

In no particular order:

- HDMI-CEC navigation- allow play/pause/stop/skip/seek/etc using the TV remote, not just the phone.
- Audio playback- allow non-video casting, such as audio tracks and/or pictures.
- Better preview images- the 'loading' image preview is the last video's 'preview' image, this should be fixed to the current video's. Replace the `Video` widget with a custom one that handles an AsyncImage for preview instead. Add a loading animation?
- Better video pre-loading- due to a bug in Kivy, the video cannot be pre-loaded, only downloaded once play is already started. This should have the side effect of better state handling.
- Installation support- pip install should create a systemd service that keeps the script running at all times, and runs it at startup. (Perhaps off a script to do this? `install-ironcast` to pair with `start-ironcast`?)
- Auto-update- check for updates, and if IronCast is not active, update and exit. (Systemd will then restart on the new version.)
- Create a `develop-ironcast` script that is identical to `start-ironcast`, but checks for updates on the current repo branch that is locally installed. Maybe only installed with `[dev]`?
- Better end-of-video tracking- when a video ends, hold on the last frame or move to the next video in the playlist (if the render controller doesn't handle that for us).
- Testing against more DLNA media controllers than BubbleUPnP- especially desktop/non-mobile options.
- See if we can get direct URIs to be sent, instead of streaming from the render controller, to save phone battery.
- Idle detection- if we haven't played a video in a while, go back to the idle screen (and declare we are no long an active video source).
- State changes should generate a LastChanged event to subscribed controllers, along with Seeks and any other major control events (since there may be multiple phones connected, or TV remote changes.)
- Volume control- we're not properly advertising that we can control volume state, despite doing so. We probably can't allow control of the audio state of the TV/soundbar, because implementation of that is flakey, so we'll need to control our own volume (or maybe only do that as a fallback?)
- Raspberry Pi Zero W2 support- see if we can get this running as a 1080p cast target on a Pi ZeroW2. That would be a great sweet spot for cost, but it's going to be tight. 4K will be limited to stronger Raspberry Pi.
- Better 4k TV support- right now it's letterboxing non-4k content on 4k TVs instead of upscaling.


## Development References

- [DLNA Spec](https://web.archive.org/web/20090123025143/http://upnp.org/specs/av/av3.asp)
- [CEC Frame Codes](https://www.cec-o-matic.com/)
- [UPnP Spec](https://openconnectivity.org/upnp-specs/UPnP-arch-DeviceArchitecture-v2.0-20200417.pdf)


With thanks to mitnk- your implementation of tiny-dlna gave me ideas of where to start on this project, as well as the motivation to do so.

