Skip to content

Commit 22f93d9

Browse files
committed
remove UserTimestamp store in favor of simple map to track ts
1 parent f68b83e commit 22f93d9

11 files changed

Lines changed: 262 additions & 350 deletions

File tree

libwebrtc/src/native/user_timestamp.rs

Lines changed: 36 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@
1818
//! in encoded video frames as trailers. The timestamps are preserved
1919
//! through the WebRTC pipeline and can be extracted on the receiver side.
2020
//!
21-
//! This works independently of e2ee encryption - timestamps can be
22-
//! embedded even when encryption is disabled.
21+
//! On the send side, user timestamps are stored in the handler's internal
22+
//! map keyed by capture timestamp. When the encoder produces a frame,
23+
//! the transformer looks up the user timestamp via the frame's CaptureTime().
24+
//!
25+
//! On the receive side, extracted user timestamps are stored in an
26+
//! internal map keyed by RTP timestamp. Decoded frames look up their
27+
//! user timestamp via lookup_user_timestamp(rtp_timestamp).
2328
2429
use cxx::SharedPtr;
2530
use webrtc_sys::user_timestamp::ffi as sys_ut;
@@ -30,94 +35,15 @@ use crate::{
3035
rtp_sender::RtpSender,
3136
};
3237

33-
/// Thread-safe store for mapping capture timestamps to user timestamps.
34-
///
35-
/// Used on the sender side to correlate video frame capture time with
36-
/// the user timestamp that should be embedded in the encoded frame.
37-
#[derive(Clone)]
38-
pub struct UserTimestampStore {
39-
sys_handle: SharedPtr<sys_ut::UserTimestampStore>,
40-
}
41-
42-
impl UserTimestampStore {
43-
/// Create a new user timestamp store.
44-
pub fn new() -> Self {
45-
Self {
46-
sys_handle: sys_ut::new_user_timestamp_store(),
47-
}
48-
}
49-
50-
/// Store a user timestamp associated with a capture timestamp.
51-
///
52-
/// Call this when capturing a video frame with a user timestamp.
53-
/// The `capture_timestamp_us` should match the `timestamp_us` field
54-
/// of the VideoFrame.
55-
pub fn store(&self, capture_timestamp_us: i64, user_timestamp_us: i64) {
56-
log::info!(
57-
target: "user_timestamp",
58-
"store: capture_ts_us={}, user_ts_us={}",
59-
capture_timestamp_us,
60-
user_timestamp_us
61-
);
62-
self.sys_handle.store(capture_timestamp_us, user_timestamp_us);
63-
}
64-
65-
/// Lookup a user timestamp by capture timestamp (for debugging).
66-
/// Returns None if not found.
67-
pub fn lookup(&self, capture_timestamp_us: i64) -> Option<i64> {
68-
let result = self.sys_handle.lookup(capture_timestamp_us);
69-
if result < 0 {
70-
None
71-
} else {
72-
Some(result)
73-
}
74-
}
75-
76-
/// Pop the oldest user timestamp from the queue.
77-
/// Returns None if the queue is empty.
78-
pub fn pop(&self) -> Option<i64> {
79-
let result = self.sys_handle.pop();
80-
if result < 0 {
81-
None
82-
} else {
83-
Some(result)
84-
}
85-
}
86-
87-
/// Peek at the oldest user timestamp without removing it.
88-
/// Returns None if the queue is empty.
89-
pub fn peek(&self) -> Option<i64> {
90-
let result = self.sys_handle.peek();
91-
if result < 0 {
92-
None
93-
} else {
94-
Some(result)
95-
}
96-
}
97-
98-
/// Clear old entries (older than the given threshold in microseconds).
99-
pub fn prune(&self, max_age_us: i64) {
100-
self.sys_handle.prune(max_age_us);
101-
}
102-
103-
pub(crate) fn sys_handle(&self) -> SharedPtr<sys_ut::UserTimestampStore> {
104-
self.sys_handle.clone()
105-
}
106-
}
107-
108-
impl Default for UserTimestampStore {
109-
fn default() -> Self {
110-
Self::new()
111-
}
112-
}
113-
11438
/// Handler for user timestamp embedding/extraction on RTP streams.
11539
///
116-
/// For sender side: Embeds user timestamps as 12-byte trailers on
117-
/// encoded frames before they are sent.
40+
/// For sender side: Stores user timestamps keyed by capture timestamp
41+
/// and embeds them as 12-byte trailers on encoded frames before they
42+
/// are sent. Use `store_user_timestamp()` to associate a user timestamp
43+
/// with a captured frame.
11844
///
11945
/// For receiver side: Extracts user timestamps from received frames
120-
/// and makes them available for retrieval.
46+
/// and makes them available for retrieval via `lookup_user_timestamp()`.
12147
#[derive(Clone)]
12248
pub struct UserTimestampHandler {
12349
sys_handle: SharedPtr<sys_ut::UserTimestampHandler>,
@@ -164,24 +90,44 @@ impl UserTimestampHandler {
16490
}
16591
}
16692

