diff --git a/api/index.php b/api/index.php
new file mode 100644
index 0000000..a267093
--- /dev/null
+++ b/api/index.php
@@ -0,0 +1,90 @@
+ uniqid('host_'),
+ 'participants' => [],
+ 'offer' => null,
+ 'host_candidates' => [],
+ 'participant_candidates' => [],
+ 'createdAt' => time()
+ ];
+ saveRoomData($roomCode, $roomData);
+ echo json_encode(['roomCode' => $roomCode]);
+ break;
+
+ case 'get-room-details':
+ $roomData = getRoomData($roomCode);
+ if ($roomData) {
+ echo json_encode($roomData);
+ } else {
+ http_response_code(404);
+ echo json_encode(['error' => 'Room not found']);
+ }
+ break;
+
+ case 'signal':
+ $roomData = getRoomData($roomCode);
+ if ($roomData) {
+ $signal = json_decode(file_get_contents('php://input'), true);
+ if (isset($signal['offer'])) {
+ $roomData['offer'] = $signal['offer'];
+ }
+ if (isset($signal['answer'])) {
+ $roomData['answer'] = $signal['answer'];
+ }
+ if (isset($signal['candidate'])) {
+ if ($signal['isHost']) {
+ $roomData['host_candidates'][] = $signal['candidate'];
+ } else {
+ $roomData['participant_candidates'][] = $signal['candidate'];
+ }
+ }
+ saveRoomData($roomCode, $roomData);
+ echo json_encode(['success' => true]);
+ } else {
+ http_response_code(404);
+ echo json_encode(['error' => 'Room not found']);
+ }
+ break;
+
+ default:
+ http_response_code(400);
+ echo json_encode(['error' => 'Invalid action']);
+}
diff --git a/api/rooms/31028b.json b/api/rooms/31028b.json
new file mode 100644
index 0000000..bbe5439
--- /dev/null
+++ b/api/rooms/31028b.json
@@ -0,0 +1 @@
+{"host":"host_6944616ee8bc2","participants":[],"offer":{"sdp":"v=0\r\no=- 3413294180788668252 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS 33176d75-0788-4713-a15f-b183b3a366bb\r\nm=audio 9 UDP\/TLS\/RTP\/SAVPF 111 63 9 0 8 13 110 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:\/SLi\r\na=ice-pwd:Ky5LAtZ9zlFMIeggYnCDQiaD\r\na=ice-options:trickle\r\na=fingerprint:sha-256 9F:E9:06:5D:C7:AC:6C:9B:80:C7:66:63:45:96:D3:3D:9B:C3:F5:53:7D:72:AA:F6:88:6C:BE:77:41:54:9B:EE\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time\r\na=extmap:3 http:\/\/www.ietf.org\/id\/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=sendrecv\r\na=msid:33176d75-0788-4713-a15f-b183b3a366bb 8fd2dac3-60f0-45f9-980d-54bbcaa8367f\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:111 opus\/48000\/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:63 red\/48000\/2\r\na=fmtp:63 111\/111\r\na=rtpmap:9 G722\/8000\r\na=rtpmap:0 PCMU\/8000\r\na=rtpmap:8 PCMA\/8000\r\na=rtpmap:13 CN\/8000\r\na=rtpmap:110 telephone-event\/48000\r\na=rtpmap:126 telephone-event\/8000\r\na=ssrc:2865566472 cname:Gp2sEBko0CE3nGQk\r\na=ssrc:2865566472 msid:33176d75-0788-4713-a15f-b183b3a366bb 8fd2dac3-60f0-45f9-980d-54bbcaa8367f\r\nm=video 9 UDP\/TLS\/RTP\/SAVPF 96 97 103 104 107 108 109 114 115 116 117 118 39 40 45 46 98 99 100 101 119 120 49 50 123 124 125\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:\/SLi\r\na=ice-pwd:Ky5LAtZ9zlFMIeggYnCDQiaD\r\na=ice-options:trickle\r\na=fingerprint:sha-256 9F:E9:06:5D:C7:AC:6C:9B:80:C7:66:63:45:96:D3:3D:9B:C3:F5:53:7D:72:AA:F6:88:6C:BE:77:41:54:9B:EE\r\na=setup:actpass\r\na=mid:1\r\na=extmap:14 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time\r\na=extmap:13 urn:3gpp:video-orientation\r\na=extmap:3 http:\/\/www.ietf.org\/id\/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:5 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/playout-delay\r\na=extmap:6 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/video-content-type\r\na=extmap:7 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/video-timing\r\na=extmap:8 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/color-space\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=sendrecv\r\na=msid:33176d75-0788-4713-a15f-b183b3a366bb 02335512-710c-4876-9558-5e749c8628ac\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8\/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx\/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:103 H264\/90000\r\na=rtcp-fb:103 goog-remb\r\na=rtcp-fb:103 transport-cc\r\na=rtcp-fb:103 ccm fir\r\na=rtcp-fb:103 nack\r\na=rtcp-fb:103 nack pli\r\na=fmtp:103 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:104 rtx\/90000\r\na=fmtp:104 apt=103\r\na=rtpmap:107 H264\/90000\r\na=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=rtcp-fb:107 ccm fir\r\na=rtcp-fb:107 nack\r\na=rtcp-fb:107 nack pli\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:108 rtx\/90000\r\na=fmtp:108 apt=107\r\na=rtpmap:109 H264\/90000\r\na=rtcp-fb:109 goog-remb\r\na=rtcp-fb:109 transport-cc\r\na=rtcp-fb:109 ccm fir\r\na=rtcp-fb:109 nack\r\na=rtcp-fb:109 nack pli\r\na=fmtp:109 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:114 rtx\/90000\r\na=fmtp:114 apt=109\r\na=rtpmap:115 H264\/90000\r\na=rtcp-fb:115 goog-remb\r\na=rtcp-fb:115 transport-cc\r\na=rtcp-fb:115 ccm fir\r\na=rtcp-fb:115 nack\r\na=rtcp-fb:115 nack pli\r\na=fmtp:115 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:116 rtx\/90000\r\na=fmtp:116 apt=115\r\na=rtpmap:117 H264\/90000\r\na=rtcp-fb:117 goog-remb\r\na=rtcp-fb:117 transport-cc\r\na=rtcp-fb:117 ccm fir\r\na=rtcp-fb:117 nack\r\na=rtcp-fb:117 nack pli\r\na=fmtp:117 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f\r\na=rtpmap:118 rtx\/90000\r\na=fmtp:118 apt=117\r\na=rtpmap:39 H264\/90000\r\na=rtcp-fb:39 goog-remb\r\na=rtcp-fb:39 transport-cc\r\na=rtcp-fb:39 ccm fir\r\na=rtcp-fb:39 nack\r\na=rtcp-fb:39 nack pli\r\na=fmtp:39 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f\r\na=rtpmap:40 rtx\/90000\r\na=fmtp:40 apt=39\r\na=rtpmap:45 AV1\/90000\r\na=rtcp-fb:45 goog-remb\r\na=rtcp-fb:45 transport-cc\r\na=rtcp-fb:45 ccm fir\r\na=rtcp-fb:45 nack\r\na=rtcp-fb:45 nack pli\r\na=fmtp:45 level-idx=5;profile=0;tier=0\r\na=rtpmap:46 rtx\/90000\r\na=fmtp:46 apt=45\r\na=rtpmap:98 VP9\/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx\/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 VP9\/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 profile-id=2\r\na=rtpmap:101 rtx\/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:119 H264\/90000\r\na=rtcp-fb:119 goog-remb\r\na=rtcp-fb:119 transport-cc\r\na=rtcp-fb:119 ccm fir\r\na=rtcp-fb:119 nack\r\na=rtcp-fb:119 nack pli\r\na=fmtp:119 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f\r\na=rtpmap:120 rtx\/90000\r\na=fmtp:120 apt=119\r\na=rtpmap:49 H265\/90000\r\na=rtcp-fb:49 goog-remb\r\na=rtcp-fb:49 transport-cc\r\na=rtcp-fb:49 ccm fir\r\na=rtcp-fb:49 nack\r\na=rtcp-fb:49 nack pli\r\na=fmtp:49 level-id=123;profile-id=1;tier-flag=0;tx-mode=SRST\r\na=rtpmap:50 rtx\/90000\r\na=fmtp:50 apt=49\r\na=rtpmap:123 red\/90000\r\na=rtpmap:124 rtx\/90000\r\na=fmtp:124 apt=123\r\na=rtpmap:125 ulpfec\/90000\r\na=ssrc-group:FID 4241518844 1775357996\r\na=ssrc:4241518844 cname:Gp2sEBko0CE3nGQk\r\na=ssrc:4241518844 msid:33176d75-0788-4713-a15f-b183b3a366bb 02335512-710c-4876-9558-5e749c8628ac\r\na=ssrc:1775357996 cname:Gp2sEBko0CE3nGQk\r\na=ssrc:1775357996 msid:33176d75-0788-4713-a15f-b183b3a366bb 02335512-710c-4876-9558-5e749c8628ac\r\n","type":"offer"},"host_candidates":[{"candidate":"candidate:671262058 1 udp 2122260223 192.168.1.35 61065 typ host generation 0 ufrag \/SLi network-id 1 network-cost 10","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"\/SLi"},{"candidate":"candidate:671262058 1 udp 2122260223 192.168.1.35 61064 typ host generation 0 ufrag \/SLi network-id 1 network-cost 10","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"\/SLi"},{"candidate":"candidate:2269660244 1 udp 1686052607 110.235.236.71 61064 typ srflx raddr 192.168.1.35 rport 61064 generation 0 ufrag \/SLi network-id 1 network-cost 10","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"\/SLi"},{"candidate":"candidate:3601363454 1 tcp 1518280447 192.168.1.35 9 typ host tcptype active generation 0 ufrag \/SLi network-id 1 network-cost 10","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"\/SLi"},{"candidate":"candidate:3601363454 1 tcp 1518280447 192.168.1.35 9 typ host tcptype active generation 0 ufrag \/SLi network-id 1 network-cost 10","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"\/SLi"}],"participant_candidates":[{"candidate":"candidate:3266519066 1 udp 1677729535 152.59.204.59 59044 typ srflx raddr 192.0.0.4 rport 59044 generation 0 ufrag hWzc network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"hWzc"},{"candidate":"candidate:3363013610 1 udp 2113939711 2409:40f0:4a:52c4:8000:: 34558 typ host generation 0 ufrag hWzc network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"hWzc"},{"candidate":"candidate:2105573526 1 udp 2113937151 192.0.0.4 59044 typ host generation 0 ufrag hWzc network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"hWzc"},{"candidate":"candidate:3866464576 1 udp 1677732095 2409:40f0:4a:52c4:8000:: 34558 typ srflx raddr 2409:40f0:4a:52c4:8000:: rport 34558 generation 0 ufrag hWzc network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"hWzc"},{"candidate":"candidate:616156537 1 udp 2113937151 192.0.0.4 43901 typ host generation 0 ufrag 2Yod network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"2Yod"},{"candidate":"candidate:3346552650 1 udp 1677729535 152.59.204.59 43901 typ srflx raddr 192.0.0.4 rport 43901 generation 0 ufrag 2Yod network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"2Yod"},{"candidate":"candidate:3043666873 1 udp 1677732095 2409:40f0:4a:52c4:8000:: 46599 typ srflx raddr 2409:40f0:4a:52c4:8000:: rport 46599 generation 0 ufrag 2Yod network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"2Yod"},{"candidate":"candidate:1154382749 1 udp 2113939711 2409:40f0:4a:52c4:8000:: 50291 typ host generation 0 ufrag zaa1 network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"zaa1"},{"candidate":"candidate:1791519031 1 udp 1677732095 2409:40f0:4a:52c4:8000:: 50291 typ srflx raddr 2409:40f0:4a:52c4:8000:: rport 50291 generation 0 ufrag zaa1 network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"zaa1"},{"candidate":"candidate:2126993791 1 udp 2113937151 192.0.0.4 47519 typ host generation 0 ufrag 7ZGz network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"7ZGz"},{"candidate":"candidate:1810717576 1 udp 2113939711 2409:40f0:4a:52c4:8000:: 45797 typ host generation 0 ufrag 7ZGz network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"7ZGz"},{"candidate":"candidate:3696654583 1 udp 1677729535 152.59.204.59 47519 typ srflx raddr 192.0.0.4 rport 47519 generation 0 ufrag 7ZGz network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"7ZGz"},{"candidate":"candidate:3385658929 1 udp 1677732095 2409:40f0:4a:52c4:8000:: 45797 typ srflx raddr 2409:40f0:4a:52c4:8000:: rport 45797 generation 0 ufrag 7ZGz network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"7ZGz"},{"candidate":"candidate:2589391388 1 udp 2113937151 192.0.0.4 48526 typ host generation 0 ufrag HbvZ network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"HbvZ"},{"candidate":"candidate:3113924513 1 udp 2113939711 2409:40f0:4a:52c4:8000:: 45983 typ host generation 0 ufrag HbvZ network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"HbvZ"},{"candidate":"candidate:2039963695 1 udp 1677729535 152.59.204.59 48526 typ srflx raddr 192.0.0.4 rport 48526 generation 0 ufrag HbvZ network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"HbvZ"},{"candidate":"candidate:193305820 1 udp 1677732095 2409:40f0:4a:52c4:8000:: 45983 typ srflx raddr 2409:40f0:4a:52c4:8000:: rport 45983 generation 0 ufrag HbvZ network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"HbvZ"},{"candidate":"candidate:2634220935 1 udp 2113937151 192.0.0.4 56775 typ host generation 0 ufrag O5xc network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"O5xc"},{"candidate":"candidate:1831648218 1 udp 2113939711 2409:40f0:4a:52c4:8000:: 54368 typ host generation 0 ufrag O5xc network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"O5xc"},{"candidate":"candidate:705196281 1 udp 1677732095 2409:40f0:4a:52c4:8000:: 54368 typ srflx raddr 2409:40f0:4a:52c4:8000:: rport 54368 generation 0 ufrag O5xc network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"O5xc"},{"candidate":"candidate:1800667044 1 udp 1677729535 152.59.204.59 56775 typ srflx raddr 192.0.0.4 rport 56775 generation 0 ufrag O5xc network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"O5xc"},{"candidate":"candidate:3672088379 1 udp 2113937151 192.0.0.4 46381 typ host generation 0 ufrag ppNW network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"ppNW"},{"candidate":"candidate:4178825862 1 udp 2113939711 2409:40f0:4a:52c4:8000:: 44751 typ host generation 0 ufrag ppNW network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"ppNW"},{"candidate":"candidate:958268680 1 udp 1677729535 152.59.204.59 46381 typ srflx raddr 192.0.0.4 rport 46381 generation 0 ufrag ppNW network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"ppNW"}],"createdAt":1766089070,"answer":{"sdp":"v=0\r\no=- 7045757228396801497 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=audio 9 UDP\/TLS\/RTP\/SAVPF 111 63 9 0 8 13 110 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:ppNW\r\na=ice-pwd:NM\/fzVh6G54XKgV0ReCI49wj\r\na=ice-options:trickle\r\na=fingerprint:sha-256 46:79:72:44:9C:EC:C0:22:58:A0:C4:0D:87:30:7F:55:E9:37:7D:35:E1:D8:78:0D:1C:E3:3C:7D:2B:E1:C7:2A\r\na=setup:active\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time\r\na=extmap:3 http:\/\/www.ietf.org\/id\/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=recvonly\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:111 opus\/48000\/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:63 red\/48000\/2\r\na=fmtp:63 111\/111\r\na=rtpmap:9 G722\/8000\r\na=rtpmap:0 PCMU\/8000\r\na=rtpmap:8 PCMA\/8000\r\na=rtpmap:13 CN\/8000\r\na=rtpmap:110 telephone-event\/48000\r\na=rtpmap:126 telephone-event\/8000\r\nm=video 9 UDP\/TLS\/RTP\/SAVPF 96 97 103 104 107 108 109 114 115 116 117 118 39 40 45 46 98 99 100 101 119 120 49 50 123 124 125\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:ppNW\r\na=ice-pwd:NM\/fzVh6G54XKgV0ReCI49wj\r\na=ice-options:trickle\r\na=fingerprint:sha-256 46:79:72:44:9C:EC:C0:22:58:A0:C4:0D:87:30:7F:55:E9:37:7D:35:E1:D8:78:0D:1C:E3:3C:7D:2B:E1:C7:2A\r\na=setup:active\r\na=mid:1\r\na=extmap:14 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time\r\na=extmap:13 urn:3gpp:video-orientation\r\na=extmap:3 http:\/\/www.ietf.org\/id\/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:5 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/playout-delay\r\na=extmap:6 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/video-content-type\r\na=extmap:7 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/video-timing\r\na=extmap:8 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/color-space\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=recvonly\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8\/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx\/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:103 H264\/90000\r\na=rtcp-fb:103 goog-remb\r\na=rtcp-fb:103 transport-cc\r\na=rtcp-fb:103 ccm fir\r\na=rtcp-fb:103 nack\r\na=rtcp-fb:103 nack pli\r\na=fmtp:103 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:104 rtx\/90000\r\na=fmtp:104 apt=103\r\na=rtpmap:107 H264\/90000\r\na=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=rtcp-fb:107 ccm fir\r\na=rtcp-fb:107 nack\r\na=rtcp-fb:107 nack pli\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:108 rtx\/90000\r\na=fmtp:108 apt=107\r\na=rtpmap:109 H264\/90000\r\na=rtcp-fb:109 goog-remb\r\na=rtcp-fb:109 transport-cc\r\na=rtcp-fb:109 ccm fir\r\na=rtcp-fb:109 nack\r\na=rtcp-fb:109 nack pli\r\na=fmtp:109 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:114 rtx\/90000\r\na=fmtp:114 apt=109\r\na=rtpmap:115 H264\/90000\r\na=rtcp-fb:115 goog-remb\r\na=rtcp-fb:115 transport-cc\r\na=rtcp-fb:115 ccm fir\r\na=rtcp-fb:115 nack\r\na=rtcp-fb:115 nack pli\r\na=fmtp:115 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:116 rtx\/90000\r\na=fmtp:116 apt=115\r\na=rtpmap:117 H264\/90000\r\na=rtcp-fb:117 goog-remb\r\na=rtcp-fb:117 transport-cc\r\na=rtcp-fb:117 ccm fir\r\na=rtcp-fb:117 nack\r\na=rtcp-fb:117 nack pli\r\na=fmtp:117 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f\r\na=rtpmap:118 rtx\/90000\r\na=fmtp:118 apt=117\r\na=rtpmap:39 H264\/90000\r\na=rtcp-fb:39 goog-remb\r\na=rtcp-fb:39 transport-cc\r\na=rtcp-fb:39 ccm fir\r\na=rtcp-fb:39 nack\r\na=rtcp-fb:39 nack pli\r\na=fmtp:39 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f\r\na=rtpmap:40 rtx\/90000\r\na=fmtp:40 apt=39\r\na=rtpmap:45 AV1\/90000\r\na=rtcp-fb:45 goog-remb\r\na=rtcp-fb:45 transport-cc\r\na=rtcp-fb:45 ccm fir\r\na=rtcp-fb:45 nack\r\na=rtcp-fb:45 nack pli\r\na=fmtp:45 level-idx=5;profile=0;tier=0\r\na=rtpmap:46 rtx\/90000\r\na=fmtp:46 apt=45\r\na=rtpmap:98 VP9\/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx\/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 VP9\/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 profile-id=2\r\na=rtpmap:101 rtx\/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:119 H264\/90000\r\na=rtcp-fb:119 goog-remb\r\na=rtcp-fb:119 transport-cc\r\na=rtcp-fb:119 ccm fir\r\na=rtcp-fb:119 nack\r\na=rtcp-fb:119 nack pli\r\na=fmtp:119 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f\r\na=rtpmap:120 rtx\/90000\r\na=fmtp:120 apt=119\r\na=rtpmap:49 H265\/90000\r\na=rtcp-fb:49 goog-remb\r\na=rtcp-fb:49 transport-cc\r\na=rtcp-fb:49 ccm fir\r\na=rtcp-fb:49 nack\r\na=rtcp-fb:49 nack pli\r\na=fmtp:49 level-id=93;profile-id=1;tier-flag=0;tx-mode=SRST\r\na=rtpmap:50 rtx\/90000\r\na=fmtp:50 apt=49\r\na=rtpmap:123 red\/90000\r\na=rtpmap:124 rtx\/90000\r\na=fmtp:124 apt=123\r\na=rtpmap:125 ulpfec\/90000\r\n","type":"answer"}}0000\r\n","type":"answer"}}
\ No newline at end of file
diff --git a/api/rooms/6ce484.json b/api/rooms/6ce484.json
new file mode 100644
index 0000000..7ccea8a
--- /dev/null
+++ b/api/rooms/6ce484.json
@@ -0,0 +1 @@
+{"host":"host_694462ae2d640","participants":[],"offer":null,"host_candidates":[],"participant_candidates":[],"createdAt":1766089390}
\ No newline at end of file
diff --git a/api/rooms/a4412f.json b/api/rooms/a4412f.json
new file mode 100644
index 0000000..4f6f65d
--- /dev/null
+++ b/api/rooms/a4412f.json
@@ -0,0 +1 @@
+{"host":"host_6944616e8a5c9","participants":[],"offer":null,"host_candidates":[],"participant_candidates":[],"createdAt":1766089070}
\ No newline at end of file
diff --git a/api/rooms/ab99e6.json b/api/rooms/ab99e6.json
new file mode 100644
index 0000000..c6e303c
--- /dev/null
+++ b/api/rooms/ab99e6.json
@@ -0,0 +1 @@
+{"host":"host_694462ade7734","participants":[],"offer":null,"host_candidates":[],"participant_candidates":[],"createdAt":1766089389}
\ No newline at end of file
diff --git a/api/rooms/ec098a.json b/api/rooms/ec098a.json
new file mode 100644
index 0000000..7a8074b
--- /dev/null
+++ b/api/rooms/ec098a.json
@@ -0,0 +1 @@
+{"host":"host_694461f1b5e71","participants":[],"offer":{"sdp":"v=0\r\no=- 2509079247093481205 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS 9493daa8-168a-4d2b-a602-4a19f1d29471\r\nm=audio 9 UDP\/TLS\/RTP\/SAVPF 111 63 9 0 8 13 110 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:cU+E\r\na=ice-pwd:yUtP91Ib\/ynvZR6rla0coCax\r\na=ice-options:trickle\r\na=fingerprint:sha-256 CF:2A:11:FA:5D:EF:D7:98:50:A2:2C:D5:A1:75:0A:53:16:D5:79:7B:0B:98:0A:A3:E1:CD:CD:6A:0F:B0:64:B6\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time\r\na=extmap:3 http:\/\/www.ietf.org\/id\/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=sendrecv\r\na=msid:9493daa8-168a-4d2b-a602-4a19f1d29471 33fed82d-c40c-4162-b436-13c017a57ccf\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:111 opus\/48000\/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:63 red\/48000\/2\r\na=fmtp:63 111\/111\r\na=rtpmap:9 G722\/8000\r\na=rtpmap:0 PCMU\/8000\r\na=rtpmap:8 PCMA\/8000\r\na=rtpmap:13 CN\/8000\r\na=rtpmap:110 telephone-event\/48000\r\na=rtpmap:126 telephone-event\/8000\r\na=ssrc:2174101789 cname:LXYpGhcO2rynA6J4\r\na=ssrc:2174101789 msid:9493daa8-168a-4d2b-a602-4a19f1d29471 33fed82d-c40c-4162-b436-13c017a57ccf\r\nm=video 9 UDP\/TLS\/RTP\/SAVPF 96 97 103 104 107 108 109 114 115 116 117 118 39 40 45 46 98 99 100 101 119 120 49 50 123 124 125\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:cU+E\r\na=ice-pwd:yUtP91Ib\/ynvZR6rla0coCax\r\na=ice-options:trickle\r\na=fingerprint:sha-256 CF:2A:11:FA:5D:EF:D7:98:50:A2:2C:D5:A1:75:0A:53:16:D5:79:7B:0B:98:0A:A3:E1:CD:CD:6A:0F:B0:64:B6\r\na=setup:actpass\r\na=mid:1\r\na=extmap:14 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time\r\na=extmap:13 urn:3gpp:video-orientation\r\na=extmap:3 http:\/\/www.ietf.org\/id\/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:5 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/playout-delay\r\na=extmap:6 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/video-content-type\r\na=extmap:7 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/video-timing\r\na=extmap:8 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/color-space\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=sendrecv\r\na=msid:9493daa8-168a-4d2b-a602-4a19f1d29471 fcb9464b-876d-48f4-a95a-e41a21ac4745\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8\/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx\/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:103 H264\/90000\r\na=rtcp-fb:103 goog-remb\r\na=rtcp-fb:103 transport-cc\r\na=rtcp-fb:103 ccm fir\r\na=rtcp-fb:103 nack\r\na=rtcp-fb:103 nack pli\r\na=fmtp:103 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:104 rtx\/90000\r\na=fmtp:104 apt=103\r\na=rtpmap:107 H264\/90000\r\na=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=rtcp-fb:107 ccm fir\r\na=rtcp-fb:107 nack\r\na=rtcp-fb:107 nack pli\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:108 rtx\/90000\r\na=fmtp:108 apt=107\r\na=rtpmap:109 H264\/90000\r\na=rtcp-fb:109 goog-remb\r\na=rtcp-fb:109 transport-cc\r\na=rtcp-fb:109 ccm fir\r\na=rtcp-fb:109 nack\r\na=rtcp-fb:109 nack pli\r\na=fmtp:109 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:114 rtx\/90000\r\na=fmtp:114 apt=109\r\na=rtpmap:115 H264\/90000\r\na=rtcp-fb:115 goog-remb\r\na=rtcp-fb:115 transport-cc\r\na=rtcp-fb:115 ccm fir\r\na=rtcp-fb:115 nack\r\na=rtcp-fb:115 nack pli\r\na=fmtp:115 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:116 rtx\/90000\r\na=fmtp:116 apt=115\r\na=rtpmap:117 H264\/90000\r\na=rtcp-fb:117 goog-remb\r\na=rtcp-fb:117 transport-cc\r\na=rtcp-fb:117 ccm fir\r\na=rtcp-fb:117 nack\r\na=rtcp-fb:117 nack pli\r\na=fmtp:117 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f\r\na=rtpmap:118 rtx\/90000\r\na=fmtp:118 apt=117\r\na=rtpmap:39 H264\/90000\r\na=rtcp-fb:39 goog-remb\r\na=rtcp-fb:39 transport-cc\r\na=rtcp-fb:39 ccm fir\r\na=rtcp-fb:39 nack\r\na=rtcp-fb:39 nack pli\r\na=fmtp:39 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f\r\na=rtpmap:40 rtx\/90000\r\na=fmtp:40 apt=39\r\na=rtpmap:45 AV1\/90000\r\na=rtcp-fb:45 goog-remb\r\na=rtcp-fb:45 transport-cc\r\na=rtcp-fb:45 ccm fir\r\na=rtcp-fb:45 nack\r\na=rtcp-fb:45 nack pli\r\na=fmtp:45 level-idx=5;profile=0;tier=0\r\na=rtpmap:46 rtx\/90000\r\na=fmtp:46 apt=45\r\na=rtpmap:98 VP9\/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx\/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 VP9\/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 profile-id=2\r\na=rtpmap:101 rtx\/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:119 H264\/90000\r\na=rtcp-fb:119 goog-remb\r\na=rtcp-fb:119 transport-cc\r\na=rtcp-fb:119 ccm fir\r\na=rtcp-fb:119 nack\r\na=rtcp-fb:119 nack pli\r\na=fmtp:119 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f\r\na=rtpmap:120 rtx\/90000\r\na=fmtp:120 apt=119\r\na=rtpmap:49 H265\/90000\r\na=rtcp-fb:49 goog-remb\r\na=rtcp-fb:49 transport-cc\r\na=rtcp-fb:49 ccm fir\r\na=rtcp-fb:49 nack\r\na=rtcp-fb:49 nack pli\r\na=fmtp:49 level-id=123;profile-id=1;tier-flag=0;tx-mode=SRST\r\na=rtpmap:50 rtx\/90000\r\na=fmtp:50 apt=49\r\na=rtpmap:123 red\/90000\r\na=rtpmap:124 rtx\/90000\r\na=fmtp:124 apt=123\r\na=rtpmap:125 ulpfec\/90000\r\na=ssrc-group:FID 3926586293 1017430750\r\na=ssrc:3926586293 cname:LXYpGhcO2rynA6J4\r\na=ssrc:3926586293 msid:9493daa8-168a-4d2b-a602-4a19f1d29471 fcb9464b-876d-48f4-a95a-e41a21ac4745\r\na=ssrc:1017430750 cname:LXYpGhcO2rynA6J4\r\na=ssrc:1017430750 msid:9493daa8-168a-4d2b-a602-4a19f1d29471 fcb9464b-876d-48f4-a95a-e41a21ac4745\r\n","type":"offer"},"host_candidates":[{"candidate":"candidate:3993187874 1 udp 2122260223 192.168.1.35 56902 typ host generation 0 ufrag cU+E network-id 1 network-cost 10","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"cU+E"},{"candidate":"candidate:3993187874 1 udp 2122260223 192.168.1.35 56903 typ host generation 0 ufrag cU+E network-id 1 network-cost 10","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"cU+E"},{"candidate":"candidate:2935571595 1 udp 1686052607 110.235.236.71 56903 typ srflx raddr 192.168.1.35 rport 56903 generation 0 ufrag cU+E network-id 1 network-cost 10","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"cU+E"},{"candidate":"candidate:2935571595 1 udp 1686052607 110.235.236.71 56902 typ srflx raddr 192.168.1.35 rport 56902 generation 0 ufrag cU+E network-id 1 network-cost 10","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"cU+E"},{"candidate":"candidate:2429342906 1 tcp 1518280447 192.168.1.35 9 typ host tcptype active generation 0 ufrag cU+E network-id 1 network-cost 10","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"cU+E"},{"candidate":"candidate:2429342906 1 tcp 1518280447 192.168.1.35 9 typ host tcptype active generation 0 ufrag cU+E network-id 1 network-cost 10","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"cU+E"}],"participant_candidates":[{"candidate":"candidate:3082498993 1 udp 2113939711 2409:40f0:4a:52c4:8000:: 35484 typ host generation 0 ufrag LI\/N network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"LI\/N"},{"candidate":"candidate:38285517 1 udp 2113937151 192.0.0.4 56423 typ host generation 0 ufrag LI\/N network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"LI\/N"},{"candidate":"candidate:3178991681 1 udp 1677729535 152.59.204.59 56423 typ srflx raddr 192.0.0.4 rport 56423 generation 0 ufrag LI\/N network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"LI\/N"},{"candidate":"candidate:2579308827 1 udp 1677732095 2409:40f0:4a:52c4:8000:: 35484 typ srflx raddr 2409:40f0:4a:52c4:8000:: rport 35484 generation 0 ufrag LI\/N network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"LI\/N"},{"candidate":"candidate:2882032921 1 udp 2113937151 192.0.0.4 60992 typ host generation 0 ufrag tCa7 network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"tCa7"},{"candidate":"candidate:3202504686 1 udp 2113939711 2409:40f0:4a:52c4:8000:: 60082 typ host generation 0 ufrag tCa7 network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"tCa7"},{"candidate":"candidate:156857489 1 udp 1677729535 152.59.204.59 60992 typ srflx raddr 192.0.0.4 rport 60992 generation 0 ufrag tCa7 network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"tCa7"},{"candidate":"candidate:482476631 1 udp 1677732095 2409:40f0:4a:52c4:8000:: 60082 typ srflx raddr 2409:40f0:4a:52c4:8000:: rport 60082 generation 0 ufrag tCa7 network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"tCa7"}],"createdAt":1766089201,"answer":{"sdp":"v=0\r\no=- 5233570653005384314 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=audio 9 UDP\/TLS\/RTP\/SAVPF 111 63 9 0 8 13 110 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:tCa7\r\na=ice-pwd:dN4iPBv4gISlA2OuA4PxmsZM\r\na=ice-options:trickle\r\na=fingerprint:sha-256 B1:EF:40:A2:82:D1:DF:D4:FD:78:4D:4F:51:45:07:2D:6C:9C:78:89:F8:29:47:4C:66:40:36:9B:75:A7:58:5C\r\na=setup:active\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time\r\na=extmap:3 http:\/\/www.ietf.org\/id\/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=recvonly\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:111 opus\/48000\/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:63 red\/48000\/2\r\na=fmtp:63 111\/111\r\na=rtpmap:9 G722\/8000\r\na=rtpmap:0 PCMU\/8000\r\na=rtpmap:8 PCMA\/8000\r\na=rtpmap:13 CN\/8000\r\na=rtpmap:110 telephone-event\/48000\r\na=rtpmap:126 telephone-event\/8000\r\nm=video 9 UDP\/TLS\/RTP\/SAVPF 96 97 103 104 107 108 109 114 115 116 117 118 39 40 45 46 98 99 100 101 119 120 49 50 123 124 125\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:tCa7\r\na=ice-pwd:dN4iPBv4gISlA2OuA4PxmsZM\r\na=ice-options:trickle\r\na=fingerprint:sha-256 B1:EF:40:A2:82:D1:DF:D4:FD:78:4D:4F:51:45:07:2D:6C:9C:78:89:F8:29:47:4C:66:40:36:9B:75:A7:58:5C\r\na=setup:active\r\na=mid:1\r\na=extmap:14 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time\r\na=extmap:13 urn:3gpp:video-orientation\r\na=extmap:3 http:\/\/www.ietf.org\/id\/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:5 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/playout-delay\r\na=extmap:6 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/video-content-type\r\na=extmap:7 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/video-timing\r\na=extmap:8 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/color-space\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=recvonly\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8\/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx\/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:103 H264\/90000\r\na=rtcp-fb:103 goog-remb\r\na=rtcp-fb:103 transport-cc\r\na=rtcp-fb:103 ccm fir\r\na=rtcp-fb:103 nack\r\na=rtcp-fb:103 nack pli\r\na=fmtp:103 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:104 rtx\/90000\r\na=fmtp:104 apt=103\r\na=rtpmap:107 H264\/90000\r\na=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=rtcp-fb:107 ccm fir\r\na=rtcp-fb:107 nack\r\na=rtcp-fb:107 nack pli\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:108 rtx\/90000\r\na=fmtp:108 apt=107\r\na=rtpmap:109 H264\/90000\r\na=rtcp-fb:109 goog-remb\r\na=rtcp-fb:109 transport-cc\r\na=rtcp-fb:109 ccm fir\r\na=rtcp-fb:109 nack\r\na=rtcp-fb:109 nack pli\r\na=fmtp:109 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:114 rtx\/90000\r\na=fmtp:114 apt=109\r\na=rtpmap:115 H264\/90000\r\na=rtcp-fb:115 goog-remb\r\na=rtcp-fb:115 transport-cc\r\na=rtcp-fb:115 ccm fir\r\na=rtcp-fb:115 nack\r\na=rtcp-fb:115 nack pli\r\na=fmtp:115 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:116 rtx\/90000\r\na=fmtp:116 apt=115\r\na=rtpmap:117 H264\/90000\r\na=rtcp-fb:117 goog-remb\r\na=rtcp-fb:117 transport-cc\r\na=rtcp-fb:117 ccm fir\r\na=rtcp-fb:117 nack\r\na=rtcp-fb:117 nack pli\r\na=fmtp:117 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f\r\na=rtpmap:118 rtx\/90000\r\na=fmtp:118 apt=117\r\na=rtpmap:39 H264\/90000\r\na=rtcp-fb:39 goog-remb\r\na=rtcp-fb:39 transport-cc\r\na=rtcp-fb:39 ccm fir\r\na=rtcp-fb:39 nack\r\na=rtcp-fb:39 nack pli\r\na=fmtp:39 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f\r\na=rtpmap:40 rtx\/90000\r\na=fmtp:40 apt=39\r\na=rtpmap:45 AV1\/90000\r\na=rtcp-fb:45 goog-remb\r\na=rtcp-fb:45 transport-cc\r\na=rtcp-fb:45 ccm fir\r\na=rtcp-fb:45 nack\r\na=rtcp-fb:45 nack pli\r\na=fmtp:45 level-idx=5;profile=0;tier=0\r\na=rtpmap:46 rtx\/90000\r\na=fmtp:46 apt=45\r\na=rtpmap:98 VP9\/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx\/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 VP9\/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 profile-id=2\r\na=rtpmap:101 rtx\/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:119 H264\/90000\r\na=rtcp-fb:119 goog-remb\r\na=rtcp-fb:119 transport-cc\r\na=rtcp-fb:119 ccm fir\r\na=rtcp-fb:119 nack\r\na=rtcp-fb:119 nack pli\r\na=fmtp:119 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f\r\na=rtpmap:120 rtx\/90000\r\na=fmtp:120 apt=119\r\na=rtpmap:49 H265\/90000\r\na=rtcp-fb:49 goog-remb\r\na=rtcp-fb:49 transport-cc\r\na=rtcp-fb:49 ccm fir\r\na=rtcp-fb:49 nack\r\na=rtcp-fb:49 nack pli\r\na=fmtp:49 level-id=93;profile-id=1;tier-flag=0;tx-mode=SRST\r\na=rtpmap:50 rtx\/90000\r\na=fmtp:50 apt=49\r\na=rtpmap:123 red\/90000\r\na=rtpmap:124 rtx\/90000\r\na=fmtp:124 apt=123\r\na=rtpmap:125 ulpfec\/90000\r\n","type":"answer"}}
\ No newline at end of file
diff --git a/api/rooms/f38da9.json b/api/rooms/f38da9.json
new file mode 100644
index 0000000..4b2113a
--- /dev/null
+++ b/api/rooms/f38da9.json
@@ -0,0 +1 @@
+{"host":"host_694461f172d06","participants":[],"offer":null,"host_candidates":[],"participant_candidates":[],"createdAt":1766089201}
\ No newline at end of file
diff --git a/assets/css/custom.css b/assets/css/custom.css
new file mode 100644
index 0000000..828c99f
--- /dev/null
+++ b/assets/css/custom.css
@@ -0,0 +1,36 @@
+
+body {
+ background-color: #F4F7F6;
+ background-image: linear-gradient(135deg, rgba(0,123,255,0.05) 0%, rgba(255,255,255,0) 25%);
+ font-family: 'Georgia', serif;
+}
+
+.display-4 {
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+ font-weight: 700;
+}
+
+.card {
+ border: 1px solid rgba(0,0,0,0.08);
+ box-shadow: 0 4px 12px rgba(0,0,0,0.06);
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
+}
+
+.card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 8px 24px rgba(0,0,0,0.08);
+}
+
+.form-control-lg {
+ text-align: center;
+ font-family: monospace;
+ letter-spacing: 0.5em;
+}
+
+.btn-lg {
+ padding: 0.75rem 1.5rem;
+}
+
+.toast-container {
+ z-index: 1090;
+}
diff --git a/assets/js/main.js b/assets/js/main.js
new file mode 100644
index 0000000..26d2434
--- /dev/null
+++ b/assets/js/main.js
@@ -0,0 +1,346 @@
+document.addEventListener('DOMContentLoaded', function () {
+ const API_URL = './api/';
+
+ // --- Main UI Elements ---
+ const selectionContainer = document.getElementById('selection-container');
+ const hostPanelContainer = document.getElementById('host-panel-container');
+ const participantPanelContainer = document.getElementById('participant-panel-container');
+ const toastContainer = document.querySelector('.toast-container');
+
+ // --- Room Joining Elements ---
+ const joinCodeInput = document.getElementById('join-code');
+ const joinRoomBtn = document.getElementById('join-room-btn');
+
+ // --- Room Creation Elements ---
+ const createRoomBtn = document.getElementById('create-room-btn');
+
+ // --- Host Panel Elements ---
+ const hostRoomCodeDisplay = document.getElementById('host-room-code');
+ const hostStatusDisplay = document.getElementById('host-status');
+ const startStreamingBtn = document.getElementById('start-streaming-btn');
+ const deleteRoomBtn = document.getElementById('delete-room-btn');
+
+ // --- Participant Panel Elements ---
+ const participantStatusDisplay = document.getElementById('participant-status');
+ const participantAudio = document.getElementById('participant-audio');
+ const leaveRoomBtn = document.getElementById('leave-room-btn');
+
+ // --- State Management ---
+ let localAudioStream = null;
+ let peerConnection = null;
+ let roomCode = null;
+ let isHost = false;
+
+ // ===================================================================
+ // 1. EVENT LISTENERS
+ // ===================================================================
+
+ if (joinCodeInput) {
+ joinCodeInput.addEventListener('input', () => {
+ joinRoomBtn.disabled = joinCodeInput.value.length < 6;
+ });
+ }
+
+ if (joinRoomBtn) {
+ joinRoomBtn.addEventListener('click', () => {
+ const code = joinCodeInput.value.toLowerCase();
+ joinRoom(code);
+ });
+ }
+
+ if (createRoomBtn) {
+ createRoomBtn.addEventListener('click', createRoom);
+ }
+
+ if (startStreamingBtn) {
+ startStreamingBtn.addEventListener('click', () => {
+ if (localAudioStream) {
+ stopStreaming();
+ } else {
+ startStreaming();
+ }
+ });
+ }
+
+ if (deleteRoomBtn) {
+ deleteRoomBtn.addEventListener('click', () => {
+ stopStreaming();
+ // TODO: Add server-side room deletion
+ hostPanelContainer.classList.add('d-none');
+ selectionContainer.classList.remove('d-none');
+ showToast('Room has been closed.');
+ });
+ }
+
+ if (leaveRoomBtn) {
+ leaveRoomBtn.addEventListener('click', () => {
+ if (peerConnection) {
+ peerConnection.close();
+ }
+ participantPanelContainer.classList.add('d-none');
+ selectionContainer.classList.remove('d-none');
+ showToast('You have left the room.');
+ });
+ }
+
+ // ===================================================================
+ // 2. API & ROOM MANAGEMENT
+ // ===================================================================
+
+ async function createRoom() {
+ try {
+ const response = await fetch(`${API_URL}?action=create-room`);
+ const data = await response.json();
+ if (data.roomCode) {
+ roomCode = data.roomCode;
+ isHost = true;
+ hostRoomCodeDisplay.textContent = roomCode;
+ selectionContainer.classList.add('d-none');
+ hostPanelContainer.classList.remove('d-none');
+ showToast('Your room is live!', 'success');
+ listenForSignals();
+ }
+ } catch (error) {
+ console.error('Error creating room:', error);
+ showToast('Could not create room. Please try again.', 'danger');
+ }
+ }
+
+ async function joinRoom(code) {
+ try {
+ const response = await fetch(`${API_URL}?action=get-room-details&roomCode=${code}`);
+ if (!response.ok) throw new Error('Room not found');
+
+ const data = await response.json();
+ roomCode = code;
+ isHost = false;
+
+ selectionContainer.classList.add('d-none');
+ participantPanelContainer.classList.remove('d-none');
+ updateParticipantStatus('joining');
+
+ await setupParticipantConnection(data);
+ listenForSignals();
+
+ } catch (error) {
+ console.error('Error joining room:', error);
+ showToast(`Could not join room: ${error.message}`, 'danger');
+ }
+ }
+
+ // ===================================================================
+ // 3. CORE STREAMING LOGIC (WebRTC)
+ // ===================================================================
+
+ async function startStreaming() {
+ updateHostStatus('connecting');
+ try {
+ const stream = await navigator.mediaDevices.getDisplayMedia({ audio: true, video: true });
+
+ if (stream.getAudioTracks().length === 0) {
+ stream.getTracks().forEach(track => track.stop());
+ showToast('No audio was shared. Please enable audio sharing.', 'danger');
+ updateHostStatus('error');
+ return;
+ }
+
+ localAudioStream = stream;
+ updateHostStatus('streaming');
+ showToast('Streaming started! Waiting for a participant...', 'success');
+
+ stream.getAudioTracks()[0].onended = () => stopStreaming();
+
+ // --- WebRTC Host Logic ---
+ peerConnection = createPeerConnection();
+ stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
+
+ const offer = await peerConnection.createOffer();
+ await peerConnection.setLocalDescription(offer);
+
+ await signal({ offer });
+
+ } catch (err) {
+ console.error('Streaming Error:', err);
+ updateHostStatus('error');
+ showToast('Could not start streaming.', 'danger');
+ }
+ }
+
+ function stopStreaming() {
+ if (localAudioStream) {
+ localAudioStream.getTracks().forEach(track => track.stop());
+ localAudioStream = null;
+ }
+ if (peerConnection) {
+ peerConnection.close();
+ peerConnection = null;
+ }
+ updateHostStatus('idle');
+ console.log('Streaming stopped.');
+ }
+
+ async function setupParticipantConnection(roomData) {
+ peerConnection = createPeerConnection();
+ peerConnection.ontrack = (event) => {
+ updateParticipantStatus('playing');
+ participantAudio.srcObject = event.streams[0];
+ participantAudio.play();
+ };
+
+ await peerConnection.setRemoteDescription(new RTCSessionDescription(roomData.offer));
+ const answer = await peerConnection.createAnswer();
+ await peerConnection.setLocalDescription(answer);
+
+ await signal({ answer });
+
+ // Add host's ICE candidates
+ if (roomData.host_candidates) {
+ for (const candidate of roomData.host_candidates) {
+ await peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
+ }
+ }
+ }
+
+
+ function createPeerConnection() {
+ const pc = new RTCPeerConnection({
+ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
+ });
+
+ pc.onicecandidate = event => {
+ if (event.candidate) {
+ signal({ candidate: event.candidate });
+ }
+ };
+
+ pc.oniceconnectionstatechange = () => {
+ console.log('ICE Connection State:', pc.iceConnectionState);
+ if (isHost) {
+ if (pc.iceConnectionState === 'connected') {
+ showToast('A participant has connected!', 'success');
+ }
+ } else {
+ if (pc.iceConnectionState === 'failed' || pc.iceConnectionState === 'disconnected') {
+ updateParticipantStatus('error');
+ }
+ }
+ };
+
+ return pc;
+ }
+
+ async function signal(data) {
+ await fetch(`${API_URL}?action=signal&roomCode=${roomCode}`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ ...data, isHost })
+ });
+ }
+
+ // Basic polling to get signals from the other party
+ async function listenForSignals() {
+ const interval = setInterval(async () => {
+ try {
+ const response = await fetch(`${API_URL}?action=get-room-details&roomCode=${roomCode}`);
+ const data = await response.json();
+
+ if (peerConnection && peerConnection.signalingState === 'stable') return;
+
+
+ if (isHost && data.answer && peerConnection.signalingState !== 'stable') {
+ await peerConnection.setRemoteDescription(new RTCSessionDescription(data.answer));
+ // Add participant's ICE candidates
+ if (data.participant_candidates) {
+ for (const candidate of data.participant_candidates) {
+ await peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
+ }
+ }
+ }
+
+ } catch (error) {
+ // console.error('Signaling listener error:', error);
+ }
+ }, 3000);
+ // Note: In a real app, you'd use WebSockets instead of polling.
+ }
+
+
+ // ===================================================================
+ // 4. UI HELPER FUNCTIONS
+ // ===================================================================
+
+ function updateHostStatus(status) {
+ startStreamingBtn.disabled = false;
+ let content = '';
+ switch (status) {
+ case 'connecting':
+ startStreamingBtn.disabled = true;
+ content = `
Requesting permission...`;
+ hostStatusDisplay.className = 'alert alert-warning';
+ break;
+ case 'streaming':
+ startStreamingBtn.innerHTML = ' Stop Streaming';
+ startStreamingBtn.className = 'btn btn-danger btn-lg';
+ content = ` Now streaming... Waiting for connections.`;
+ hostStatusDisplay.className = 'alert alert-success';
+ break;
+ case 'error':
+ content = ' Could not start streaming.';
+ hostStatusDisplay.className = 'alert alert-danger';
+ break;
+ case 'idle':
+ default:
+ startStreamingBtn.innerHTML = ' Start Streaming';
+ startStreamingBtn.className = 'btn btn-success btn-lg';
+ content = 'Not currently streaming.';
+ hostStatusDisplay.className = 'alert alert-info';
+ break;
+ }
+ hostStatusDisplay.innerHTML = content;
+ }
+
+ function updateParticipantStatus(status) {
+ let content = '';
+ switch (status) {
+ case 'joining':
+ content = `Connecting to host...
`;
+ participantStatusDisplay.className = 'alert alert-info';
+ break;
+ case 'playing':
+ content = ` Live audio is playing.`;
+ participantStatusDisplay.className = 'alert alert-success';
+ break;
+ case 'error':
+ content = ' Connection lost. Please try rejoining.';
+ participantStatusDisplay.className = 'alert alert-danger';
+ if (participantAudio.srcObject) {
+ participantAudio.srcObject.getTracks().forEach(track => track.stop());
+ participantAudio.srcObject = null;
+ }
+ break;
+ }
+ participantStatusDisplay.innerHTML = content;
+ }
+
+ function showToast(message, type = 'info') {
+ if (!toastContainer) return;
+ const bgClass = {
+ info: 'bg-primary',
+ success: 'bg-success',
+ danger: 'bg-danger'
+ }[type] || 'bg-primary';
+ const toastEl = document.createElement('div');
+ toastEl.className = `toast align-items-center text-white ${bgClass} border-0`;
+ toastEl.setAttribute('role', 'alert');
+ toastEl.innerHTML = `
+
+ `;
+ toastContainer.appendChild(toastEl);
+ const toast = new bootstrap.Toast(toastEl, { delay: 5000 });
+ toast.show();
+ toastEl.addEventListener('hidden.bs.toast', () => toastEl.remove());
+ }
+});
\ No newline at end of file
diff --git a/index.php b/index.php
index 7205f3d..bc51af0 100644
--- a/index.php
+++ b/index.php
@@ -1,150 +1,131 @@
-
+
-
-
- New Style
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
Analyzing your requirements and generating your website…
-
- Loading…
-
-
= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-
This page will update automatically as the plan is implemented.
-
Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
-
-
-
+
+
+
+
+
+
+ LiveAudio Rooms
+ Share your device audio in real-time. Create a room or join with a code.
+
+
+
+
+
+
+
+
+
+
Create a Room
+
Become the host and stream audio to your friends.
+
+
+
+
+
+
+
+
+
+
+
Join a Room
+
Enter the 6-character code to start listening.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Your Room is Live!
+
Share this code with your participants:
+
+
+
+
+ Not currently streaming. Click "Start Streaming" to begin.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Waiting for audio to start...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+