Skip to content

Commit 00497c6

Browse files
committed
Create VideoPanel component
1 parent 1475c05 commit 00497c6

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import React, { useEffect, useRef, useState } from "react";
2+
import Peer, { MediaConnection } from "peerjs";
3+
import "./styles.scss";
4+
import { Button } from "antd";
5+
import {
6+
ApiOutlined,
7+
PhoneOutlined,
8+
VideoCameraOutlined,
9+
} from "@ant-design/icons";
10+
11+
const VideoPanel = () => {
12+
const matchId = localStorage.getItem("collabId")?.toString() ?? "";
13+
const currentUsername = localStorage.getItem("user")?.toString();
14+
const matchedUsername = localStorage.getItem("matchedUser")?.toString();
15+
const currentId = currentUsername + "-" + matchId ?? "";
16+
const partnerId = matchedUsername + "-" + matchId ?? "";
17+
18+
const remoteVideoRef = useRef<HTMLVideoElement>(null);
19+
const currentUserVideoRef = useRef<HTMLVideoElement>(null);
20+
const [peerInstance, setPeerInstance] = useState<Peer | null>(null);
21+
const [callInstance, setCallInstance] = useState<MediaConnection | null>(
22+
null
23+
);
24+
const [userStream, setUserStream] = useState<MediaStream | null>(null);
25+
const [videoOn, setVideoOn] = useState<boolean>(true);
26+
27+
const handleCall = () => {
28+
navigator.mediaDevices
29+
.getUserMedia({
30+
video: true,
31+
audio: true,
32+
})
33+
.then((stream) => {
34+
if (peerInstance) {
35+
const call = peerInstance?.call(partnerId, stream);
36+
setCallInstance(call);
37+
if (call) {
38+
call.on("stream", (userVideoStream: MediaStream) => {
39+
if (remoteVideoRef.current) {
40+
remoteVideoRef.current.srcObject = userVideoStream;
41+
}
42+
});
43+
44+
if (userStream) {
45+
const videoTrack = userStream.getVideoTracks()[0];
46+
47+
const sender = call.peerConnection.getSenders().find((s) => {
48+
if (s.track) {
49+
return s.track.kind === "video";
50+
}
51+
});
52+
if (sender) {
53+
sender.replaceTrack(videoTrack); // Replace the video track in the call
54+
}
55+
}
56+
}
57+
}
58+
});
59+
};
60+
61+
useEffect(() => {
62+
if (currentId) {
63+
let peer: Peer;
64+
if (typeof window !== "undefined") {
65+
peer = new Peer(
66+
currentId
67+
// {
68+
// host: "localhost",
69+
// port: 4444,
70+
// path: "/",
71+
// }
72+
);
73+
74+
setPeerInstance(peer);
75+
76+
navigator.mediaDevices
77+
.getUserMedia({
78+
video: true,
79+
audio: true,
80+
})
81+
.then((stream) => {
82+
setUserStream(stream);
83+
if (currentUserVideoRef.current) {
84+
currentUserVideoRef.current.srcObject = stream;
85+
}
86+
87+
peer.on("call", (call) => {
88+
call.answer(stream);
89+
call.on("stream", (userVideoStream) => {
90+
if (remoteVideoRef.current) {
91+
remoteVideoRef.current.srcObject = userVideoStream;
92+
}
93+
});
94+
});
95+
});
96+
}
97+
return () => {
98+
if (peer) {
99+
peer.destroy();
100+
}
101+
};
102+
}
103+
}, []);
104+
105+
const toggleVideo = () => {
106+
if (userStream) {
107+
console.log(userStream.getVideoTracks());
108+
const videoTrack = userStream.getVideoTracks()[0];
109+
110+
if (videoTrack) {
111+
if (videoOn) {
112+
// Stop the video track
113+
videoTrack.enabled = false;
114+
115+
setVideoOn(false);
116+
if (callInstance) {
117+
const sender = callInstance.peerConnection
118+
.getSenders()
119+
.find((s) => {
120+
if (s.track) {
121+
return s.track.kind === "video";
122+
}
123+
});
124+
if (sender) {
125+
sender.replaceTrack(videoTrack); // Replace the video track in the call
126+
}
127+
}
128+
} else {
129+
// Resume the video track
130+
videoTrack.enabled = true;
131+
setVideoOn(true);
132+
}
133+
}
134+
}
135+
};
136+
137+
return (
138+
<div className="video-panel">
139+
<p className="header-tag">Video Feed for: {currentUsername}</p>
140+
<video
141+
className="user-video"
142+
playsInline
143+
ref={currentUserVideoRef}
144+
autoPlay
145+
muted
146+
/>
147+
<Button
148+
onClick={toggleVideo}
149+
icon={<VideoCameraOutlined />}
150+
type={videoOn ? "default" : "primary"}
151+
>
152+
{videoOn ? "Off Webcam" : "On Webcam"}
153+
</Button>
154+
<Button onClick={handleCall} icon={<ApiOutlined />} type="primary">
155+
Initiate Call
156+
</Button>
157+
<p className="header-tag">Video Feed for: {matchedUsername}</p>
158+
<video
159+
className="matched-user-video"
160+
playsInline
161+
ref={remoteVideoRef}
162+
autoPlay
163+
muted
164+
/>
165+
</div>
166+
);
167+
};
168+
169+
export default VideoPanel;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.video-container {
2+
position: relative;
3+
width: 100%;
4+
}
5+
6+
.user-video,
7+
.matched-user-video {
8+
width: 100%;
9+
}
10+
11+
.header-tag {
12+
font-weight: bold;
13+
}

0 commit comments

Comments
 (0)