如何修改正在进行的连接上的流以暂停/恢复流传输
Posted
技术标签:
【中文标题】如何修改正在进行的连接上的流以暂停/恢复流传输【英文标题】:How to modify stream on ongoing connection to pause/resume stream transmission 【发布时间】:2021-09-28 23:42:16 【问题描述】:我最近开始为我的学校学习和构建一个应用程序,用于在我学校的服务器 (VPS) 上使用 WebRTC 和 PeerJs 进行远程在线课程。到目前为止,我能够建立 1 对 1 对等连接,但很难暂停和恢复流传输。
我正在寻求一些帮助,了解如何在活动连接时为自己和远程用户暂停和恢复视频和音频流。当我执行localStream.getVideoTracks()[0].enabled = false
时,它只会为我禁用视频(而不是远程用户)。
正如一些人建议的replaceTrack API,但我不是找不到关于它的教程,因为我是新手。
我的代码(感谢Link)如下所示:
var url = new URL(window.location.href)
var disableStreamInBeginning = url.searchParams.get("disableStreamInBeginning")
var passwordProtectedRoom = url.searchParams.get("passwordProtectedRoom")
var muteAllInBeginning = url.searchParams.get("muteAllInBeginning")
var isVideoCall = url.searchParams.get("isVideoCall")
var singleOrConference = url.searchParams.get("singleOrConference")
const conferenceView = document.getElementById('conference')
const loader = document.getElementById('loader')
const localVideoView = document.getElementById('local-video')
const remoteVideoView = document.getElementById('remote-video')
const remoteVideoDiv = document.getElementById('remote-video-div')
if(typeof disableStreamInBeginning !== 'undefined' && disableStreamInBeginning == 'true')
var disbaleSelfStream = true
else
var disbaleSelfStream = false
if(typeof passwordProtectedRoom !== 'undefined' && passwordProtectedRoom == 'true')
var passwordProtected = true
else
var passwordProtected = false
if(typeof muteAllInBeginning !== 'undefined' && muteAllInBeginning == 'true')
var muteAll = true
else
var muteAll = false
if(typeof isVideoCall !== 'undefined' && isVideoCall == 'true')
var videoCall = true
else
var videoCall = false
if(typeof singleOrConference !== 'undefined' && singleOrConference == 'conference')
var isConference = true
conferenceView.style.display = 'block'
else
var isConference = false
localVideoView.style.opacity = 0
remoteVideoView.style.opacity = 0
remoteVideoDiv.style.opacity = 0
var selectedCamera = 'user'
let localStream;
const socket = io('/');
localVideoView.muted = true;
const peers = ;
const peer = new Peer(undefined,
host: '/',
port: '443',
path: '/myapp',
secure: true
)
// Handelling incoming call connection
peer.on("call", async (call) =>
let stream = null;
try
stream = await navigator.mediaDevices.getUserMedia(
video:
facingMode: selectedCamera
,
audio: true
);
call.answer(stream);
call.on("stream", (remoteVideoStream) =>
addVideoStream(remoteVideoView, remoteVideoStream);
);
catch (err)
console.log('peer.on("call": ' + err);
;
);
// On new user connected
socket.on("user-connected", async (userId) =>
connectDataToNewUser(userId);
try
stream = await navigator.mediaDevices.getUserMedia(
audio: true,
video: true,
)
catch (err)
console.log('socket.on("user-connected": ' + err);
;
connectMediaToNewUser(userId, stream);
);
// Show own Video on own device screen
(async () =>
try
localStream= await navigator.mediaDevices.getUserMedia(
video:
facingMode: selectedCamera
,
audio: true
);
addVideoStream(localVideoView, localStream);
catch (err)
console.log('(async () =>: ' + err);
)();
peer.on("open", (id) =>
socket.emit("join-room", ROOM_ID, id);
);
peer.on("error", (err) =>
console.log('peer.on("error": ' + err);
)
socket.on("user-disconnected", (userId) =>
if (peers[userId])
peers[userId].close();
);
// Set up event listener for an "another user" data connection established event
peer.on("connection", (conn) =>
conn.on("data", (data) =>
console.log('Received data ' + data);
);
// Set up event listener for connection conn established event
conn.on("open", () =>
conn.send('Hello!');
);
);
// Initiate a Data call (Messages) to user
const connectDataToNewUser = (userId) =>
let conn = peer.connect(userId);
conn.on("data", (data) =>
console.log('Received data: ' + data);
);
conn.on("open", () =>
conn.send('hi!');
);
;
// Initiate a Media call (Audio/Video) to user
const connectMediaToNewUser = (userId, stream) =>
const call = peer.call(userId, stream);
call.on("stream", (userVideoStream) =>
addVideoStream(remoteVideoView, userVideoStream);
);
call.on("close", () =>
remoteVideoView.remove();
);
call.on("error", (error) =>
console.log('connectMediaToNewUser' + error);
);
peers[userId] = call;
;
const addVideoStream = (video, stream) =>
video.srcObject = stream;
video.addEventListener("loadedmetadata", () =>
if(disbaleSelfStream)
systemStream.getVideoTracks()[0].enabled = false
systemStream.getAudioTracks()[0].enabled = false
else
loader.style.opacity = 0
video.style.opacity = 1
video.play()
remoteVideoDiv.style.opacity = 0
);
;
服务器端代码:
const express = require('express')
const app = express()
const httpPort = process.env.PORT || 80
const httpsPort = 443
const ExpressPeerServer = require('peer')
const path = require('path')
const http = require('http')
const https = require('https')
const fs = require('fs')
// Certificate & credentials
const privateKey = fs.readFileSync(path.join(__dirname, 'certs', 'key.pem'))
const certificate = fs.readFileSync(path.join(__dirname, 'certs', 'cert.pem'))
const credentials =
key: privateKey,
cert: certificate
const httpsServer = https.createServer(credentials, app).listen(httpsPort, () => console.log('Peer Server listening to port ' + httpsPort) )
const peerServer = ExpressPeerServer(httpsServer,
debug: true,
path: '/myapp'
)
app.use(peerServer)
const io = require('socket.io')(httpsServer,
forceNew: true,
transports: ["polling"],
)
const v4: uuidV4 = require('uuid')
app.set('view engine', 'ejs')
app.use(express.static('public'))
app.get('/', (req, res) =>
res.redirect(`/$uuidV4()`)
)
app.get('/:room', (req, res) =>
res.render('room', roomId: req.params.room )
)
io.on('connection', (socket) =>
socket.on('join-room', (roomId, userId) =>
socket.join(roomId)
socket.broadcast.to(roomId).emit('user-connected', userId)
socket.on('disconnect', () =>
socket.broadcast.to(roomId).emit('user-disconnected', userId)
)
socket.on('text-message', message =>
socket.broadcast.to(roomId).emit('text-message-received', message)
)
socket.on('system-stream-updated', remoteUserId =>
socket.broadcast.to(roomId).emit('new-remote-stream', remoteUserId)
)
)
)
还有 room.ejs(如果需要)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script>
const ROOM_ID = "<%= roomId %>"
</script>
<script src="peer.min.js" defer></script>
<script src="/socket.io/socket.io.js" defer></script>
<script src="client.js" defer></script>
<title>Interface</title>
<style type="text/css">
html, body
padding: 0;
margin: 0;
.container, .local-video
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
.remote-video-div
position: absolute;
max-width: 30%;
width: 30%;
margin: 16px;
.remote-video
max-width: 100%;
width: 100%;
margin-bottom: -5px;
.video-inset
outline: unset;
visibility: hidden;
position: relative;
margin:0;
padding:0;
.background-black
background-color: #000000 !important;
.display-none
display: none;
.loader
margin: 250px auto;
border: 7px solid #9e9c9c;
border-radius: 50%;
border-top: 7px solid #ffffff;
width: 40px;
height: 40px;
-webkit-animation: spin 2s linear infinite; /* Safari */
animation: spin 2s linear infinite;
/* Safari */
@-webkit-keyframes spin
0% -webkit-transform: rotate(0deg);
100% -webkit-transform: rotate(360deg);
@keyframes spin
0% transform: rotate(0deg);
100% transform: rotate(360deg);
</style>
<link rel="icon" type="image/ico" href="favicon.ico"/>
</head>
<body>
<div class="local-video-div background-black">
<video class="local-video" autoplay></video>
</div>
<div class="container background-black display-none" id="loader">
<div class="loader"></div>
</div>
<div class="remote-video-div background-black">
<video class="remote-video" autoplay onclick="remoteVideoClick()"></video>
</div>
<div class="container background-black display-none" id="conference">
</div>
</body>
</html>
提前致谢。
【问题讨论】:
@Julio Spinelli,期待您的帮助。 所以你也需要用 peerjs 进行单向调用吗?因为您当前的代码将使用两种方式流式传输。 【参考方案1】:我遇到了同样的问题,正在寻找解决方案。这很有趣,因为你的问题本身就解决了我的问题!我这样做了...
<button
onClick=() =>
(stream.getVideoTracks()[0].enabled =
!stream.getVideoTracks()[0].enabled)
>
顺便说一句,您可能已经注意到(从“onClick”)我正在做这个反应。但是,在您的情况下,我认为您应该首先从设备获取视频流并将其设置为变量。然后使用该流变量调用用户,当您需要它时,您可以通过执行 stream.getVideoTracks()[0].enabled = !stream.getVideoTracks()[0].enabled 来停止和启动流式传输。但是,请确保您有一个流的真实来源,并始终从那里引用它。我这样做是为了做出反应,它对我有用。希望它也适合你!
【讨论】:
以上是关于如何修改正在进行的连接上的流以暂停/恢复流传输的主要内容,如果未能解决你的问题,请参考以下文章