4444 .visualizer { width : 100% ; height : 100px ; margin-top : 2rem ; opacity : 0.5 ; }
4545
4646 # connection-state { font-size : 0.8rem ; color : var (--secondary ); margin-top : 1rem ; text-transform : uppercase; letter-spacing : 0.1em ; }
47+
48+ .debug-panel {
49+ margin-top : 3rem ; padding : 1.5rem ; background : rgba (0 , 0 , 0 , 0.3 ); border-radius : 20px ;
50+ text-align : left; font-family : monospace; font-size : 0.75rem ; color : # 10b981 ;
51+ max-height : 200px ; overflow-y : auto; border : 1px solid var (--border );
52+ }
53+ .debug-panel div { margin-bottom : 0.25rem ; border-bottom : 1px solid rgba (255 , 255 , 255 , 0.05 ); padding-bottom : 0.25rem ; }
54+ .debug-label { color : var (--secondary ); font-weight : bold; }
4755 </ style >
4856</ head >
4957< body >
@@ -58,54 +66,101 @@ <h1>{{.Stream.Name}}</h1>
5866
5967 < div id ="connection-state "> Ready</ div >
6068 < canvas id ="viz " class ="visualizer "> </ canvas >
69+
70+ < div class ="debug-panel " id ="debug-log ">
71+ < div > < span class ="debug-label "> [SYSTEM]</ span > Debug console initialized.</ div >
72+ </ div >
6173 </ div >
6274
6375 < script >
6476 lucide . createIcons ( ) ;
6577 let pc ;
6678 const mount = "{{.Stream.MountName}}" ;
6779
80+ function log ( label , msg ) {
81+ const el = document . getElementById ( 'debug-log' ) ;
82+ const div = document . createElement ( 'div' ) ;
83+ div . innerHTML = `<span class="debug-label">[${ label } ]</span> ${ msg } ` ;
84+ el . prepend ( div ) ;
85+ }
86+
6887 async function startWebRTC ( ) {
6988 const btn = document . getElementById ( 'start-btn' ) ;
7089 const stateEl = document . getElementById ( 'connection-state' ) ;
7190
7291 btn . disabled = true ;
7392 stateEl . textContent = "Connecting..." ;
93+ log ( 'CORE' , 'Starting RTCPeerConnection...' ) ;
7494
7595 pc = new RTCPeerConnection ( {
7696 iceServers : [ { urls : 'stun:stun.l.google.com:19302' } ]
7797 } ) ;
7898
99+ pc . onicecandidate = ( e ) => {
100+ if ( e . candidate ) log ( 'ICE' , `Found candidate: ${ e . candidate . protocol } ${ e . candidate . address } ` ) ;
101+ } ;
102+
103+ pc . onicegatheringstatechange = ( ) => log ( 'ICE' , `Gathering State: ${ pc . iceGatheringState } ` ) ;
104+ pc . oniceconnectionstatechange = ( ) => log ( 'ICE' , `Conn State: ${ pc . iceConnectionState } ` ) ;
105+ pc . onsignalingstatechange = ( ) => log ( 'SIG' , `Signaling State: ${ pc . signalingState } ` ) ;
106+
79107 pc . ontrack = ( event ) => {
108+ log ( 'CORE' , 'Audio track received!' ) ;
80109 const stream = event . streams [ 0 ] ;
81- const audio = new Audio ( ) ;
110+ let audio = document . getElementById ( 'webrtc-audio' ) ;
111+ if ( ! audio ) {
112+ audio = document . createElement ( 'audio' ) ;
113+ audio . id = 'webrtc-audio' ;
114+ audio . style . display = 'none' ;
115+ document . body . appendChild ( audio ) ;
116+ }
82117 audio . srcObject = stream ;
83- audio . play ( ) ;
118+ audio . play ( ) . then ( ( ) => log ( 'CORE' , 'Playback started successfully' ) ) . catch ( e => log ( 'ERROR' , `Playback failed: ${ e . message } ` ) ) ;
84119 initVisualizer ( stream ) ;
85120 } ;
86121
87122 pc . onconnectionstatechange = ( ) => {
88123 stateEl . textContent = pc . connectionState ;
124+ log ( 'CORE' , `Connection State: ${ pc . connectionState } ` ) ;
89125 if ( pc . connectionState === 'connected' ) {
90126 btn . innerHTML = '<i data-lucide="volume-2"></i>' ;
91127 lucide . createIcons ( ) ;
92128 }
129+ if ( pc . connectionState === 'failed' ) {
130+ stateEl . textContent = "Connection Failed" ;
131+ btn . disabled = false ;
132+ btn . innerHTML = '<i data-lucide="refresh-cw"></i>' ;
133+ lucide . createIcons ( ) ;
134+ }
93135 } ;
94136
95137 // Add receiver for audio
96138 pc . addTransceiver ( 'audio' , { direction : 'recvonly' } ) ;
139+ log ( 'SIG' , 'Added recvonly audio transceiver' ) ;
97140
98141 const offer = await pc . createOffer ( ) ;
142+ log ( 'SIG' , 'SDP Offer created' ) ;
99143 await pc . setLocalDescription ( offer ) ;
100144
145+ log ( 'HTTP' , `Sending offer to server for mount ${ mount } ...` ) ;
101146 const response = await fetch ( `/webrtc/offer?mount=${ encodeURIComponent ( mount ) } ` , {
102147 method : 'POST' ,
103148 body : JSON . stringify ( pc . localDescription ) ,
104149 headers : { 'Content-Type' : 'application/json' }
105150 } ) ;
106151
152+ if ( ! response . ok ) {
153+ const err = await response . text ( ) ;
154+ stateEl . textContent = "Error: " + err ;
155+ log ( 'ERROR' , `Signaling failed: ${ err } ` ) ;
156+ btn . disabled = false ;
157+ return ;
158+ }
159+
107160 const answer = await response . json ( ) ;
161+ log ( 'SIG' , 'SDP Answer received from server' ) ;
108162 await pc . setRemoteDescription ( answer ) ;
163+ log ( 'CORE' , 'Remote description set, awaiting ICE...' ) ;
109164 }
110165
111166 function initVisualizer ( stream ) {
0 commit comments