93+
/// Store a user timestamp for a given capture timestamp (sender side).
94+
///
95+
/// The `capture_timestamp_us` must be the TimestampAligner-adjusted
96+
/// timestamp (as produced by `VideoTrackSource::on_captured_frame`),
97+
/// NOT the original `timestamp_us` from the VideoFrame. The transformer
98+
/// looks up the user timestamp by the frame's `CaptureTime()` which is
99+
/// derived from the aligned value.
100+
///
101+
/// In normal usage this is called automatically by the C++ layer —
102+
/// callers should set `user_timestamp_us` on the `VideoFrame` and let
103+
/// `capture_frame` / `on_captured_frame` handle the rest.
104+
pub fn store_user_timestamp(&self, capture_timestamp_us: i64, user_timestamp_us: i64) {
105+
log::info!(
106+
target: "user_timestamp",
107+
"store: capture_ts_us={}, user_ts_us={}",
108+
capture_timestamp_us,
109+
user_timestamp_us
110+
);
111+
self.sys_handle.store_user_timestamp(capture_timestamp_us, user_timestamp_us);
112+
}
113+
167114
pub(crate) fn sys_handle(&self) -> SharedPtr<sys_ut::UserTimestampHandler> {
168115
self.sys_handle.clone()
169116
}
170117
}
171118

172119
/// Create a sender-side user timestamp handler.
173120
///
174-
/// This handler will embed user timestamps from the provided store
175-
/// into encoded frames before they are packetized and sent.
121+
/// This handler will embed user timestamps into encoded frames before
122+
/// they are packetized and sent. Use `store_user_timestamp()` to
123+
/// associate a user timestamp with a captured frame's capture timestamp.
176124
pub fn create_sender_handler(
177125
peer_factory: &PeerConnectionFactory,
178-
store: &UserTimestampStore,
179126
sender: &RtpSender,
180127
) -> UserTimestampHandler {
181128
UserTimestampHandler {
182129
sys_handle: sys_ut::new_user_timestamp_sender(
183130
peer_factory.handle.sys_handle.clone(),
184-
store.sys_handle(),
185131
sender.handle.sys_handle.clone(),
186132
),
187133
}
@@ -195,13 +141,11 @@ pub fn create_sender_handler(
195141
/// timestamp for a specific decoded frame.
196142
pub fn create_receiver_handler(
197143
peer_factory: &PeerConnectionFactory,
198-
store: &UserTimestampStore,
199144
receiver: &RtpReceiver,
200145
) -> UserTimestampHandler {
201146
UserTimestampHandler {
202147
sys_handle: sys_ut::new_user_timestamp_receiver(
203148
peer_factory.handle.sys_handle.clone(),
204-
store.sys_handle(),
205149
receiver.handle.sys_handle.clone(),
206150
),
207151
}

libwebrtc/src/native/video_source.rs

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use parking_lot::Mutex;
2323
use webrtc_sys::{video_frame as vf_sys, video_frame::ffi::VideoRotation, video_track as vt_sys};
2424

2525
use crate::{
26-
native::user_timestamp::UserTimestampStore,
26+
native::user_timestamp::UserTimestampHandler,
2727
video_frame::{I420Buffer, VideoBuffer, VideoFrame},
2828
video_source::VideoResolution,
2929
};
@@ -48,7 +48,6 @@ pub struct NativeVideoSource {
4848

4949
struct VideoSourceInner {
5050
captured_frames: usize,
51-
user_timestamp_store: Option<UserTimestampStore>,
5251
}
5352

5453
impl NativeVideoSource {
@@ -59,7 +58,6 @@ impl NativeVideoSource {
5958
)),
6059
inner: Arc::new(Mutex::new(VideoSourceInner {
6160
captured_frames: 0,
62-
user_timestamp_store: None,
6361
})),
6462
};
6563

@@ -84,7 +82,11 @@ impl NativeVideoSource {
8482
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
8583
builder.pin_mut().set_timestamp_us(now.as_micros() as i64);
8684

87-
source.sys_handle.on_captured_frame(&builder.pin_mut().build());
85+
source.sys_handle.on_captured_frame(
86+
&builder.pin_mut().build(),
87+
false,
88+
0,
89+
);
8890
}
8991
}
9092
});
@@ -97,41 +99,43 @@ impl NativeVideoSource {
9799
}
98100

