fix(desktop): bound WebRTC offer wait

This commit is contained in:
Haitao Pan 2026-06-13 07:10:28 +08:00
parent 2309d5bbb4
commit 5932b70f70
2 changed files with 35 additions and 18 deletions

View File

@ -11,6 +11,7 @@ const int desktopReliableInputChannelId = 0;
const int desktopMoveInputChannelId = 1;
const int desktopMoveChannelMaxPacketLifeTimeMs = 100;
const int desktopMoveBufferedAmountLimit = 16 * 1024;
const Duration desktopOfferRequestTimeout = Duration(seconds: 15);
String desktopConnectionStateName(RTCPeerConnectionState state) {
final value = state.toString().split('.').last;
@ -307,19 +308,27 @@ class DesktopClient {
await _peerConnection!.setLocalDescription(offer);
// Send SDP Offer to Bridge
final response = await controller.gatewayAcpClientInternal.request(
method: 'xworkmate.desktop.offer',
params: desktopOfferParams(
sessionId: sessionId,
sdpOffer: offer.sdp,
display: display,
width: width,
height: height,
fps: fps,
bitrate: bitrate,
useGpu: useGpu,
),
);
final response = await controller.gatewayAcpClientInternal
.request(
method: 'xworkmate.desktop.offer',
params: desktopOfferParams(
sessionId: sessionId,
sdpOffer: offer.sdp,
display: display,
width: width,
height: height,
fps: fps,
bitrate: bitrate,
useGpu: useGpu,
),
)
.timeout(
desktopOfferRequestTimeout,
onTimeout: () => throw TimeoutException(
'Timed out waiting for desktop SDP answer',
desktopOfferRequestTimeout,
),
);
final sdpAnswerData = response['result']?['sdpAnswer'];
if (sdpAnswerData == null) {

View File

@ -64,6 +64,7 @@ class _DesktopViewState extends State<DesktopView> {
StreamSubscription<MediaStream>? _streamSubscription;
StreamSubscription<String>? _stateSubscription;
Timer? _firstFrameStatsTimer;
int _firstFrameStatsPolls = 0;
bool get _hasVideoFrame => desktopHasRenderedVideoFrame(
hasStream: _hasStream,
@ -123,10 +124,6 @@ class _DesktopViewState extends State<DesktopView> {
_localRenderer.onResize = () {
if (_localRenderer.videoWidth > 0 && _localRenderer.videoHeight > 0) {
_markRemoteDesktopFrameReady();
return;
}
if (mounted) {
setState(() {});
}
};
}
@ -144,13 +141,24 @@ class _DesktopViewState extends State<DesktopView> {
void _startFirstFrameDiagnostics() {
_firstFrameStatsTimer?.cancel();
_firstFrameStatsPolls = 0;
unawaited(_collectFirstFrameStats());
_firstFrameStatsTimer = Timer.periodic(const Duration(seconds: 2), (_) {
_scheduleFirstFrameStatsPoll(const Duration(milliseconds: 500));
}
void _scheduleFirstFrameStatsPoll(Duration delay) {
_firstFrameStatsTimer?.cancel();
_firstFrameStatsTimer = Timer(delay, () {
if (!_hasStream || _hasVideoFrame || !mounted) {
_stopFirstFrameDiagnostics();
return;
}
_firstFrameStatsPolls += 1;
unawaited(_collectFirstFrameStats());
final nextDelay = _firstFrameStatsPolls < 4
? const Duration(milliseconds: 500)
: const Duration(seconds: 2);
_scheduleFirstFrameStatsPoll(nextDelay);
});
}