mirror of
git://f0xx.org/ac/ac-be-issues
synced 2026-07-29 05:00:33 +03:00
initial
This commit is contained in:
210
public/assets/js/live_education.js
Normal file
210
public/assets/js/live_education.js
Normal file
@@ -0,0 +1,210 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var MAX_DEMO_S = 300;
|
||||
var timer = null;
|
||||
var secondsLeft = MAX_DEMO_S;
|
||||
var mediaStream = null;
|
||||
var sessionId = '';
|
||||
var webrtc = null;
|
||||
|
||||
function basePath() {
|
||||
return document.body.getAttribute('data-base-path') || '';
|
||||
}
|
||||
|
||||
function el(id) {
|
||||
return document.getElementById(id);
|
||||
}
|
||||
|
||||
function detectPlatform() {
|
||||
var ua = navigator.userAgent || '';
|
||||
if (/Firefox\//i.test(ua)) return 'firefox';
|
||||
if (/Edg\//i.test(ua)) return 'edge';
|
||||
if (/Chrome\//i.test(ua)) return 'chrome';
|
||||
if (/Safari\//i.test(ua)) return 'safari';
|
||||
return 'desktop';
|
||||
}
|
||||
|
||||
function apiUrl() {
|
||||
return basePath() + '/api/live_cast.php';
|
||||
}
|
||||
|
||||
function postJson(body, cb) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', apiUrl(), true);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
|
||||
xhr.onload = function () {
|
||||
var payload = null;
|
||||
try {
|
||||
payload = JSON.parse(xhr.responseText);
|
||||
} catch (e) {
|
||||
cb(null);
|
||||
return;
|
||||
}
|
||||
cb(payload);
|
||||
};
|
||||
xhr.onerror = function () { cb(null); };
|
||||
xhr.send(JSON.stringify(body));
|
||||
}
|
||||
|
||||
function setStatus(text) {
|
||||
var node = el('edu-status');
|
||||
if (node) node.textContent = text;
|
||||
}
|
||||
|
||||
function updateTimer() {
|
||||
var node = el('edu-timer');
|
||||
if (!node) return;
|
||||
var m = Math.floor(secondsLeft / 60);
|
||||
var s = secondsLeft % 60;
|
||||
node.textContent = m + ':' + (s < 10 ? '0' : '') + s;
|
||||
}
|
||||
|
||||
function renderShare(session) {
|
||||
var box = el('edu-share');
|
||||
if (!box || !session) return;
|
||||
var joinUrl = session.join_short_url || '';
|
||||
var qrUrl = session.join_qr_url || '';
|
||||
var longJoin = basePath() + '/live/join?session_id=' + encodeURIComponent(session.session_id || sessionId);
|
||||
if (!joinUrl) joinUrl = longJoin;
|
||||
var html = '<h2>Share this demo</h2><p class="muted">Viewers open this link in another browser (same LAN or online).</p>';
|
||||
html += '<p><a href="' + joinUrl + '" target="_blank" rel="noopener">' + joinUrl + '</a></p>';
|
||||
if (qrUrl) {
|
||||
html += '<figure class="twofa-qr-wrap"><img src="' + qrUrl + '" width="160" height="160" alt="Viewer QR code"><figcaption class="muted">Scan to open viewer page</figcaption></figure>';
|
||||
}
|
||||
box.hidden = false;
|
||||
box.innerHTML = html;
|
||||
}
|
||||
|
||||
function stopDemo() {
|
||||
if (timer) {
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
if (webrtc) {
|
||||
webrtc.stop();
|
||||
webrtc = null;
|
||||
}
|
||||
if (mediaStream) {
|
||||
mediaStream.getTracks().forEach(function (t) { t.stop(); });
|
||||
mediaStream = null;
|
||||
}
|
||||
var preview = el('edu-preview');
|
||||
if (preview) preview.srcObject = null;
|
||||
if (sessionId) {
|
||||
postJson({ action: 'heartbeat', session_id: sessionId, status: 'ended' }, function () {});
|
||||
sessionId = '';
|
||||
}
|
||||
var share = el('edu-share');
|
||||
if (share) share.hidden = true;
|
||||
el('edu-start').disabled = false;
|
||||
el('edu-stop').disabled = true;
|
||||
setStatus('Demo ended. Thanks for trying AndroidCast education mode.');
|
||||
}
|
||||
|
||||
function startWebRtc() {
|
||||
if (!window.LiveCastWebRtc || !sessionId || !mediaStream) return;
|
||||
webrtc = window.LiveCastWebRtc.connect({
|
||||
basePath: basePath(),
|
||||
sessionId: sessionId,
|
||||
role: 'caster',
|
||||
localStream: mediaStream,
|
||||
onStatus: setStatus,
|
||||
onStats: function (stats) {
|
||||
var nerds = el('edu-stats');
|
||||
if (!nerds) return;
|
||||
nerds.hidden = false;
|
||||
nerds.textContent = 'Stats: ICE ' + (stats.ice_state || '—')
|
||||
+ ' · out ' + (stats.outbound_kbps || 0) + ' kbps'
|
||||
+ ' · RTT ' + (stats.rtt_ms || 0) + ' ms';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function startDemo() {
|
||||
if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
|
||||
setStatus('Screen sharing is not supported in this browser.');
|
||||
return;
|
||||
}
|
||||
if (!window.RTCPeerConnection) {
|
||||
setStatus('WebRTC is not available in this browser.');
|
||||
return;
|
||||
}
|
||||
setStatus('Requesting screen share permission…');
|
||||
navigator.mediaDevices.getDisplayMedia({ video: true, audio: false })
|
||||
.then(function (stream) {
|
||||
mediaStream = stream;
|
||||
var preview = el('edu-preview');
|
||||
if (preview) {
|
||||
preview.hidden = false;
|
||||
preview.srcObject = stream;
|
||||
preview.play().catch(function () {});
|
||||
}
|
||||
stream.getVideoTracks()[0].addEventListener('ended', stopDemo);
|
||||
setStatus('Creating demo session…');
|
||||
postJson({
|
||||
action: 'create_intent',
|
||||
platform: 'education_' + detectPlatform(),
|
||||
max_duration_s: MAX_DEMO_S,
|
||||
codec_video: 'browser_screen',
|
||||
codec_audio: 'none',
|
||||
bw_mode: 'demo'
|
||||
}, function (resp) {
|
||||
if (!resp || !resp.ok || !resp.session) {
|
||||
setStatus('Could not register demo session. Try again later.');
|
||||
stopDemo();
|
||||
return;
|
||||
}
|
||||
sessionId = resp.session.session_id || '';
|
||||
renderShare(resp.session);
|
||||
startWebRtc();
|
||||
secondsLeft = MAX_DEMO_S;
|
||||
updateTimer();
|
||||
el('edu-start').disabled = true;
|
||||
el('edu-stop').disabled = false;
|
||||
setStatus('Live demo — share the link so others can watch.');
|
||||
timer = setInterval(function () {
|
||||
secondsLeft -= 1;
|
||||
updateTimer();
|
||||
if (secondsLeft <= 0) {
|
||||
stopDemo();
|
||||
}
|
||||
}, 1000);
|
||||
if (window.AndroidCastAnalytics && window.AndroidCastAnalytics.trackEvent) {
|
||||
window.AndroidCastAnalytics.trackEvent('live_education_start', { platform: detectPlatform() });
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(function () {
|
||||
setStatus('Screen share permission denied or cancelled.');
|
||||
});
|
||||
}
|
||||
|
||||
function boot() {
|
||||
if (!el('live-education-app')) return;
|
||||
updateTimer();
|
||||
var startBtn = el('edu-start');
|
||||
var stopBtn = el('edu-stop');
|
||||
if (startBtn) startBtn.addEventListener('click', startDemo);
|
||||
if (stopBtn) {
|
||||
stopBtn.disabled = true;
|
||||
stopBtn.addEventListener('click', stopDemo);
|
||||
}
|
||||
var notifBtn = el('edu-notify');
|
||||
if (notifBtn && 'Notification' in window) {
|
||||
notifBtn.addEventListener('click', function () {
|
||||
Notification.requestPermission().then(function (perm) {
|
||||
setStatus(perm === 'granted' ? 'Notifications enabled.' : 'Notifications not granted.');
|
||||
});
|
||||
});
|
||||
} else if (notifBtn) {
|
||||
notifBtn.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', boot);
|
||||
} else {
|
||||
boot();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user