On this page Configure video supportPrepare the hotspot and displayTurn packets into displayed framesPreserve the session and network peeriOS screen mirroring
HARDWARE SDK / FreeRTOS

Video projection

Integrate H.264 / MJPEG reception, decoding, presentation and mirror control.

Receive phone H.264 / MJPEG video over Wi-Fi, decode it and present it on the LCD. Ordinary video and independent mirroring can use the managed FreeRTOS interface; mirroring requires an explicitly enabled separate control connection. Complete first adding and primary connection; large-screen navigation must also handle navigation HUD.

Configure video support

After integrating HUD on a large screen, configure its supported decoder before creating the SDK. For example, a 1024×600 screen with MJPEG:

c.width = 1024;
c.height = 600;
c.mjpeg.enabled = true;
c.mjpeg.fps = 13;
c.mjpeg.bitrate = 12000000; // bit/s

These are example values. Choose a frame rate your display can sustain. Use c.h264 for H.264 support. Each enabled codec needs 1–30 FPS and a positive bitrate. Dimensions must be nonzero, even, and no larger than 1920×1080.

Prepare the hotspot and display

e is the original event. For asynchronous completion, use the copy saved when it arrived.

Event Board action Completion
MOTO_EVENT_WIFI, purpose=0 Reuse the running business AP; verify IP, DHCP and UDP listener moto_terminal_wifi_ready(t, &e, &ap)
MOTO_EVENT_STREAM_PREPARE Prepare decoder and receive/display buffers for e.data.stream moto_terminal_complete(t, &e, MOTO_SUCCEEDED, 0)
MOTO_EVENT_STREAM_START Receive this stream; save e.session and stream_id Confirm frames after actual display
MOTO_EVENT_STREAM_STOP Stop receiving, decoding and display submissions Release this stream’s resources

STREAM_STOP ends video, not navigation: do not clear valid HUD data just because video stopped. Clear expired prompts on HUD_EXPIRED and navigation UI on NAV_END or CLOSED.

Prepare the hotspot within 30 seconds and video within 10 seconds. Report failures using complete(..., MOTO_FAILED, reason). A Wi-Fi request with purpose=1 is for firmware updates and purpose=2 is for advertising transfers; neither enters the video path.

ap is a moto_terminal_hotspot. Fill its actual SSID (1–32 bytes), password (8–63 bytes), IP and UDP port. The reference hotspot uses 192.168.4.1:5001. Other addresses must match the authenticated device endpoint and actual listener; changing this example alone does not configure a different network. Report readiness after the hotspot is connectable; keep passwords out of logs.

Before reporting readiness, verify WPA2 with the configured device AP password, the AP interface matching the reported IP, a working DHCP service for that subnet, and a UDP listener bound to port 5001. Retain AP association and DHCP lease information to associate the video source with the current phone. Submitting an AP-start request is not readiness. On MOTO_FULL, retain the original event and hotspot parameters and retry later; release video resources if the session becomes invalid; retain the primary AP and listener.

Turn packets into displayed frames

The reassembler in moto/video.h joins UDP packets into compressed frames. Your decoder converts those frames into pixels:

UDP → moto_video_receive → complete-frame callback
→ MJPEG / H.264 decode → LCD display completion → moto_terminal_presented

After creating the reassembler, bind the stream and receive packets as described below. Frame memory is borrowed only during its callback; copy it for asynchronous decoding. Request H.264 recovery through moto_terminal_keyframe when a keyframe is needed.

Preserve the session and network peer

