by Pivec Labs
TutorialHost-Broadcast

Host-Broadcast

⏱ 15–20 min Uses the shipped HostBroadcastDemo scene

Prerequisites: NetCrafter Live installed; com.unity.webrtc installed (Package Manager); your own self-hosted coturn + rendezvous server up and running (see the Server Deployment Guide or just run the Server Setup Wizard); a second machine, build, or Editor instance to view the broadcast from.

What you'll build: Nothing — this tutorial runs the demo scene that already ships with the package (Examples/HostBroadcastDemo/) and explains what it's doing, so you can see a real NetCrafterLiveBroadcast integration working before you build your own UI around it.

01

Open the demo scene#

text
Assets/PivecLabs/NetCrafterLive/Examples/HostBroadcastDemo/HostBroadcastDemo.unity

Double-click it in the Project window. Select the Read Me First GameObject in the Hierarchy to see the same summary in the Inspector.

The scene has one NetCrafterLiveBroadcast GameObject and one HostBroadcastDemoController GameObject wiring a plain UI to it. A single instance of this scene can act as either the host or a viewer — which one it does depends entirely on which button you click, not a separate scene or a compile-time choice, since a real game usually can't know in advance which player will host.

Everything except the two video previews themselves — title, buttons, toggles, status/code/error labels, the viewer grid — lives in a collapsible settings panel, visible by default. The Hide Settings/Show Settings button in the top corner (a sibling of the panel, so it's never hidden along with it) toggles it; the video previews stay on screen either way.

02

Get a server running, assign Relay Settings#

Same as the 1-to-1 tutorial: run the Server Setup Wizard (Tools → Pivec Labs → NetCrafter Live) if you haven't already, then select the NetCrafterLiveBroadcast GameObject in this scene and click Assign Project's Relay Settings in its Inspector. The demo ships with connectionSettings unassigned on purpose — this is the one manual step every fresh scene needs.

03

Start a broadcast#

Press Play. Click Start Broadcast. Within a couple of seconds:

  • The Broadcast code label fills in — from BroadcastCodeReady.
  • Status shows Broadcasting.
  • Your camera feed appears in the local preview panel (labelled "what viewers see"), driven by LocalVideoTextureAvailable — media is captured once here, regardless of how many viewers eventually join.

Share the broadcast code with as many viewers as you want, or click the Copy button next to the code label to grab it straight from broadcast.CurrentBroadcastCode onto the clipboard instead of selecting the label text by hand.

The Start Broadcast button itself only appears when broadcast.allowHosting is true (the default) — this is the same field a receive-only spectator build would set false, see Viewer-only builds below.

04

Join as a viewer#

On another machine/build/Editor instance, open the same scene, assign Relay Settings there too, paste the broadcast code into the input field, and click Join Broadcast.

  • The viewer's status reaches Viewer: Connected once negotiation completes.
  • The viewer's remote preview panel fills in with the host's video, driven by RemoteVideoTextureAvailable. Audio plays automatically.
  • Back on the host, a small tile appears in the Viewers grid the moment that viewer's peer connection is created (ViewerJoined) — a colored presence dot plus the viewer's id, no video (there's nothing to preview; see below). The dot recolors live as that viewer's connection state changes (ViewerStateChanged: yellow while connecting, green once connected, red on failure/disconnect) and the tile disappears entirely if the viewer leaves or the connection fails for good (ViewerLeft).

Join from a few more instances if you want to see the viewer grid actually behave like a grid.

05

Why viewers are receive-only#

Notice a viewer's side never asks for camera/microphone permission at all, and there's no local-preview panel on the viewer side. That's not a limitation of this demo — it's the real design: NetCrafterLiveBroadcast viewers connect with recvonly WebRTC transceivers, meaning nothing is ever sent back to the host. For a broadcast (one game feed or camera shown to many watchers), that's exactly right — and it's a real, deliberate selling point of this architecture, not an oversight: fewer permission prompts for viewers, less upload bandwidth for the host to worry about as the audience grows, and one less thing that can go wrong per viewer.

If a viewer's connection ever did send the host a track, the host would log it as an explicit anomaly rather than silently accepting it — see the API Reference's note on this.

06

Try the other options#

Same toggles as the 1-to-1 demo, same reasoning, plus the host-only naming difference called out below:

  • Use RenderTexture source (host) — host-only, switches videoSource to stream from the demo's built-in rotating-cube camera rig instead of a webcam. Viewers are unaffected either way (they never capture anything, so this toggle doesn't even appear on the receiving end conceptually — it's purely a host-side choice).
  • Force-Relay — same setting, same reasoning as the 1-to-1 tutorial. See the Player Hosting Guide for what it actually does and the stale-credential symptom it's most likely to expose.
  • World-space preview — flips broadcast.videoDisplayMode between ScreenSpace2D (default) and WorldSpace3D, applying to whichever side (host or viewer) this instance is currently acting as. With it on, the local/remote previews move from the screen-space RawImages to two draggable 3D panels instead — click and drag one around; it tilts slightly near its edges. See the Player Hosting Guide's display-modes section for the full pattern and the API Reference for the enum itself.
07

Viewer-only builds#

allowHosting (default true — see Part 3 above) is the field a dedicated spectator build sets to false: it gates StartBroadcast() only, JoinBroadcast() and every viewer-side capability are unaffected. It's enforced inside StartBroadcast() itself, not just by hiding the button, so a viewer-only build stays viewer-only against a stray hotkey or script bug too. The demo's controller mirrors this convention: it hides the Start Broadcast button up front (startBroadcastButton.gameObject.SetActive(broadcast.allowHosting)) rather than leaving it visible and relying on the runtime guard alone. See the Player Hosting Guide's viewer-only builds section for the full walkthrough.

08

How it works#

HostBroadcastDemoController is a thin UI layer over NetCrafterLiveBroadcast's public API — nothing it does isn't already available to you:

csharp
startBroadcastButton.onClick.AddListener(() => broadcast.StartBroadcast());
joinBroadcastButton.onClick.AddListener(() => broadcast.JoinBroadcast(joinCodeInput.text));

broadcast.BroadcastCodeReady += code => /* show the code */;
broadcast.ViewerJoined += viewerId => /* spawn a presence tile */;
broadcast.ViewerLeft += viewerId => /* remove that tile */;
broadcast.ViewerStateChanged += (viewerId, state) => /* recolor that tile's dot */;
broadcast.LocalVideoTextureAvailable += tex => localPreview.texture = tex;   // host
broadcast.RemoteVideoTextureAvailable += tex => remotePreview.texture = tex; // viewer
broadcast.VideoDisplayModeChanged += mode => /* swap screen-space <-> world-space preview objects */;

The viewer grid itself is an ordinary Unity pattern, not anything WebRTC-specific: an inactive template tile (ViewerTileTemplate, a colored dot + a label) gets Instantiate()d once per ViewerJoined and Destroy()ed once per ViewerLeft, tracked in a Dictionary<string, GameObject> keyed by viewer id.

09

Where to go from here#

  • API Reference — the complete NetCrafterLiveBroadcast field/event/method list, including RemoveViewer() (host-side kick, not used by this demo) and allowHosting.
  • Player Hosting Guide — what actually happens on the wire for StartBroadcast()/JoinBroadcast(), a from-scratch viewer-grid example to build your own UI on top of, display modes, and building a viewer-only build.
  • Manual — the Relay Settings and Server Setup Wizard tabs in full.