如何使用SignalR广播媒体流?.NET Core屏幕共享实现求助
.NET Core + SignalR 实现屏幕共享:MediaStream传输与广播方案
问题根源
你直接尝试通过SignalR传递MediaStream对象是行不通的——MediaStream是浏览器本地的媒体对象,无法被序列化为可传输的格式,SignalR无法直接处理这类对象的跨网络传输。
解决方案思路
需要将屏幕流拆解为可传输的媒体片段,通过SignalR分段发送,接收端再将这些片段拼接还原成可播放的流:
- 前端用
MediaRecorder捕获屏幕流的媒体片段(Blob格式) - 将Blob分段发送到SignalR Hub
- 后端Hub直接转发这些片段给所有客户端
- 接收端通过
MediaSource和SourceBuffer拼接片段,实现流式播放
修改后的代码实现
1. 前端HTML(无需修改)
<div class="container"> <div class="row p-1"> <h1>WebRTC Screen Sharing Demo</h1> <hr> <button onclick="captureScreen()">Capture</button> <video id="local-video" muted autoplay></video> </div> </div> <script src="~/js/signalr/dist/browser/signalr.js"></script> <script src="~/js/stream.js"></script>
2. 前端Stream.js
"use strict"; var connection = new signalR.HubConnectionBuilder().withUrl("/streamHub").build(); let mediaRecorder = null; let mediaSource = new MediaSource(); const videoElement = document.getElementById("local-video"); videoElement.srcObject = mediaSource; let sourceBuffer = null; // 初始化MediaSource的SourceBuffer mediaSource.addEventListener('sourceopen', () => { sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp8"'); sourceBuffer.mode = 'sequence'; }); // 接收服务器转发的媒体片段并播放 connection.on("ClientReceiveStream", function (blobData) { const blob = new Blob([blobData], { type: 'video/webm' }); if (!sourceBuffer.updating) { blob.arrayBuffer().then(buffer => { sourceBuffer.appendBuffer(buffer); }); } }); // 启动SignalR连接 connection.start().then(function () { console.log("Connection started"); }).catch(function (err) { return console.error(err.toString()); }); async function captureScreen() { let mediaStream = null; try { mediaStream = await navigator.mediaDevices.getDisplayMedia({ video: { cursor: "always" }, audio: false }); // 创建MediaRecorder,指定WebM格式 mediaRecorder = new MediaRecorder(mediaStream, { mimeType: 'video/webm; codecs="vp8"' }); // 每500ms捕获一个媒体片段并发送 mediaRecorder.ondataavailable = (event) => { if (event.data.size > 0) { connection.invoke("ServerSendStream", event.data).catch(function (err) { return console.error(err.toString()); }); } }; // 开始录制,设置片段间隔 mediaRecorder.start(500); // 停止屏幕共享时清理资源 mediaStream.getTracks().forEach(track => { track.addEventListener('ended', () => { mediaRecorder.stop(); }); }); } catch (ex) { console.log("Error occurred", ex); } }
3. 后端StreamHub
using Microsoft.AspNetCore.SignalR; public class StreamHub : Hub { // 接收前端发送的媒体片段(SignalR会自动将Blob转换为byte[]) public async Task ServerSendStream(byte[] mediaSegment) { // 将片段广播给所有客户端 await Clients.All.SendAsync("ClientReceiveStream", mediaSegment); } }
关键说明
- 选择
video/webm格式是因为它兼容性好且体积适中,你也可以根据需求更换为其他支持的格式(如MP4) - 录制间隔(500ms)可根据网络状况调整,间隔越小延迟越低,但带宽占用越高
- 如果需要支持多房间或指定客户端转发,可以修改
Clients.All为Clients.Others或根据分组转发 - 生产环境中建议添加错误处理、断线重连逻辑,以及带宽控制
内容的提问来源于stack exchange,提问作者Dr. MAF
相关产品推荐
相关产品推荐

