11<!DOCTYPE html>
2+ < html lang ="en ">
23< head >
4+ < meta charset ="UTF-8 ">
5+ < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
6+ < title > WebRTC FFmpeg Get Started</ title >
7+ < style >
8+ body {
9+ font-family : Arial, sans-serif;
10+ margin : 0 ;
11+ padding : 0 ;
12+ background : # f8f9fa ;
13+ }
14+ .container {
15+ max-width : 700px ;
16+ margin : 0 auto;
17+ padding : 1rem ;
18+ display : flex;
19+ flex-direction : column;
20+ align-items : center;
21+ }
22+ video {
23+ width : 640px ;
24+ height : 480px ;
25+ background : # 000 ;
26+ border-radius : 8px ;
27+ margin-bottom : 1rem ;
28+ max-width : 100% ;
29+ max-height : 100vh ;
30+ }
31+ .controls {
32+ width : 100% ;
33+ display : flex;
34+ flex-direction : column;
35+ gap : 0.75rem ;
36+ align-items : stretch;
37+ }
38+ .button-group {
39+ display : flex;
40+ flex-direction : row;
41+ gap : 1rem ;
42+ justify-content : center;
43+ margin-top : 0.5rem ;
44+ }
45+ @media (min-width : 480px ) {
46+ .controls {
47+ flex-direction : column;
48+ gap : 0.75rem ;
49+ align-items : stretch;
50+ }
51+ }
52+ input [type = "text" ] {
53+ flex : 1 1 0 ;
54+ padding : 0.75rem ;
55+ font-size : 1rem ;
56+ border : 1px solid # ccc ;
57+ border-radius : 4px ;
58+ min-width : 0 ;
59+ }
60+ button {
61+ padding : 1rem 2rem ;
62+ font-size : 1.25rem ;
63+ min-width : 120px ;
64+ border : none;
65+ border-radius : 4px ;
66+ color : # fff ;
67+ cursor : pointer;
68+ transition : background 0.2s ;
69+ }
70+ button .btn-start {
71+ background : # 28a745 ;
72+ }
73+ button .btn-start : active {
74+ background : # 218838 ;
75+ }
76+ button .btn-close {
77+ background : # dc3545 ;
78+ }
79+ button .btn-close : active {
80+ background : # b52a37 ;
81+ }
82+ button : disabled {
83+ opacity : 0.6 ;
84+ cursor : not-allowed;
85+ }
86+ </ style >
387 < script type ="text/javascript ">
488 const WEBSOCKET_URL = "ws://127.0.0.1:8080/ws"
589 const STUN_URL = "stun:stun.cloudflare.com" ;
16100 return `${ protocol } //${ host } ${ path } ` ;
17101 }
18102
103+ function setButtonStates ( startEnabled , closeEnabled ) {
104+ document . getElementById ( 'startBtn' ) . disabled = ! startEnabled ;
105+ document . getElementById ( 'closeBtn' ) . disabled = ! closeEnabled ;
106+ }
107+
19108 async function start ( ) {
109+ // Disable both buttons while connecting
110+ setButtonStates ( false , false ) ;
20111 pc = new RTCPeerConnection ( {
21112 iceServers : [
22113 {
26117 } ) ;
27118
28119 pc . ontrack = evt => {
29- console . log ( "Adding track to video control." ) ;
30- document . querySelector ( '#videoCtl' ) . srcObject = evt . streams [ 0 ] ;
31-
32- evt . streams [ 0 ] . onunmute = ( ) => {
33- console . log ( "Adding track to video control." ) ;
34- } ;
35-
36- evt . streams [ 0 ] . onended = ( ) => {
37- console . log ( "Track ended." ) ;
38- } ;
39- }
40-
120+ console . log ( "Adding track to video control." ) ;
121+ document . querySelector ( '#videoCtl' ) . srcObject = evt . streams [ 0 ] ;
122+ evt . streams [ 0 ] . onunmute = ( ) => {
123+ console . log ( "Adding track to video control." ) ;
124+ } ;
125+ evt . streams [ 0 ] . onended = ( ) => {
126+ console . log ( "Track ended." ) ;
127+ } ;
128+ }
129+
41130 pc . onicecandidate = evt => evt . candidate && ws . send ( JSON . stringify ( evt . candidate ) ) ;
42131
43- pc . onclose = ( ) => {
44- console . log ( "pc close" ) ;
45- } ;
46-
132+ pc . onconnectionstatechange = ( ) => {
133+ console . log ( `Peer connection state changed to ${ pc . connectionState } ` ) ;
134+ connectionReady . peer = ( pc . connectionState === 'connected' ) ;
135+ updateButtonStates ( ) ;
136+ }
137+
138+ pc . onclose = ( ) => {
139+ console . log ( "pc close" ) ;
140+ setButtonStates ( true , false ) ;
141+ } ;
142+
47143 ws = new WebSocket ( document . querySelector ( '#websockurl' ) . value , [ ] ) ;
48144
145+ ws . onopen = function ( ) {
146+ // Only enable Close after connection is open
147+ setButtonStates ( false , true ) ;
148+ } ;
149+
49150 ws . onmessage = async function ( evt ) {
50151 console . log ( "WebSocket message received:" , evt . data ) ;
51152 var obj = JSON . parse ( evt . data ) ;
72173 async function closePeer ( ) {
73174 await pc ?. close ( ) ;
74175 await ws ?. close ( ) ;
176+ setButtonStates ( true , false ) ;
75177 } ;
76178 </ script >
77179</ head >
78180< body >
79-
80- < video controls autoplay ="autoplay " id ="videoCtl " width ="640 " height ="480 "> </ video >
81-
82- < div >
83- < input type ="text " id ="websockurl " size ="40 " />
84- < button type ="button " class ="btn btn-success " onclick ="start(); "> Start</ button >
85- < button type ="button " class ="btn btn-success " onclick ="closePeer(); "> Close</ button >
181+ < div class ="container ">
182+ < video controls autoplay ="autoplay " id ="videoCtl " playsinline width ="640 " height ="480 "> </ video >
183+ < form class ="controls " onsubmit ="return false; ">
184+ < input type ="text " id ="websockurl " autocomplete ="off " inputmode ="url " placeholder ="WebSocket URL " />
185+ < div class ="button-group ">
186+ < button type ="button " id ="startBtn " class ="btn-start " onclick ="start(); "> Start</ button >
187+ < button type ="button " id ="closeBtn " class ="btn-close " onclick ="closePeer(); "> Close</ button >
188+ </ div >
189+ </ form >
86190 </ div >
87-
191+ < script >
192+ document . querySelector ( '#websockurl' ) . value = getWebSocketUrl ( ) ;
193+ // Initial state: Start enabled, Close disabled
194+ document . getElementById ( 'startBtn' ) . disabled = false ;
195+ document . getElementById ( 'closeBtn' ) . disabled = true ;
196+ </ script >
88197</ body >
89-
90- < script >
91- document . querySelector ( '#websockurl' ) . value = getWebSocketUrl ( ) ;
92- </ script >
198+ </ html >
0 commit comments