alloy: Add component updater support for Widevine

Issue #3149 resolved
Marshall Greenblatt created an issue

Applications using the Alloy runtime must currently download Widevine binaries from a Google CDN and register them using the CefRegisterWidevineCdm function as documented here. Chrome, on the other hand, uses the component updater to update the binaries at runtime when necessary.

Manual download and registration of Widevine with the Alloy runtime has proven problematic for the following reasons:

  1. CEF code must be kept in sync with Chrome code, which is an error-prone process (see issue #3138 as a recent example).
  2. Communications from the Widevine team must be carefully monitored to know what CDM version to download for a particular platform and Chromium version combination.
  3. Failure by the client to download and register the correct CDM version will cause playback errors.
  4. The Chrome runtime currently uses the component updater (same code as Chrome), and we don’t want to require separate approaches for the Chrome and Alloy runtimes.

The original Widevine implementation in CEF used the component updater (see issue #1631). That implementation was subsequently replaced by the CefRegisterWidevineCdm approach currently in use (see issue #2009). The stated reasons for dropping component updater support at that time (mid-2016) were:

  1. There may be a delay of arbitrary length before the CDM binaries are downloaded;
  2. The remote service controls the specific CDM version that is downloaded;
  3. The downloaded CDM version may not work with the Chromium version in use by the client application -- the newest available CDM version is always downloaded and Google only tests that CDM version with the current Google Chrome stable version.

Recent communications with Google (mid-2021) provide the following responses:

  • Re # 1: “The CDM is normally bundled with a new Chrome installation process. On upgrade, the CDM component will auto-download after X time, I believe the default is either 600s or 900s. If the user attempts DRM playback before the CDM exists, there will be a delay until the CDM retrieval is dynamically executed and completed.”
  • Re # 2: “We have cleaned up the CDM rollout process to be more stable. The CDM rollout process/schedule looks like this:
    [T0] Available on Chrome beta channel for upcoming Chrome release
    [T1] Available on Chrome stable channel (and Component Updater) for current Chrome release (this means CDM is available on latest Chrome, not previous Chrome releases yet)
    [T1 + 2 weeks] CDM is available via Component Updater for all compatible Chrome releases (right now, it's M68 or later)
    [T1 + 2 weeks] Direct HTTP download links are updated and current.txt is updated with latest CDM version”
  • Re # 3: “Minimal testing is conducted on previous versions of Chrome - usually 1-2 versions back but this is not always guaranteed. We expect the CDM to work as long as the CDM interface is unchanged (currently at 10), which goes back as far as M68.”

Based on the above, we have decided to restore component updater usage with the Alloy runtime. The existing CefRegisterWidevineCdm approach will be removed.

Official response

  • Marshall Greenblatt reporter

    The quick test for Widevine support is to visit https://shaka-player-demo.appspot.com/support.html and notice that "com.widevine.alpha" is non-null under "drm". The CDM files will be downloaded under CefSettings.user_data_path (e.g. default of “C:\Users\[User]\AppData\Local\CEF\User Data\WidevineCdm” on Windows, “~/Application Support/CEF/User Data/WidevineCdm“ on MacOS and "~/.config/cef_user_data/WidevineCdm" on Linux).

    The longer test is to play a video with the Widevine DRM (WV) symbol at https://shaka-player-demo.appspot.com/demo/. Note that proprietary codecs like MP4 are not supported by default CEF builds. This video is a good test example.

    You can also try executing a JavaScript snippet from the DevTools console, like:

    await navigator.requestMediaKeySystemAccess('com.widevine.alpha', [{
      sessionTypes: ['temporary'],
      videoCapabilities: [{
        contentType: 'video/webm; codecs="vp09.00.10.08"',
        robustness: 'SW_SECURE_DECODE'
      }]
    }])
    

    The component updater can be disabled by passing the --disable-component-update command-line flag, in which case Widevine will not be downloaded or initialized.

    Faster execution of the component updater after application start can be triggered by passing the --component-updater=fast-update command-line flag. Other supported values for that flag are listed here.

    Windows and MacOS support loading of the Widevine CDM after component updater download without first requiring a client restart. A restart is required on Linux because the CDM must be loaded into the zygote at startup (see description here).

Comments (13)

  1. Marshall Greenblatt reporter

    This work is currently scheduled for M93 which will reach stable at the end of August 2021.

  2. Marshall Greenblatt reporter

    Note that Google currently bundles Widevine binaries with the Chrome installer. It is expected that Widevine will load from disk if you create the correct directory structure before initializing CEF (e.g. you might still choose to download Widevine using client code, and have it available after the next client restart). However, going forward, update of the CDM during runtime will only be supported via the Component Updater.

  3. Marshall Greenblatt reporter

    The quick test for Widevine support is to visit https://shaka-player-demo.appspot.com/support.html and notice that "com.widevine.alpha" is non-null under "drm". The CDM files will be downloaded under CefSettings.user_data_path (e.g. default of “C:\Users\[User]\AppData\Local\CEF\User Data\WidevineCdm” on Windows, “~/Application Support/CEF/User Data/WidevineCdm“ on MacOS and "~/.config/cef_user_data/WidevineCdm" on Linux).

    The longer test is to play a video with the Widevine DRM (WV) symbol at https://shaka-player-demo.appspot.com/demo/. Note that proprietary codecs like MP4 are not supported by default CEF builds. This video is a good test example.

    You can also try executing a JavaScript snippet from the DevTools console, like:

    await navigator.requestMediaKeySystemAccess('com.widevine.alpha', [{
      sessionTypes: ['temporary'],
      videoCapabilities: [{
        contentType: 'video/webm; codecs="vp09.00.10.08"',
        robustness: 'SW_SECURE_DECODE'
      }]
    }])
    

    The component updater can be disabled by passing the --disable-component-update command-line flag, in which case Widevine will not be downloaded or initialized.

    Faster execution of the component updater after application start can be triggered by passing the --component-updater=fast-update command-line flag. Other supported values for that flag are listed here.

    Windows and MacOS support loading of the Widevine CDM after component updater download without first requiring a client restart. A restart is required on Linux because the CDM must be loaded into the zygote at startup (see description here).

  4. Marshall Greenblatt reporter

    Important breakpoints (in order) for debugging Widevine component updater behavior:

    Breakpoints for debugging CDM behavior from the renderer:

    • IsKeySystemSupported (renderer) calls CdmRegistryImpl::GetCdmInfo (browser) to retrieve the info that was populated by RegisterWidevineCdmWithChrome.

      ChromeKeySystemsProvider is responsible in the renderer process for refreshing the key system status after Widevine is installed as a component update.

    • Example IsKeySystemSupported call stack in the renderer triggered by a call to navigator.requestMediaKeySystemAccess from JavaScript code:

      ```

      content.dll!content::IsKeySystemSupported(const std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>> & key_system, mojo::StructPtr<media::mojom::KeySystemCapability> * key_system_capability) Line 26 C++ libcef.dll!anonymous namespace'::AddWidevine(std::__1::vector<std::__1::unique_ptr<media::KeySystemProperties,std::__1::default_delete<media::KeySystemProperties>>,std::__1::allocator<std::__1::unique_ptr<media::KeySystemProperties,std::__1::default_delete<media::KeySystemProperties>>>> * concrete_key_systems) Line 314 C++ libcef.dll!AddChromeKeySystems(std::__1::vector<std::__1::unique_ptr<media::KeySystemProperties,std::__1::default_delete<media::KeySystemProperties>>,std::__1::allocator<std::__1::unique_ptr<media::KeySystemProperties,std::__1::default_delete<media::KeySystemProperties>>>> * key_systems_properties) Line 410 C++ libcef.dll!AlloyContentRendererClient::AddSupportedKeySystems(std::__1::vector<std::__1::unique_ptr<media::KeySystemProperties,std::__1::default_delete<media::KeySystemProperties>>,std::__1::allocator<std::__1::unique_ptr<media::KeySystemProperties,std::__1::default_delete<media::KeySystemProperties>>>> * key_systems) Line 416 C++ content.dll!content::RenderMediaClient::AddSupportedKeySystems(std::__1::vector<std::__1::unique_ptr<media::KeySystemProperties,std::__1::default_delete<media::KeySystemProperties>>,std::__1::allocator<std::__1::unique_ptr<media::KeySystemProperties,std::__1::default_delete<media::KeySystemProperties>>>> * key_systems) Line 31 C++ media.dll!media::KeySystemsImpl::UpdateSupportedKeySystems() Line 423 C++ media.dll!media::KeySystemsImpl::KeySystemsImpl() Line 351 C++ media.dll!base::NoDestructor<media::KeySystemsImpl,nullptr_t>::NoDestructor<>() Line 71 C++ media.dll!media::KeySystemsImpl::GetInstance() Line 334 C++ media.dll!media::KeySystems::GetInstance() Line 766 C++ blink_platform_media.dll!blink::WebEncryptedMediaClientImpl::WebEncryptedMediaClientImpl(media::CdmFactory * cdm_factory, media::MediaPermission * media_permission, std::__1::unique_ptr<blink::KeySystemConfigSelector::WebLocalFrameDelegate,std::__1::default_delete<blink::KeySystemConfigSelector::WebLocalFrameDelegate>> web_frame_delegate) Line 105 C++ content.dll!std::__1::make_unique<blink::WebEncryptedMediaClientImpl,media::CdmFactory *,media::MediaPermission *,std::unique_ptr<blink::KeySystemConfigSelector::WebLocalFrameDelegate>>(media::CdmFactory * && __args, media::MediaPermission * && __args, std::__1::unique_ptr<blink::KeySystemConfigSelector::WebLocalFrameDelegate,std::__1::default_delete<blink::KeySystemConfigSelector::WebLocalFrameDelegate>> && __args) Line 725 C++ content.dll!content::MediaFactory::EncryptedMediaClient() Line 585 C++ content.dll!content::RenderFrameImpl::EncryptedMediaClient() Line 4445 C++ blink_modules.dll!blink::MediaKeysController::EncryptedMediaClient(blink::ExecutionContext * context) Line 23 C++ blink_modules.dll!blink::NavigatorRequestMediaKeySystemAccess::requestMediaKeySystemAccess(blink::ScriptState * script_state, blink::Navigator & navigator, const WTF::String & key_system, const blink::HeapVector<blink::Member<blink::MediaKeySystemConfiguration>,0> & supported_configurations, blink::ExceptionState & exception_state) Line 196 C++ blink_modules.dll!blink::anonymous namespace'::v8_navigator::RequestMediaKeySystemAccessOperationCallback(const v8::FunctionCallbackInfo<v8::Value> & info) Line 1763 C++ v8.dll!v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo handler) Line 155 C++```

  5. Marshall Greenblatt reporter

    widevine: Use component updater with the Alloy runtime (fixes issue #3149)

    Widevine CDM binaries will be downloaded on supported platforms shortly after application startup. Widevine support will then become available within a few seconds after successful installation on Windows or after the next application restart on other platforms. The CDM files will be downloaded to a "WidevineCdm" directory inside the CefSettings.user_data_path directory.

    Pass the --disable-component-update command-line flag to disable Widevine download and installation. Pass the --component-updater=fast-update command- line flag to force Widevine download immediately after application startup.

    See the related issue for additional usage details.

    → <<cset 240b869db5cc>>

  6. Marshall Greenblatt reporter

    widevine: Use component updater with the Alloy runtime (fixes issue #3149)

    Widevine CDM binaries will be downloaded on supported platforms shortly after application startup. Widevine support will then become available within a few seconds after successful installation on Windows or after the next application restart on other platforms. The CDM files will be downloaded to a "WidevineCdm" directory inside the CefSettings.user_data_path directory.

    Pass the --disable-component-update command-line flag to disable Widevine download and installation. Pass the --component-updater=fast-update command- line flag to force Widevine download immediately after application startup.

    See the related issue for additional usage details.

    → <<cset 5a0b3ea93778>>

  7. Marshall Greenblatt reporter

    widevine: Fix ARM compile error due to unused variable (see issue #3149)

    alloy_browser_main.cc:223:17: error: unused variable 'cus' [-Werror,-Wunused-variable] auto* const cus = g_browser_process->component_updater();

    → <<cset 17d2d13030cb>>

  8. Marshall Greenblatt reporter

    widevine: Fix ARM compile error due to unused variable (see issue #3149)

    alloy_browser_main.cc:223:17: error: unused variable 'cus' [-Werror,-Wunused-variable] auto* const cus = g_browser_process->component_updater();

    → <<cset 6a52098b6251>>

  9. Log in to comment