在JavaFX中静音WebView,是否可能?

时间:2018-03-13 16:29:15

标签: java javafx webview javafx-webview

很简单。是否可以静音或控制JavaFX WebView的音量?我用谷歌搜索了一段时间,但我无法提及这一点。我查看了WebViewWebEngine的代码,似乎没有任何关于控制音量的内容。

我仍然需要同一个应用中的其他MediaPlayer来工作和制作声音,因此,我无法对整个应用程序进行静音。

3 个答案:

答案 0 :(得分:11)

目前, WebView WebEngine 控件中的声音系统有 NO 此类API。

但你可以注入 JavaScript 来静音/取消静音并控制声音。此方法仅适用于HTML5元素<视频> < audio> ,因为 Flash JS 等初始化音频的内容一般无法限制。我已经为您创建了示例程序:

WebView mute/unmute - program

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        WebView myWebView = new WebView();
        WebEngine engine = myWebView.getEngine();
        //dirty code xD

        Button btn = new Button("Load Youtube");
        btn.setOnAction((ActionEvent event) -> engine.load("http://www.youtube.com/embed/A6hrw6KGdtM?autoplay=1"));

        Button btn2 = new Button("Mute");
        btn2.setOnAction((ActionEvent event) -> engine.executeScript(getJSAudioVideo(true)));

        Button btn3 = new Button("Unmute");
        btn3.setOnAction((ActionEvent event) -> engine.executeScript(getJSAudioVideo(false)));

        Button btn4 = new Button("+");
        btn4.setOnAction((ActionEvent event) -> engine.executeScript(getJSSoundVolume(0.9)));

        Button btn5 = new Button("-");
        btn5.setOnAction((ActionEvent event) -> engine.executeScript(getJSSoundVolume(0.1)));

        VBox root = new VBox();
        root.getChildren().addAll(myWebView, btn, btn2, btn3, btn4, btn5);

        Scene scene = new Scene(root, 800, 500);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Mute a WebView in JavaFX, is it possible?");

        primaryStage.show();
    }

    /**
     * @param mute
     * @return JS code for mute/unmute
     */
    public String getJSAudioVideo(boolean mute){
        return "var videos = document.querySelectorAll('video'),\n" +
                "    audios = document.querySelectorAll('listen');\n" +
                "    [].forEach.call(videos, function(video) { video.muted = "+String.valueOf(mute)+"; });\n" +
                "    [].forEach.call(audios, function(audio) { audio.muted = "+String.valueOf(mute)+"; });";
    }

    /**
     * @param volume
     * @return JS code for setting volume sound
     */
    public String getJSSoundVolume(double volume){
        //max 1.0, min 0.0 Default: 1.0
        double _volume = (volume > 1.0 || volume < 0.0) ? 1.0 : volume;

        return "var videos = document.querySelectorAll('video'),\n" +
                "    audios = document.querySelectorAll('listen');\n" +
                "    [].forEach.call(videos, function(video) { video.volume = "+String.valueOf(_volume)+"; });\n" +
                "    [].forEach.call(audios, function(audio) { audio.volume = "+String.valueOf(_volume)+"; });";

    }

    public static void main(String[] args) {
        launch(args);
    }
}

答案 1 :(得分:9)

我们都知道它是API的一个缺失部分,那么你可以自己实现它呢?让我们来看看WebView到底是什么:

  

嵌入式浏览器组件基于WebKit [...]   默认情况下,WebKit不支持网页呈现。为了呈现和显示HTML内容,Oracle必须使用Java Graphics 2D API编写自己的渲染器。

这意味着引擎必须具有实现功能。 WebKit的实现位于com.sun.webkit package (相当一部分类只是本机调用的包装器)。当然,在大多数情况下,您不想使用com.sun.*课程,但目前您正在使用JavaFX,因此它并不重要。

如果我们在太阳的源头跳一点,我们可以找到WCMediaPlayer.class一些抽象的音频方法,如:

protected abstract void setRate(float rate);
protected abstract void setVolume(float volume);
protected abstract void setMute(boolean mute);
protected abstract void setSize(int w, int h);
protected abstract void setPreservesPitch(boolean preserve);

C&#39; mon Java,我来打电话给你:

volumeMethod = WCMediaPlayer.class.getDeclaredMethod("setVolume", float.class);
volumeMethod.setAccessible(true);

感谢您的帮助,但我如何获得WCMediaPlayer个实例?我们必须查看对new WCMediaPlayerImpl()的引用。疑难杂症! WCGraphicsManager.class通过fwkCreateMediaPlayer()方法创建MediaPlayer,毕竟它将指针和实例放在refMap中:

