⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 277481 in webkit


Ignore:
Timestamp:
May 13, 2021, 9:44:10 PM (5 years ago)
Author:
Devin Rousso
Message:

[Modern Media Controls] REGRESSION(r268308) AirPlay briefly disappears and then reappears when hovering over controls
​https://bugs.webkit.org/show_bug.cgi?id=225780
<rdar://problem/77984683>

Reviewed by Eric Carlson.

r268308 adjusted AVRoutePickerViewTargetPicker::isAvailable, which is used to control
whether AVRoutePickerViewTargetPicker (which uses the AVRouteDetectorMultipleRoutesDetectedDidChange
notification and actually stops listening for it in stopMonitoringPlaybackTargets) or
AVOutputDeviceMenuControllerTargetPicker (which uses ObjC KVO and doesn't actually do
anything in stopMonitoringPlaybackTargets when the last JS "webkitplaybacktargetavailabilitychanged"
event listener is removed, meaning that WebKit never senda a new value to the WebProcess) is
used. When using AVRoutePickerViewTargetPicker, WebKit calls -[AVRouteDetector setRouteDetectionEnabled:]
whenever the first JS "webkitplaybacktargetavailabilitychanged" event listener is added
(with the argument YES) and the last JS "webkitplaybacktargetavailabilitychanged" event
listener is removed (with the argument NO). In the latter scenario (which is the case with
builtin media controls), -[AVRouteDetector setRouteDetectionEnabled:] will dispatch a
AVRouteDetectorMultipleRoutesDetectedDidChange notification and mark itself as not having
multiple routes (-[AVRouteDetector multipleRoutesDetected]). This work is done in the
UIProcess and the result is sent to the WebProcess, meaning that even though there are no
more JS event listeners WebKit still updates the cached state of whether multiple routes
exist. This means that the next time a JS event listener is added, WebKit will ask the
UIProcess to update (which will re-enable route detection, which will dispatch a AVRouteDetectorMultipleRoutesDetectedDidChange
notification) but then immediately dispatch a JS "webkitplaybacktargetavailabilitychanged"
event using the cached state. Once the request from the UIProcess comes back, WebKit will
then dispatch *another* JS "webkitplaybacktargetavailabilitychanged" event with the new
non-cached value.

  • platform/graphics/avfoundation/objc/AVRoutePickerViewTargetPicker.h:
  • platform/graphics/avfoundation/objc/AVRoutePickerViewTargetPicker.mm:

