Sending files & bytes

Use byte streams to send files, images, or any other kind of data between participants.

Overview

Byte streams provide a simple way to send files, images, or other binary data between participants in realtime. Each individual stream is associated with a topic, and you must register a handler to receive incoming streams for that topic. Streams can target specific participants or the entire room.

To send text data, use text streams instead.

Sending files

To send a file or an image, use the sendFile method. Precise support varies by SDK, as this is integrated with the platform's own file APIs.

// Send a `File` object
const file = ($('file') as HTMLInputElement).files?.[0]!;
const info = await room.localParticipant.sendFile(file, {
mimeType: file.type,
topic: 'my-topic',
// Optional, allows progress to be shown to the user
onProgress: (progress) => console.log('sending file, progress', Math.ceil(progress * 100)),
});
console.log(`Sent file with stream ID: ${info.id}`);

Streaming bytes

To stream any kind of binary data, open a stream writer with the streamBytes method. You must explicitly close the stream when you are done sending data.

let writer = try await room.localParticipant
.streamBytes(for: "my-topic")
print("Opened byte stream with ID: \(writer.info.id)")
// Example sending arbitrary binary data
// For sending files, use `sendFile` instead
let dataChunks = [Data([0x00, 0x01]), Data([0x03, 0x04])]
for chunk in dataChunks {
try await writer.write(chunk)
}
// The stream must be explicitly closed when done
try await writer.close()
print("Closed byte stream with ID: \(writer.info.id)")

Handling incoming streams

Whether the data was sent as a file or a stream, it is always received as a stream. You must register a handler to receive it.

room.registerByteStreamHandler('my-topic', (reader, participantInfo) => {
const info = reader.info;
// Optional, allows you to display progress information if the stream was sent with `sendFile`
reader.onProgress = (progress) => {
console.log(`"progress ${progress ? (progress * 100).toFixed(0) : 'undefined'}%`);
};
// Option 1: Process the stream incrementally using a for-await loop.
for await (const chunk of reader) {
// Collect these however you want.
console.log(`Next chunk: ${chunk}`);
}
// Option 2: Get the entire file after the stream completes.
const result = new Blob(await reader.readAll(), { type: info.mimeType });
console.log(
`File "${info.name}" received from ${participantInfo.identity}\n` +
` Topic: ${info.topic}\n` +
` Timestamp: ${info.timestamp}\n` +
` ID: ${info.id}\n` +
` Size: ${info.size}` // Optional, only available if the stream was sent with `sendFile`
);
});

Stream properties

These are all of the properties available on a text stream, and can be set from the send/stream methods or read from the handler.

PropertyDescriptionType
idUnique identifier for this stream.string
topicTopic name used to route the stream to the appropriate handler.string
timestampWhen the stream was created.number
mimeTypeThe MIME type of the stream data. Auto-detected for files, otherwise defaults to application/octet-stream.string
nameThe name of the file being sent.string
sizeTotal expected size in bytes, if known.number
attributesAdditional attributes as needed for your application.string dict
destinationIdentitiesIdentities of the participants to send the stream to. If empty, will be sent to all.array

Concurrency

Multiple streams can be written or read concurrently. If you call sendFile or streamBytes multiple times on the same topic, the recipient's handler will be invoked multiple times, once for each stream. These invocations will occur in the same order as the streams were opened by the sender, and the stream readers will be closed in the same order in which the streams were closed by the sender.

Joining mid-stream

Participants who join a room after a stream has been initiated will not receive any of it. Only participants connected at the time the stream is opened are eligible to receive it.

Chunk sizes

The processes for writing and reading streams are optimized separately. This means the number and size of chunks sent may not match the number and size of those received. However, the full data received is guaranteed to be complete and in order. Chunks are generally smaller than 15kB.

Note

Streams are a simple and powerful way to send data, but if you need precise control over individual packet behavior, the lower-level data packets API may be more appropriate.

Was this page helpful?