Field refMapField = WCGraphicsManager.class.getDeclaredField("refMap");
refMapField.setAccessible(true);

幸运的是,经理已经公开了getGraphicsManager()方法来获取实例:

WCGraphicsManager graphicsManager = WCGraphicsManager.getGraphicsManager();
refMap = (Map<Integer, Ref>) refMapField.get(graphicsManager);

捕获的地图包含Ref个实例(还有其他WC*个实例),因此您必须对其进行过滤:

Collection<WCMediaPlayer> mediaPlayers = refMap.values().stream()
    .filter(ref -> ref instanceof WCMediaPlayer)
    .map(ref -> (WCMediaPlayer) ref)
    .collect(Collectors.toList());

您可能期望工作示例,所以这里是我使用的代码:

WebEngineTest Preview

public class WebEngineTest extends Application {

    private Map<Integer, Ref> refMap;
    private Method volumeMethod;

    @Override
    @SuppressWarnings("unchecked")
    public void start(Stage primaryStage) throws Exception {
        WebView webView = new WebView();
        WebEngine engine = webView.getEngine();
        engine.load("https://www.youtube.com/watch?v=hRAZBSoAsgs");

        Field refMapField = WCGraphicsManager.class.getDeclaredField("refMap");
        refMapField.setAccessible(true);

        volumeMethod = WCMediaPlayer.class.getDeclaredMethod("setVolume", float.class);
        volumeMethod.setAccessible(true);

        WCGraphicsManager graphicsManager = WCGraphicsManager.getGraphicsManager();
        refMap = (Map<Integer, Ref>) refMapField.get(graphicsManager);

        Button button = new Button("Volume");
        button.setOnAction(event -> setVolume(0.1f));

        Group group = new Group();
        group.getChildren().addAll(webView, button);

        Scene scene = new Scene(group, 625, 625);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public void setVolume(float volume) {
        Collection<WCMediaPlayer> mediaPlayers = this.getMediaPlayers();
        mediaPlayers.forEach(mediaPlayer -> setVolumeMethod(mediaPlayer, volume));
    }

    private void setVolumeMethod(Object instance, Object... args) {
        try {
            volumeMethod.invoke(instance, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Collection<WCMediaPlayer> getMediaPlayers() {
        return refMap.values().stream()
                .filter(ref -> ref instanceof WCMediaPlayer)
                .map(ref -> (WCMediaPlayer) ref)
                .collect(Collectors.toList());
    }

}

最后,请记住这些调用的顺序。例如,refMap不包含所有Refs,直到引擎状态不是SUCCEEDEDWCGraphicsManager.getGraphicsManager()返回null如果未创建图形元素一点都不。

可能最好的方法是结合这些解决方案。如果没有JavaFX提供的scenerio和糟糕的API,很难支持Web技术组合。您还可以尝试嵌入其他浏览器,例如Chromium。

答案 2 :(得分:6)

说到 WebView ,它是Node类的扩展。它封装了WebEngine对象,将HTML内容合并到应用程序的场景中,并提供应用效果和转换的属性和方法。在WebView对象上调用的getEngine()方法返回与之关联的Web引擎。 Source

因此,WebView现在不支持任何用于静音/音量控制的API。有一个API可以静音MediaPlayer中加载的内容(即。)

获取muteProperty的状态:Source link

public final boolean isMute()

检查静音条件:Source link

public final void setMute(boolean value)

要将视频静音,请将值设置为true:Source link

getElementById("Your video Id");

或以其他方式使用JavaScript API来静音视频/音频:

vid.muted = true;

并将控件设置为静音:

$urlTest = 'http://localhost:9090/JAXRS_POST_Request/rest/Request/insertDataToDB';

$data = 'FirstName=Mickey&LastName=Mouse';

$rCURL = curl_init();
curl_setopt($rCurl, CURLOPT_POST, true);//
curl_setopt($rCURL, CURLOPT_POSTFIELDS, $data);
curl_setopt($rCURL, CURLOPT_URL, $urlTest);
curl_setopt($rCURL, CURLOPT_HEADER, 0);
curl_setopt($rCurl, CURLOPT_RETURNTRANSFER, true);

if(curl_exec($rCurl) === false){

    echo 'Curl error: ' . curl_error($rCurl);

}else{

  $response_post = curl_exec($rCURL);

}

curl_close($rCurl);

Source Link