我在nodejs中运行了这个服务器:
const express = require('express');
const socketio = require('socket.io');
const http = require('http');
// Create server
const app = express();
const server = http.Server(app);
// Map HTML and Javascript files as static
app.use(express.static('public'));
// Init Socket IO Server
const io = socketio(server);
// Array to map all clients connected in socket
let connectedUsers = [];
// Called whend a client start a socket connection
io.on('connection', (socket) => {
// It's necessary to socket knows all clients connected
connectedUsers.push(socket.id);
// Emit to myself the other users connected array to start a connection with each them
const otherUsers = connectedUsers.filter(socketId => socketId !== socket.id);
socket.emit('other-users', otherUsers);
console.log(socket.id);
// Send Offer To Start Connection
socket.on('offer', (socketId, description) => {
socket.to(socketId).emit('offer', socket.id, description);
});
// Send Answer From Offer Request
socket.on('answer', (socketId, description) => {
socket.to(socketId).emit('answer', description);
});
// Send Signals to Establish the Communication Channel
socket.on('candidate', (socketId, candidate) => {
socket.to(socketId).emit('candidate', candidate);
});
// Remove client when socket is disconnected
socket.on('disconnect', () => {
connectedUsers = connectedUsers.filter(socketId => socketId !== socket.id);
});
});
// Return Index HTML when access root route
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'public', 'index.html'));
});
// Start server in port 3000 or the port passed at "PORT" env variable
server.listen(process.env.PORT || 3000,
() => console.log('Server Listen On: *:', process.env.PORT || 3000));
这就是site.js:
console.log('Main JS!');
// Map All HTML Elements
var messagesEl = document.querySelector('.messages');
var messageInput = document.getElementById('message-input');
var remoteVideo;
$(document).ready(function () {
var videoGrid = document.getElementById('video-grid');
var localVideo = document.getElementById('local-video');
var sendButton = document.getElementById('message-button');
remoteVideo = document.getElementById('remote-video');
// Open Camera To Capture Audio and Video
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
// Show My Video
videoGrid.style.display = 'grid';
localVideo.srcObject = stream;
// Start a Peer Connection to Transmit Stream
initConnection(stream);
})
.catch(error => console.log(error));
// Map the 'message-button' click
sendButton.addEventListener('click', () => {
// GET message from input
const message = messageInput.value;
// Clean input
messageInput.value = '';
// Log Message Like Sended
logMessage(`Send: ${message}`);
// GET the channel (can be local or remote)
const channel = localChannel || remoteChannel;
// Send message. The other client will receive this message in 'onmessage' function from channel
channel.send(message);
});
})
const logMessage = (message) => {
const newMessage = document.createElement('div');
newMessage.innerText = message;
messagesEl.appendChild(newMessage);
};
var pcConfig = {
'iceServers': [
{
'urls': 'stun:stun.l.google.com:19302'
}
]
};
const initConnection = (stream) => {
const socket = io('http://192.168.1.217:3000',{transports: ['websocket']});
let localConnection;
let remoteConnection;
let localChannel;
let remoteChannel;
// Start a RTCPeerConnection to each client
socket.on('other-users', (otherUsers) => {
// Ignore when not exists other users connected
if (!otherUsers || !otherUsers.length) return;
const socketId = otherUsers[0];
// Ininit peer connection
localConnection = new RTCPeerConnection(pcConfig);
// Add all tracks from stream to peer connection
stream.getTracks().forEach(track => localConnection.addTrack(track, stream));
// Send Candidtates to establish a channel communication to send stream and data
localConnection.onicecandidate = ({ candidate }) => {
candidate && socket.emit('candidate', socketId, candidate);
};
// Receive stream from remote client and add to remote video area
localConnection.ontrack = ({ streams: [ stream ] }) => {
remoteVideo.srcObject = stream;
};
// Start the channel to chat
localChannel = localConnection.createDataChannel('chat_channel');
// Function Called When Receive Message in Channel
localChannel.onmessage = (event) => logMessage(`Receive: ${event.data}`);
// Function Called When Channel is Opened
localChannel.onopen = (event) => logMessage(`Channel Changed: ${event.type}`);
// Function Called When Channel is Closed
localChannel.onclose = (event) => logMessage(`Channel Changed: ${event.type}`);
// Create Offer, Set Local Description and Send Offer to other users connected
localConnection
.createOffer()
.then(offer => localConnection.setLocalDescription(offer))
.then(() => {
socket.emit('offer', socketId, localConnection.localDescription);
});
});
// Receive Offer From Other Client
socket.on('offer', (socketId, description) => {
// Ininit peer connection
remoteConnection = new RTCPeerConnection(pcConfig);
// Add all tracks from stream to peer connection
stream.getTracks().forEach(track => remoteConnection.addTrack(track, stream));
// Send Candidtates to establish a channel communication to send stream and data
remoteConnection.onicecandidate = ({ candidate }) => {
candidate && socket.emit('candidate', socketId, candidate);
};
// Receive stream from remote client and add to remote video area
remoteConnection.ontrack = ({ streams: [ stream ] }) => {
remoteVideo.srcObject = stream;
};
// Chanel Received
remoteConnection.ondatachannel = ({ channel }) => {
// Store Channel
remoteChannel = channel;
// Function Called When Receive Message in Channel
remoteChannel.onmessage = (event) => logMessage(`Receive: ${event.data}`);
// Function Called When Channel is Opened
remoteChannel.onopen = (event) => logMessage(`Channel Changed: ${event.type}`);
// Function Called When Channel is Closed
remoteChannel.onclose = (event) => logMessage(`Channel Changed: ${event.type}`);
}
// Set Local And Remote description and create answer
remoteConnection
.setRemoteDescription(description)
.then(() => remoteConnection.createAnswer())
.then(answer => remoteConnection.setLocalDescription(answer))
.then(() => {
socket.emit('answer', socketId, remoteConnection.localDescription);
});
});
// Receive Answer to establish peer connection
socket.on('answer', (description) => {
localConnection.setRemoteDescription(description);
});
// Receive candidates and add to peer connection
socket.on('candidate', (candidate) => {
// GET Local or Remote Connection
const conn = localConnection || remoteConnection;
conn.addIceCandidate(new RTCIceCandidate(candidate));
});
}
前端:
@page
@model IndexModel
<h1>Hello!</h1>
<!-- My Video and Remote Video from connection -->
<div id="video-grid">
<video playsinline autoplay muted id="local-video"></video>
<video playsinline autoplay id="remote-video"></video>
</div>
<!-- Input to send messages -->
<div>
<span style="font-weight: bold">Message: </span>
<input type="text" id="message-input" title="Message to Send!">
<button id="message-button">Send</button>
</div>
<!-- Area to Print Images -->
<div class="messages"></div>
我所做的是,我已经设置了前端与site.js和index.html在IIS windows 10本地,使我可以测试和访问流在我的浏览器和移动终端。
成功地我已经设法让本地流工作,但远程流不工作,由于某种原因.我添加了一个回合服务器来解决这个问题.但我发现,在我的本地笔记本电脑/ PC上运行的服务器是不拿起连接到移动终端,甚至浏览器.
当我将此更改为“localhost”时,浏览器可以连接,本地和远程视频工作正常:
const socket = io('http://localhost:3000',{transports: ['websocket']});
但是,当我将IP地址更改为本地机器时,浏览器似乎无法连接到服务器,反过来,移动终端根本无法连接到服务器。
我已经在iis中添加了https,ssl到网站上,当我没有这样做时,移动终端本地视频不工作,但一旦我将ssl添加到网站上,本地视频就开始正常工作。
因此,我的问题是,远程流不是从移动的和浏览器设备显示。
这和ssl有什么关系吗?
1条答案
按热度按时间unguejic1#
是的,这是因为要在浏览器中访问相机/麦克风,页面应该具有安全上下文。
Mozilla docs:
getUserMedia()是一个强大的特性,只能在安全的上下文中使用;在不安全的上下文中,navigator.mediaDevices是未定义的,从而阻止了对getUserMedia()的访问。简而言之,安全上下文是使用HTTPS或file:///URL方案加载的页面,或者是从localhost加载的页面。
出于测试目的,可以通过使用ngrok等https代理或使用nginx等反向代理将本地主机请求代理到服务器来绕过此限制。此外,基于chromium-based的浏览器允许您传递
--unsafely-treat-insecure-origin-as-secure="http://youraddress"
,这应该会授予“youraddress”http页面安全上下文。对于生产,需要SSL。