(WebCore::AVRoutePickerViewTargetPicker::startingMonitoringPlaybackTargets):
(WebCore::AVRoutePickerViewTargetPicker::stopMonitoringPlaybackTargets):
(WebCore::AVRoutePickerViewTargetPicker::availableDevicesDidChange):
Add a flag that ignores the next AVRouteDetectorMultipleRoutesDetectedDidChange
notification since it's guaranteed to be false after setRouteDetectionEnabled:NO.

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r277479 r277481  
     12021-05-13  Devin Rousso  <drousso@apple.com>
     2
     3        [Modern Media Controls] REGRESSION(r268308) AirPlay briefly disappears and then reappears when hovering over controls
     4        https://bugs.webkit.org/show_bug.cgi?id=225780
     5        <rdar://problem/77984683>
     6
     7        Reviewed by Eric Carlson.
     8
     9        r268308 adjusted `AVRoutePickerViewTargetPicker::isAvailable`, which is used to control
     10        whether `AVRoutePickerViewTargetPicker` (which uses the `AVRouteDetectorMultipleRoutesDetectedDidChange`
     11        notification and actually stops listening for it in `stopMonitoringPlaybackTargets`) or
     12        `AVOutputDeviceMenuControllerTargetPicker` (which uses ObjC KVO and doesn't actually do
     13        anything in `stopMonitoringPlaybackTargets` when the last JS `"webkitplaybacktargetavailabilitychanged"`
     14        event listener is removed, meaning that WebKit never senda a new value to the WebProcess) is
     15        used. When using `AVRoutePickerViewTargetPicker`, WebKit calls `-[AVRouteDetector setRouteDetectionEnabled:]`
     16        whenever the first JS `"webkitplaybacktargetavailabilitychanged"` event listener is added
     17        (with the argument `YES`) and the last JS `"webkitplaybacktargetavailabilitychanged"` event
     18        listener is removed (with the argument `NO`). In the latter scenario (which is the case with
     19        builtin media controls), `-[AVRouteDetector setRouteDetectionEnabled:]` will dispatch a
     20        `AVRouteDetectorMultipleRoutesDetectedDidChange` notification and mark itself as not having
     21        multiple routes (`-[AVRouteDetector multipleRoutesDetected]`). This work is done in the
     22        UIProcess and the result is sent to the WebProcess, meaning that even though there are no
     23        more JS event listeners WebKit still updates the cached state of whether multiple routes
     24        exist. This means that the next time a JS event listener is added, WebKit will ask the
     25        UIProcess to update (which will re-enable route detection, which will dispatch a `AVRouteDetectorMultipleRoutesDetectedDidChange`
     26        notification) but then immediately dispatch a JS `"webkitplaybacktargetavailabilitychanged"`
     27        event using the cached state. Once the request from the UIProcess comes back, WebKit will
     28        then dispatch *another* JS "webkitplaybacktargetavailabilitychanged" event with the new
     29        non-cached value.
     30
     31        * platform/graphics/avfoundation/objc/AVRoutePickerViewTargetPicker.h:
     32        * platform/graphics/avfoundation/objc/AVRoutePickerViewTargetPicker.mm:
     33        (WebCore::AVRoutePickerViewTargetPicker::startingMonitoringPlaybackTargets):
     34        (WebCore::AVRoutePickerViewTargetPicker::stopMonitoringPlaybackTargets):
     35        (WebCore::AVRoutePickerViewTargetPicker::availableDevicesDidChange):
     36        Add a flag that ignores the next `AVRouteDetectorMultipleRoutesDetectedDidChange`
     37        notification since it's guaranteed to be `false` after `setRouteDetectionEnabled:NO`.
     38
    1392021-05-13  Wenson Hsieh  <wenson_hsieh@apple.com>
    240
  • trunk/Source/WebCore/platform/graphics/avfoundation/objc/AVRoutePickerViewTargetPicker.h

    r272611 r277481  
    6767    RetainPtr<WebAVRoutePickerViewHelper> m_routePickerViewDelegate;
    6868    bool m_hadActiveRoute { false };
     69    bool m_ignoreNextMultipleRoutesDetectedDidChangeNotification { false };
    6970};
    7071
  • trunk/Source/WebCore/platform/graphics/avfoundation/objc/AVRoutePickerViewTargetPicker.mm

    r276621 r277481  
    138138void AVRoutePickerViewTargetPicker::startingMonitoringPlaybackTargets()
    139139{
     140    m_ignoreNextMultipleRoutesDetectedDidChangeNotification = false;
     141
    140142    routeDetector().routeDetectionEnabled = YES;
    141143}
    … …  
    143145void AVRoutePickerViewTargetPicker::stopMonitoringPlaybackTargets()
    144146{
    145     if (m_routeDetector)
    146         [m_routeDetector setRouteDetectionEnabled:NO];
     147    if (!m_routeDetector)
     148        return;
     149
     150    // `-[AVRouteDetector multipleRoutesDetected]` will always return `NO` if route detection is
     151    // disabled and `-[AVRouteDetector setRouteDetectionEnabled:]` will always dispatch a
     152    // `AVRouteDetectorMultipleRoutesDetectedDidChange` notification, so ignore the next one in
     153    // order to prevent the cached value in the WebProcess from always being `false` when the last
     154    // JS `"webkitplaybacktargetavailabilitychanged"` event listener is removed.
     155    m_ignoreNextMultipleRoutesDetectedDidChangeNotification = true;
     156
     157    [m_routeDetector setRouteDetectionEnabled:NO];
    147158}
    148159
    … …  
    178189void AVRoutePickerViewTargetPicker::availableDevicesDidChange()
    179190{
     191    if (m_ignoreNextMultipleRoutesDetectedDidChangeNotification) {
     192        m_ignoreNextMultipleRoutesDetectedDidChangeNotification = false;
     193        return;
     194    }
     195
    180196    if (client())
    181197        client()->availableDevicesChanged();
Note: See TracChangeset for help on using the changeset viewer.