Service for persisting a session indefinitely across multiple Chromecast devices.


Keywords
chrome, chromecast, multiple, screens, persist, chromecast-device, mdns, multicast, node, receiver
License
ISC
Install
npm install multicast@2.1.5

Documentation

MultiCast v2.0

npm version Build Status

💚 A persistent solution to presenting content across multiple Chromecast devices, inspired by Greenscreen.

Developed with Node, Express, and Mongo.

Usage

Home

home

From the home page, you can manage displays via Chromecasts, manage all available content via Channels, create and trigger alerts via Push Alerts, or takeover all display by starting a Takeover.

Channels

channels

All content is managed via Channels, which are unique URLs that can be assigned to each individual device. There is no limit on the number of Channels you can have available at any one time, and you can freely switch between them on a per-device basis.

To access Channels, select Channels from the homepage, or click Channels in the top right of the interface.

channel

A channel consists of a Name and Layout. The channel's name will be used to refer to it throughout the interface, but will never be displayed on the actual device when it is being cast. The channel's layout allows one or more URLs to be embedded (via iframe) into the page that will be cast. Two layouts are provided, though creating additional layouts is not especially difficult (see Creating Layouts).

Devices

devices

Chromecast devices are now interfaced with as mDNS devices via the new Castv2 API. This removes the Chrome/Chromium browser restriction that previously existed with Chromecast devices, and even allows Multicast to be run remotely from a headless server (see Setup).

All Chromecast devices on the same network as the host will display here. Devices can be registered to be activated as Multicast receivers and assigned a channel, receive push alerts, and so on.

To register a device, click on the device's name or click Register Chromecast.

register

A device's name will be whatever the Chromecast's name was when it was set up. A device's Location can be set to anything you would like to clarify where it is located. Make sure to choose something descriptive, as this will make Channel management easier down the line.

You can choose not to select a Channel when registering a device - doing so will leave the device on the default registration screen until a Channel is selected.

device

Once a device has been registered, you can select its name from the Devices list to change the Channel it is displaying, refresh its Channel content, or Reconnect it if loses connection.

Push Alerts

push

Push Alerts are useful for displaying small pieces of information to all receiver devices. Alerts will begin displaying on all connected receivers as soon as they are created, and will continue to display until their set duration is reached or the receiver is reset.

Channel Takeover

takeover

A Channel Takeover allows all receiver devices to be temporarily, indefinitely redirected to a single channel. A Takeover will begin immediately after it is started, and will last until it is manually stopped from the homepage.

*Takeovers will also affect devices that are registered after they have begun.

Getting Started

Prerequisites

This project requires Node.js and NPM (bundled with Node), as well as a MongoDB server. Since Node is cross-platform, it should work on Windows, MacOS, and Linux.

This project depends on node_mdns, which in turn requires a mDNS stack. Follow the installation instructions here for whichever platform you are on to install a mDNS stack. If you're on Linux, this is as simple as

Debian/Ubuntu

sudo apt-get install build-essential libavahi-compat-libdnssd-dev

RedHat/Fedora/CentOS

sudo yum install gcc gcc-c++ avahi avahi-compat-libdns_sd avahi-compat-libdns_sd-devel nss_mdns

Setup

If you don't already have access to a MongoDB server installation, follow the guide here.

Grab the latest stable copy of Node/NPM from here or install it via nvm.

In order to access the Chromecast API, you need to register as a Cast developer (it costs $5).

Once you've done this, log in to the Cast Developer SDK Console and click Add New Application. Choose Custom Receiver, then name it Multicast and set the Receiver Application URL to http://YOUR_LOCAL_IP:3944/landing. Disable Guest Mode and then Save.

NOTE: Make sure to use your LAN IP here (192.168.1.xx or similar), not your WAN/external IP. This should resolve to your server only within your local network.

You now need to register your Chromecast devices as developer devices. For each device, locate the Serial Number (located on the back of the device and on the box), click Add New Device, and enter the Serial Number and a brief Description. (NOTE: This may take up to 15 minutes to take effect. Go grab a cup of coffee and then head back.)

Installation is a snap with NPM.

npm i multicast -g
multicast config
multicast start

Head over to http://YOUR_LOCAL_IP:3944/ in your browser to get started, then simply follow the Usage guide to get off the ground.

For development, you can install locally via Github - clone this repository to your local machine, then head into the cloned directory and create a .config file for your setup.

git clone https://github.com/superhawk610/multicast
cd multicast
cp .config.template .config
vim .config

NOTE: You should leave mongoAuthSource and mongoPort set to their default unless you know what you're doing.

Install Node modules

npm install

Build files using Gulp

gulp

Run the application

node .

Firewall Settings

In order for a Chromecast to establish and maintain a connection with a Cast sender, the sender must open two ports:

1900/UDP (DIAL) 5353/UDP (mDNS)

Make sure that the device running MultiCast has these ports open, as well as the standard HTTP ports

