diff --git a/src/room/track/LocalAudioTrack.ts b/src/room/track/LocalAudioTrack.ts index 020705f664..d292944e49 100644 --- a/src/room/track/LocalAudioTrack.ts +++ b/src/room/track/LocalAudioTrack.ts @@ -139,6 +139,8 @@ export default class LocalAudioTrack extends LocalTrack { this.monitorInterval = setInterval(() => { this.monitorSender(); }, monitorFrequency); + + this.registerTimeSyncUpdate(); } protected monitorSender = async () => { diff --git a/src/room/track/LocalTrack.ts b/src/room/track/LocalTrack.ts index be93ebb305..9aacb383ea 100644 --- a/src/room/track/LocalTrack.ts +++ b/src/room/track/LocalTrack.ts @@ -54,6 +54,8 @@ export default abstract class LocalTrack< protected manuallyStopped: boolean = false; + protected lastTimeSyncUpdate = 0; + private restartLock: Mutex; /** @@ -541,5 +543,23 @@ export default abstract class LocalTrack< this.emit(TrackEvent.TrackProcessorUpdate); } + protected registerTimeSyncUpdate() { + const loop = () => { + this.timeSyncHandle = requestAnimationFrame(() => loop()); + // for local tracks we don't have access to appropriate timestamps on the sender reports so we generate them manually by following + // how the spec computes timestamps as part of "contributing sources" https://w3c.github.io/webrtc-pc/#dom-rtcrtpcontributingsource-timestamp + const timestamp = performance.timeOrigin + performance.now(); + + if (!this.isMuted && timestamp - this.lastTimeSyncUpdate > 100) { + this.emit(TrackEvent.TimeSyncUpdate, { + timestamp, + rtpTimestamp: 0, + }); + this.lastTimeSyncUpdate = timestamp; + } + }; + loop(); + } + protected abstract monitorSender(): void; } diff --git a/src/room/track/LocalVideoTrack.ts b/src/room/track/LocalVideoTrack.ts index 6546daca6e..837d3c5b79 100644 --- a/src/room/track/LocalVideoTrack.ts +++ b/src/room/track/LocalVideoTrack.ts @@ -108,6 +108,8 @@ export default class LocalVideoTrack extends LocalTrack { this.monitorInterval = setInterval(() => { this.monitorSender(); }, monitorFrequency); + + this.registerTimeSyncUpdate(); } stop() {