In MOQT, content is organized into tracks (media streams) and objects (individual data units). This hierarchical structure enables efficient streaming, caching, and retrieval of media content.
export type Track = { /** Globally unique identifier for the track */ fullTrackName: FullTrackName /** Hint controlling which objects should be forwarded/prioritized */ forwardingPreference: ObjectForwardingPreference /** Accessors for live and/or past objects */ trackSource: TrackSource /** Priority 0 (highest) to 255 (lowest) advertised with objects */ publisherPriority: number /** Optional compact numeric alias for protocol efficiency */ trackAlias?: bigint}
Tracks are the primary unit of organization in MOQT. Each track has a unique name and can contain both live and historical content.
For wire efficiency, tracks can use numeric aliases instead of full names:
// Full track name on first referenceconst track: Track = { fullTrackName: FullTrackName.tryNew('live/conference', 'video'), trackAlias: 1n, // Compact alias for subsequent references // ...}// Objects reference track by alias (saves bandwidth)const datagram = DatagramObject.new( 1n, // trackAlias instead of full name 100n, // groupId 5n, // objectId 128, // publisherPriority null, // extensionHeaders payload, // object data false // endOfGroup)
export class MoqtObject { public readonly location: Location // Position in track public readonly subgroupId: bigint | null // Subgroup identifier public readonly fullTrackName: FullTrackName public readonly publisherPriority: number public readonly objectForwardingPreference: ObjectForwardingPreference public readonly objectStatus: ObjectStatus public readonly extensionHeaders: KeyValuePair[] | null public readonly payload: Uint8Array | null get groupId(): bigint { return this.location.group } get objectId(): bigint { return this.location.object }}
const statusObj = MoqtObject.newWithStatus( fullTrackName, new Location(100n, 10n), 128, ObjectForwardingPreference.Subgroup, 0n, null, ObjectStatus.EndOfGroup // Marks end of group 100)
Locations uniquely identify objects within a track:
export class Location { public readonly group: bigint // Group index (e.g., GOP, segment) public readonly object: bigint // Object index within group compare(other: Location): number { // Returns -1, 0, or 1 for ordering } equals(other: Location): boolean { return this.group === other.group && this.object === other.object }}
Location examples:
// First frame of first GOPconst keyframe = new Location(0n, 0n)// Fifth frame of third GOPconst frame = new Location(2n, 4n)// Comparing locationsif (frame.compare(keyframe) > 0) { console.log('frame comes after keyframe')}
Groups typically correspond to natural content boundaries (GOPs, segments, chapters) while objects represent individual units within those boundaries (frames, chunks).
export enum ObjectStatus { Normal = 0x0, // Regular object with payload DoesNotExist = 0x1, // Object not available EndOfGroup = 0x3, // Marks group boundary EndOfTrack = 0x4, // Marks track termination}
Processing objects by status:
function processObject(obj: MoqtObject) { switch (obj.objectStatus) { case ObjectStatus.Normal: if (obj.payload) { decodeAndRender(obj.payload) } break case ObjectStatus.EndOfGroup: console.log(`Group ${obj.groupId} complete`) finalizeGroup(obj.groupId) break case ObjectStatus.EndOfTrack: console.log('Track ended gracefully') closePlayer() break case ObjectStatus.DoesNotExist: console.warn(`Missing: group ${obj.groupId}, object ${obj.objectId}`) handleMissing(obj.location) break }}