session identifies the control session, stream_id identifies the video stream, and peer_token is a nonzero identifier allocated by your network adapter to a verified phone. Store them separately. They are not interchangeable; never use a constant such as 1 for the peer token.

  1. Verify the phone using the current AP association, DHCP lease and connection context. Accept only that phone’s source IP and pin its video source port. An arbitrary first UDP packet is not proof of an authenticated phone.
  2. After MOTO_EVENT_STREAM_START arrives on the secure channel, copy the full event to the video task. Allocate a token for this verified network peer.
  3. Call moto_video_begin_codec(video, peer_token, stream_id, width, height, codec) and check the result. Feed packets to the reassembler only after MOTO_OK.
  4. For each datagram that passes source validation, call moto_video_receive(video, peer_token, bytes, size, now_ms) with the same token throughout the stream. Call moto_video_tick(video, now_ms) every 10–20 ms. Preserve packet boundaries; each UDP datagram is at most 1400 bytes. Tick has no token argument.
  5. Preserve each frame’s session, stream_id and frame_id through decoding. Call moto_terminal_presented after actual display while the original stream is still valid. Retry MOTO_FULL only for that still-valid stream.
  6. On STREAM_STOP, NAV_END, CLOSED or network loss, call moto_video_stop(video) from the video task, revoke the token and cancel old decode/display work. Discard late acknowledgements from a stopped stream.

Call sequence (verified_peer comes from your network adapter; stream is the saved e.data.stream):

moto_result rc = moto_video_begin_codec(
    video, verified_peer, stream.stream_id,
    stream.width, stream.height, stream.codec);
// After MOTO_OK, process verified datagrams on the same video task:
rc = moto_video_receive(video, verified_peer, bytes, size, monotonic_ms);
moto_video_tick(video, monotonic_ms);
// Stop the current stream:
moto_video_stop(video);

Serialize all moto_video_* calls on one instance. Frame and keyframe callbacks must not reenter it. Abort preparation if reassembler creation fails. Stop all callers before moto_video_destroy(video) during teardown.

iOS screen mirroring

Join the device access point and authenticate the Wi-Fi business session first. Select screen mirroring in the APP, then confirm Start Broadcast in the system panel. The broadcast extension starts encoding only after the terminal acknowledges video preparation and start. Starting a broadcast does not establish that pixels reached the display; verify LCD presentation receipts and the actual screen.

Screen mirroring shares the video receiver, decoder and display interfaces with navigation video, without starting navigation HUD. Bluetooth is not a prerequisite for mirroring.

For Managed, call moto_terminal_set_mirror(terminal, true) after successful create and before start, checking its result before starting. It requires complete config.network, working video support and a primary port other than 5005. Advanced external primary transport is unsupported by this entry. Serialize setup on the lifecycle-owner task; stop/start retains it. The SDK task owns mirror TLS on TCP 5005, authorization and cleanup. Customers still supply video reception, decoding and display without creating another mirror SDK task.

Core integrations can use moto_config.mirror_control=true, mirror_auxiliary and moto_connect_mirror, with instances serialized on one owner thread. PROFILE key32 declares mirror-control support. On unexpected primary TCP loss, Core uses moto_detach_mirror to preserve an already delegated, valid mirror and continues polling; Managed owns this flow automatically.

The extension renews its stream-scoped grant every two seconds and receives presentation/keyframe feedback. Primary TCP EOF/I/O failure may preserve a valid mirror; whole-network loss, explicit stop, revocation or expiry releases media. An r26 terminal declaring PROFILE39 allows a matching APP SDK build to recover primary business through fresh TLS and current owner/mirror authorization. Keep controls disabled until recovery, then refresh vehicle state. Older terminals require broadcasting to stop before reconnecting. See primary recovery.

The extension stops sending after ten seconds without a response; the terminal ends mirroring after twenty seconds without renewal. Auxiliary closure must not be treated as primary business CLOSED. Video remains unencrypted UDP on port 5001.

The current APP has one home-screen projection entry. Without Wi-Fi audio authorization it uses video only, requests no audio permission and hides the vehicle-management audio section. Audio is attached only when authorization and runtime conditions allow it, with the user completing system permission flows.

Managed audio also requires pre-start moto_terminal_set_audio, a real sink and the separate TLS 5006 channel. See audio integration for capability gates, capture sources and teardown.