99101
pub fn capture_frame<T: AsRef<dyn VideoBuffer>>(&self, frame: &VideoFrame<T>) {
100-
let mut inner = self.inner.lock();
101-
inner.captured_frames += 1;
102-
103102
let mut builder = vf_sys::ffi::new_video_frame_builder();
104103
builder.pin_mut().set_rotation(frame.rotation.into());
105104
builder.pin_mut().set_video_frame_buffer(frame.buffer.as_ref().sys_handle());
106105

107106
let capture_ts = if frame.timestamp_us == 0 {
108-
// If the timestamp is set to 0, default to now
109107
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
110108
now.as_micros() as i64
111109
} else {
112110
frame.timestamp_us
113111
};
114112
builder.pin_mut().set_timestamp_us(capture_ts);
115113

116-
// If a user timestamp is provided and a store is available, record
117-
// the mapping so the UserTimestampTransformer can embed it into the
118-
// encoded RTP frame.
119-
if let Some(user_ts) = frame.user_timestamp_us {
120-
if let Some(store) = &inner.user_timestamp_store {
121-
store.store(capture_ts, user_ts);
122-
}
123-
}
114+
// Pass the user timestamp to the C++ on_captured_frame so it can
115+
// store the mapping keyed by the TimestampAligner-adjusted capture
116+
// timestamp. This is the only correct key because the aligner runs
117+
// inside on_captured_frame and replaces timestamp_us with a value
118+
// derived from rtc::TimeMicros() (monotonic), which is what
119+
// CaptureTime() returns in TransformSend.
120+
let (has_user_ts, user_ts) = match frame.user_timestamp_us {
121+
Some(ts) => (true, ts),
122+
None => (false, 0),
123+
};
124+
125+
self.inner.lock().captured_frames += 1;
124126

125-
self.sys_handle.on_captured_frame(&builder.pin_mut().build());
127+
self.sys_handle.on_captured_frame(&builder.pin_mut().build(), has_user_ts, user_ts);
126128
}
127129

