я написал стрименговый сервис напиши что можно добавить  вот мой код , Вот мой код площадки для стрименга 
index.html
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Платформа трансляций</title>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <div class="container" id="mainContainer">
        <!-- Главный экран -->
        <div id="welcomeScreen">
            <h1>Добро пожаловать на платформу трансляций</h1>
            <div class="buttons">
                <button id="startStreamerBtn" class="btn">Начать трансляцию</button>
                <button id="startViewerBtn" class="btn">Смотреть трансляции</button>
            </div>
        </div>

        <!-- Экран стримера -->
        <div id="streamerScreen" style="display: none;">
            <h2>Начать трансляцию</h2>
            
            <!-- Выбор источника трансляции -->
            <div class="source-selection">
                <label>
                    <input type="radio" name="source" value="camera" checked>
                    Веб-камера
                </label>
                <label>
                    <input type="radio" name="source" value="file">
                    Видео-файл
                </label>
            </div>
            
            <!-- Загрузка видео-файла -->
            <div id="fileInputContainer" style="display: none; margin-top: 15px;">
                <input type="file" id="videoFileInput" accept="video/*">
            </div>
            
            <!-- Кнопки управления трансляцией -->
            <div class="buttons">
                <button id="startStreamBtn" class="btn">Начать стрим</button>
                <button id="endStreamBtn" class="btn" style="display:none;">Закончить стрим</button>
            </div>
            
            <!-- Информация о трансляции -->
            <div id="streamInfo" style="display:none; margin-top: 20px;">
                <p>Трансляция активна! Ссылка для зрителей:</p>
                <input type="text" id="streamLink" readonly>
                <!-- Видео для локального отображения -->
                <video id="localVideo" autoplay muted playsinline></video>
                <!-- Видео-файл, который транслируется -->
                <video id="uploadedVideo" style="display:none;"></video>
                <!-- Прогресс-бар -->
                <div id="progressContainer">
                    <progress id="videoProgress" value="0" max="100"></progress>
                    <span id="progressLabel">0%</span>
                </div>
                <!-- Чат -->
                <div class="chatContainer">
                    <div class="chatMessages"></div>
                    <form class="chatForm">
                        <input type="text" class="chatInput" placeholder="Введите сообщение...">
                        <button type="submit">Отправить</button>
                    </form>
                </div>
            </div>
        </div>

        <!-- Экран зрителя -->
        <div id="viewerScreen" style="display: none;">
            <h2>Активные трансляции</h2>
            <ul id="streamsList">
                <!-- Список активных стримов будет динамически заполнен -->
            </ul>
        </div>

        <!-- Экран просмотра трансляции -->
        <div id="streamScreen" style="display: none;">
            <h2>Просмотр трансляции</h2>
            <div id="streamContainer">
                <video id="remoteVideo" autoplay playsinline controls></video>
                <!-- Чат -->
                <div class="chatContainer">
                    <div class="chatMessages"></div>
                    <form class="chatForm">
                        <input type="text" class="chatInput" placeholder="Введите сообщение...">
                        <button type="submit">Отправить</button>
                    </form>
                </div>
            </div>
        </div>
    </div>

    <script src="/socket.io/socket.io.js"></script>
    <script src="js/main.js"></script>
</body>
</html>
main.js 
// public/js/main.js

const socket = io();

// DOM Elements
const mainContainer = document.getElementById('mainContainer');
const welcomeScreen = document.getElementById('welcomeScreen');
const streamerScreen = document.getElementById('streamerScreen');
const viewerScreen = document.getElementById('viewerScreen');
const streamScreen = document.getElementById('streamScreen');

const startStreamerBtn = document.getElementById('startStreamerBtn');
const startViewerBtn = document.getElementById('startViewerBtn');

// Стример элементы
const startStreamBtn = document.getElementById('startStreamBtn');
const endStreamBtn = document.getElementById('endStreamBtn');
const streamInfo = document.getElementById('streamInfo');
const streamLinkInput = document.getElementById('streamLink');
const localVideo = document.getElementById('localVideo');
const uploadedVideo = document.getElementById('uploadedVideo');
const sourceRadios = document.getElementsByName('source');
const fileInputContainer = document.getElementById('fileInputContainer');
const videoFileInput = document.getElementById('videoFileInput');
const videoProgress = document.getElementById('videoProgress');
const progressLabel = document.getElementById('progressLabel');

// Чат элементы
const chatContainers = document.querySelectorAll('.chatContainer');
const chatMessagesElements = document.querySelectorAll('.chatMessages');
const chatForms = document.querySelectorAll('.chatForm');
const chatInputs = document.querySelectorAll('.chatInput');

