The video stops and does not resume after track.stop()
Asked Answered
R

1

2

I'm creating simple video-chat one-to-one using PeerJS and React. Everything is working fine except the camera muting. When participant A muting camera, it's muting on both clients but when participant A unmutes it, participant B can see only the static image instead of the opponent video.

I have a global state webcamState which changed when the corresponding button was clicked:

  const videoRef = useRef<any>(null);
  const webcamState = useSelector(getWebcamState);

  const [stream, setStream] = useState<MediaStream | null>(null);
  const [isWebcamLoading, setIsWebcamLoading] = useState(true);

  const loadUserMedia = () => {
    setIsWebcamLoading(true);
    getUserMedia(
      { video: webcamState, audio: micState },
      (newStream: MediaStream) => {
        videoRef.current.srcObject = newStream;
        setStream(newStream);
        setIsWebcamLoading(false);
      },
      (err: any) => {
        setIsWebcamLoading(false);
      },
    );
  };

useEffect(() => {
    if (videoRef?.current?.srcObject) {
      videoRef.current.srcObject.getVideoTracks().forEach((track: any) => (track.enabled = webcamState));

      if (!webcamState) {
        videoRef.current.srcObject.getVideoTracks().forEach((track: any) => track.stop());
        videoRef.current.pause();
      } else {
        loadUserMedia();
      }
    }
  }, [webcamState]);

Then this stream exporting from this hook and passed into another to initialize Peer call (and peer answer as well):

export interface IPeerOptions {
  opponentVideoRef: React.MutableRefObject<null>;
  currentVideoRef: React.MutableRefObject<null>;
  currentStream: MediaStream;
  userId: string;
}

export const initializePeerCall = (options: IPeerOptions): Peer => {
  const call = options.peer.call(options.opponentId, options.currentStream);
  call.on('stream', stream => {
    options.opponentVideoRef = setVideo(options.opponentVideoRef, stream);
  });

  call.on('error', err => {
    console.log(err);
  });
  call.on('close', () => {
    console.log('Connection closed');
  });
  return options.peer;
};

No errors appear in the console

But if I will remove the following line: videoRef.current.srcObject.getVideoTracks().forEach((track: any) => track.stop()); everything will work fine as expected

Maybe anyone faced something similar?

UPD: I tried this but the result was the same:

useEffect(() => {
    if (videoRef?.current?.srcObject) {
      videoRef.current.srcObject.getVideoTracks().forEach((track: any) => (track.enabled = webcamState));

      if (!webcamState) {
        videoRef.current.srcObject.getVideoTracks().forEach((track: any) => track.stop());
        loadUserMedia();
      } else {
        loadUserMedia();
      }
    }
  }, [webcamState]);

Notification:

 const onOpponentVideoStatusChanged = (newStatus: boolean) => {
    setOpponentState(prev => {
      return { microphoneState: !!prev?.microphoneState, webcamState: newStatus };
    });
    options.opponentVideoRef.current.srcObject.getVideoTracks().forEach((track: any) => (track.enabled = newStatus));
  };

As I understand after long investigation, user B still getting the same stream after user A created a new one. How can I fix it?

Repentance answered 1/2, 2023 at 19:56 Comment(0)
D
0

If you turn track off using track.stop(), you can not resume it.

I did get new stream when I have to resume it.

React.useEffect(()=>{
  if(mediaStream) { // mediaStream could be state locally or globally.
     const videoTrack = mediaStream.getVideoTracks();
      videoTrack.forEach((t) => {
        t.enabled = false;
        t.stop();
      });
  }
  // get MediaStream again with contraints 

}, [isAudioOnly]);
Dessalines answered 2/2, 2023 at 8:20 Comment(10)
I did the same way. As you can see I'm calling loadUserMedia which creates a new stream each time when video turns on. Or maybe I do it wrong way?Repentance
In your case, when !webcamState is true, loadUserMedia didn't called.Dessalines
Tried to add loadUserMedia call after track.stop() but with still result is the sameRepentance
Did you apply new stream like videoRef.current.srcObject = newStream?Dessalines
It's applying in loadUserMedia. I have added 'UPD' section in my question so you can take a lookRepentance
can you please provide your exaple of video turning on?Repentance
I think t.enabled = is not required.. could you remove this?Dessalines
Yeah, tried to remove it for camera disabling but with the same error. Actually problem may be also on the other side: when opponent switched its camera state, I notify the user about it using sockets. I will add code of notification to the UPD sectionRepentance
As I understand after long investigation, user B still getting the same stream after user A created a new one. How can I fix it?Repentance
Did you come up with the solution? If yes please share! @LevKostychenkoSampson

© 2022 - 2025 — McMap. All rights reserved.