CHAT over NDI v1.0

Metadata Specification (v1.0)

Roberto Musso, December 2025

1. Purpose

This document defines a small XML metadata format to carry bidirectional text messages over NDI metadata streams.

Goals:

  • Provide a simple, interoperable chat channel between NDI endpoints (UIs, controllers, gateways).

  • Allow different devices/apps to map CHAT messages to their own UI (chat window, log panel, on-screen overlays, etc.).

  • Support multi-participant scenarios via explicit sessionId and senderId.

This specification is intentionally minimal but extensible.

2. Design Overview

CHAT messages travel as NDI metadata frames whose root element is:

<ndi_metadata type="chat" version="1.0">...</ndi_metadata>

Inside the root, each metadata frame carries one or more β€œchat sessions”, each containing one or more β€œmessages”.

High-level model:

  • <Session> A logical conversation or chat room (e.g. point-to-point, group, production channel).

  • <Message> A single chat event (text message, status, system notification).

Typical example (single session, single message):

NDI endpoints decide how to interpret Session.id, SenderId, MessageType, etc., and how to render them in their UI.

3. Root Element

3.1 <ndi_metadata>

  • Element name: ndi_metadata

  • Attributes:

    • type (required): MUST be "chat".

    • version (optional): schema version. Current: "1.0".

Constraints:

  • Exactly one <ndi_metadata> root element per NDI metadata frame.

  • No XML prolog (<?xml ... ?>) – the XML fragment is embedded directly in the NDI metadata payload.

  • Implementations SHOULD ignore NDI metadata frames whose type is not "chat".

4. Session and Message Structure

4.1 <Session>

Represents a logical chat conversation.

  • Parent: <ndi_metadata>

  • Attributes:

    • id (required): identifier of the chat session.

      • SHOULD be stable and unique within the sender’s or facility’s context.

      • Recommended format: lower-case snake_case or similar (e.g. session_production_A, session_replay_room, global_broadcast).

    • scope (optional): semantic scope of the session.

      • point_to_point – one-to-one conversation (e.g. director ↔ replay operator).

      • group – multi-participant (e.g. β€œproduction team”).

      • broadcast – messages intended for anyone listening.

Implementations MAY define additional values.

Multiple <Session> elements MAY appear in one metadata frame to carry messages for separate conversations.

Example with two sessions:

4.2 <Message>

Represents a single chat event within a session.

  • Parent: <Session>

  • Children (standard elements):

    • <MessageId>

    • <SenderId>

    • <MessageType>

    • <Text>

    • <Lang>

    • <Format>

    • <Priority>

    • <InReplyTo> (optional)

    • <TimestampUtc>

Order of child elements is not semantically significant, but examples use a consistent order for readability.

A single <Session> MAY contain multiple <Message> elements in one frame, for batching.

Example (session with two messages):

5. Standard Message Elements

This section defines the standard child elements of <Message>.

Unless otherwise stated, all elements are optional but recommended. Implementations SHOULD ignore unknown elements and treat missing optional elements with sensible defaults.

Standard elements:

  • <MessageId>

  • <SenderId>

  • <MessageType>

  • <Text>

  • <Lang>

  • <Format>

  • <Priority>

  • <InReplyTo>

  • <TimestampUtc>

  • <To> (optional destination hint)

Order of elements is not semantically significant.

5.1 <MessageId>

Logical identifier of the message.

  • Parent: <Message>

  • Type: string.

  • Usage: SHOULD be unique within the context of a session (Session.id).

    • Useful for de-duplication, threading, and acknowledgements.

Examples:

  • msg_0001

  • d_20251206_00123

  • replay_room_000045

If omitted, receivers MAY generate a local identifier, but SHOULD treat such messages as not safely referenceable (e.g. for threading).

5.2 <SenderId>

Identifier of the originator of the message.

  • Parent: <Message>

  • Type: string

Semantics:

  • Logical identity of the chat participant (UI, controller, device).

  • SHOULD be stable and unique within the chat domain (e.g. facility, production, or logical application domain).

Examples:

  • director_room

  • replay_room

  • automation_1

  • studio_A_panel

Receivers can use SenderId to:

  • render distinct labels or colors,

  • tag messages by origin (for logs, filters),

  • enforce access control policies if desired.

