@@ -23,9 +23,12 @@ const VideoPanel = () => {
2323 const [ callInstance , setCallInstance ] = useState < MediaConnection | null > (
2424 null
2525 ) ;
26+ const [ remoteCallInstance , setRemoteCallInstance ] =
27+ useState < MediaConnection | null > ( null ) ;
2628 const [ userStream , setUserStream ] = useState < MediaStream | null > ( null ) ;
2729 const [ videoOn , setVideoOn ] = useState < boolean > ( true ) ;
2830 const [ muteOn , setMuteOn ] = useState < boolean > ( false ) ;
31+ const [ isCalling , setIsCalling ] = useState < boolean > ( false ) ;
2932
3033 const handleCall = ( ) => {
3134 navigator . mediaDevices
@@ -37,6 +40,7 @@ const VideoPanel = () => {
3740 if ( peerInstance ) {
3841 const call = peerInstance ?. call ( partnerId , stream ) ;
3942 setCallInstance ( call ) ;
43+ setIsCalling ( true ) ; // Set isCalling as true since it is the initiator
4044 if ( call ) {
4145 call . on ( "stream" , ( userVideoStream : MediaStream ) => {
4246 if ( remoteVideoRef . current ) {
@@ -100,6 +104,8 @@ const VideoPanel = () => {
100104
101105 peer . on ( "call" , ( call ) => {
102106 call . answer ( stream ) ;
107+ setIsCalling ( true ) ; // When a peer initiates call, on answer, set the calling state to true
108+ setRemoteCallInstance ( call ) ; // Set remote call instance media connection
103109 call . on ( "stream" , ( userVideoStream ) => {
104110 if ( remoteVideoRef . current ) {
105111 remoteVideoRef . current . srcObject = userVideoStream ;
@@ -116,6 +122,17 @@ const VideoPanel = () => {
116122 }
117123 } , [ ] ) ;
118124
125+ // When remote peer initiates end call, we set isCalling to false
126+ useEffect ( ( ) => {
127+ remoteCallInstance ?. on ( "close" , ( ) => {
128+ setIsCalling ( false ) ;
129+ } ) ;
130+
131+ callInstance ?. on ( "close" , ( ) => {
132+ setIsCalling ( false ) ;
133+ } ) ;
134+ } , [ remoteCallInstance ?. open , callInstance ?. open ] ) ;
135+
119136 const toggleVideo = ( ) => {
120137 if ( userStream ) {
121138 const videoTrack = userStream . getVideoTracks ( ) [ 0 ] ;
@@ -126,8 +143,10 @@ const VideoPanel = () => {
126143 videoTrack . enabled = false ;
127144
128145 setVideoOn ( false ) ;
129- if ( callInstance ) {
130- const sender = callInstance . peerConnection
146+ if ( callInstance && remoteCallInstance ?. open ) {
147+ const sender = (
148+ callInstance . peerConnection || remoteCallInstance . peerConnection
149+ )
131150 . getSenders ( )
132151 . find ( ( s ) => {
133152 if ( s . track ) {
@@ -147,6 +166,18 @@ const VideoPanel = () => {
147166 }
148167 } ;
149168
169+ const handleCloseConnection = ( ) => {
170+ if ( callInstance && callInstance . open ) {
171+ callInstance . close ( ) ;
172+ setIsCalling ( false ) ;
173+ }
174+
175+ if ( remoteCallInstance && remoteCallInstance . open ) {
176+ remoteCallInstance . close ( ) ;
177+ setIsCalling ( false ) ;
178+ }
179+ } ;
180+
150181 const toggleMute = ( ) => {
151182 if ( userStream ) {
152183 const audioTrack = userStream . getAudioTracks ( ) [ 0 ] ;
@@ -161,8 +192,10 @@ const VideoPanel = () => {
161192 audioTrack . enabled = false ;
162193 setMuteOn ( true ) ;
163194
164- if ( callInstance ) {
165- const sender = callInstance . peerConnection
195+ if ( callInstance && remoteCallInstance ?. open ) {
196+ const sender = (
197+ callInstance . peerConnection || remoteCallInstance . peerConnection
198+ )
166199 . getSenders ( )
167200 . find ( ( s ) => {
168201 if ( s . track ) {
@@ -186,6 +219,7 @@ const VideoPanel = () => {
186219 playsInline
187220 ref = { currentUserVideoRef }
188221 autoPlay
222+ muted
189223 />
190224 < div className = "buttons-container" >
191225 < Button
@@ -232,17 +266,70 @@ const VideoPanel = () => {
232266 >
233267 { muteOn ? "On Mic" : "Off Mic" }
234268 </ Button >
235- < Button onClick = { handleCall } icon = { < ApiOutlined /> } type = "primary" >
236- Call
269+ < Button
270+ onClick = { isCalling ? handleCloseConnection : handleCall }
271+ icon = {
272+ isCalling ? (
273+ < div className = "icon-padding" >
274+ < svg
275+ xmlns = "http://www.w3.org/2000/svg"
276+ width = "1.2em"
277+ height = "1.2em"
278+ viewBox = "0 0 24 24"
279+ >
280+ < g fill = "none" >
281+ < path
282+ stroke = "currentColor"
283+ strokeLinecap = "round"
284+ strokeWidth = { 2 }
285+ d = "m20 4l-4 4m0-4l4 4"
286+ > </ path >
287+ < path
288+ fill = "currentColor"
289+ d = "m15.1 15.027l-.543-.516zm.456-.48l.544.517zm2.417-.335l-.374.65zm1.91 1.1l-.374.65zm.539 3.446l.543.517zm-1.42 1.496l-.545-.517zm-1.326.71l.074.745zm-9.86-4.489l.543-.516zm-4.813-9.51l-.749.041zm6.475 1.538l.543.517zm.156-2.81l.613-.433zM8.374 3.91l-.613.433zM5.26 3.609l.544.516zM3.691 5.26l-.543-.516zm7.372 7.795l.544-.517zm4.582 2.488l.455-.48l-1.088-1.033l-.455.48zm1.954-.682l1.91 1.1l.749-1.3l-1.911-1.1zm2.279 3.38l-1.42 1.495l1.087 1.034l1.42-1.496zm-2.275 1.975c-1.435.141-5.18.02-9.244-4.258l-1.087 1.033c4.429 4.663 8.654 4.898 10.478 4.717zm-9.244-4.258c-3.876-4.081-4.526-7.523-4.607-9.033l-1.498.08c.1 1.85.884 5.634 5.018 9.986zm1.376-6.637l.286-.302l-1.087-1.033l-.287.302zm.512-4.062L8.986 3.477l-1.225.866l1.26 1.783zm-5.53-2.168L3.149 4.745l1.088 1.033l1.57-1.653zm4.474 5.713a38 38 0 0 0-.545-.515l-.002.002l-.003.003l-.05.058a1.6 1.6 0 0 0-.23.427c-.098.275-.15.639-.084 1.093c.13.892.715 2.091 2.242 3.7l1.088-1.034c-1.428-1.503-1.78-2.428-1.846-2.884c-.032-.22 0-.335.013-.372l.008-.019l-.028.037l-.018.02s-.002 0-.545-.516m1.328 4.767c1.523 1.604 2.673 2.234 3.55 2.377c.451.073.816.014 1.092-.095a1.5 1.5 0 0 0 .421-.25l.036-.034l.014-.014l.007-.006l.003-.003l.001-.002s.002-.001-.542-.518c-.544-.516-.543-.517-.543-.518l.002-.001l.002-.003l.005-.005l.01-.01l.037-.032q.015-.008-.004.001c-.02.008-.11.04-.3.009c-.402-.066-1.27-.42-2.703-1.929zM8.986 3.477C7.972 2.043 5.944 1.8 4.718 3.092l1.087 1.033c.523-.55 1.444-.507 1.956.218zM3.752 6.926c-.022-.4.152-.8.484-1.148L3.148 4.745c-.536.564-.943 1.347-.894 2.261zm14.705 12.811c-.279.294-.57.452-.854.48l.147 1.492c.747-.073 1.352-.472 1.795-.939zM10.021 9.02c.968-1.019 1.036-2.613.226-3.76l-1.225.866c.422.597.357 1.392-.088 1.86zm9.488 6.942c.821.473.982 1.635.369 2.28l1.087 1.033c1.305-1.374.925-3.673-.707-4.613zm-3.409-.898c.385-.406.986-.497 1.499-.202l.748-1.3c-1.099-.632-2.46-.45-3.335.47z"
290+ > </ path >
291+ </ g >
292+ </ svg >
293+ </ div >
294+ ) : (
295+ < div className = "icon-padding" >
296+ < svg
297+ xmlns = "http://www.w3.org/2000/svg"
298+ width = "1.2em"
299+ height = "1.2em"
300+ viewBox = "0 0 24 24"
301+ >
302+ < g fill = "none" >
303+ < path
304+ stroke = "currentColor"
305+ strokeLinecap = "round"
306+ strokeWidth = { 2 }
307+ d = "M13.5 2s2.334.212 5.303 3.182c2.97 2.97 3.182 5.303 3.182 5.303m-7.778-4.949s.99.282 2.475 1.767s1.768 2.475 1.768 2.475"
308+ > </ path >
309+ < path
310+ fill = "currentColor"
311+ d = "m15.1 15.027l-.543-.516zm.456-.48l.544.517zm2.417-.335l-.374.65zm1.91 1.1l-.374.65zm.539 3.446l.543.517zm-1.42 1.496l-.545-.517zm-1.326.71l.074.745zm-9.86-4.489l.543-.516zm-4.813-9.51l-.749.041zm6.475 1.538l.543.517zm.156-2.81l.613-.433zM8.374 3.91l-.613.433zM5.26 3.609l.544.516zM3.691 5.26l-.543-.516zm7.372 7.795l.544-.517zm4.582 2.488l.455-.48l-1.088-1.033l-.455.48zm1.954-.682l1.91 1.1l.749-1.3l-1.911-1.1zm2.279 3.38l-1.42 1.495l1.087 1.034l1.42-1.496zm-2.275 1.975c-1.435.141-5.18.02-9.244-4.258l-1.087 1.033c4.429 4.663 8.654 4.898 10.478 4.717zm-9.244-4.258c-3.876-4.081-4.526-7.523-4.607-9.033l-1.498.08c.1 1.85.884 5.634 5.018 9.986zm1.376-6.637l.286-.302l-1.087-1.033l-.287.302zm.512-4.062L8.986 3.477l-1.225.866l1.26 1.783zm-5.53-2.168L3.149 4.745l1.088 1.033l1.57-1.653zm4.474 5.713a38 38 0 0 0-.545-.515l-.002.002l-.003.003l-.05.058a1.6 1.6 0 0 0-.23.427c-.098.275-.15.639-.084 1.093c.13.892.715 2.091 2.242 3.7l1.088-1.034c-1.428-1.503-1.78-2.428-1.846-2.884c-.032-.22 0-.335.013-.372l.008-.019l-.028.037l-.018.02s-.002 0-.545-.516m1.328 4.767c1.523 1.604 2.673 2.234 3.55 2.377c.451.073.816.014 1.092-.095a1.5 1.5 0 0 0 .421-.25l.036-.034l.014-.014l.007-.006l.003-.003l.001-.002s.002-.001-.542-.518c-.544-.516-.543-.517-.543-.518l.002-.001l.002-.003l.005-.005l.01-.01l.037-.032q.015-.008-.004.001c-.02.008-.11.04-.3.009c-.402-.066-1.27-.42-2.703-1.929zM8.986 3.477C7.972 2.043 5.944 1.8 4.718 3.092l1.087 1.033c.523-.55 1.444-.507 1.956.218zM3.752 6.926c-.022-.4.152-.8.484-1.148L3.148 4.745c-.536.564-.943 1.347-.894 2.261zm14.705 12.811c-.279.294-.57.452-.854.48l.147 1.492c.747-.073 1.352-.472 1.795-.939zM10.021 9.02c.968-1.019 1.036-2.613.226-3.76l-1.225.866c.422.597.357 1.392-.088 1.86zm9.488 6.942c.821.473.982 1.635.369 2.28l1.087 1.033c1.305-1.374.925-3.673-.707-4.613zm-3.409-.898c.385-.406.986-.497 1.499-.202l.748-1.3c-1.099-.632-2.46-.45-3.335.47z"
312+ > </ path >
313+ </ g >
314+ </ svg >
315+ </ div >
316+ )
317+ }
318+ type = "primary"
319+ danger = { isCalling }
320+ >
321+ { isCalling ? "End" : "Call" }
237322 </ Button >
238323 </ div >
239324 { /* <p className="header-tag">Video Feed for: {matchedUsername}</p> */ }
240- < video
241- className = "matched-user-video"
242- playsInline
243- ref = { remoteVideoRef }
244- autoPlay
245- />
325+ { isCalling && (
326+ < video
327+ className = "matched-user-video"
328+ playsInline
329+ ref = { remoteVideoRef }
330+ autoPlay
331+ />
332+ ) }
246333 </ div >
247334 ) ;
248335} ;
0 commit comments