New issue
Advanced search Search tips

Issue 848768 link

Starred by 1 user

Issue metadata

Status: Fixed
Owner:
Closed: Jun 2018
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Mac
Pri: 1
Type: Bug

Blocking:
issue 848747



Sign in to add a comment

Chrome intermittently fires signalingstate after setLocalDescription succeeds, against spec.

Reported by jbruar...@mozilla.com, Jun 1 2018

Issue description

UserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:62.0) Gecko/20100101 Firefox/62.0

Steps to reproduce the problem:
1. Open https://jsfiddle.net/jib1/bbfvdxrr/
2. Share camera permission if necessary

What is the expected behavior?
Fiddle should always emit (and does so in the spec and e.g. in Firefox):

  stable
  fired have-local-offer
  have-local-offer
  fired stable
  stable

What went wrong?
Fiddle in Chrome sometimes emits this:

  stable
  have-local-offer
  fired have-local-offer
  fired stable
  stable

and at other times:

  stable
  fired have-local-offer
  have-local-offer
  fired stable
  stable

Chrome is sometimes firing the signalingstate event *after* setLocalDescription succeeds—which is against the spec—and at other times it is firing it *before*, which is to spec.

Did this work before? No 

Does this work in other browsers? N/A

Chrome version: 66.0.3359.181  Channel: stable
OS Version: OS X 10.12
Flash Version: Shockwave Flash 29.0 r0

This blocks https://bugs.chromium.org/p/chromium/issues/detail?id=848747

First discovered in https://github.com/web-platform-tests/wpt/pull/11054#issuecomment-390097676

Relevant spec link: https://w3c.github.io/webrtc-pc/#set-description

Step 4.4.1.6.2.2.2:
  "If description is set as a local description, ... If description is of type "offer", ... and set signaling state to "have-local-offer"."

Step 4.4.1.6.2.2.4:

  "If connection's signaling state changed above, fire a simple event named signalingstatechange at connection."
 
Blocking: 848747
Components: -Blink>WebRTC Blink>WebRTC>PeerConnection
Cc: hbos@chromium.org
Labels: Needs-Triage-M66

Comment 4 by hbos@chromium.org, Jun 4 2018

Cc: hta@chromium.org steveanton@chromium.org orphis@chromium.org
Labels: -Pri-2 Pri-1
Status: Available (was: Unconfirmed)
This is blocking WPT exports, making it Pri-1. Anyone cc'd volunteering to take a closer look?

The signaling state is surfaced to Chrome in a PostTask[1][2] that is not coordinated with the PostTask that is used to surface "setLocalDescription completed" so that randomly there may or may not be a JavaScript task execution cycle between the tasks. Also, when the signalingstatechange reaches JavaScript land, it is scheduled to fire in the next cycle[3].

I think the right thing to do is to always coordinate any updated state information in a single callback, so that Chrome can do a single PostTask with all updated information. Otherwise we're at risk of things happening in-between state changes.

This was a problem before for setRemoteDescription in that each stream was surfaced in a separate observer callback - a separate PostTask - so the result of SRD was not an "all or nothing" operation. The fix for that was to process all relevant state changes in the setRemoteDescription callback, and then add remote streams at the same time when we reach the JS thread.

Can the signaling state only change due to user invoked APIs such as setLocalDescription and setRemoteDescription? If so we could just copy the third_party/webrtc signaling state information in the SLD/SRD callback and handle that in the same PostTask as the rest of the operation.

[1] https://cs.chromium.org/chromium/src/content/renderer/media/webrtc/rtc_peer_connection_handler.cc?sq=package:chromium&dr&g=0&l=1184

[2] https://cs.chromium.org/chromium/src/third_party/webrtc/pc/peerconnection.cc?sq=package:chromium&dr&g=0&l=3537

[3] https://cs.chromium.org/chromium/src/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc?q=rtc_peer_connection.cc&sq=package:chromium&dr&l=1878

Comment 5 by hbos@chromium.org, Jun 4 2018