128-
/// Set the user timestamp store used by this source.
130+
/// Set the user timestamp handler used by this source.
129131
///
130132
/// When set, any frame captured with a `user_timestamp_us` value will
131-
/// automatically have its timestamp pushed into the store so the
133+
/// automatically have its timestamp stored in the handler so the
132134
/// `UserTimestampTransformer` can embed it into the encoded frame.
133-
pub fn set_user_timestamp_store(&self, store: UserTimestampStore) {
134-
self.inner.lock().user_timestamp_store = Some(store);
135+
/// The handler is set on the C++ VideoTrackSource so it has access to
136+
/// the TimestampAligner-adjusted capture timestamp for correct keying.
137+
pub fn set_user_timestamp_handler(&self, handler: UserTimestampHandler) {
138+
self.sys_handle.set_user_timestamp_handler(handler.sys_handle());
135139
}
136140

137141
pub fn video_resolution(&self) -> VideoResolution {

libwebrtc/src/video_source.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub mod native {
5050
use std::fmt::{Debug, Formatter};
5151

5252
use super::*;
53-
use crate::native::user_timestamp::UserTimestampStore;
53+
use crate::native::user_timestamp::UserTimestampHandler;
5454
use crate::video_frame::{VideoBuffer, VideoFrame};
5555

5656
#[derive(Clone)]
@@ -79,13 +79,14 @@ pub mod native {
7979
self.handle.capture_frame(frame)
8080
}
8181

82-
/// Set the user timestamp store used by this source.
82+
/// Set the user timestamp handler used by this source.
8383
///
8484
/// When set, any frame captured with a `user_timestamp_us` value will
85-
/// automatically have its timestamp pushed into the store so the
85+
/// automatically have its timestamp stored in the handler (keyed by
86+
/// the TimestampAligner-adjusted capture timestamp) so the
8687
/// `UserTimestampTransformer` can embed it into the encoded frame.
87-
pub fn set_user_timestamp_store(&self, store: UserTimestampStore) {
88-
self.handle.set_user_timestamp_store(store)
88+
pub fn set_user_timestamp_handler(&self, handler: UserTimestampHandler) {
89+
self.handle.set_user_timestamp_handler(handler)
8990
}
9091

9192
pub fn video_resolution(&self) -> VideoResolution {

livekit/src/room/e2ee/manager.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use libwebrtc::{
1919
frame_cryptor::{
2020
DataPacketCryptor, EncryptedPacket, EncryptionAlgorithm, EncryptionState, FrameCryptor,
2121
},
22-
user_timestamp::{self, UserTimestampStore},
22+
user_timestamp,
2323
},
2424
rtp_receiver::RtpReceiver,
2525
rtp_sender::RtpSender,
@@ -107,10 +107,8 @@ impl E2eeManager {
107107

108108
// Always set up user timestamp extraction for remote video tracks.
109109
if let RemoteTrack::Video(video_track) = &track {
110-
let store = UserTimestampStore::new();
111110
let handler = user_timestamp::create_receiver_handler(
112111
LkRuntime::instance().pc_factory(),
113-
&store,
114112
&receiver,
115113
);
116114
video_track.set_user_timestamp_handler(handler.clone());
@@ -143,21 +141,19 @@ impl E2eeManager {
143141

144142
// Always set up user timestamp embedding for local video tracks.
145143
if let LocalTrack::Video(video_track) = &track {
146-
let store = UserTimestampStore::new();
147-
video_track.set_user_timestamp_store(store.clone());
144+
let handler = user_timestamp::create_sender_handler(
145+
LkRuntime::instance().pc_factory(),
146+
&sender,
147+
);
148+
video_track.set_user_timestamp_handler(handler.clone());
148149

149-
// Also set the store on the video source so that capture_frame()
150-
// can automatically push user timestamps into it.
150+
// Also set the handler on the video source so that capture_frame()
151+
// can automatically store user timestamps into it.
151152
#[cfg(not(target_arch = "wasm32"))]
152153
if let RtcVideoSource::Native(ref native_source) = video_track.rtc_source() {
153-
native_source.set_user_timestamp_store(store.clone());
154+
native_source.set_user_timestamp_handler(handler.clone());
154155
}
155156

156-
let handler = user_timestamp::create_sender_handler(
157-
LkRuntime::instance().pc_factory(),
158-
&store,
159-
&sender,
160-
);
161157
user_timestamp_handler = Some(handler);
162158
}
163159

0 commit comments

Comments
 (0)