javascript - 在 Chrome 扩展中使用 sendMessage 时 webkitMediaStream 对象类型丢失

标签 javascript json google-chrome-extension casting sendmessage

所以我尝试从选项卡捕获网络音频并将其传递到另一个与页面上的 DOM 元素一起使用的脚本。

扩展脚本

background.js 中,我使用以下脚本:

    chrome.tabCapture.capture(constraints, function(stream) {
        console.log("\ngot stream");
        console.log(stream);

        chrome.tabs.sendMessage(tabID, {
            "message": "stream",
            "stream": stream
        });
    });

Developer Toolkit 向我显示创建的对象确实是一个 MediaStream 对象。 (我想要并且看起来工作正常)。

扩展控制台:

MediaStream {onremovetrack: null, onaddtrack: null, onended: null, ended: false, id: "c0jm4lYJus3XCwQgesUGT9lpyPQiWlGKHb7q"…}

内容脚本

我在页面本身上使用内容脚本(注入(inject)),然后将 JSON 序列化对象拉回:

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  if (request.message === "stream") {
    var thisStream = request.stream;
    console.log(thisStream);
    if (!thisStream) {
      console.log("stream is null");
      return;
    }    
    loadStream(thisStream);
  }
  else if (request.message === "statusChanged") {
    console.log("statusChanged");
  }
});

页面控制台

不幸的是,因为JSON序列化,对象类型丢失了:

对象 {onremovetrack: null, onaddtrack: null, onended: null, ended: false, id: "c0jm4lYJus3XCwQgesUGT9lpyPQiWlGKHb7q"…}

我需要将对象重铸为 MediaStream 对象并尝试了以下所有操作均失败了:

尝试 1:失败

var stream = new webkitMediaStream;
function loadStream(thisStream) {
    stream = thisStream;
}

尝试 2:失败

var stream;
function loadStream(thisStream) {
    stream = new webkitMediaStream(thisStream);
}

尝试 3:失败

var stream;
function loadStream(thisStream) {
    stream = Object.create(webkitMediaStream, thisStream);
}

注意: MediaStream 对象的构造函数 webkitMediaStream

我需要一个更好的方法来将对象从扩展脚本(chrome.tab.capture() 方法工作的唯一地方)传递到内容脚本(唯一有访问并可以修改页面的 DOM 元素),

我需要一种将 JSON 序列化对象重新转换为功能齐全的 MediaStream 对象的方法。

提前致谢!

JRad 坏人

最佳答案

扩展消息始终是 JSON 序列化的,因此很明显您不能发送 MediaStream从后台页面到网页。问题是,你真的需要发送 MediaStream 吗?从背景到内容脚本?

  • 如果您只需要,例如显示视频,然后你可以使用 URL.createObjectURL 得到 blob: - 流的 URL 并将其分配给 video.src看视频。 URL.createObjectURL 创建的 URL只能被同源页面使用,所以你需要创建<video>chrome-extension:// 中标记页;在选项卡或框架中。如果您想在框架中执行此操作,请确保该页面列在 web_accessible_resources 中。 .

如果您真的需要 MediaStream选项卡中选项卡的对象,然后是 RTCPeerConnection 可用于发送流。此 WebRTC API 通常用于在网络中的对等点之间交换媒体流,但它也可用于在另一个选项卡或浏览器中将流从一个页面发送到另一个页面。

这是一个完整的例子。访问任何网页,然后单击扩展按钮。然后该扩展程序将在显示当前选项卡的页面中插入一个视频。

背景.js

function sendStreamToTab(tabId, stream) {
    var pc = new webkitRTCPeerConnection({iceServers:[]});
    pc.addStream(stream);
    pc.createOffer(function(offer) {
        pc.setLocalDescription(offer, function() {
            // Use chrome.tabs.connect instead of sendMessage
            // to make sure that the lifetime of the stream
            // is tied to the lifetime of the consumer (tab).
            var port = chrome.tabs.connect(tabId, {name: 'tabCaptureSDP'});
            port.onDisconnect.addListener(function() {
                stopStream(stream);
            });
            port.onMessage.addListener(function(sdp) {
                pc.setRemoteDescription(new RTCSessionDescription(sdp));
            });
            port.postMessage(pc.localDescription);
        });
    });
}

