Search code examples
javascriptreactjswebrtc

Video element didn't show up after successfully getting local stream WebRTC


Currently, I am creating a P2P video call application. And I want when I click the open my camera, then the camera will be opened and the media stream will be fed to my video tag. Here is the code, the file index.jsx, some code are suppressed for brevity:

const ForwardRefConference = forwardRef(Conference);
const [localAudioEnabled, setLocalAudioEnabled] = useState(false);
const [localVideoEnabled, setLocalVideoEnabled] = useState(false);
let settings = {
    selectedAudioDevice: "",
    selectedVideoDevice: "",
    resolution: "vga",
    bandwidth: 512,
    codec: "vp8",
    isDevMode: false,
    audio: localAudioEnabled,
    video: localVideoEnabled
};
const startPublishingVideo = (sid, uid) => {
    settings.video = true;
    setLocalVideoEnabled(true);
    conference.current.handleLocalStream();
}

return (
 <div>
 <button
                      className={style.btn_function}
                      onClick={startPublishingVideo}
                    />
{<ForwardRefConference
                    uid={uid}
                    sid={sid}
                    rtc={rtc}
                    peers={peers}
                    vidFit={vidFit}
                    settings={settings}
                    localAudioEnabled={localAudioEnabled}
                    localVideoEnabled={localVideoEnabled}
                    ref={conference}
                  />}</div>)

Here is the Conference component, which contains the components for rendering video, and here is the part I use the get user media:

const dohandleLocalStream = async () => {
    const { settings, rtc } = props;
    Ion.LocalStream.getUserMedia({
        codec: settings.codec.toUpperCase(),
        resolution: settings.resolution,
        bandwidth: settings.bandwidth,
        // audio: settings.audio,
        // video: settings.video,
        audio: true,
        video: true
      })
        .then((media) => {
          console.log("rtc.publish media=", media);
          rtc.publish(media);
          localStreamObj.stream = media;
          setLocalStreamObj(localStreamObj);
          console.log(
            "got local stream from " + JSON.stringify(localStreamObj.stream)
          );
        })
        .catch((e) => console.log("handleLocalStream error => " + e));

    doMuteMediaTrack("video", props.localVideoEnabled);
};

Here is what I return from Conference:

return ({localStreamObj.stream && (
        <div className="conference-local-video-layout">
          <LocalVideoView
            key={id + " -video"}
            id={id + "-video"}
            label="Local Stream"
            stream={localStreamObj.stream}
            audioMuted={audioMuted}
            videoMuted={videoMuted}
            videoType="localVideo"
            controls
          />
        </div>
)})

And here is the LocalVideoView, which will get the stream from Conference and render it to the video tag:

    const videoRef = useRef(null);
    useEffect(() => {
        videoRef.current.srcObject = props.stream;
        console.log('current video stream: ' + JSON.stringify(props.stream));
        return () => {
            if (videoRef.current) {
                videoRef.current.srcObject = null;
            }
        }
    }, []   )

    const {id, label, audioMuted, videoMuted, videoType} = props;

    

    return (
        <div className="local-video-container" style={{borderWidth: `${minimize ? '0px' : '0.5px'}`}}>
            <video
                ref={videoRef} 
                id={id}
                autoPlay
                playsInline
                muted={true}
                className="local-video-size"
            />)

When I open my camera, the webcam activated but I still cannot see the video element displayed. As far as I know, when I get the local stream and then I set the state variable localStreamObj then the component should be re-render but it won't. And also when I try to get the userMedia right after the page gets loaded, then the video element then displayed. I am not sure why because I'm new to React, thanks for any help!


Solution

  • I have figured out why the video didn't display in the first place. Because of this:

    localStreamObj.stream = media;
    setLocalStreamObj(localStreamObj);
    

    I am mutating the existing object and still setting this old object and that must be a reason why it didn't trigger re-rendering.

    When I try to create a new object and set it to the state variable, like this:

    const mediaStream = {
       stream: media
    }
    setLocalStreamObj(mediaStream);
    

    Then it works as expected.