- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
let socket = io();
socket.on(`connect`, () => {
console.log(`new User Connected`);
});
jQuery(`#video-form`).on(`submit`, (event) => {
event.preventDefault();
socket.emit(`offer`, () => {
console.log(`Starting call`);
});
});
/////////////////////////////
'use strict';
let isChannelReady = false;
let isInitiator = false;
let isStarted = false;
let localStream;
let pc;
let remoteStream;
let turnReady;
let pcConfig = {
'iceServers': [{
'url': 'stun:stun.1.google.com:19302'
}]
};
// Set up audio and video regardless of what devices are present.
let sdpConstraints = {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': true
}
};
/////////////////////////////////////////////
let room = 'foo';
// Could prompt for room name:
// room = prompt('Enter room name:');
if (room !== '') {
socket.emit('create or join', room);
console.log('Attempted to create or join room', room);
}
socket.on('created', function (room) {
console.log('Created room ' + room);
isInitiator = true;
});
socket.on('full', function (room) {
console.log('Room ' + room + ' is full');
});
socket.on('join', function (room) {
console.log('Another peer made a request to join room ' + room);
console.log('This peer is the initiator of room ' + room + '!');
isChannelReady = true;
});
socket.on('joined', function (room) {
console.log('joined: ' + room);
isChannelReady = true;
});
socket.on('log', function (array) {
console.log.apply(console, array);
});
////////////////////////////////////////////////
function sendMessage(message) {
console.log('Client sending message: ', message);
socket.emit('message', message);
}
// This client receives a message
socket.on('message', function (message) {
console.log('Client received message:', message);
if (message === 'got user media') {
//isStarted = true;
isInitiator = true;
isChannelReady = true;
maybeStart(message);
} else if (message.type === 'offer') {
if (!isInitiator && !isStarted) {
maybeStart(message);
}
pc.setRemoteDescription(new RTCSessionDescription(message));
doAnswer(message);
} else if (message.type === 'answer' && isStarted) {
pc.setRemoteDescription(new RTCSessionDescription(message));
} else if (message.type === 'candidate' && isStarted) {
let candidate = new RTCIceCandidate({
sdpMLineIndex: message.label,
candidate: message.candidate
});
pc.addIceCandidate(candidate);
} else if (message === 'bye' && isStarted) {
handleRemoteHangup();
}
});
////////////////////////////////////////////////////
let localVideo = document.querySelector('#localVideo');
let remoteVideo = document.querySelector('#remoteVideo');
navigator.getUserMedia = navigator.getUserMedia || navigator.mediaDevices.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
let constraints = {
audio: false,
video: true
};
navigator.mediaDevices.getUserMedia(constraints)
.then(gotStream)
.catch(function (e) {
alert('getUserMedia() error: ' + e.name);
});
function gotStream(stream) {
console.log('Adding local stream.');
// if (navigator.webkitGetUserMedia) {
localVideo.src = window.URL.createObjectURL(stream);
// }
// else {
// localStream.src = stream;
// }
localStream = stream;
sendMessage('got user media');
if (isInitiator) {
maybeStart();
}
}
console.log('Getting user media with constraints', constraints);
if (location.hostname !== 'localhost') {
requestTurn();
}
function maybeStart(message) {
// isChannelReady = true;
// isInitiator = true;
console.log('>>>>>>> maybeStart() ', isStarted, localStream, isChannelReady);
if (!isStarted && typeof localStream !== 'undefined' && isChannelReady) {
console.log('>>>>>> creating peer connection');
createPeerConnection(message);
pc.addStream(localStream);
isStarted = true;
console.log('isInitiator', isInitiator);
if (isInitiator) {
doCall();
}
}
}
window.onbeforeunload = function () {
sendMessage('bye');
};
/////////////////////////////////////////////////////////
function createPeerConnection(message) {
try {
//let msg = JSON.parse(message.data);
pc = new RTCPeerConnection(pcConfig) || webkitRTCPeerConnection(pcConfig) || mozRTCPeerConnection(pcConfig);
pc.setRemoteDescription(new RTCSessionDescription(message));
console.log(`SetRemomteDescription`);
pc.onicecandidate = handleIceCandidate;
console.log(`handleIceCandidate`);
pc.onaddstream = handleRemoteStreamAdded;
console.log(`handleRemoteStreamAdde`);
pc.onremovestream = handleRemoteStreamRemoved;
console.log('Created RTCPeerConnnection');
} catch (e) {
console.log('Failed to create PeerConnection, exception: ' + e.message);
alert('Cannot create RTCPeerConnection object.');
}
}
function handleIceCandidate(event) {
console.log('icecandidate event: ', event);
if (event.candidate) {
sendMessage({
type: 'candidate',
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate
});
} else {
console.log('End of candidates.');
}
}
function handleRemoteStreamAdded(event) {
//if (navigator.webkitGetUserMedia) {
console.log('Remote stream added.');
remoteVideo.src = window.URL.createObjectURL(event.stream);
// }
// else {
// remoteStream.srcObject = event.stream;
// }
remoteStream = event.stream;
}
function handleCreateOfferError(event) {
console.log('createOffer() error: ', event);
}
function doCall() {
console.log('Sending offer to peer');
pc.createOffer(setLocalAndSendMessage, handleCreateOfferError);
}
function doAnswer(message) {
console.log('Sending answer to peer.');
pc.createAnswer(message.id).then(
setLocalAndSendMessage).catch(
onCreateSessionDescriptionError);
}
function setLocalAndSendMessage(sessionDescription) {
// Set Opus as the preferred codec in SDP if Opus is present.
// sessionDescription.sdp = preferOpus(sessionDescription.sdp);
pc.setLocalDescription(sessionDescription);
console.log('setLocalAndSendMessage sending message', sessionDescription);
sendMessage(sessionDescription);
}
function onCreateSessionDescriptionError(error) {
trace('Failed to create session description: ' + error.toString());
}
function requestTurn(turnURL) {
let turnExists = false;
for (let i in pcConfig.iceServers) {
if (pcConfig.iceServers[i].url.substr(0, 5) === 'turn:') {
turnExists = true;
turnReady = true;
break;
}
}
if (!turnExists) {
console.log('Getting TURN server from ', turnURL);
// No TURN server. Get one from computeengineondemand.appspot.com:
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
let turnServer = JSON.parse(xhr.responseText);
console.log('Got TURN server: ', turnServer);
pcConfig.iceServers.push({
'url': 'turn:192.158.29.39:3478?transport=tcp', //+ turnServer.username + '@' + turnServer.turn,
'username':'28224511:1379330808',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA='
});
turnReady = true;
}
};
//xhr.open('GET', turnURL, true);
//xhr.send();
}
}
// function handleRemoteStreamAdded(event) {
// console.log('Remote stream added.');
// remoteVideo.src = window.URL.createObjectURL(event.stream);
// remoteStream = event.stream;
// }
function handleRemoteStreamRemoved(event) {
console.log('Remote stream removed. Event: ', event);
}
function hangup() {
console.log('Hanging up.');
stop();
sendMessage('bye');
}
function handleRemoteHangup() {
console.log('Session terminated.');
stop();
isInitiator = false;
}
function stop() {
isStarted = false;
// isAudioMuted = false;
// isVideoMuted = false;
pc.close();
pc = null;
}
///////////////////////////////////////////
// Set Opus as the default audio codec if it's present.
function preferOpus(sdp) {
let sdpLines = sdp.split('\r\n');
let mLineIndex;
// Search for m line.
for (let i = 0; i < sdpLines.length; i++) {
if (sdpLines[i].search('m=audio') !== -1) {
mLineIndex = i;
break;
}
}
if (mLineIndex === null) {
return sdp;
}
// If Opus is available, set it as the default in m line.
for (let i = 0; i < sdpLines.length; i++) {
if (sdpLines[i].search('opus/48000') !== -1) {
let opusPayload = extractSdp(sdpLines[i], /:(\d+) opus\/48000/i);
if (opusPayload) {
sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex],
opusPayload);
}
break;
}
}
// Remove CN in m line and sdp.
sdpLines = removeCN(sdpLines, mLineIndex);
sdp = sdpLines.join('\r\n');
return sdp;
}
function extractSdp(sdpLine, pattern) {
let result = sdpLine.match(pattern);
return result && result.length === 2 ? result[1] : null;
}
// Set the selected codec to the first in m line.
function setDefaultCodec(mLine, payload) {
let elements = mLine.split(' ');
let newLine = [];
let index = 0;
for (let i = 0; i < elements.length; i++) {
if (index === 3) { // Format of media starts from the fourth.
newLine[index++] = payload; // Put target payload to the first.
}
if (elements[i] !== payload) {
newLine[index++] = elements[i];
}
}
return newLine.join(' ');
}
// Strip CN from sdp before CN constraints is ready.
function removeCN(sdpLines, mLineIndex) {
let mLineElements = sdpLines[mLineIndex].split(' ');
// Scan from end for the convenience of removing an item.
for (let i = sdpLines.length - 1; i >= 0; i--) {
let payload = extractSdp(sdpLines[i], /a=rtpmap:(\d+) CN\/\d+/i);
if (payload) {
let cnPos = mLineElements.indexOf(payload);
if (cnPos !== -1) {
// Remove CN payload from m line.
mLineElements.splice(cnPos, 1);
}
// Remove CN line in sdp
sdpLines.splice(i, 1);
}
}
sdpLines[mLineIndex] = mLineElements.join(' ');
return sdpLines;
}
后端代码:
const path = require(`path`);
const http = require(`http`);
const express = require(`express`);
const socketIO = require(`socket.io`);
const {generateMessage} = require(`./utils/message`);
const {isRealString} = require(`./utils/validation`);
const publicPath = path.join(__dirname,`../public`);
let app = express();
let server = http.createServer(app);
let io = socketIO(server);
app.use(express.static(publicPath));
app.get(`/video`,(req,res)=>{
res.sendFile(path.join(__dirname,`../public/videochat.html`));
});
io.on(`connection`,(socket)=>{
console.log(`New User Connected`);
socket.emit(`newMessage`,generateMessage(`Admin`, `Welcome to Chat App`));
socket.broadcast.emit(`newMessage`,generateMessage(`Admin`,`New User Joined`));
socket.on(`join`,(params,callback)=>{
if(!isRealString(params.name) || !isRealString(params.room)){
callback(`Name and Room name is required`);
}
callback();
});
socket.on('createMessage',(message,callback)=>{
console.log(`create Message`,message);
io.emit(`newMessage`,generateMessage(message.from,message.text));
callback();
});
socket.on(`offer`,(callback)=>{
console.log(`Call is Starting`);
callback();
});
/////////////////////////////////////////
function log() {
let array = ['Message from server:'];
array.push.apply(array, arguments);
socket.emit('log', array);
}
socket.on('message', function (message) {
log('Client said: ', message);
// for a real app, would be room-only (not broadcast)
socket.emit('message', message);
});
socket.on(`sdp`,(data)=>{
console.log('Received SDP from ' + socket.id);
socket.emit('sdp received', data.sdp);
});
socket.on('create or join', function (room) {
log('Received request to create or join room ' + room);
let numClients = io.sockets.sockets.length;
log('Room ' + room + ' now has ' + numClients + ' client(s)');
if (numClients === 1) {
socket.join(room);
log('Client ID ' + socket.id + ' created room ' + room);
socket.emit('created', room, socket.id);
} else if (numClients === 2) {
log('Client ID ' + socket.id + ' joined room ' + room);
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room, socket.id);
io.sockets.in(room).emit('ready');
} else { // max two clients
socket.emit('full', room);
}
});
socket.on('ipaddr', function () {
let ifaces = os.networkInterfaces();
for (let dev in ifaces) {
ifaces[dev].forEach(function (details) {
if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
socket.emit('ipaddr', details.address);
}
});
}
});
socket.on('bye', function () {
console.log('received bye');
});
});
server.listen(3000,`192.168.0.105`,()=>{
console.log(`Server is Up`)
});
我收到此错误:- 无法创建 PeerConnection,异常:无法构造“RTCSessionDescription”:参数 1(“descriptionInitDict”)不是对象。
还得到未捕获( promise 中)DOMException:无法设置远程报价 sdp:在错误状态下调用:kHaveLocalOffer
最佳答案
这一行:
function doCall() {
console.log('Sending offer to peer');
pc.createOffer(setLocalAndSendMessage, handleCreateOfferError);
}
更改为:
pc.createOffer().then(setDescription).catch(errorHandler);
function setDescription(description) {
console.log('Got description', description);
pc.setLocalDescription(description).then(function() {
console.log("Sending SDP");
socket.emit('signal', {'sdp': description});
}).catch(errorHandler);
}
您应该处理发出的 SDP:
function gotMessageFromServer(signal) {
console.log('Got message', signal);
if(signal.sdp) {
console.log("Set remote description: ", signal);
pc.setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(function() {
// Only create answers in response to offers
if(signal.sdp.type === 'offer') {
console.log("Sending answer");
pc.createAnswer().then(setDescription).catch(errorHandler);
}
}).catch(errorHandler);
} else if(signal.ice) {
console.log('Got remote ice candidate: ', signal);
pc.addIceCandidate(new RTCIceCandidate(signal.ice)).catch(errorHandler);
}
}
关于javascript - 创建PeerConnection失败,异常: Failed to construct 'RTCSessionDescription' : parameter 1 ('descriptionInitDict' ) is not an object,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48989688/
我遵循了一本名为“Sitepoint Full Stack Javascript with MEAN”的书中的教程,我刚刚完成了第 6 章,应该已经创建了一个带有“数据库”的“服务器”。数据库只不过是
在 Jquery 中,我创建两个数组,一个嵌入另一个数组,就像这样...... arrayOne = [{name:'a',value:1}, {name:'b',value:2}] var arra
这个问题在这里已经有了答案: What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wa
我被放在别人的代码上,有一个类用作其他组件的基础。当我尝试 ng serve --aot(或 build --prod)时,我得到以下信息。 @Component({ ...,
我正在测试一些代码,并使用数据创建了一个 json 文件。 问题是我在警报中收到“[object Object],[object Object]”。没有数据。 我做错了什么? 这是代码:
我想打印 [object Object],[object Object] 以明智地 "[[{ 'x': '1', 'y': '0' }, { 'x': '2', 'y': '1' }]]"; 在 ja
我有一个功能 View ,我正在尝试以特殊格式的方式输出。但我无法让列表功能正常工作。 我得到的唯一返回是[object Object][object Object] [object Object]
在使用优秀的 Sim.js 和 Three.js 库处理 WebGL 项目时,我偶然发现了下一个问题: 一路走来,它使用了 THREE.Ray 的下一个构造函数: var ray = new THRE
我正在使用 Material UI 进行多重选择。这是我的代码。 {listStates.map(col => (
我的代码使用ajax: $("#keyword").keyup(function() { var keyword = $("#keyword").val(); if (keyword.
我遇到了下一个错误,无法理解如何解决它。 Can't resolve all parameters for AuthenticationService: ([object Object], ?, [o
我正在尝试创建一个显示动态复选框的表单,至少应选中其中一个才能继续。我还需要获取一组选中的复选框。 这是组件的代码: import { Component, OnInit } from '@angul
我正在开发 NodeJs 应用程序,它是博客应用程序。我使用了快速验证器,我尝试在 UI 端使用快速闪存消息将帖子保存在数据库中之前使用闪存消息验证数据,我成功地将数据保存在数据库中,但在提交表单后消
我知道有些人问了同样的问题并得到了解答。我已经查看了所有这些,但仍然无法解决我的问题。我有一个 jquery snipet,它将值发送到处理程序,处理程序处理来自 JS 的值并将数据作为 JSON 数
我继承了一个非常草率的项目,我的任务是解释为什么它不好。我注意到他们在整个代码中都进行了这样的比较 (IQueryable).FirstOrDefault(x => x.Facility == fac
我只是在删除数组中的对象时偶然发现了这一点。 代码如下: friends = []; friends.push( { a: 'Nexus', b: 'Muffi
这两个代码片段有什么区别: object = nil; [object release] 对比 [object release]; object = nil; 哪个是最佳实践? 最佳答案 object
我应该为其他人将从中继承的第一个父对象传递哪个参数,哪个参数更有效 Object.create(Object.prototype) Object.create(Object) Object.creat
我在不同的对象上安排不同的选择器 [self performSelector:@selector(doSmth) withObject:objectA afterDelay:1]; [self per
NSLog(@"%p", &object); 和 NSLog(@"%p", object); 有什么区别? 两者似乎都打印出一个内存地址,但我不确定哪个是对象的实际内存地址。 最佳答案 这就是我喜欢的
我是一名优秀的程序员,十分优秀!