Edit Code · SiloConnect Video Chat
Back to CMS
Open Page
Source Code Viewer
9184 bytes loaded
<?php $pageTitle = "SiloTalk Meetings"; $logo = "/silocloud/assets/images/SiloTalk.png"; require __DIR__ . "/../silotalk/partials/customer-session.php"; $siloNumber = $_GET["silo_number"] ?? ($_COOKIE["public_silo_number"] ?? "S3600000"); $meetingCode = $_GET["meeting_code"] ?? ""; $threadUid = $_GET["thread_uid"] ?? "thr_olivia"; ?> <!doctype html> <html lang="en"> <head><link rel="icon" type="image/png" href="/silocloud/assets/images/cloud.png"> <meta charset="utf-8"> <title>SiloTalk Meetings</title> <link rel="apple-touch-icon" href="/silocloud/assets/images/SiloTalk.png"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/silocloud/apps/silotalk/assets/silotalk-suite.css?v=20260528"> <style> .meet-app{height:100vh;display:grid;grid-template-columns:246px 1fr 370px;background:#f5f7fb} .sidebarx{background:#fff;border-right:1px solid #e3e8f0;padding:18px} .stage{padding:16px;display:grid;grid-template-rows:72px 1fr 82px;gap:14px;min-width:0} .stage-top{background:#fff;border:1px solid #e3e8f0;border-radius:10px;box-shadow:0 10px 28px rgba(15,23,42,.06);display:flex;align-items:center;justify-content:space-between;padding:0 18px} .video-grid{display:grid;grid-template-columns:repeat(2,minmax(220px,1fr));gap:14px;min-height:0} .tile{background:linear-gradient(135deg,#111827,#334155);border:1px solid #1f2937;border-radius:10px;color:#fff;display:flex;align-items:center;justify-content:center;position:relative;min-height:220px;font-size:46px;font-weight:900} .tile small{position:absolute;left:14px;bottom:14px;background:rgba(0,0,0,.45);padding:7px 10px;border-radius:8px;font-size:13px} .tile video{width:100%;height:100%;object-fit:cover;border-radius:10px} .controls{background:#fff;border:1px solid #e3e8f0;border-radius:10px;display:flex;align-items:center;justify-content:center;gap:12px} .ctrl{height:44px;border:1px solid #d9e1ec;background:#fff;border-radius:8px;font-weight:800;padding:0 14px;cursor:pointer} .ctrl.red{background:#ef4444;color:#fff;border-color:#ef4444} .ctrl.green{background:#16a34a;color:#fff;border-color:#16a34a} .panel{background:#fff;border-left:1px solid #e3e8f0;padding:14px;display:grid;grid-template-rows:auto auto 1fr auto;gap:12px;min-height:0} .messages{overflow:auto;border:1px solid #e3e8f0;border-radius:10px;padding:12px;background:#fbfcff} .meeting-list{overflow:auto;border:1px solid #e3e8f0;border-radius:10px;padding:10px;max-height:230px} pre{white-space:pre-wrap;background:#f7f9fc;border:1px solid #e3e8f0;border-radius:8px;padding:10px;max-height:170px;overflow:auto} </style> </head> <body> <div class="meet-app app" data-user-uid="<?=htmlspecialchars($userUid)?>" data-device-uid="browser_meeting"> <aside class="sidebarx"> <div class="brand"><img src="<?=htmlspecialchars($logo)?>"><div><b>SiloTalk</b><br><small>Meetings</small></div></div> <?php include __DIR__ . "/../silotalk/partials/customer-nav.php"; ?> </aside> <main class="stage"> <header class="stage-top"> <div> <b id="meetingTitle">SiloTalk Meeting Room</b><br> <small id="meetingMeta">Secure communications room - <?=htmlspecialchars($siloNumber)?></small> </div> <span class="pill" id="meetingState">READY</span> </header> <section class="video-grid"> <div class="tile"><video id="localVideo" autoplay muted playsinline></video><small>Local Endpoint</small></div> <div class="tile"><video id="remoteVideo" autoplay playsinline></video><small>Remote Endpoint</small></div> <div class="tile">ST<small>SiloTalk Room</small></div> <div class="tile">SFU<small>Media Bridge</small></div> </section> <footer class="controls"> <button class="ctrl green" onclick="createMeeting()">Create Meeting</button> <button class="ctrl" onclick="joinMeeting()">Join</button> <button class="ctrl" onclick="startLocalMedia(false)">Mic</button> <button class="ctrl" onclick="startLocalMedia(true)">Camera</button> <button class="ctrl" onclick="openThread()">Thread</button> <button class="ctrl red" onclick="endMeeting()">End</button> </footer> </main> <aside class="panel"> <div class="card"> <div class="head"><h2>Meeting Control</h2></div> <div class="body"> <input id="title" placeholder="Meeting title" value="SiloTalk Meeting" style="width:100%;margin-bottom:8px"> <input id="owner_silo" placeholder="Owner Silo Number" value="<?=htmlspecialchars($siloNumber)?>" style="width:100%;margin-bottom:8px"> <input id="meeting_code" placeholder="Meeting Code" value="<?=htmlspecialchars($meetingCode)?>" style="width:100%;margin-bottom:8px"> <input id="thread_uid" placeholder="Optional Thread UID" value="<?=htmlspecialchars($threadUid)?>" style="width:100%"> </div> </div> <div class="meeting-list" id="meetingList">Loading meetings...</div> <div class="messages" id="messages">Loading thread...</div> <div class="toolbar"> <input id="body" placeholder="Message meeting thread..." style="flex:1"> <button class="btn" onclick="sendMsg()">Send</button> </div> <pre id="debug"></pre> </aside> </div> <script src="/silocloud/apps/silotalk/assets/silotalk-suite.js?v=20260528"></script> <script> const ADAPTER="/silocloud/apps/silotalk/api/carrier-adapter.php"; let activeMeeting=null; let localStream=null; async function api(action,payload=null,params={}){ const qs=new URLSearchParams({action,...params}); const opts=payload?{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(payload)}:{}; const r=await fetch(`${ADAPTER}?${qs}`,opts); return r.json(); } function out(x){debug.textContent=JSON.stringify(x,null,2);} function esc(s){return String(s-"").replace(/[&<>"']/g,m=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[m]));} async function createMeeting(){ meetingState.textContent="CREATING"; const r=await api("gateway_meeting_create",{ title:title.value, owner_uid:SiloTalk.USER_UID, owner_silo_number:owner_silo.value, thread_uid:thread_uid.value }); out(r); if(r.ok){ activeMeeting=r.meeting; meeting_code.value=r.meeting.meeting_code||""; meetingTitle.textContent=r.meeting.title||title.value; meetingMeta.textContent="Meeting " + (r.meeting.meeting_code||r.meeting.meeting_uid) + " - RTC " + (r.meeting.rtc_room||"pending"); meetingState.textContent="ACTIVE"; loadMeetings(); }else{ meetingState.textContent="PENDING"; } } async function joinMeeting(){ if(!meeting_code.value){alert("Enter meeting code.");return;} meetingState.textContent="JOINING"; const r=await api("gateway_meeting_join",{ meeting_code:meeting_code.value, user_uid:SiloTalk.USER_UID, silo_number:owner_silo.value, role:"participant" }); out(r); meetingState.textContent=r.ok?"JOINED":"JOIN FAILED"; } async function loadMeeting(code){ const r=await api("gateway_meeting_get",null,{meeting_code:code}); out(r); if(r.ok && r.gateway_response && r.gateway_response.meeting){ activeMeeting=r.gateway_response.meeting; meeting_code.value=activeMeeting.meeting_code||code; meetingTitle.textContent=activeMeeting.title||"SiloTalk Meeting"; meetingMeta.textContent="Meeting " + (activeMeeting.meeting_code||"") + " - RTC " + (activeMeeting.rtc_room||""); meetingState.textContent=activeMeeting.status||"ACTIVE"; } } async function loadMeetings(){ const r=await api("meetings"); meetingList.innerHTML=(r.meetings||[]).map(m=>` <div class="row"> <div><b>${esc(m.title)}</b><br><small>${esc(m.meeting_code||m.meeting_uid||"")} - ${esc(m.status||"active")}</small></div> <button class="btn gray" onclick="meeting_code.value='${esc(m.meeting_code||"")}';loadMeeting('${esc(m.meeting_code||"")}')">Open</button> </div> `).join("")||"<small>No meetings.</small>"; } async function startLocalMedia(video){ try{ localStream=await navigator.mediaDevices.getUserMedia({audio:true,video}); localVideo.srcObject=localStream; meetingState.textContent=video?"CAMERA ACTIVE":"MIC ACTIVE"; }catch(e){ alert("Media failed: "+e.message); } } async function loadMsgs(){ const d=await api("messages",null,{thread_uid:thread_uid.value,user_uid:SiloTalk.USER_UID}); messages.innerHTML=(d.messages||[]).map(m=>`<div class="row"><div><b>${esc(m.sender_name||m.sender_uid)}</b><br><small>${esc(m.body)}</small></div></div>`).join("")||"<small>No messages.</small>"; } async function sendMsg(){ if(!body.value.trim())return; await api("send_message",{thread_uid:thread_uid.value,sender_uid:SiloTalk.USER_UID,body:body.value}); body.value=""; loadMsgs(); } function openThread(){ location.href="/silocloud/apps/silotalk/chat.php?user_uid="+encodeURIComponent(SiloTalk.USER_UID)+"&thread="+encodeURIComponent(thread_uid.value); } function endMeeting(){ if(localStream)localStream.getTracks().forEach(t=>t.stop()); localVideo.srcObject=null; remoteVideo.srcObject=null; meetingState.textContent="ENDED"; } loadMeetings(); loadMsgs(); setInterval(loadMsgs,3000); </script> </body> </html>