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!
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.