You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebRTC应用屏幕共享流保存及切换异常技术求助

Hi Mitzi, let's tackle these two issues one by one—first the screen share switch-back problem, then saving the screen share stream.

1. Fixing the Screen Share Switch-Back Issue

From what you described, the most common culprits here are improper media stream/track management or failing to re-trigger the Chrome screen share authorization flow when switching back. Here's how to resolve it:

Common Root Causes & Fixes

  • Forgot to stop/destroy old tracks: When switching to the camera, if you don't properly stop the screen share track and remove it from the PeerConnection, it can hog resources and prevent a new screen share stream from being initialized.
  • Reusing a stale screen share stream: Screen share streams can't be restarted once stopped—you need to re-request access via the Chrome extension every time you want to switch back.
  • PeerConnection track replacement logic is broken: You need to explicitly remove the old video track (camera) before adding the new screen share track.

Example Implementation (Frontend JS)

First, update your camera switch function to clean up the screen share resources:

function switchToCamera() {
  // Clean up existing screen share stream/tracks
  if (window.screenStream) {
    window.screenStream.getTracks().forEach(track => track.stop());
    // Remove the screen share track from PeerConnection
    peerConnection.getSenders().forEach(sender => {
      if (sender.track?.kind === 'video' && sender.track.label.includes('screen')) {
        peerConnection.removeTrack(sender);
      }
    });
    window.screenStream = null;
  }

  // Initialize camera stream and attach to PeerConnection
  navigator.mediaDevices.getUserMedia({ video: true })
    .then(cameraStream => {
      window.cameraStream = cameraStream;
      const cameraTrack = cameraStream.getVideoTracks()[0];
      // Add camera track to PeerConnection (replace existing if needed)
      const existingVideoSender = peerConnection.getSenders().find(s => s.track?.kind === 'video');
      if (existingVideoSender) {
        existingVideoSender.replaceTrack(cameraTrack);
      } else {
        peerConnection.addTrack(cameraTrack, cameraStream);
      }
      // Update local video display
      localVideo.srcObject = cameraStream;
    });
}

Then, update the switch-back to screen share function to re-request authorization and clean up the camera resources:

function switchBackToScreenShare() {
  // Clean up existing camera stream/tracks
  if (window.cameraStream) {
    window.cameraStream.getTracks().forEach(track => track.stop());
    const existingVideoSender = peerConnection.getSenders().find(s => s.track?.kind === 'video');
    if (existingVideoSender) {
      peerConnection.removeTrack(existingVideoSender);
    }
    window.cameraStream = null;
  }

  // Re-trigger Chrome screen share authorization
  chrome.desktopCapture.chooseDesktopMedia(['screen', 'window'], streamId => {
    if (!streamId) return; // User canceled the selection

    const screenConstraints = {
      video: {
        mandatory: {
          chromeMediaSource: 'desktop',
          chromeMediaSourceId: streamId,
          maxWidth: screen.width,
          maxHeight: screen.height
        }
      }
    };

    navigator.mediaDevices.getUserMedia(screenConstraints)
      .then(screenStream => {
        window.screenStream = screenStream;
        const screenTrack = screenStream.getVideoTracks()[0];
        // Add screen share track to PeerConnection
        peerConnection.addTrack(screenTrack, screenStream);
        // Update local video display
        localVideo.srcObject = screenStream;
      });
  });
}

Additional Check

Make sure your Chrome extension's manifest includes the necessary permissions (desktopCapture, activeTab, etc.) and that you're handling any extension-specific callback logic correctly.

2. Saving Screen Share Streams in WebRTC

You can use the browser's MediaRecorder API to capture the screen share stream, then save it locally or upload it to your ASP.NET backend.

Frontend Recording Logic

Add this code to capture and save the screen share stream:

function startScreenShareRecording(screenStream) {
  // Choose a supported MIME type (WebM is widely supported)
  const recordingOptions = { mimeType: 'video/webm; codecs=vp9' };
  if (!MediaRecorder.isTypeSupported(recordingOptions.mimeType)) {
    recordingOptions.mimeType = 'video/webm; codecs=vp8'; // Fallback to VP8
  }

  const mediaRecorder = new MediaRecorder(screenStream, recordingOptions);
  const recordedChunks = [];

  // Collect recorded data chunks
  mediaRecorder.ondataavailable = (event) => {
    if (event.data.size > 0) recordedChunks.push(event.data);
  };

  // On stop, create a blob and handle save/upload
  mediaRecorder.onstop = () => {
    const recordingBlob = new Blob(recordedChunks, { type: recordingOptions.mimeType });
    
    // Option 1: Download recording to user's local machine
    const downloadUrl = URL.createObjectURL(recordingBlob);
    const downloadLink = document.createElement('a');
    downloadLink.href = downloadUrl;
    downloadLink.download = `screen-share-${new Date().toISOString().slice(0,19)}.webm`;
    downloadLink.click();
    URL.revokeObjectURL(downloadUrl);

    // Option 2: Upload to ASP.NET backend
    fetch('/api/ScreenShare/SaveRecording', {
      method: 'POST',
      body: recordingBlob,
      headers: { 'Content-Type': recordingOptions.mimeType }
    })
    .then(response => response.json())
    .then(result => console.log('Recording saved to server:', result.fileName))
    .catch(err => console.error('Upload failed:', err));
  };

  // Start recording (save recorder reference to stop later)
  window.screenRecorder = mediaRecorder;
  mediaRecorder.start(1000); // Capture chunks every 1 second
}

// Call this to stop recording
function stopScreenShareRecording() {
  if (window.screenRecorder) {
    window.screenRecorder.stop();
    window.screenRecorder = null;
  }
}

ASP.NET Backend Endpoint

Add this controller action to receive and save the recording:

using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using System.IO;
using System.Threading.Tasks;

[ApiController]
[Route("api/ScreenShare")]
public class ScreenShareController : ControllerBase
{
    private readonly IWebHostEnvironment _hostingEnv;

    public ScreenShareController(IWebHostEnvironment hostingEnv)
    {
        _hostingEnv = hostingEnv;
    }

    [HttpPost("SaveRecording")]
    public async Task<IActionResult> SaveRecording()
    {
        var recordingsDir = Path.Combine(_hostingEnv.WebRootPath, "ScreenRecordings");
        if (!Directory.Exists(recordingsDir))
        {
            Directory.CreateDirectory(recordingsDir);
        }

        var fileName = $"Recording_{DateTime.Now:yyyyMMddHHmmssfff}.webm";
        var filePath = Path.Combine(recordingsDir, fileName);

        using (var stream = new FileStream(filePath, FileMode.Create))
        {
            await Request.Body.CopyToAsync(stream);
        }

        return Ok(new { fileName = fileName });
    }
}

Make sure to configure your ASP.NET app to allow large file uploads if needed (update maxAllowedContentLength in web.config or Program.cs for .NET Core/.NET 5+).

内容的提问来源于stack exchange,提问作者Mitzi Lev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:47:03