If omitted, receivers MAY treat the message as anonymous.

5.3 <MessageType>

Type of the message.

  • Parent: <Message>

  • Type: string (enum)

Recommended baseline values:

  • text – standard human-readable chat text.

  • system – system notification (join/leave, warnings, status).

  • typing – typing indicator (user is composing).

  • ack – acknowledgement of another message (often used with InReplyTo).

  • custom – application-specific type (requires extra semantics on top of).

Implementations:

  • SHOULD support at least text.

  • MAY define additional values as needed.

  • SHOULD NOT fail if encountering unknown values; instead, they MAY fall back to generic handling (e.g. render as standard text).

Examples:

If omitted, receivers MAY assume text as a default, but this is not required.

5.4 <Text>

Message content.

  • Parent: <Message>

  • Type: UTF-8 string

Semantics:

  • For MessageType="text": the actual chat text.

  • For MessageType="system": human-readable system message (status, alerts).

  • For other types: MAY be used as a human-friendly description; precise semantics are implementation-specific.

Implementations SHOULD support at least plain text rendering.

Example:

Size considerations

NDI metadata is not intended for very large payloads. Implementations SHOULD:

  • keep <Text> reasonably short (typical chat messages),

  • avoid using CHAT for large blobs or file transfer.

For large content, an out-of-band mechanism is recommended (e.g. URL or reference), with CHAT used to carry references plus short human-readable descriptions.

5.5 <Lang>

Language of the message, if known.

  • Parent: <Message>

  • Type: string

  • Format: recommended BCP 47 language code, e.g.:

    • en, it, fr

    • en-US, pt-BR

If omitted, receivers MAY assume a default language or ignore language information entirely.

Example:

This field is primarily useful for:

  • multi-language environments,

  • filtering or UI adaptations based on language.

5.6 <Format>

Text formatting description.

  • Parent: <Message>

  • Type: string (enum)

Recommended values:

  • plain – plain text, no markup.

  • markdown – Markdown or a constrained subset.

  • html – HTML snippet (use only in trusted environments).

If omitted, receivers SHOULD treat the text as plain.

Example:

Implementations that do not support rich text MAY:

  • ignore formatting hints,

  • render the content as plain text.

CHAT does not prescribe a specific Markdown or HTML subset; this is application-specific.

5.7 <Priority>

Relative priority or urgency.

  • Parent: <Message>

  • Type: string (enum)

Recommended values:

  • low

  • normal

  • high

  • critical

Usage examples:

  • low – non-essential information, debug chatter.

  • normal – regular production chat.

  • high – attention-critical; UI may highlight or pin the message.

  • critical – urgent; UI may trigger audible alerts or overlays.

Example:

If omitted, receivers SHOULD treat priority as normal.

Applications MAY map these values to their own severity or notification systems.

5.8 <InReplyTo>

Reference to another message.

  • Parent: <Message>

  • Type: string

Semantics:

  • Contains the MessageId of a previous message within the same session.

  • Used to express:

    • simple reply threads,

    • acknowledgements (with MessageType="ack"),

    • correlations between command and response messages.

Example (acknowledgement):

Receivers MAY:

  • group messages by InReplyTo for threaded display,

  • use it for correlation in logs or automation,

  • ignore it if threading is not implemented.

If InReplyTo points to an unknown MessageId, the receiver SHOULD still accept the message but may not be able to render the full thread context.

5.9 <TimestampUtc>

Timestamp of when the message was generated, in UTC.

  • Parent: <Message>

  • Type: string (ISO 8601 / RFC 3339)

  • Format:

    • YYYY-MM-DDThh:mm:ssZ, or

    • YYYY-MM-DDThh:mm:ss.sssZ for millisecond precision.

Example:

Usage:

  • hOLA

Implementations SHOULD preserve TimestampUtc when re-emitting or relaying messages.

5.10 <To> (optional destination hint)

Optional routing hint for intended recipient(s) within a session.

  • Parent: <Message>

  • Type: string

Semantics:

  • If <To> is omitted, the message SHOULD be treated as broadcast to all participants in the session (Session.id).

  • If <To> is present, it identifies one or more intended recipients using the same logical ID space as SenderId.

Single-recipient example (unicast A β†’ B):

