217 أسطر
6.3 KiB
JavaScript
217 أسطر
6.3 KiB
JavaScript
'use strict';
|
|
|
|
const videoElement = document.getElementById('video');
|
|
const startCameraButton = document.getElementById('startCamera');
|
|
const startScreenButton = document.getElementById('startScreen');
|
|
const stopButton = document.getElementById('stop');
|
|
const apiSecretInput = document.getElementById('apiSecret');
|
|
const rtmpInput = document.getElementById('rtmp');
|
|
const copyButton = document.getElementById('copy');
|
|
const popup = document.getElementById('popup');
|
|
const popupMessage = document.getElementById('popupMessage');
|
|
const closePopup = document.getElementById('closePopup');
|
|
|
|
/*
|
|
Low Latency: 1-2 seconds
|
|
Standard Use Case: 5 seconds
|
|
High Bandwidth/Stability: 10 seconds
|
|
*/
|
|
const chunkDuration = 4000; // ms
|
|
|
|
let mediaRecorder = null;
|
|
let rtmpKey = null;
|
|
let socket = null;
|
|
|
|
function toggleButtons(disabled = true) {
|
|
startCameraButton.disabled = disabled;
|
|
startScreenButton.disabled = disabled;
|
|
stopButton.disabled = disabled;
|
|
}
|
|
|
|
function showPopup(message, type) {
|
|
popup.classList.remove('success', 'error', 'warning', 'info');
|
|
popup.classList.add(type);
|
|
popupMessage.textContent = message;
|
|
popup.classList.remove('hidden');
|
|
setTimeout(() => {
|
|
hidePopup();
|
|
}, 5000); // Hide after 5 seconds
|
|
}
|
|
|
|
function hidePopup() {
|
|
popup.classList.add('hidden');
|
|
}
|
|
|
|
function showError(message) {
|
|
showPopup(message, 'error');
|
|
}
|
|
|
|
async function startCapture(constraints) {
|
|
try {
|
|
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
attachMediaStream(stream);
|
|
return stream;
|
|
} catch (err) {
|
|
console.error('Error accessing media devices.', err);
|
|
showError('Error accessing media devices. Please check your camera and microphone permissions.');
|
|
}
|
|
}
|
|
|
|
async function startScreenCapture(constraints) {
|
|
try {
|
|
const stream = await navigator.mediaDevices.getDisplayMedia(constraints);
|
|
attachMediaStream(stream);
|
|
return stream;
|
|
} catch (err) {
|
|
console.error('Error accessing screen media.', err);
|
|
showError('Error accessing screen sharing. Please try again or check your screen sharing permissions.');
|
|
}
|
|
}
|
|
|
|
function attachMediaStream(stream) {
|
|
videoElement.srcObject = stream;
|
|
videoElement.playsInline = true;
|
|
videoElement.autoplay = true;
|
|
videoElement.muted = true;
|
|
videoElement.volume = 0;
|
|
videoElement.controls = false;
|
|
}
|
|
|
|
async function initRTMP() {
|
|
const apiSecret = apiSecretInput.value;
|
|
socket.emit('initRTMP', { apiSecret });
|
|
}
|
|
|
|
async function streamRTMP(data) {
|
|
const apiSecret = apiSecretInput.value;
|
|
|
|
const arrayBuffer = await data.arrayBuffer();
|
|
const chunkSize = 1000000; // 1mb
|
|
const totalChunks = Math.ceil(arrayBuffer.byteLength / chunkSize);
|
|
|
|
for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
|
|
const chunk = arrayBuffer.slice(chunkIndex * chunkSize, (chunkIndex + 1) * chunkSize);
|
|
socket.emit('streamRTMP', { apiSecret: apiSecret, rtmpStreamKey: rtmpKey, data: chunk });
|
|
}
|
|
}
|
|
|
|
async function stopRTMP() {
|
|
if (mediaRecorder) {
|
|
const apiSecret = apiSecretInput.value;
|
|
mediaRecorder.stop();
|
|
socket.emit('stopRTMP', { apiSecret: apiSecret, rtmpStreamKey: rtmpKey });
|
|
}
|
|
videoElement.srcObject = null;
|
|
rtmpInput.value = '';
|
|
toggleButtons(false);
|
|
stopButton.disabled = true;
|
|
}
|
|
|
|
async function startStreaming(stream) {
|
|
if (!stream) return;
|
|
|
|
try {
|
|
socket = io({ transports: ['websocket'] });
|
|
|
|
socket.on('connect', () => {
|
|
console.log('Connected to server');
|
|
initRTMP();
|
|
});
|
|
|
|
socket.on('initRTMP', (data) => {
|
|
console.log('initRTMP', data);
|
|
const { rtmp, rtmpStreamKey } = data;
|
|
rtmpInput.value = rtmp;
|
|
rtmpKey = rtmpStreamKey;
|
|
toggleButtons(true);
|
|
stopButton.disabled = false;
|
|
startMediaRecorder(stream);
|
|
});
|
|
|
|
socket.on('stopRTMP', () => {
|
|
console.log('RTMP stopped successfully!');
|
|
});
|
|
|
|
socket.on('error', (error) => {
|
|
console.error('Error:', error);
|
|
showError(error);
|
|
stopRTMP();
|
|
});
|
|
|
|
socket.on('disconnect', () => {
|
|
console.log('Disconnected from server');
|
|
stopRTMP();
|
|
});
|
|
} catch (error) {
|
|
showPopup('Error start Streaming: ' + error.message, 'error');
|
|
console.error('Error start Streaming', error);
|
|
stopRTMP();
|
|
}
|
|
}
|
|
|
|
function getSupportedMimeTypes() {
|
|
const possibleTypes = ['video/webm;codecs=vp8,opus', 'video/mp4'];
|
|
return possibleTypes.filter((mimeType) => {
|
|
return MediaRecorder.isTypeSupported(mimeType);
|
|
});
|
|
}
|
|
|
|
async function startMediaRecorder(stream) {
|
|
if (!stream) return;
|
|
|
|
const supportedMimeTypes = getSupportedMimeTypes();
|
|
console.log('MediaRecorder supported options', supportedMimeTypes);
|
|
mediaRecorder = new MediaRecorder(stream, { mimeType: supportedMimeTypes[0] });
|
|
|
|
mediaRecorder.ondataavailable = async (event) => {
|
|
if (event.data.size > 0) {
|
|
await streamRTMP(event.data);
|
|
}
|
|
};
|
|
|
|
mediaRecorder.onstop = (event) => {
|
|
console.log('Media recorder stopped');
|
|
stopTracks(stream);
|
|
};
|
|
|
|
mediaRecorder.start(chunkDuration); // Record in chunks of the specified duration
|
|
}
|
|
|
|
function stopTracks(stream) {
|
|
stream.getTracks().forEach((track) => {
|
|
track.stop();
|
|
});
|
|
}
|
|
|
|
async function startCameraStreaming() {
|
|
const stream = await startCapture({ video: true, audio: true });
|
|
await startStreaming(stream);
|
|
}
|
|
|
|
async function startScreenStreaming() {
|
|
const stream = await startScreenCapture({ video: true, audio: true });
|
|
await startStreaming(stream);
|
|
}
|
|
|
|
function copyRTMP() {
|
|
const rtmpInput = document.getElementById('rtmp');
|
|
if (!rtmpInput.value) {
|
|
return showPopup('No RTMP URL detected', 'info');
|
|
}
|
|
rtmpInput.select();
|
|
document.execCommand('copy');
|
|
showPopup('Copied: ' + rtmpInput.value, 'success');
|
|
}
|
|
|
|
startCameraButton.addEventListener('click', startCameraStreaming);
|
|
startScreenButton.addEventListener('click', startScreenStreaming);
|
|
stopButton.addEventListener('click', stopRTMP);
|
|
copyButton.addEventListener('click', copyRTMP);
|
|
closePopup.addEventListener('click', hidePopup);
|
|
|
|
window.addEventListener('beforeunload', async () => {
|
|
if (mediaRecorder) {
|
|
await stopRTMP();
|
|
}
|
|
});
|