Skip to content

Commit

Permalink
Support key system in HTMLMediaElement.canPlayType (#4429)
Browse files Browse the repository at this point in the history
b/378908084
  • Loading branch information
jasonzhangxx authored Nov 18, 2024
1 parent 3c4b5f4 commit 34382e9
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 17 deletions.
2 changes: 2 additions & 0 deletions cobalt/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ android_library("cobalt_apk_java") {
"apk/app/src/main/java/dev/cobalt/coat/javabridge/AmatiDeviceInspector.java",
"apk/app/src/main/java/dev/cobalt/coat/javabridge/CobaltJavaScriptAndroidObject.java",
"apk/app/src/main/java/dev/cobalt/coat/javabridge/CobaltJavaScriptInterface.java",
"apk/app/src/main/java/dev/cobalt/coat/javabridge/HTMLMediaElementExtension.java",

# "apk/app/src/main/java/dev/cobalt/coat/CobaltMediaSession.java",
"apk/app/src/main/java/dev/cobalt/coat/CobaltService.java",
Expand Down Expand Up @@ -118,6 +119,7 @@ android_assets("cobalt_apk_assets") {
testonly = true
sources = [
"apk/app/src/app/assets/amati_device_inspector.js",
"apk/app/src/app/assets/html_media_element_extension.js",
"apk/app/src/app/assets/not_empty.txt",
"apk/app/src/app/assets/test/not_empty.txt",
"apk/app/src/app/assets/web/cobalt_blue_splash_screen.css",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @license
* Copyright The Cobalt Authors.
* SPDX-License-Identifier: Apache-2.0
*/

HTMLMediaElement.prototype.canPlayType = HTMLMediaElementExtension.canPlayType;
console.log("HTMLMediaElement.canPlayType has been overwritten");
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import dev.cobalt.coat.javabridge.AmatiDeviceInspector;
import dev.cobalt.coat.javabridge.CobaltJavaScriptAndroidObject;
import dev.cobalt.coat.javabridge.CobaltJavaScriptInterface;
import dev.cobalt.coat.javabridge.HTMLMediaElementExtension;
import dev.cobalt.media.AudioOutputManager;
import dev.cobalt.media.MediaCodecCapabilitiesLogger;
import dev.cobalt.media.VideoSurfaceView;
Expand Down Expand Up @@ -172,11 +173,12 @@ protected void createContent(final Bundle savedInstanceState) {
}
if (mStartupUrl == null || mStartupUrl.isEmpty()) {
String[] args = getStarboardBridge().getArgs();
mStartupUrl = Arrays.stream(args)
.filter(line -> line.contains(URL_ARG))
.findAny()
.map(arg -> arg.substring(arg.indexOf(URL_ARG) + URL_ARG.length()))
.orElse(null);
mStartupUrl =
Arrays.stream(args)
.filter(line -> line.contains(URL_ARG))
.findAny()
.map(arg -> arg.substring(arg.indexOf(URL_ARG) + URL_ARG.length()))
.orElse(null);
}
if (!TextUtils.isEmpty(mStartupUrl)) {
mShellManager.setStartupUrl(Shell.sanitizeUrl(mStartupUrl));
Expand Down Expand Up @@ -355,37 +357,47 @@ protected void onCreate(Bundle savedInstanceState) {
}

/**
* Initializes the Java Bridge to allow communication between Java and JavaScript.
* This method injects Java objects into the WebView and loads corresponding JavaScript code.
* Initializes the Java Bridge to allow communication between Java and JavaScript. This method
* injects Java objects into the WebView and loads corresponding JavaScript code.
*/
private void initializeJavaBridge() {
Log.i(TAG, "initializeJavaBridge");

WebContents webContents = getActiveWebContents();
if (webContents == null) {
// WebContents not initialized yet, post a delayed runnable to check again
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
initializeJavaBridge(); // Recursive call to check again
}
}, JAVA_BRIDGE_INITIALIZATION_DELAY_MILLI_SECONDS);
return;
// WebContents not initialized yet, post a delayed runnable to check again
new Handler(Looper.getMainLooper())
.postDelayed(
new Runnable() {
@Override
public void run() {
initializeJavaBridge(); // Recursive call to check again
}
},
JAVA_BRIDGE_INITIALIZATION_DELAY_MILLI_SECONDS);
return;
}

// --- Initialize the Java Bridge ---

// 1. Gather all Java objects that need to be exposed to JavaScript.
// TODO(b/379701165): consider to refine the way to add JavaScript interfaces.
javaScriptAndroidObjectList.add(new AmatiDeviceInspector(this));
javaScriptAndroidObjectList.add(new HTMLMediaElementExtension(this));

// 2. Use JavascriptInjector to inject Java objects into the WebContents.
// This makes the annotated methods in these objects accessible from JavaScript.
JavascriptInjector javascriptInjector = JavascriptInjector.fromWebContents(webContents, false);

javascriptInjector.setAllowInspection(true);
for (CobaltJavaScriptAndroidObject javascriptAndroidObject : javaScriptAndroidObjectList) {
Log.d(TAG, "Add JavaScriptAndroidObject:" + javascriptAndroidObject.getJavaScriptInterfaceName());
javascriptInjector.addPossiblyUnsafeInterface(javascriptAndroidObject, javascriptAndroidObject.getJavaScriptInterfaceName(), CobaltJavaScriptInterface.class);
Log.d(
TAG,
"Add JavaScriptAndroidObject:" + javascriptAndroidObject.getJavaScriptInterfaceName());
javascriptInjector.addPossiblyUnsafeInterface(
javascriptAndroidObject,
javascriptAndroidObject.getJavaScriptInterfaceName(),
CobaltJavaScriptInterface.class);
}

// 3. Load and evaluate JavaScript code that interacts with the injected Java objects.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2024 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dev.cobalt.coat.javabridge;

import android.content.Context;

/** Implementation of HTMLMediaElement extensions. */
public class HTMLMediaElementExtension implements CobaltJavaScriptAndroidObject {

private final Context context;

public HTMLMediaElementExtension(Context context) {
this.context = context;
}

@Override
public String getJavaScriptInterfaceName() {
return "HTMLMediaElementExtension";
}

@Override
public String getJavaScriptAssetName() {
return "html_media_element_extension.js";
}

@CobaltJavaScriptInterface
public String canPlayType(String mimeType, String keySystem) {
return nativeCanPlayType(mimeType, keySystem);
}

private static native String nativeCanPlayType(String mimeType, String keySystem);
}
33 changes: 33 additions & 0 deletions starboard/android/shared/application_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "starboard/common/time.h"
#include "starboard/event.h"
#include "starboard/key.h"
#include "starboard/media.h"
#include "starboard/shared/starboard/audio_sink/audio_sink_internal.h"

namespace starboard {
Expand Down Expand Up @@ -124,6 +125,38 @@ Java_dev_cobalt_coat_CobaltSystemConfigChangeReceiver_nativeDateTimeConfiguratio
tzset();
}

extern "C" SB_EXPORT_PLATFORM jstring
Java_dev_cobalt_coat_javabridge_HTMLMediaElementExtension_nativeCanPlayType(
JniEnvExt* env,
jobject jcaller,
jstring j_mime_type,
jstring j_key_system) {
std::string mime_type, key_system;
if (j_mime_type) {
mime_type = env->GetStringStandardUTFOrAbort(j_mime_type);
}
if (j_key_system) {
key_system = env->GetStringStandardUTFOrAbort(j_key_system);
}
SbMediaSupportType support_type =
SbMediaCanPlayMimeAndKeySystem(mime_type.c_str(), key_system.c_str());
const char* ret;
switch (support_type) {
case kSbMediaSupportTypeNotSupported:
ret = "";
break;
case kSbMediaSupportTypeMaybe:
ret = "maybe";
break;
case kSbMediaSupportTypeProbably:
ret = "probably";
break;
}
SB_LOG(INFO) << __func__ << " (" << mime_type << ", " << key_system
<< ") --> " << ret;
return env->NewStringStandardUTFOrAbort(ret);
}

int ApplicationAndroid::GetOverlayedIntValue(const char* var_name) {
ScopedLock lock(overlay_mutex_);
if (overlayed_int_variables_.find(var_name) !=
Expand Down

0 comments on commit 34382e9

Please sign in to comment.