@@ -23,9 +23,12 @@ const VideoPanel = () => {
23
23
const [ callInstance , setCallInstance ] = useState < MediaConnection | null > (
24
24
null
25
25
) ;
26
+ const [ remoteCallInstance , setRemoteCallInstance ] =
27
+ useState < MediaConnection | null > ( null ) ;
26
28
const [ userStream , setUserStream ] = useState < MediaStream | null > ( null ) ;
27
29
const [ videoOn , setVideoOn ] = useState < boolean > ( true ) ;
28
30
const [ muteOn , setMuteOn ] = useState < boolean > ( false ) ;
31
+ const [ isCalling , setIsCalling ] = useState < boolean > ( false ) ;
29
32
30
33
const handleCall = ( ) => {
31
34
navigator . mediaDevices
@@ -37,6 +40,7 @@ const VideoPanel = () => {
37
40
if ( peerInstance ) {
38
41
const call = peerInstance ?. call ( partnerId , stream ) ;
39
42
setCallInstance ( call ) ;
43
+ setIsCalling ( true ) ; // Set isCalling as true since it is the initiator
40
44
if ( call ) {
41
45
call . on ( "stream" , ( userVideoStream : MediaStream ) => {
42
46
if ( remoteVideoRef . current ) {
@@ -100,6 +104,8 @@ const VideoPanel = () => {
100
104
101
105
peer . on ( "call" , ( call ) => {
102
106
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
103
109
call . on ( "stream" , ( userVideoStream ) => {
104
110
if ( remoteVideoRef . current ) {
105
111
remoteVideoRef . current . srcObject = userVideoStream ;
@@ -116,6 +122,17 @@ const VideoPanel = () => {
116
122
}
117
123
} , [ ] ) ;
118
124
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
+
119
136
const toggleVideo = ( ) => {
120
137
if ( userStream ) {
121
138
const videoTrack = userStream . getVideoTracks ( ) [ 0 ] ;
@@ -126,8 +143,10 @@ const VideoPanel = () => {
126
143
videoTrack . enabled = false ;
127
144
128
145
setVideoOn ( false ) ;
129
- if ( callInstance ) {
130
- const sender = callInstance . peerConnection
146
+ if ( callInstance && remoteCallInstance ?. open ) {
147
+ const sender = (
148
+ callInstance . peerConnection || remoteCallInstance . peerConnection
149
+ )
131
150
. getSenders ( )
132
151
. find ( ( s ) => {
133
152
if ( s . track ) {
@@ -147,6 +166,18 @@ const VideoPanel = () => {
147
166
}
148
167
} ;
149
168
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
+
150
181
const toggleMute = ( ) => {
151
182
if ( userStream ) {
152
183
const audioTrack = userStream . getAudioTracks ( ) [ 0 ] ;
@@ -161,8 +192,10 @@ const VideoPanel = () => {
161
192
audioTrack . enabled = false ;
162
193
setMuteOn ( true ) ;
163
194
164
- if ( callInstance ) {
165
- const sender = callInstance . peerConnection
195
+ if ( callInstance && remoteCallInstance ?. open ) {
196
+ const sender = (
197
+ callInstance . peerConnection || remoteCallInstance . peerConnection
198
+ )
166
199
. getSenders ( )
167
200
. find ( ( s ) => {
168
201
if ( s . track ) {
@@ -186,6 +219,7 @@ const VideoPanel = () => {
186
219
playsInline
187
220
ref = { currentUserVideoRef }
188
221
autoPlay
222
+ muted
189
223
/>
190
224
< div className = "buttons-container" >
191
225
< Button
@@ -232,17 +266,70 @@ const VideoPanel = () => {
232
266
>
233
267
{ muteOn ? "On Mic" : "Off Mic" }
234
268
</ 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" }
237
322
</ Button >
238
323
</ div >
239
324
{ /* <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
+ ) }
246
333
</ div >
247
334
) ;
248
335
} ;
0 commit comments