// Зритель элементы
const streamsList = document.getElementById('streamsList');
const remoteVideo = document.getElementById('remoteVideo');

// Навигация
startStreamerBtn.addEventListener('click', () => {
    welcomeScreen.style.display = 'none';
    streamerScreen.style.display = 'block';
});

startViewerBtn.addEventListener('click', () => {
    welcomeScreen.style.display = 'none';
    viewerScreen.style.display = 'block';
    fetchStreams();
});

// Общие переменные
let streamId = null;
let isStreamer = false;

// Чат функциональность
let currentStreamId = null;

// WebRTC Variables
let localStream = null;
let videoStream = null; // Используется для передачи потоков
const peers = {};
let peerConnection = null;

// Current Source: 'camera' или 'file'
let currentSource = 'camera';

// Обработка выбора источника трансляции
if (sourceRadios) {
    Array.from(sourceRadios).forEach(radio => {
        radio.addEventListener('change', () => {
            currentSource = radio.value;
            if (currentSource === 'file') {
                fileInputContainer.style.display = 'block';
            } else {
                fileInputContainer.style.display = 'none';
                // Останавливаем видео-файл при переключении обратно на камеру
                if (uploadedVideo.src) {
                    uploadedVideo.pause();
                    uploadedVideo.src = '';
                    videoStream = null;
                    uploadedVideo.style.display = 'none';
                }
            }
        });
    });
}

// Обработка загрузки видео-файла
if (videoFileInput) {
    videoFileInput.addEventListener('change', () => {
        const file = videoFileInput.files[0];
        if (file) {
            const fileURL = URL.createObjectURL(file);
            uploadedVideo.src = fileURL;
            uploadedVideo.style.display = 'block';
            uploadedVideo.load();
            uploadedVideo.play();
            uploadedVideo.onplaying = () => {
                // Захватываем поток после начала воспроизведения
                videoStream = uploadedVideo.captureStream();
                console.log('Видео-файл захвачен:', videoStream);
                // Если стрим уже начат, добавляем видео-файл к существующим соединениям
                if (streamInfo.style.display === 'block') {
                    addVideoStreamToPeers();
                }
            };

            // Обновление прогресс-бара
            uploadedVideo.ontimeupdate = () => {
                if (uploadedVideo.duration) { // Проверка на существование duration
                    const percentage = (uploadedVideo.currentTime / uploadedVideo.duration) * 100;
                    videoProgress.value = percentage;
                    progressLabel.textContent = `${Math.floor(percentage)}%`;
                }
            };

            uploadedVideo.onended = () => {
                // Автоматически останавливаем трансляцию при окончании видео-файла
                endStream();
            };
        }
    });
}

// Чат отправка сообщений для каждой формы чата
chatForms.forEach((form, index) => {
    form.addEventListener('submit', (e) => {
        e.preventDefault();
        const chatInput = chatInputs[index];
        const messageText = chatInput.value.trim();
        if (messageText) {
            const message = {
                sender: isStreamer ? 'Стример' : 'Зритель',
                text: messageText
            };
            socket.emit('chat-message', { streamId: currentStreamId, message });
            chatInput.value = '';
            // Не вызываем addChatMessage() здесь, поскольку сообщения приходят через сокеты
        }
    });
});

// Отображение сообщения в чате
function addChatMessage(chatMessages, message) {
    const messageElem = document.createElement('div');
    messageElem.className = 'chat-message';
    messageElem.innerHTML = `<strong>${message.sender}:</strong> ${message.text}`;
    chatMessages.appendChild(messageElem);
    chatMessages.scrollTop = chatMessages.scrollHeight;
}

// Приём сообщений чата
socket.on('chat-message', (message) => {
    chatMessagesElements.forEach(chatMessages => {
        addChatMessage(chatMessages, message);
    });
});

// Приём истории чата
socket.on('chat-history', (messages) => {
    chatMessagesElements.forEach(chatMessages => {
        chatMessages.innerHTML = '';
        messages.forEach(message => {
            addChatMessage(chatMessages, message);
        });
    });
});

// Стример функциональность

// Start Stream
if (startStreamBtn) {
    startStreamBtn.addEventListener('click', async () => {
        streamId = await createStream();
        if (streamId) {
            streamInfo.style.display = 'block';
            startStreamBtn.style.display = 'none';
            endStreamBtn.style.display = 'inline-block';
            streamLinkInput.value = `${window.location.origin}?streamId=${streamId}`;
            currentStreamId = streamId;
            isStreamer = true;

            if (currentSource === 'camera') {
                // Захват видео с веб-камеры
                startLocalVideo();
            } else if (currentSource === 'file') {
                // Воспроизведение видео-файла и захват потока
                if (uploadedVideo.src) {
                    if (videoStream) {
                        // Ничего не делаем, поток уже захвачен в обработчике onplaying
                    } else {
                        alert('Ожидание захвата видео-файла...');
                    }
                } else {
                    alert('Пожалуйста, выберите видео-файл для трансляции.');
                }
            }
        }
    });
}

