Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/data-channel-raw-bytes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.7": minor
---

Add `PixelStreaming.emitData(messageType, bytes)` for sending raw byte payloads through the data channel without JSON encoding (#608). The bytes are sent as the payload of a registered to-streamer message type — the registered id is prepended as a single byte, the rest of the buffer is the application's payload verbatim. Useful for custom binary protocols (e.g. UTF-8 strings, packed structs) where the receiving UE side decodes the payload itself. The lower-level `WebRtcPlayerController.emitData` and `SendMessageController.sendBytesToStreamer` are also exposed for advanced callers.
23 changes: 23 additions & 0 deletions Frontend/library/src/PixelStreaming/PixelStreaming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,29 @@ export class PixelStreaming {
return true;
}

/**
* Send raw bytes to the UE application through the data channel without
* any JSON encoding or per-field encoding. The bytes are sent as the
* payload of a registered to-streamer message type — the message id
* is prepended as a single byte.
*
* The message type must be registered via
* `streamMessageController.toStreamerMessages.set(...)` so the id is
* known. Useful for custom binary protocols where the receiving side
* (UE) decodes the payload itself.
*
* @param messageType - Name of a registered to-streamer message type.
* @param bytes - Payload to send, not including the message id byte.
* @returns true if the bytes were submitted, false if rejected (video
* not ready, message type not registered, or data channel not open).
*/
public emitData(messageType: string, bytes: Uint8Array | ArrayBuffer): boolean {
if (!this._webRtcController.videoPlayer.isVideoReady()) {
return false;
}
return this._webRtcController.emitData(messageType, bytes);
}

/**
* Send a console command to UE application. Only allowed if UE has signaled that it allows
* console commands.
Expand Down
40 changes: 40 additions & 0 deletions Frontend/library/src/UeInstanceMessage/SendMessageController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,44 @@ export class SendMessageController {

this.dataChannelSender.sendData(data.buffer);
}

/**
* Send a raw byte payload for a registered to-streamer message type. The
* registered message id is prepended as a single byte, then the bytes
* are sent through the data channel as-is — no JSON encoding, no
* per-field structure validation.
*
* Useful for custom protocols where the application owns the binary
* payload format on both ends. The application must have called
* `streamMessageController.toStreamerMessages.set(...)` (or relied on
* a default-registered type such as `UIInteraction`) so the message id
* is known.
*
* @param messageType - Name of a registered to-streamer message type.
* @param bytes - Payload to send, not including the message id byte.
* @returns true if the bytes were submitted to the data channel; false
* if the message type isn't registered or the channel can't send.
*/
sendBytesToStreamer(messageType: string, bytes: Uint8Array | ArrayBuffer): boolean {
const messageFormat = this.toStreamerMessagesMapProvider.toStreamerMessages.get(messageType);
if (messageFormat === undefined) {
Logger.Error(
`Attempted to send raw bytes for message type "${messageType}" but no such type is registered. Register it via streamMessageController.toStreamerMessages.set(...)`
);
return false;
}

if (!this.dataChannelSender.canSend()) {
Logger.Info(`Data channel cannot send yet, skipping raw bytes for: ${messageType}`);
return false;
}

const payload = bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : bytes;
const buffer = new ArrayBuffer(1 + payload.byteLength);
const view = new Uint8Array(buffer);
view[0] = messageFormat.id;
view.set(payload, 1);
this.dataChannelSender.sendData(buffer);
return true;
}
}
8 changes: 8 additions & 0 deletions Frontend/library/src/WebRtcPlayer/WebRtcPlayerController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1827,6 +1827,14 @@ export class WebRtcPlayerController {
this.streamMessageController.toStreamerHandlers.get('Command')([JSON.stringify(descriptor)]);
}

/**
* Send raw bytes through the data channel for a registered to-streamer
* message type. See {@link SendMessageController.sendBytesToStreamer}.
*/
emitData(messageType: string, bytes: Uint8Array | ArrayBuffer): boolean {
return this.sendMessageController.sendBytesToStreamer(messageType, bytes);
}

/**
* Send a console command message
*/
Expand Down
Loading