components/mirroring/service/README.md
//components/mirroring/service)This directory contains the internal implementation of the Cast Mirroring Service.
This service is designed to run in a sandboxed utility process. It handles the heavy lifting of Cast streaming: session negotiation, capturing media from the browser, encoding, packetizing, and transmitting it to a Cast receiver.
Sandboxing & Resources: Because this code runs in a sandboxed utility
process (specifically kMirroringSandbox or kHardwareVideoEncoding), it
cannot make direct system calls to open sockets, capture screens, or
access the GPU. All external resources must be requested asynchronously over
Mojo via the mojom::ResourceProvider
interface (implemented by the browser process).
Threading/Sequences: The service operates primarily on a single main
sequence. The SEQUENCE_CHECKER macro is heavily used to enforce this. The
network and media encoding may utilize background threads or the
io_task_runner, but state mutations and Mojo message handling must happen
on the main sequence.
Open Screen Environment: The service bridges Chromium's
base::TaskRunner and
base::Time into the
openscreen::cast::Environment
required by the Open Screen library. This bridging is implemented by the
Chromium-wide //components/openscreen_platform/
component and is instantiated during session creation in
OpenscreenSessionHost.
The Mirroring Service manages the Cast Streaming session negotiation, relying heavily on the Open Screen library which implements the underlying Cast protocols and the OFFER/ANSWER exchange mechanisms.
To prioritize performance and power efficiency, the Mirroring Service may send up to two offers when establishing a session:
Hardware-First Offer: The service initially sends an OFFER containing
only hardware-accelerated video codecs.
Software Fallback: If the receiver rejects this initial offer (indicated
by a kNoStreamSelected error from Open Screen), the service gracefully
falls back by sending a second OFFER that includes software-based video
codecs (e.g., software VP8 or VP9).
*** note This two-stage negotiation ensures hardware encoding is prioritized while maintaining compatibility with receivers that might only support specific software codecs.
If you are new to the Mirroring Service, these are the key classes to understand, in order of execution:
mojom::MirroringService interface.
It is the entry point that the browser process calls to Start() a session.
It primarily manages the lifecycle of the
OpenscreenSessionHost.openscreen::cast::SenderSession,
handles the two-stage OFFER/ANSWER negotiation, sets up the network via
Mojo, and wires up the capture/audio sources to the RTP streams. It uses a
relatively simple state model, transitioning between kInitializing,
kMirroring, kRemoting, and kStopped.VideoCaptureClient &
CapturedAudioInput
media::VideoFrame and audio PCM
data from the user's screen or tab.media::cast::VideoSender
(or AudioSender) and handles the actual encoding and pushing of media
frames to the Open Screen
SenderPacketRouter.base::Feature flags
owned by the Mirroring Service. This is the central location for
kill-switches and experimental feature toggles.OpenscreenSessionHost asks the browser's
ResourceProvider for a
network::mojom::NetworkContext.
It uses this to create a UDP socket.
This socket is wrapped in an
openscreen::cast::Environment
and passed into the Open Screen SenderSession.
VideoCaptureClient receives a raw
media::VideoFrame from the browser.
The frame is passed into RtpStream.
RtpStream pushes it into
media::cast::VideoSender
(which encodes it via hardware or software).
The encoded frame is passed to the Open Screen
cast::Sender
to be packetized and sent over the UDP socket.
There are several ways to test changes to the Mirroring Service, ranging from fast local unit tests to full end-to-end integration.
The Mirroring Service has a comprehensive suite of unit tests located within
this directory (e.g.,
openscreen_session_host_unittest.cc).
These tests use mock browser interactions and mock network contexts to validate
the state machine without needing a real Cast device.
autoninja -C out/Default mirroring_unittests && ./out/Default/mirroring_unittests
For end-to-end local testing without a physical Chromecast, you can use the
Open Screen cast_receiver executable.
Build the receiver within your Chromium checkout:
autoninja -C out/Default cast_receiver
Generate a developer certificate and start the receiver. Find a valid
network interface (e.g., eth0 or en0) and run:
./out/Default/cast_receiver -g <interface_name>
Note: This generates generated_root_cast_receiver.crt in your current
directory and starts the receiver listening on that interface.
Launch Chrome pointing to this developer certificate:
./out/Default/chrome --cast-developer-certificate-path=/path/to/generated_root_cast_receiver.crt
The cast_receiver will now appear as a Cast destination in Chrome's Cast
dialog, allowing you to mirror tabs or your desktop directly to the local
terminal window. See the
Open Screen USING.md
document for more detailed instructions.
For final validation, test against a physical, production Chromecast or Google Nest Hub device on the same local network. Start Chrome normally, select "Cast..." from the "Cast, Save, and Share" context menu, and ensure the session establishes and mirrors / remotes successfully with your changes.
When debugging a dropped connection, stuttering frames, or a failed negotiation, rely on the following Chromium tools:
The Cast and Mirroring components are heavily instrumented with VLOG. To see
these logs, launch Chrome from the command line with the following flags:
./out/Default/chrome --enable-logging=stderr --vmodule="*mirroring*=2,*cast*=2,*openscreen*=2"
This will print detailed connection states, packet drops, and bandwidth estimates directly to your terminal.
Navigate to chrome://media-router-internals in your browser. This page is
crucial for Cast debugging. It contains:
chrome://tracing or Perfetto)If you are manually recording a performance trace for latency investigations or dropped frames (instead of using the "Record Trace" button mentioned above), ensure you capture the following specific categories:
media.cast: High-level media encoding and pipeline states.cast_perf_test: Instant trace events for specific frame lifecycle milestones
(e.g., when a frame is received from capture, encoded, and sent).openscreen: Network-level packetization, RTP/RTCP events, and pacing from
the underlying Open Screen library.media and gpu: To investigate issues with hardware encoding or video
capture.