الملفات
codepill-sfu/rtmpServers/demo/client-server-socket/client/client.js
2024-07-07 16:04:46 +02:00

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();
}
});