Skip to content

Add data stream sending support#84

Open
pham-tuan-binh wants to merge 13 commits intomainfrom
feature/data-stream-sending
Open

Add data stream sending support#84
pham-tuan-binh wants to merge 13 commits intomainfrom
feature/data-stream-sending

Conversation

@pham-tuan-binh
Copy link
Copy Markdown
Collaborator

@pham-tuan-binh pham-tuan-binh commented Apr 7, 2026

Summary

  • Rename data_stream_managerdata_stream_reader to clarify it handles incoming streams only
  • Add data_stream_writer module as the symmetric counterpart for outgoing streams
  • Add public API: livekit_room_data_stream_open(), livekit_room_data_stream_write(), livekit_room_data_stream_close()
  • Add generate_uuid() helper for stream identifiers
  • Split CONFIG_LK_MAX_DATA_STREAMS into CONFIG_LK_MAX_DATA_STREAM_READERS and CONFIG_LK_MAX_DATA_STREAM_WRITERS
  • UTF-8 aware chunking for text streams (never splits multi-byte characters)
  • Dedicated livekit_data_stream_options_t for the open call

Design

The writer mirrors the reader's fixed-slot pattern. Opening a stream allocates a slot, sends a header packet, and returns an opaque stream handle. Writes are auto-chunked into 15KB pieces (matching the Rust SDK). Closing sends the trailer and releases the slot. All functions follow the same handle-first convention as the reader and rpc_manager.

All packets go through the existing reliable data channel send path via engine_send_data_packet().

Usage

livekit_data_stream_options_t opts = { .topic = "lk.chat", .is_text = true };
livekit_data_stream_handle_t stream;
livekit_room_data_stream_open(room_handle, &opts, &stream);
livekit_room_data_stream_write(room_handle, stream, (const uint8_t*)"hello world", 11);
livekit_room_data_stream_close(room_handle, stream);

Test plan

  • idf.py build in minimal example
  • Open a text stream, write data, close — verify packets arrive at a web/Rust client on the same topic
  • Verify UTF-8 aware chunking behavior with multi-byte characters across chunk boundaries
  • Verify chunk splitting with payloads > 15KB
  • Verify slot exhaustion returns LIVEKIT_ERR_NO_MEM

The data stream manager module handles incoming streams only.
Rename it to data_stream_reader in preparation for adding a
symmetric data_stream_writer module for outgoing streams.
Add generate_uuid() to utils for generating random UUID v4 strings
using esp_random(). This will be used for data stream identifiers.
Add data_stream_writer as the symmetric counterpart to
data_stream_reader for outgoing data streams. The writer manages
a fixed array of stream slots and handles protobuf packet
construction, auto-chunking (15KB), and sending via a callback.
Add livekit_room_data_stream_open/write/close for sending outgoing
data streams. The writer is created during room initialization and
wired through the existing reliable data channel send path.

The writer strdup's the topic on open and frees it on close/destroy,
matching the reader's ownership pattern.
Replace reuse of livekit_data_stream_header_t with a purpose-built
livekit_data_stream_options_t that only contains the fields the
caller controls (topic, is_text, total_length, has_total_length).
This follows the livekit_data_publish_options_t pattern and avoids
the "which fields do I fill in?" ambiguity.
Replace CONFIG_LK_MAX_DATA_STREAMS with separate
CONFIG_LK_MAX_DATA_STREAM_READERS and CONFIG_LK_MAX_DATA_STREAM_WRITERS
so incoming and outgoing stream limits can be tuned independently.
Use PRIx32 instead of %x to avoid -Werror=format on Xtensa
where uint32_t is long unsigned int.
Text streams now avoid splitting multi-byte UTF-8 characters across
chunk boundaries by walking back from the cut point past any
continuation bytes.

Update README and doxygen with text and byte stream sending examples.
@pham-tuan-binh pham-tuan-binh requested a review from ladvoc April 7, 2026 09:16
Follow the codebase convention where all opaque pointer types use
the _handle_t suffix. Remove the redundant internal data_stream_t
typedef — the writer now uses livekit_data_stream_handle_t directly.
Rename data_stream_descriptor_t to data_stream_reader_descriptor_t
and data_stream_write_descriptor_t to data_stream_writer_descriptor_t
to match the reader/writer module naming convention.
Restore data_stream_writer_handle_t as void* to match the
data_stream_reader_handle_t pattern used throughout the codebase.
All writer functions now take the writer handle as first argument,
matching the reader and rpc_manager patterns. The descriptor no
longer stores a back-pointer to its parent writer.

The public write/close functions now take the room handle so
livekit.c can forward the writer handle to the internal API.
A prior global replace of livekit_data_stream_t accidentally caught
livekit_data_stream_trailer_t, renaming it to the invalid
livekit_data_stream_handle_trailer_t. Restore the correct name.
@pham-tuan-binh pham-tuan-binh force-pushed the feature/data-stream-sending branch from f7bc319 to dcddeaa Compare April 7, 2026 10:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant