Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of Cef.RegisterWidevineCdm #1935

Merged
merged 6 commits into from Feb 13, 2017

Conversation

justinstenning
Copy link
Contributor

@justinstenning justinstenning commented Feb 13, 2017

Implementation of Cef.RegisterWidevineCdm with test as per feature request #1934

I have completed testing, however in order for others to test you need to:

  1. have access to WidevineCdm binaries (it might be possible test using Chrome copy, possibly with manifest.json changes - see Feature Request - Expose CefRegisterWidevineCdm #1934 for list of files required and example manifest.json)
  2. uncomment the call to Cef.RegisterWidevineCdm(@".\WidevineCdm"); in CefExample.Init
  3. place the Widevine binaries in a folder called 'WidevineCdm' within the CefSharp.Wpf.Example build directory (e.g. bin\x64\Debug\WidevineCdm)

Please advise if any changes needed, styling issues, etc...

Description of changes:

  • Added types CefSharp/CdmRegistration.cs (return value of registration process) and enumeration CefSharp/CdmRegistrationErrorCode.cs to CefSharp
  • Added RegisterWidevineCdm metho to Cef.h in CefSharp.Core
  • Added CefRegisterCdmCallbackWrapper.h to CefSharp.Core project

@justinstenning
Copy link
Contributor Author

I have just noticed that I didn't postfix the RegisterWidevineCdm method name with "Async".

Please advise if this should be the case (it returns a Task<CdmRegistration^>^).

Copy link
Member

@amaitland amaitland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments made inline, overall it looks promising 👍

/// will receive a |result| value of CEF_CDM_REGISTRATION_ERROR_NOT_SUPPORTED.
/// </summary>
/// <returns>Returns the CDM registration result.</returns>
static Task<CdmRegistration^>^ RegisterWidevineCdm(String^ path)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know a similar pattern has been used in the past, I've revised my take on this, would prefer to wrap the underlying API as close to 1:1 as possible and implement any async wrappers in C#.

Please add IRegisterCdmCallback as a param and return void here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By all means add an overload that has the same signature

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overload should be RegisterWidevineCdmAsync, you are correct.

private class CefRegisterCdmCallbackWrapper : public CefRegisterCdmCallback
{
private:
gcroot<TaskCompletionSource<CdmRegistration^>^> _taskCompletionSource;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace with IRegisterCdmCallback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want a base concrete implementation of IRegisterCdmCallback as well or just implement an example within the example project?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you wish to have Cef.RegisterWidevineCdmAsync then add a concrete implementation to the CefSharp project.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to be a pain, I'm fairly new to the CefSharp codebase and not that familiar with other areas of it.

In order to call the underlying CefRegisterWidevineCdm it wants a CefRegisterCdmCallback (defined in the Cef codebase). Can you please point me to an example where a similar process takes place but using the interface as you described?

Or are you saying pass our own defined interface into the callback wrapper and use that to trigger back through to the caller? But still use the CefRegisterCdmCallback internally.

Again, sorry for the noobness!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind I get it, just replace the _taskCompletionSource with it. :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind I get it, just replace the _taskCompletionSource with it. :)

Pretty much, see https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Core/Internals/CefCompletionCallbackAdapter.h for an example.

Also IRegisterCdmCallback should implement IDisposable

}
</script>
</head>
<body onload="doTest()">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably be some sort of disclaimer here that explains widevine CDM requires additional steps to enable and propritary codes are not supported in the default Nuget packages as they require licensing.

What happens if you open this page with a default build?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Widevine not registered and not using proprietary codecs just says that widevine is "NOT AVAILABLE", and some of the codecs are listed as not supporting playback.

I'll add a note at the end of the page re proprietary codecs and contacting Widevine for access to widevine - and a link to the issue #1934.

@@ -41,6 +42,10 @@ public static void Init(bool osr, bool multiThreadedMessageLoop, IBrowserProcess
// Environment.SetEnvironmentVariable("GOOGLE_DEFAULT_CLIENT_ID", "");
// Environment.SetEnvironmentVariable("GOOGLE_DEFAULT_CLIENT_SECRET", "");

// Widevine CDM registration - pass in directory where Widevine CDM binaries and manifest.json are located.
// To organize access to Widevine binaries: https://www.widevine.com/contact.html
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should link to the issue #1934

@justinstenning
Copy link
Contributor Author

justinstenning commented Feb 13, 2017

@amaitland your review comments should now all be addressed:

  • added IRegisterCdmCallback and simple concrete class for convenience.
  • Cef.RegisterWidevineCdm async result replaced with IRegisterCdmCallback parameter. One override with no parameter still provided as often the result of the process will be of no interest - this also keeps the example simple.
  • CdmSupportTest.html includes links to additional setup steps for both Widevine and proprietary codecs
  • CefExample.cs links to issue for more details. The call to Cef.RegisterWidevineCdm is left uncommented as it has no impact if the directory does not exist, this means someone could try out the Wpf Example without recompiling and just placing the widevine package in place.

/// </summary>
static void RegisterWidevineCdm(String^ path, IRegisterCdmCallback^ callback)
{
auto adapter = new CefRegisterCdmCallbackAdapter(callback);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no point creating a CefRegisterCdmCallbackAdapter instance of callback is null, so add nullptr check here and remove the RegisterWidevineCdm overload.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean pass nullptr into CefRegisterWidevineCdm when there is no callback provided? (tested and yep that doesn't cause any issues with the CEF API - at this time anyway).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/--cef(optional_param=callback)--/

The CEF API says it's optional, so yes pass in NULL when there is no callback.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


~CefRegisterCdmCallbackAdapter()
{
if (static_cast<IRegisterCdmCallback^>(_callback) != nullptr)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can call delete on a nullptr, ends up being a noop, so no need to check this.

r->ErrorCode = (CdmRegistrationErrorCode)result;
r->ErrorMessage = StringUtils::ToClr(error_message);

if (static_cast<IRegisterCdmCallback^>(_callback) != nullptr)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to only create an instance if there is a callback and remove this check.

///
/// If any of these files are missing or if the manifest file has incorrect
/// contents the registration will fail and |callback| will receive a |result|
/// value of CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments should be updated to make relevant in context of CefSharp.

/// <summary>
/// Provides a simple callback implementation of <see cref="IRegisterCdmCallback"/> for use with Widevine CDM registration.
/// </summary>
public class RegisterCdmCallback: IRegisterCdmCallback
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having the default implementation implement a TaskCompletionSource wrapper would be consistent with the rest of the codebase and allow you to add Cef.RegisterWidevineCdmAsync

@amaitland
Copy link
Member

@spazzarama Few more minor changes required 👍

@justinstenning
Copy link
Contributor Author

@amaitland those changes should be addressed now. Let me know if anything else needs to be sorted.

@amaitland amaitland merged commit 2298ea0 into cefsharp:master Feb 13, 2017
@amaitland
Copy link
Member

@spazzarama Merged with the following changes ee5fd34

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants