From 690ad46f076ecda7831e26968178aaeaa60151a4 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Fri, 5 Sep 2025 17:45:59 +0800 Subject: [PATCH 1/2] Use UTC timestamp for data stream header --- lib/src/participant/local.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/participant/local.dart b/lib/src/participant/local.dart index 9150837b..331c1d14 100644 --- a/lib/src/participant/local.dart +++ b/lib/src/participant/local.dart @@ -1236,7 +1236,7 @@ extension DataStreamParticipantMethods on LocalParticipant { final info = TextStreamInfo( id: streamId, mimeType: 'text/plain', - timestamp: DateTime.now().millisecondsSinceEpoch, + timestamp: DateTime.now().toUtc().millisecondsSinceEpoch, topic: options?.topic ?? '', size: options?.totalSize ?? 0, ); @@ -1333,7 +1333,7 @@ extension DataStreamParticipantMethods on LocalParticipant { name: options?.name ?? 'unknown', id: streamId, mimeType: options?.mimeType ?? 'application/octet-stream', - timestamp: DateTime.now().millisecondsSinceEpoch, + timestamp: DateTime.now().toUtc().millisecondsSinceEpoch, topic: options?.topic ?? '', size: options?.totalSize ?? 0, attributes: options?.attributes ?? {}, @@ -1345,7 +1345,7 @@ extension DataStreamParticipantMethods on LocalParticipant { streamId: streamId, topic: options?.topic, encryptionType: options?.encryptionType, - timestamp: Int64(DateTime.now().millisecondsSinceEpoch), + timestamp: Int64(DateTime.now().toUtc().millisecondsSinceEpoch), byteHeader: lk_models.DataStream_ByteHeader( name: info.name, ), From 9c9f1a99cac4a1cb6316c37ac333fc3e2c75e1fd Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Sun, 7 Sep 2025 23:36:52 +0800 Subject: [PATCH 2/2] Use timestamp() to get now utc --- lib/src/core/engine.dart | 2 +- lib/src/core/room.dart | 12 ++++++------ lib/src/core/signal_client.dart | 4 ++-- lib/src/participant/local.dart | 8 ++++---- lib/src/participant/participant.dart | 6 +++--- lib/src/support/region_url_provider.dart | 6 +++--- web/e2ee.sfi_guard.dart | 8 ++++---- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lib/src/core/engine.dart b/lib/src/core/engine.dart index e8e09b6a..3efb9021 100644 --- a/lib/src/core/engine.dart +++ b/lib/src/core/engine.dart @@ -726,7 +726,7 @@ class Engine extends Disposable with EventsEmittable { .info('onDisconnected state:${connectionState} reason:${reason.name}'); if (reconnectAttempts == 0) { - reconnectStart = DateTime.now(); + reconnectStart = DateTime.timestamp(); } if (reconnectAttempts! >= _reconnectCount) { diff --git a/lib/src/core/room.dart b/lib/src/core/room.dart index 7a019d86..d835e117 100644 --- a/lib/src/core/room.dart +++ b/lib/src/core/room.dart @@ -48,7 +48,7 @@ import '../types/data_stream.dart'; import '../types/other.dart'; import '../types/rpc.dart'; import '../types/transcription_segment.dart'; -import '../utils.dart'; +import '../utils.dart' show unpackStreamId; import 'engine.dart'; import '../track/web/_audio_api.dart' @@ -853,8 +853,8 @@ class Room extends DisposableChangeNotifier with EventsEmittable { text: segment.text, id: segment.id, firstReceivedTime: - _transcriptionReceivedTimes[segment.id] ?? DateTime.now(), - lastReceivedTime: DateTime.now(), + _transcriptionReceivedTimes[segment.id] ?? DateTime.timestamp(), + lastReceivedTime: DateTime.timestamp(), isFinal: segment.final_5, language: segment.language, ); @@ -863,7 +863,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable { for (var segment in segments) { segment.isFinal ? _transcriptionReceivedTimes.remove(segment.id) - : _transcriptionReceivedTimes[segment.id] = DateTime.now(); + : _transcriptionReceivedTimes[segment.id] = DateTime.timestamp(); } final transcription = TranscriptionEvent( @@ -1301,7 +1301,7 @@ extension DataStreamRoomMethods on Room { var streamController = DataStreamController( info: info, streamController: StreamController(), - startTime: DateTime.now().millisecondsSinceEpoch, + startTime: DateTime.timestamp().millisecondsSinceEpoch, ); _byteStreamControllers[streamHeader.streamId] = streamController; @@ -1334,7 +1334,7 @@ extension DataStreamRoomMethods on Room { var streamController = DataStreamController( info: info, streamController: StreamController(), - startTime: DateTime.now().millisecondsSinceEpoch, + startTime: DateTime.timestamp().millisecondsSinceEpoch, ); _textStreamControllers[streamHeader.streamId] = streamController; diff --git a/lib/src/core/signal_client.dart b/lib/src/core/signal_client.dart index a25ed8f2..c3fa208e 100644 --- a/lib/src/core/signal_client.dart +++ b/lib/src/core/signal_client.dart @@ -36,7 +36,7 @@ import '../support/disposable.dart'; import '../support/platform.dart'; import '../support/websocket.dart'; import '../types/other.dart'; -import '../utils.dart'; +import '../utils.dart' show Utils, UriExt; class SignalClient extends Disposable with EventsEmittable { ConnectionState _connectionState = ConnectionState.disconnected; @@ -361,7 +361,7 @@ class SignalClient extends Disposable with EventsEmittable { void _sendPing() { _sendRequest(lk_rtc.SignalRequest() - ..ping = Int64(DateTime.now().millisecondsSinceEpoch)); + ..ping = Int64(DateTime.timestamp().millisecondsSinceEpoch)); } void _startPingInterval() { diff --git a/lib/src/participant/local.dart b/lib/src/participant/local.dart index 331c1d14..f524b425 100644 --- a/lib/src/participant/local.dart +++ b/lib/src/participant/local.dart @@ -53,7 +53,7 @@ import '../types/other.dart'; import '../types/participant_permissions.dart'; import '../types/rpc.dart'; import '../types/video_dimensions.dart'; -import '../utils.dart'; +import '../utils.dart' show buildStreamId, mimeTypeToVideoCodecString, Utils, compareVersions, isSVCCodec; import 'participant.dart'; /// Represents the current participant in the room. Instance of [LocalParticipant] is automatically @@ -1236,7 +1236,7 @@ extension DataStreamParticipantMethods on LocalParticipant { final info = TextStreamInfo( id: streamId, mimeType: 'text/plain', - timestamp: DateTime.now().toUtc().millisecondsSinceEpoch, + timestamp: DateTime.timestamp().millisecondsSinceEpoch, topic: options?.topic ?? '', size: options?.totalSize ?? 0, ); @@ -1333,7 +1333,7 @@ extension DataStreamParticipantMethods on LocalParticipant { name: options?.name ?? 'unknown', id: streamId, mimeType: options?.mimeType ?? 'application/octet-stream', - timestamp: DateTime.now().toUtc().millisecondsSinceEpoch, + timestamp: DateTime.timestamp().millisecondsSinceEpoch, topic: options?.topic ?? '', size: options?.totalSize ?? 0, attributes: options?.attributes ?? {}, @@ -1345,7 +1345,7 @@ extension DataStreamParticipantMethods on LocalParticipant { streamId: streamId, topic: options?.topic, encryptionType: options?.encryptionType, - timestamp: Int64(DateTime.now().toUtc().millisecondsSinceEpoch), + timestamp: Int64(info.timestamp), byteHeader: lk_models.DataStream_ByteHeader( name: info.name, ), diff --git a/lib/src/participant/participant.dart b/lib/src/participant/participant.dart index d36d84ae..c4089195 100644 --- a/lib/src/participant/participant.dart +++ b/lib/src/participant/participant.dart @@ -27,7 +27,7 @@ import '../support/disposable.dart'; import '../types/other.dart'; import '../types/participant_permissions.dart'; import '../types/participant_state.dart'; -import '../utils.dart'; +import '../utils.dart' show mapDiff; /// Represents a Participant in the room, notifies changes via delegates as /// well as ChangeNotifier/providers. @@ -96,7 +96,7 @@ abstract class Participant return DateTime.fromMillisecondsSinceEpoch(pi.joinedAt.toInt() * 1000, isUtc: true); } - return DateTime.now(); + return DateTime.timestamp(); } /// if [Participant] is currently speaking. @@ -161,7 +161,7 @@ abstract class Participant } _isSpeaking = speaking; if (speaking) { - lastSpokeAt = DateTime.now(); + lastSpokeAt = DateTime.timestamp(); } events.emit(SpeakingChangedEvent( diff --git a/lib/src/support/region_url_provider.dart b/lib/src/support/region_url_provider.dart index ba92bdb9..c2eead28 100644 --- a/lib/src/support/region_url_provider.dart +++ b/lib/src/support/region_url_provider.dart @@ -39,7 +39,7 @@ class RegionUrlProvider { 'region availability is only supported for LiveKit Cloud domains'); } if (regionSettings == null || - DateTime.now().microsecondsSinceEpoch - lastUpdateAt > + DateTime.timestamp().microsecondsSinceEpoch - lastUpdateAt > settingsCacheTime) { regionSettings = await fetchRegionSettings(); } @@ -79,7 +79,7 @@ class RegionUrlProvider { var regionSettings = lk_models.RegionSettings( regions: regions, ); - lastUpdateAt = DateTime.now().microsecondsSinceEpoch; + lastUpdateAt = DateTime.timestamp().microsecondsSinceEpoch; return regionSettings; } else { throw ConnectException( @@ -93,7 +93,7 @@ class RegionUrlProvider { setServerReportedRegions(lk_models.RegionSettings regions) { regionSettings = regions; - lastUpdateAt = DateTime.now().millisecondsSinceEpoch; + lastUpdateAt = DateTime.timestamp().millisecondsSinceEpoch; } String getCloudConfigUrl(Uri serverUrl) { diff --git a/web/e2ee.sfi_guard.dart b/web/e2ee.sfi_guard.dart index 3778230d..afb75916 100644 --- a/web/e2ee.sfi_guard.dart +++ b/web/e2ee.sfi_guard.dart @@ -12,8 +12,8 @@ class SifGuard { void recordSif() { consecutiveSifCount += 1; - sifSequenceStartedAt ??= DateTime.now().millisecondsSinceEpoch; - lastSifReceivedAt = DateTime.now().millisecondsSinceEpoch; + sifSequenceStartedAt ??= DateTime.timestamp().millisecondsSinceEpoch; + lastSifReceivedAt = DateTime.timestamp().millisecondsSinceEpoch; } void recordUserFrame() { @@ -26,7 +26,7 @@ class SifGuard { // reset if we received more user frames than SIFs userFramesSinceSif > consecutiveSifCount || // also reset if we got a new user frame and the latest SIF frame hasn't been updated in a while - DateTime.now().millisecondsSinceEpoch - lastSifReceivedAt > + DateTime.timestamp().millisecondsSinceEpoch - lastSifReceivedAt > MAX_SIF_DURATION) { reset(); } @@ -35,7 +35,7 @@ class SifGuard { bool isSifAllowed() { return consecutiveSifCount < MAX_SIF_COUNT && (sifSequenceStartedAt == null || - DateTime.now().millisecondsSinceEpoch - sifSequenceStartedAt! < + DateTime.timestamp().millisecondsSinceEpoch - sifSequenceStartedAt! < MAX_SIF_DURATION); }