// End Stream
if (endStreamBtn) {
    endStreamBtn.addEventListener('click', () => {
        endStream();
    });
}

// Create Stream on Server
function createStream() {
    return new Promise((resolve) => {
        socket.emit('create-stream', (generatedStreamId) => {
            resolve(generatedStreamId);
        });
    });
}

// Start Local Video
async function startLocalVideo() {
    try {
        localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
        localVideo.srcObject = localStream;
        videoStream = localStream; // Используется для передачи в Peer Connections
        console.log('Локальный поток захвачен:', videoStream);
    } catch (err) {
        console.error('Ошибка доступа к камере/микрофону:', err);
        alert('Не удалось получить доступ к камере/микрофону.');
    }
}

// Добавление видео-файла к существующим Peer Connections
function addVideoStreamToPeers() {
    for (const viewerId in peers) {
        const peer = peers[viewerId];
        if (videoStream) {
            videoStream.getTracks().forEach(track => {
                peer.pc.addTrack(track, videoStream);
            });
            // Инициируем повторную сигнализацию
            renegotiate(peer.pc, viewerId);
        } else {
            console.warn('Нет видео-потока для добавления к Peer Connection:', viewerId);
        }
    }
}

// Повторная сигнализация
async function renegotiate(pc, viewerSocketId) {
    try {
        const offer = await pc.createOffer();
        await pc.setLocalDescription(offer);
        socket.emit('signal', { to: viewerSocketId, from: socket.id, description: pc.localDescription });
    } catch (err) {
        console.error('Ошибка повторной сигнализации:', err);
    }
}

// Handle Viewer Joined
socket.on('viewer-joined', (viewerSocketId) => {
    console.log('Новый зритель присоединился:', viewerSocketId);
    createPeerConnection(viewerSocketId, true);
});

// Handle Signaling Data
socket.on('signal', async (data) => {
    const { from, candidate, description } = data;
    if (isStreamer) {
        if (!peers[from]) {
            createPeerConnection(from, false);
        }
        const peer = peers[from];

        if (description) {
            if (description.type === 'answer') {
                await peer.pc.setRemoteDescription(new RTCSessionDescription(description));
            }
        } else if (candidate) {
            try {
                await peer.pc.addIceCandidate(new RTCIceCandidate(candidate));
            } catch (err) {
                console.error('Ошибка добавления ICE-кандидата:', err);
            }
        }
    } else {
        // Для зрителя
        if (!peerConnection) {
            createViewerPeerConnection(from);
        }

        if (description) {
            if (description.type === 'offer') {
                await peerConnection.setRemoteDescription(new RTCSessionDescription(description));
                const answer = await peerConnection.createAnswer();
                await peerConnection.setLocalDescription(answer);
                socket.emit('signal', { to: from, from: socket.id, description: peerConnection.localDescription });
            }
        } else if (candidate) {
            try {
                await peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
            } catch (err) {
                console.error('Ошибка добавления ICE-кандидата:', err);
            }
        }
    }
});

// Создание Peer Connection для стримера
function createPeerConnection(viewerSocketId, isInitiator) {
    const peer = {};
    peer.pc = new RTCPeerConnection({
        iceServers: [
            { urls: 'stun:stun.l.google.com:19302' },
            // Добавьте TURN-серверы здесь при необходимости
        ]
    });

    peers[viewerSocketId] = peer;

    // Добавление треков из videoStream в Peer Connection
    if (videoStream) {
        videoStream.getTracks().forEach(track => peer.pc.addTrack(track, videoStream));
    } else {
        console.warn('Нет видео-потока для передачи зрителю:', viewerSocketId);
    }

    // Обработка ICE-кандидатов
    peer.pc.onicecandidate = (event) => {
        if (event.candidate) {
            socket.emit('signal', { to: viewerSocketId, from: socket.id, candidate: event.candidate });
        }
    };

    // Обработка событий соединения
    peer.pc.onconnectionstatechange = () => {
        console.log(`Состояние соединения с ${viewerSocketId}:`, peer.pc.connectionState);
        if (peer.pc.connectionState === 'disconnected' || peer.pc.connectionState === 'failed' || peer.pc.connectionState === 'closed') {
            peer.pc.close();
            delete peers[viewerSocketId];
            console.log(`Соединение с ${viewerSocketId} закрыто.`);
        }
    };

    // Создание предложения, если инициатор
    if (isInitiator) {
        createOffer(peer.pc, viewerSocketId);
    }
}

