1
1
'use client' ;
2
2
3
- import React , { useRef , useState } from 'react' ;
3
+ import React , { useRef , useState , useEffect } from 'react' ;
4
4
import io , { Socket } from 'socket.io-client' ;
5
5
import SimplePeer , { Instance } from 'simple-peer' ;
6
6
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' ;
@@ -19,36 +19,49 @@ const AudioSharing = () => {
19
19
const peerRef = useRef < Instance | null > ( null ) ;
20
20
const audioStreamRef = useRef < MediaStream | null > ( null ) ;
21
21
const initializedRef = useRef ( false ) ;
22
+ const audioElementsRef = useRef < HTMLAudioElement [ ] > ( [ ] ) ;
22
23
23
24
const SERVER_URL =
24
25
process . env . NEXT_PUBLIC_AUDIO_SERVER_URL || 'http://localhost:5555' ;
25
26
26
- // Add TURN server credentials from environment variables
27
27
const TURN_SERVER = process . env . NEXT_PUBLIC_TURN_SERVER || '' ;
28
28
const TURN_USERNAME = process . env . NEXT_PUBLIC_TURN_USERNAME ;
29
29
const TURN_CREDENTIAL = process . env . NEXT_PUBLIC_TURN_PASSWORD ;
30
30
31
- if ( ! TURN_SERVER || ! TURN_USERNAME || ! TURN_CREDENTIAL ) {
32
- // Log which specific TURN variables are missing
33
- console . error ( 'Missing TURN env:' , {
34
- server : ! ! TURN_SERVER ,
35
- username : ! ! TURN_USERNAME ,
36
- credential : ! ! TURN_CREDENTIAL ,
37
- } ) ;
38
- }
39
31
const cleanupAudio = ( ) => {
32
+ console . log ( 'Cleaning up audio connections...' ) ;
33
+
34
+ // Stop and cleanup all audio tracks
40
35
if ( audioStreamRef . current ) {
41
36
audioStreamRef . current . getTracks ( ) . forEach ( ( track ) => {
42
37
track . stop ( ) ;
43
38
} ) ;
44
39
audioStreamRef . current = null ;
45
40
}
41
+
42
+ // Destroy peer connection
46
43
if ( peerRef . current ) {
47
44
peerRef . current . destroy ( ) ;
48
45
peerRef . current = null ;
49
46
}
47
+
48
+ // Disconnect socket
49
+ if ( socketRef . current ) {
50
+ socketRef . current . disconnect ( ) ;
51
+ socketRef . current = null ;
52
+ }
53
+
54
+ // Stop and remove all audio elements
55
+ audioElementsRef . current . forEach ( ( audio ) => {
56
+ audio . pause ( ) ;
57
+ audio . srcObject = null ;
58
+ } ) ;
59
+ audioElementsRef . current = [ ] ;
60
+
61
+ // Reset states
50
62
setIsAudioEnabled ( false ) ;
51
63
setConnectionStatus ( 'Not Connected' ) ;
64
+ initializedRef . current = false ;
52
65
} ;
53
66
54
67
const createPeer = ( stream : MediaStream , initiator : boolean ) => {
@@ -61,10 +74,8 @@ const AudioSharing = () => {
61
74
trickle : false ,
62
75
config : {
63
76
iceServers : [
64
- // Maintain existing STUN servers
65
77
{ urls : 'stun:stun.l.google.com:19302' } ,
66
78
{ urls : 'stun:global.stun.twilio.com:3478' } ,
67
- // Add TURN server configuration
68
79
{
69
80
urls : TURN_SERVER ,
70
81
username : TURN_USERNAME ,
@@ -75,14 +86,15 @@ const AudioSharing = () => {
75
86
} ) ;
76
87
77
88
peer . on ( 'signal' , ( data : SignalData ) => {
78
- console . log ( 'Sending signal data:' , data ) ;
89
+ console . log ( 'Sending signal data' ) ;
79
90
socketRef . current ?. emit ( 'signal' , data ) ;
80
91
} ) ;
81
92
82
93
peer . on ( 'stream' , ( remoteStream : MediaStream ) => {
83
94
console . log ( 'Received remote stream' ) ;
84
95
const audio = new Audio ( ) ;
85
96
audio . srcObject = remoteStream ;
97
+ audioElementsRef . current . push ( audio ) ; // Track audio element for cleanup
86
98
audio
87
99
. play ( )
88
100
. catch ( ( error ) => console . error ( 'Error playing audio:' , error ) ) ;
@@ -98,7 +110,6 @@ const AudioSharing = () => {
98
110
cleanupAudio ( ) ;
99
111
} ) ;
100
112
101
- // Add connection state logging
102
113
peer . on ( 'connect' , ( ) => {
103
114
console . log ( 'Peer connection established successfully' ) ;
104
115
setConnectionStatus ( 'Connected' ) ;
@@ -129,7 +140,7 @@ const AudioSharing = () => {
129
140
} ) ;
130
141
131
142
socketRef . current . on ( 'signal' , async ( data : SignalData ) => {
132
- console . log ( 'Received signal data:' , data ) ;
143
+ console . log ( 'Received signal data' ) ;
133
144
134
145
if ( data . type === 'offer' && ! peerRef . current ) {
135
146
try {
@@ -195,6 +206,28 @@ const AudioSharing = () => {
195
206
}
196
207
} ;
197
208
209
+ // Cleanup effect when component unmounts
210
+ useEffect ( ( ) => {
211
+ // Cleanup function that will run when component unmounts
212
+ return ( ) => {
213
+ console . log ( 'AudioSharing component unmounting, cleaning up...' ) ;
214
+ cleanupAudio ( ) ;
215
+ } ;
216
+ } , [ ] ) ;
217
+
218
+ // Add window unload handler to ensure cleanup even when page closes
219
+ useEffect ( ( ) => {
220
+ const handleUnload = ( ) => {
221
+ cleanupAudio ( ) ;
222
+ } ;
223
+
224
+ window . addEventListener ( 'beforeunload' , handleUnload ) ;
225
+
226
+ return ( ) => {
227
+ window . removeEventListener ( 'beforeunload' , handleUnload ) ;
228
+ } ;
229
+ } , [ ] ) ;
230
+
198
231
return (
199
232
< div className = "flex items-center gap-4" >
200
233
< button
0 commit comments