diff --git a/index.html b/index.html index d0e54cb..86c28b7 100644 --- a/index.html +++ b/index.html @@ -2,62 +2,58 @@ - libdatachannel media example - + CrossDesk Web Client + -

libdatachannel streamer example client

+
+

CrossDesk Web Client

-

Options

-
- - +
+

连接设置

+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+

ICE 连接状态:

+
+
+

ICE 收集状态:

+
+
+

信令状态:

+
+
+ + + +
+

数据通道

+

+      
- - - -

State

-

ICE Connection state:

-

ICE Gathering state:

-

Signaling state:

- - - -

Data Channel

-

-
-    

SDP

- -

Offer

-

-
-    

Answer

-

 
     
   
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..fd27d37
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,120 @@
+:root {
+  --primary-color: #2196f3;
+  --background-color: #f5f5f5;
+  --border-radius: 8px;
+}
+
+body {
+  margin: 0;
+  padding: 20px;
+  font-family: "Segoe UI", -apple-system, BlinkMacSystemFont, sans-serif;
+  background-color: var(--background-color);
+  color: #333;
+}
+
+.container {
+  max-width: 1280px;
+  margin: 0 auto;
+  padding: 20px;
+}
+
+h1 {
+  color: var(--primary-color);
+  text-align: center;
+  margin-bottom: 30px;
+}
+
+h2 {
+  color: #444;
+  margin-top: 30px;
+}
+
+.card {
+  background: white;
+  border-radius: var(--border-radius);
+  padding: 20px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  margin-bottom: 20px;
+}
+
+.option {
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+}
+
+.option label {
+  min-width: 120px;
+  color: #666;
+}
+
+input[type="text"],
+input[type="password"] {
+  padding: 8px 12px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  width: 200px;
+  font-size: 14px;
+}
+
+button {
+  background-color: var(--primary-color);
+  color: white;
+  border: none;
+  padding: 10px 20px;
+  border-radius: 4px;
+  cursor: pointer;
+  font-weight: 500;
+  transition: background-color 0.2s;
+}
+
+button:hover {
+  background-color: #1976d2;
+}
+
+button:disabled {
+  background-color: #ccc;
+  cursor: not-allowed;
+}
+
+#disconnect {
+  background-color: #f44336;
+}
+
+#disconnect:hover {
+  background-color: #d32f2f;
+}
+
+.states {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 15px;
+}
+
+.state-item {
+  background: white;
+  padding: 15px;
+  border-radius: var(--border-radius);
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+#media {
+  background: #222;
+  border-radius: var(--border-radius);
+  padding: 20px;
+  margin-top: 20px;
+}
+
+video {
+  width: 100%;
+  border-radius: 4px;
+}
+
+#data-channel {
+  background: #f8f9fa;
+  border-radius: var(--border-radius);
+  padding: 15px;
+  font-family: monospace;
+  height: 200px;
+  border: 1px solid #ddd;
+}
\ No newline at end of file
diff --git a/web_client.js b/web_client.js
index 10c2662..221a7f5 100644
--- a/web_client.js
+++ b/web_client.js
@@ -4,12 +4,10 @@ const iceConnectionLog = document.getElementById('ice-connection-state'),
   dataChannelLog = document.getElementById('data-channel');
 
 clientId = "000000";
-transmissionId = "475319798"
-transmissionPwd = "111111"
 const websocket = new WebSocket('wss://api.crossdesk.cn:9090');
 
 websocket.onopen = () => {
-  document.getElementById('start').disabled = false;
+  document.getElementById('connect').disabled = false;
   sendLogin();
 }
 
@@ -23,7 +21,6 @@ websocket.onmessage = async (evt) => {
     console.log("logged in as " + clientId);
 
   } else if (message.type == "offer") {
-    document.getElementById('offer-sdp').textContent = message.sdp;
     await handleOffer(message)
   }
 }
@@ -56,37 +53,33 @@ function createPeerConnection() {
   signalingLog.textContent = pc.signalingState;
 
   // Receive audio/video track
-  // Receive audio/video track — 更健壮的处理
+  // More robust handling of audio/video track
   pc.ontrack = (evt) => {
     console.log('ontrack event:', evt);
     const video = document.getElementById('video');
 
-    // 只处理 video track
+    // Only handle video track
     if (evt.track.kind !== 'video') return;
 
-    // 如果已有流,就别再重新设置 srcObject
+    // Don't reset srcObject if stream already exists
     if (!video.srcObject) {
-      const stream = evt.streams && evt.streams[0]
-        ? evt.streams[0]
-        : new MediaStream([evt.track]);
-
+      const stream = evt.streams && evt.streams[0] ? evt.streams[0] : new MediaStream([evt.track]);
       video.srcObject = stream;
       video.muted = true;
       video.playsInline = true;
-
-      // 延迟一点再播放,避免 srcObject 切换导致 AbortError
+      // Set delayed playback
       setTimeout(() => {
         video.play().catch(err => {
           console.warn('video.play() failed:', err);
         });
-      }, 200);
-
+      }, 500);
       console.log('attached new video stream:', stream.id);
     } else {
-      // 如果已有流,则只添加 track
+      // Add track directly to existing stream
       video.srcObject.addTrack(evt.track);
       console.log('added track to existing stream:', evt.track.id);
     }
+
   };
 
   // Receive data channel
@@ -148,13 +141,12 @@ async function sendAnswer(pc) {
   await waitGatheringComplete();
 
   const answer = pc.localDescription;
-  document.getElementById('answer-sdp').textContent = answer.sdp;
 
   msg = JSON.stringify({
     type: "answer",
-    transmission_id: transmissionId,
+    transmission_id: getTransmissionId(),
     user_id: clientId,
-    remote_user_id: transmissionId,
+    remote_user_id: getTransmissionId(),
     sdp: answer.sdp,
   });
   console.log("send answer: " + msg);
@@ -176,25 +168,45 @@ function sendLogin() {
   console.log("send login");
 }
 
+function leaveTransmission() {
+  websocket.send(JSON.stringify({
+    type: "leave_transmission",
+    user_id: clientId,
+    transmission_id: getTransmissionId(),
+  }));
+}
+
+function getTransmissionId() {
+  return document.getElementById('transmission-id').value;
+}
+
+// Add function to get password
+function getTransmissionPwd() {
+  return document.getElementById('transmission-pwd').value;
+}
+
+// Modify sendRequest function to use dynamic password
 function sendRequest() {
   websocket.send(JSON.stringify({
     type: "join_transmission",
     user_id: clientId,
-    transmission_id: transmissionId + '@' + transmissionPwd,
+    transmission_id: getTransmissionId() + '@' + getTransmissionPwd(),
   }));
 }
 
-function start() {
-  document.getElementById('start').style.display = 'none';
-  document.getElementById('stop').style.display = 'inline-block';
+function connect() {
+  document.getElementById('connect').style.display = 'none';
+  document.getElementById('disconnect').style.display = 'inline-block';
   document.getElementById('media').style.display = 'block';
   sendRequest();
 }
 
-function stop() {
-  document.getElementById('stop').style.display = 'none';
+function disconnect() {
+  document.getElementById('disconnect').style.display = 'none';
   document.getElementById('media').style.display = 'none';
-  document.getElementById('start').style.display = 'inline-block';
+  document.getElementById('connect').style.display = 'inline-block';
+
+  leaveTransmission();
 
   // close data channel
   if (dc) {