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` objectconst 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 useronProgress: (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` insteadlet dataChunks = [Data([0x00, 0x01]), Data([0x03, 0x04])]for chunk in dataChunks {try await writer.write(chunk)}// The stream must be explicitly closed when donetry 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.
Property | Description | Type |
---|---|---|
id | Unique identifier for this stream. | string |
topic | Topic name used to route the stream to the appropriate handler. | string |
timestamp | When the stream was created. | number |
mimeType | The MIME type of the stream data. Auto-detected for files, otherwise defaults to application/octet-stream . | string |
name | The name of the file being sent. | string |
size | Total expected size in bytes, if known. | number |
attributes | Additional attributes as needed for your application. | string dict |
destinationIdentities | Identities 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.
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.