// Функция для создания и отправки предложения
async function createOffer(pc, viewerSocketId) {
    try {
        const offer = await pc.createOffer();
        await pc.setLocalDescription(offer);
        socket.emit('signal', { to: viewerSocketId, from: socket.id, description: pc.localDescription });
    } catch (err) {
        console.error('Ошибка создания предложения:', err);
    }
}

// Закрытие всех Peer Connections и остановка трансляции
function endStream() {
    // Закрытие всех peer connections
    for (const viewerId in peers) {
        peers[viewerId].pc.close();
        delete peers[viewerId];
    }

    // Остановить все локальные треки
    if (localStream) {
        localStream.getTracks().forEach(track => track.stop());
        localStream = null;
        localVideo.srcObject = null;
    }

    // Останавливаем видео-файл
    if (uploadedVideo.src) {
        uploadedVideo.pause();
        uploadedVideo.src = '';
        videoStream = null;
        uploadedVideo.style.display = 'none';
    }

    // Уведомление сервера о завершении трансляции
    socket.emit('end-stream', streamId);

    // Сброс UI
    streamInfo.style.display = 'none';
    startStreamBtn.style.display = 'inline-block';
    endStreamBtn.style.display = 'none';
    streamLinkInput.value = '';
    videoProgress.value = 0;
    progressLabel.textContent = '0%';
    chatMessagesElements.forEach(chatMessages => {
        chatMessages.innerHTML = '';
    });

    isStreamer = false;
    currentStreamId = null;
}

// Зритель функциональность

function fetchStreams() {
    fetch(`/streams`)
        .then(response => response.json())
        .then(data => {
            renderStreams(data);
        })
        .catch(err => {
            console.error('Ошибка при получении списка трансляций:', err);
        });
}

// Render streams list
function renderStreams(streams) {
    streamsList.innerHTML = '';
    if (streams.length === 0) {
        streamsList.innerHTML = '<p>Нет активных трансляций в данный момент.</p>';
        return;
    }
    streams.forEach(streamId => {
        const listItem = document.createElement('li');
        listItem.className = 'stream-item';

        const button = document.createElement('button');
        button.textContent = `Трансляция #${streamId}`;
        button.addEventListener('click', () => {
            joinStream(streamId);
        });

        listItem.appendChild(button);
        streamsList.appendChild(listItem);
    });
}

// Обновление списка трансляций в реальном времени
socket.on('update-streams', (activeStreams) => {
    if (viewerScreen.style.display === 'block') {
        renderStreams(activeStreams);
    }
});

// Присоединение к трансляции
function joinStream(streamId) {
    currentStreamId = streamId;
    isStreamer = false;

    viewerScreen.style.display = 'none';
    streamScreen.style.display = 'block';

    socket.emit('join-stream', streamId, (response) => {
        if (response.success) {
            console.log('Присоединился к трансляции:', streamId);
        } else {
            alert(response.message);
            window.location.reload();
        }
    });
}

// Создание Peer Connection для зрителя
function createViewerPeerConnection(streamerId) {
    peerConnection = new RTCPeerConnection({
        iceServers: [
            { urls: 'stun:stun.l.google.com:19302' },
            // Добавьте TURN-серверы здесь при необходимости
        ]
    });

    // Обработка ICE-кандидатов
    peerConnection.onicecandidate = (event) => {
        if (event.candidate) {
            socket.emit('signal', { to: streamerId, from: socket.id, candidate: event.candidate });
        }
    };

    // Получение удалённого потока
    peerConnection.ontrack = (event) => {
        if (remoteVideo.srcObject !== event.streams[0]) {
            remoteVideo.srcObject = event.streams[0];
            console.log('Получен удалённый поток:', event.streams[0]);
        }
    };

    // Обработка состояний соединения
    peerConnection.onconnectionstatechange = () => {
        console.log(`Состояние соединения:`, peerConnection.connectionState);
        if (peerConnection.connectionState === 'disconnected' || peerConnection.connectionState === 'failed' || peerConnection.connectionState === 'closed') {
            remoteVideo.srcObject = null;
            peerConnection.close();
            peerConnection = null;
            alert('Соединение было прервано.');
            window.location.reload();
        }
    };
}

// Handle stream ended
socket.on('stream-ended', () => {
    alert('Трансляция завершена.');
    window.location.reload();
});

// Обработка ссылок на прямой переход к трансляции
window.addEventListener('load', () => {
    const urlParams = new URLSearchParams(window.location.search);
    const streamIdParam = urlParams.get('streamId');
    if (streamIdParam) {
        // Автоматически присоединяемся к трансляции
        welcomeScreen.style.display = 'none';
        joinStream(streamIdParam);
    }
});