Multi-recipient example (A β†’ B and C):

  • Multiple recipients MAY be specified as a comma-separated list.

  • Implementations SHOULD trim whitespace around each ID when parsing.

Usage notes:

  • <To> is a hint that intermediaries (e.g. an NDI sender acting as a hub) or receivers MAY use to implement:

    • unicast routing (only to a specific participant),

    • multicast routing (subset of participants),

    • or filtering logic at the receiver.

  • Applications that do not understand or use <To> SHOULD ignore it and treat the message as broadcast.

In user-facing chat UIs, <To> is often derived from conventions in <Text> such as @recipient. Parsing such conventions is considered application logic and is out of scope for this specification.

6. Participant Identity & Multi-Endpoint Scenarios

In many NDI workflows:

  • A single NDI source can have multiple receivers (workstations, panels, automation, etc.).

  • Each receiver could send CHAT metadata back to the same source.

To keep semantics clear:

  • Session.id identifies the conversation (logical room / channel).

  • SenderId identifies the participant.

Recommended practices:

  1. Stable participant IDs

Each UI or controller SHOULD use a stable SenderId (e.g. director_room, replay_room) instead of per-connection IDs.

  1. Access control

Implementations MAY define policies:

  • Allow all SenderId for a given Session.id.

  • Restrict write access to a subset of SenderId.

  • Treat some sessions as read-only or system-only.

  1. Anonymous senders

If a system does not set SenderId, receivers MAY treat messages as anonymous and:

  • display a generic origin (Unknown), or

  • ignore them in strictly controlled environments.

Unlike GPIO, CHAT typically does not require strict single-controller arbitration, so there is no required controllerId equivalent. However, implementations MAY combine SenderId with NDI connection information for additional policies if needed.

7. Typical Usage Patterns

7.1 Point-to-point chat (director ↔ replay)

  • Use a dedicated Session.id, e.g. session_director_replay.

  • Both sides send Message elements within that session.

  • Receivers display messages from all SenderId in that session.

Example:

7.2 Group chat (control room)

  • Session.id = "session_control_room", scope="group".

  • Multiple participants (SenderId) write to the same session.

  • UI may visually distinguish participants by color or label.

7.3 System notifications

  • MessageType = "system".

  • Used for join/leave notices, warnings, or status messages, possibly generated by automation rather than humans.

Example:

8. Extensibility & Vendor-Specific Fields

The core schema is intentionally small. Implementations MAY add extension elements or attributes, provided that:

  • Extensions do not break receivers that ignore unknown elements/attributes.

  • Core semantics (Session, Message, Text, TimestampUtc, etc.) remain intact.

Examples of possible extensions:

  • Delivery status (e.g. Delivered, Seen).

  • Rich presence information (online/offline).

  • Additional routing hints (e.g. severity categories, channel mapping).

Recommended pattern:

  • Use extra child elements within <Message> or <Session>.

  • If needed, use XML namespaces or identifiable prefixes to avoid collisions.

9. Evolution

  • Senders SHOULD include a version attribute on <ndi_metadata> (e.g. "1.0").

  • Receivers SHOULD:

    • ignore unknown elements and attributes,

    • use sensible defaults for missing optional fields.

Future versions may:

  • add optional elements (delivery receipts, presence, attachments metadata),

  • refine recommended enums (MessageType, Priority, etc.),

  • define best practices for latency, batching, or message ordering.

Implementations SHOULD be written to be forward-compatible, especially regarding:

  • new MessageType values,

  • new optional message fields,

  • additional scope values for <Session>.

10. Summary

The CHAT over NDI metadata format defines:

  • A root <ndi_metadata type="chat"> element.

  • A flexible hierarchy of:

    • <Session> (conversation container),

    • <Message> (individual chat events).

  • Core message elements:

    • MessageId, SenderId, MessageType, Text, Lang, Format, Priority, InReplyTo, TimestampUtc.

On top of this neutral, NDI-friendly schema, endpoints are free to:

  • Render messages in chat windows, logs, or on-screen overlays.

  • Implement UI features like threading, acknowledgements, and priorities.

  • Evolve their internal behavior without changing the on-wire XML contract.

This approach keeps NDI metadata clean and protocol-agnostic, while enabling a simple, interoperable, bidirectional text messaging system across NDI-based workflows.

Last updated

Was this helpful?