80/TCP/UDP (HTTP) 443/TCP/UDP (HTTPS)

Flags

--serve-only - Do not attempt to connect to any devices, just serve files via Express. Useful for debugging.

Having Trouble?

Common Errors

*** WARNING *** The program 'nodejs' uses the Apple Bonjour compatibility layer
of Avahi. *** WARNING *** Please fix your application to use the native API of
Avahi! *** WARNING *** For more information see
http://0pointer.de/avahi-compat?s=libdns_sd&e=nodejs *** WARNING *** The program
'nodejs' called 'DNSServiceRegister()' which is not supported (or only supported
partially) in the Apple Bonjour compatibility layer of Avahi. *** WARNING ***
Please fix your application to use the native API of Avahi! *** WARNING *** For
more information see
http://0pointer.de/avahi-compat?s=libdns_sd&e=nodejs&f=DNSServiceRegister

Don't worry about this. This warning shows up in all Node apps on Linux that depend on libavahi-compat-libdnssd-dev. You can safely ignore it.

Can't launch after installing via NPM? Make sure your NODE_PATH environment variable correctly includes the global store for node dependencies. On Linux:

export NODE_PATH=/opt/lib/node_modules

Multicast can't find your devices? Make sure they've already been setup and powered on and the display that they're connected to is powered on and displaying their output.

If you can view them from other Cast-enabled apps but not from Multicast, its likely an issue with your firewall. Make sure you configured your firewall correctly (see Firewall Settings).

Using Node 8.6+?

EDIT: This has been patched as of node_mdns 2.3.4. This fix is no longer required.

The most recent version of node_mdns has an incompatibility with v8.6 due to changed syntax for a method (see this pull request). Until it is fixed in the main branch, you will need to patch it yourself. Edit node_modules/mdns/lib/resolver_sequence_tasks.js and make the following change (roughly line 115):

   function getaddrinfo_0_11(host, family, cb) {
     var req = new cares.GetAddrInfoReqWrap()
-      , err = cares.getaddrinfo(req, host, family)
+      , err = cares.getaddrinfo(req, host, family, 0, false)
       ;
     req.oncomplete = function oncomplete(err, addresses) {
         getaddrinfo_complete(err, addresses, cb);

Running CentOS and Seeing This Error?

Error: getaddrinfo -3008

Make sure you have nss_mdns installed:

sudo yum install nss_mdns

Issues

If you run into any problems while using this, please report them here.

Authors

superhawk610 Aaron Ross - author - superhawk610

Brekmister Brekmister - contributor

ocelotsloth Mark Stenglein - contributor - ocelotsloth

andrewpryor Andrew Pryor - contributor - andrewpryor

Contributing

  • NEW: Use a code editor that supports Prettier and the included .prettierrc.yml
  • Follow the existing code formatting (2 spaces, not tabs, no hanging brackets, no semicolons, etc)
  • Comment your code to explain anything more complex than a routine action
  • Provide rationale for any changes you request
  • Use thorough commit/pull request messages

Active Branches

main (stable) all features in this branch are fully implemented and ready to go

api (unstable) this branch implements receiver grouping and remote control by splitting all functions out into an independent REST API

rotation (stable) this branch adds the ability to display channels at 90/180/270 degress of rotation

authentication (unstable) this branch adds a login page and POST/DELETE request verification

logging (unstable) this branch adds real-time logging & monitoring of all console/page-load errors from receiver devices back to Multicast's web interface

Creating Layouts

Creating a channel layout is simple, and consists of two things:

CSS Layout

Copy app/views/layouts/template.pug and change the name to your new channel layout name (e.g. - my-layout.pug).

Change the class applied to the body to the name of your channel layout (e.g. - body.my-layout).

In build/css/channel.css, add rules to style each iframe in your layout, prefixing each with body.layout-name, replacing layout-name with your layout name. Refer to the existing rules for inspiration.

NOTE: Channel sections are currently limited to 4 per channel. To increase this, change maxSectionCount on app/views/channel.pug.

CSS Icon Design

In app/views/channel.pug, add a div under #channel-layout with the class layout and layout-name, again replacing layout-name with your layout name. Make sure this div has the class active when the channel is using your layout, as such:

.layout.layout-name(class=(channel && channel.layout == 'layout-name' ? 'active' : ''))

Style this div in build/css/channel-edit.css to conform to the existing channel layouts:

width: 250px;
height: 150px;
border: 1px solid rgb(202, 206, 215);

Once you finish, don't forget to gulp everything to apply your new layout.

Security Disclosure

This project relies on node-castv2 which uses an outdated version of protobuf. I am in the process of getting this vulnerability patched - current status is tracked here. Details of the vulnerability can be found here.

License

This project is licensed under the MIT License - see LICENSE for more details.

Acknowledgments

Special thanks to Greenscreen and the team over at Groupon for inspiring this product.