所以我尝试从选项卡捕获网络音频并将其传递到另一个与页面上的 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/