Background information: All third_party/webrtc code executes on a thread separate from JavaScript (renderer main thread). setLocalDescription/setRemoteDescription is async in the spec, but implemented as (more or less) synchronously in third_party/webrtc. Async behavior is achieved in Chrome by not blocking the main thread when invoking SLD/SRD, and sync behavior is achieved in Chrome by blocking the main thread when invoking other operations - but usually they're synchronous in third_party/webrtc.

(This necessarily leads to spec non-conformance in some cases where async and sync operations are mixed, but these are typically non-representative edge cases. I have a bug filed for that somewhere, but that is not blocking this.)

In the SLD/SRD case, the synchronous implementation means that in third_party/webrtc when you call SLD it either happens or not. But surfacing what happened in multiple PostTasks you can get into a state in JavaScript where some of the things have happened and other things are queued to happen but have not been processed yet. If that makes sense.

Comment 6 by hbos@chromium.org, Jun 4 2018

Owner: hbos@chromium.org
Status: Started (was: Available)
Ah, I'll take a stab at it!
Project Member

Comment 7 by bugdroid1@chromium.org, Jun 7 2018

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/c220be7c001dbe68a36afc3e02838c510b0b3b0f

commit c220be7c001dbe68a36afc3e02838c510b0b3b0f
Author: Henrik Boström <hbos@chromium.org>
Date: Thu Jun 07 16:30:41 2018

Fire RTCPeerConnection.onsignalingstatechange in the correct order.

With this change, onsignalingstatechange always fires before the
setLocalDescription's promise resolves.

Before this change, signaling state changes were surfaced with callbacks
firing separately from the callback that setLocalDescription or
setRemoteDescription had completed. As a result, the result of a SLD/SRD
operation was surfaced in two PostTasks instead of one. This could lead
to flaky behavior where JavaScript task execeution cycles may or may not
execute between PostTasks which lead to undefined order. Also when the
signalingstatechange was surfaced to the JS thread the firing of the
event was delayed by a task execution cycle due to
ScheduleDispatchEvent.
- If both PostTasks were handled in the same cycle, the event firing
  would be scheduled and the promise resolved, such that the promise's
  then() is invoked just before the event fires (scheduled after
  promise). This is NOT in accordance with the spec.
- If onsignalingstatechange's PostTask was handled in its own cycle,
  the event would be scheduled such that by the time the
  setLocalDescription's callback's PostTask occurs resolving the
  promise, the event would fire before the promise's then(). This IS
  in accordance with the spec.

With this change, the onsignalingstatechange event is fired without
delay, and it is processed in by the same observer that handles the
SLD/SRD callback, so the order is always guaranteed to be the same.

In addition, this CL removes the usage of
WebRTCPeerConnectionHandlerClient::SignalingState and relies on the
webrtc::PeerConnectionInterface::SignalingState enum directly. This
is part of the Onion Souping work (crbug.com/787254).

Bug:  848768 , 787254
Change-Id: I7bc10439c44c6ff6beab0289975295ff2e051b9c
Reviewed-on: https://chromium-review.googlesource.com/1085302
Commit-Queue: Henrik Boström <hbos@chromium.org>
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#565291}
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/content/renderer/media/webrtc/mock_web_rtc_peer_connection_handler_client.h
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/content/renderer/media/webrtc/peer_connection_tracker.cc
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/content/renderer/media/webrtc/peer_connection_tracker.h
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/content/renderer/media/webrtc/rtc_peer_connection_handler.h
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/content/renderer/media/webrtc/webrtc_set_remote_description_observer.cc
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/content/renderer/media/webrtc/webrtc_set_remote_description_observer.h
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-expected.txt
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription.html
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/third_party/blink/public/platform/web_rtc_peer_connection_handler_client.h
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
[modify] https://crrev.com/c220be7c001dbe68a36afc3e02838c510b0b3b0f/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h

Comment 8 by hbos@chromium.org, Jun 7 2018

Cc: foolip@chromium.org
Status: Fixed (was: Started)

Sign in to add a comment