Conversation
|
Some things from talking to claude (maybe you find it useful):
|
| def _timestamp_now() -> int: | ||
| return int(time.time() * 1000) | ||
|
|
||
| def with_user_timestamp_now(self) -> DataTrackFrame: |
There was a problem hiding this comment.
Could it be static instead?
DataTrackFrame.now(payload=..)
There was a problem hiding this comment.
I would probably stick with this since we may add additional timestamp fields in the future (e.g., a single frame could have both a capture and sensor timestamp).
There was a problem hiding this comment.
I'm kind of wondering if this utility is needed at all then? It would be even more complicated if we have multiple timestamps. They don't really help much IMO
| self._closed = True | ||
| FfiClient.instance.queue.unsubscribe(self._queue) | ||
|
|
||
| def close(self) -> None: |
There was a problem hiding this comment.
Let's make sure we have aclose (to be future proof)
| track.try_push(frame) | ||
| except rtc.PushFrameError as e: | ||
| logging.error("Failed to push frame: %s", e) |
There was a problem hiding this comment.
From an API perspective, I feel like it's kind of weird that "pushing" can fail? Since it looks like a queue?
There was a problem hiding this comment.
V1 only supports lossy delivery, and queuing on the publisher side is minimal; this will error if attempting to push frames too fast (rather than queuing stale data).
There was a problem hiding this comment.
There was a discussion about this back during the planning phase; originally it was going to be called "publish," but it was changed to "push" to disambiguate from publishing the track itself. The "try" prefix is to denote this is not guaranteed to succeed and to give us a path to introduce an async variant just called "push" to support reliable delivery in a future version.
| def unpublish(self) -> None: | ||
| """Unpublishes the track.""" | ||
| req = proto_ffi.FfiRequest() | ||
| req.local_data_track_unpublish.track_handle = self._ffi_handle.handle | ||
| FfiClient.instance.request(req) |
There was a problem hiding this comment.
Should this be async as well? Or maybe this shouldnt' even be here. But in LocalParticipant instead? for consistency
There was a problem hiding this comment.
Based on how applications work with data tracks, we found it is more convenient to have here. This is the same API in the other SDKs. Also, currently not async in the Rust impl.
There was a problem hiding this comment.
I see, tho isn't it better to be consistent with audio/video?
There was a problem hiding this comment.
Even if the API is better, it introduces more cognitive load to have different APIs for similar purposes
…ython-client-implementation
SFU used in CI testing doesn't currently have data tracks enabled. Tested locally and verified this case passes.
| frame = rtc.DataTrackFrame(payload=data, user_timestamp=int(time.time() * 1000)) | ||
| track.try_push(frame) | ||
| except rtc.PushFrameError as e: | ||
| logging.error("Failed to push frame: %s", e) |
There was a problem hiding this comment.
🟡 Publisher example logs empty string for PushFrameError because exception doesn't pass message to super().init
PushFrameError.__init__ at livekit-rtc/livekit/rtc/data_track.py:42-43 stores the message as self.message but never calls super().__init__(message). When the publisher example formats the exception with %s, Python calls str(e) which returns str(self.args) — an empty tuple () renders as empty string. The log output will be "Failed to push frame: " with no actual error information. The subscriber example at examples/data_tracks/subscriber.py:27 correctly uses e.message, demonstrating the intended access pattern.
| logging.error("Failed to push frame: %s", e) | |
| logging.error("Failed to push frame: %s", e.message) |
Was this helpful? React with 👍 or 👎 to provide feedback.
No description provided.