function stopStream(stream) {
    var tracks = this.getTracks();
    for (var i = 0; i < tracks.length; ++i) {
        tracks[i].stop();
    }
}

function captureTab(tabId) {
    // Note: this method must be invoked by the user as defined
    // in https://crbug.com/489258, e.g. chrome.browserAction.onClicked.
    chrome.tabCapture.capture({
        audio: true,
        video: true,
        audioConstraints: {
            mandatory: {
                chromeMediaSource: 'tab',
            },
        },
        videoConstraints: {
            mandatory: {
                chromeMediaSource: 'tab',
            },
        },
    }, function(stream) {
        if (!stream) {
            alert('Stream creation failed: ' + chrome.runtime.lastError.message);
        }
        chrome.tabs.executeScript(tabId, {file: 'contentscript.js'}, function() {
            if (chrome.runtime.lastError) {
                stopStream(stream);
                alert('Script injection failed:' + chrome.runtime.lastError.message);
            } else {
                sendStreamToTab(tabId, stream);
            }
        });
    });
}

chrome.browserAction.onClicked.addListener(function(tab) {
    captureTab(tab.id);
});

contentscript.js

function onReceiveStream(stream) {
    // Just to show that we can receive streams:
    var video = document.createElement('video');
    video.style.border = '1px solid black';
    video.src = URL.createObjectURL(stream);
    document.body.insertBefore(video, document.body.firstChild);
}

function onReceiveOfferSDP(sdp, sendResponse) {
    var pc = new webkitRTCPeerConnection({iceServers:[]});
    pc.onaddstream = function(event) {
        onReceiveStream(event.stream);
    };
    pc.setRemoteDescription(new RTCSessionDescription(sdp), function() {
        pc.createAnswer(function(answer) {
            pc.setLocalDescription(answer);
            sendResponse(pc.localDescription);
        });
    });
}

// Run once to prevent the message from being handled twice when
// executeScript is called multiple times.
if (!window.hasRun) {
    window.hasRun = 1;
    chrome.runtime.onConnect.addListener(function(port) {
        if (port.name === 'tabCaptureSDP') {
            port.onMessage.addListener(function(remoteDescription) {
                onReceiveOfferSDP(remoteDescription, function(sdp) {
                    port.postMessage(sdp);
                });
            });
        }
    });
}

list .json

{
    "name": "tabCapture to tab",
    "version": "1",
    "manifest_version": 2,
    "background": {
        "scripts": ["background.js"],
        "persistent": false
    },
    "browser_action": {
        "default_title": "Capture tab"
    },
    "permissions": [
        "activeTab",
        "tabCapture"
    ]
}

关于javascript - 在 Chrome 扩展中使用 sendMessage 时 webkitMediaStream 对象类型丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30731277/

相关文章:

javascript - 获取 <p> 标签上的选定文本

javascript - 谷歌浏览器扩展 : is it possible to get console output (js errors, console.log 等)

javascript - 在 Chrome 扩展中分离面板,如 Font Face Ninja 或 CSS Peeper?

javascript - 是否有任何显示公告消息让用户知道新版本更新?

javascript - 为什么要将prototype的构造函数设置为它的构造函数?

javascript - 有人可以解释 return 语句如何与 javascript 中的递归一起使用吗?

json - 如何使用 gin gonic 在 Go 中上传多部分文件和 json?

PostgreSQL 9.3+下的JSON,这么难看?

javascript - 按钮悬停时变为透明

c# - 使用 JSON.NET 反序列化 IOrderedEnumerable<T>