исрпвь ошибку 
client.js:178 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'appendChild')
    at createPeerConnection (client.js:178:27)
    at connectToPeer (client.js:227:11)
    at Socket.<anonymous> (client.js:123:5)
    at Emitter.emit (index.js:136:20)
    at Socket.emitEvent (socket.js:553:20)
    at Socket.onevent (socket.js:540:18)
    at Socket.onpacket (socket.js:508:22)
    at Emitter.emit (index.js:136:20)
    at manager.js:217:18
вот код
// public/client.js
const socket = io();

// Элементы интерфейса
const localVideo = document.getElementById('localVideo');
const remoteVideosContainer = document.getElementById('remoteVideosContainer'); // Убедитесь, что такой элемент существует в HTML
const chat = document.getElementById('chat');
const messageInput = document.getElementById('message-input');
const sendButton = document.getElementById('send-button');
const toggleAudioButton = document.getElementById('toggleAudio');
const toggleVideoButton = document.getElementById('toggleVideo');
const shareScreenButton = document.getElementById('shareScreen');

// Получение медиапотоков
let localStream;
let screenStream;
const peers = {};

// Конфигурация ICE серверов с дополнительными STUN и TURN серверами
const config = {
    iceServers: [
        // Дополнительные STUN-серверы от Google
        { urls: 'stun:stun.l.google.com:19302' },
        { urls: 'stun:stun1.l.google.com:19302' },
        { urls: 'stun:stun2.l.google.com:19302' },
        { urls: 'stun:stun3.l.google.com:19302' },
        { urls: 'stun:stun4.l.google.com:19302' },
        
        // Пример добавления TURN-сервера
        {
            urls: 'turn:YOUR_TURN_SERVER_URL', // Замените на ваш TURN-сервер
            username: 'YOUR_TURN_USERNAME',    // Замените на имя пользователя TURN
            credential: 'YOUR_TURN_CREDENTIAL' // Замените на пароль TURN
        }
    ]
};

// Функция для проверки доступных устройств
async function getAvailableMedia() {
    try {
        const devices = await navigator.mediaDevices.enumerateDevices();
        const hasAudio = devices.some(device => device.kind === 'audioinput');
        const hasVideo = devices.some(device => device.kind === 'videoinput');

        let constraints = {};
        if (hasVideo) constraints.video = true;
        if (hasAudio) constraints.audio = true;

        if (!hasVideo && !hasAudio) {
            throw new Error('Нет доступных устройств ввода.');
        }

        return constraints;
    } catch (err) {
        console.error('Ошибка при проверке устройств:', err);
        throw err;
    }
}

// Получение локального видео и аудио с проверкой устройств
getAvailableMedia()
    .then(constraints => navigator.mediaDevices.getUserMedia(constraints))
    .then(stream => {
        localStream = stream;
        localVideo.srcObject = stream;
    })
    .catch(err => {
        console.error('Ошибка получения медиапотоков:', err);
        appendMessage(`Ошибка получения медиапотоков: ${err.message}`);
        // Вы можете добавить дополнительную логику, например, отключить функциональность, требующую медиапотоков
    });

// Обработка отправки сообщений
sendButton.addEventListener('click', () => {
    const message = messageInput.value;
    if (message.trim() !== '') {
        appendMessage(`Вы: ${message}`);
        // Отправка сообщения через Data Channel каждому пиру
        for (let peerId in peers) {
            if (peers[peerId].dataChannel && peers[peerId].dataChannel.readyState === 'open') {
                peers[peerId].dataChannel.send(message);
            }
        }
        messageInput.value = '';
    }
});

// Функция для добавления сообщений в чат
function appendMessage(message) {
    const msg = document.createElement('div');
    msg.textContent = message;
    chat.appendChild(msg);
    chat.scrollTop = chat.scrollHeight;
}

// Обработка сигналов от сервера
socket.on('signal', async (data) => {
    const { from, signal } = data;
    if (!peers[from]) {
        await createPeerConnection(from, false);
    }
    const peer = peers[from].peerConnection;

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

// Обработка подключения нового пользователя
socket.on('user-connected', (userId) => {
    console.log('Пользователь подключился: ' + userId);
    connectToPeer(userId);
});

// Обработка отключения пользователя
socket.on('user-disconnected', (userId) => {
    console.log('Пользователь отключился: ' + userId);
    if (peers[userId]) {
        peers[userId].peerConnection.close();
        if (peers[userId].dataChannel) {
            peers[userId].dataChannel.close();
        }
        delete peers[userId];
        appendMessage(`Пир ${userId} отключился`);
        
        // Удаление соответствующего видеоэлемента
        const videoElement = document.getElementById(`remoteVideo_${userId}`);
        if (videoElement) {
            remoteVideosContainer.removeChild(videoElement);
        }
    }
});

// Создание и инициализация Peer Connection
async function createPeerConnection(peerId, isInitiator) {
    const peerConnection = new RTCPeerConnection(config);

    // Добавление локальных потоков
    if (localStream) {
        localStream.getTracks().forEach(track => {
            peerConnection.addTrack(track, localStream);
        });
    }

    // Создание Data Channel для текстовых сообщений
    let dataChannel;
    if (isInitiator) {
        dataChannel = peerConnection.createDataChannel('chat');
        dataChannel.onmessage = (event) => {
            appendMessage(`Пир ${peerId}: ${event.data}`);
        };
    } else {
        peerConnection.ondatachannel = (event) => {
            dataChannel = event.channel;
            dataChannel.onmessage = (event) => {
                appendMessage(`Пир ${peerId}: ${event.data}`);
            };
        };
    }

    // Создание элемента видео для удалённого потока
    const remoteVideo = document.createElement('video');
    remoteVideo.id = `remoteVideo_${peerId}`;
    remoteVideo.autoplay = true;
    remoteVideo.playsInline = true;
    remoteVideo.style.width = '300px'; // Настройте по необходимости
    remoteVideosContainer.appendChild(remoteVideo);

    // Обработка полученных треков
    peerConnection.ontrack = (event) => {
        if (event.streams && event.streams[0]) {
            remoteVideo.srcObject = event.streams[0];
        }
    };

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

    // Обработка состояния соединения
    peerConnection.oniceconnectionstatechange = () => {
        if (peerConnection.iceConnectionState === 'disconnected' || peerConnection.iceConnectionState === 'failed') {
            if (peers[peerId]) {
                peerConnection.close();
                if (peers[peerId].dataChannel) {
                    peers[peerId].dataChannel.close();
                }
                delete peers[peerId];
                appendMessage(`Пир ${peerId} отключился`);
                
                // Удаление соответствующего видеоэлемента
                const videoElement = document.getElementById(`remoteVideo_${peerId}`);
                if (videoElement) {
                    remoteVideosContainer.removeChild(videoElement);
                }
            }
        }
    };

    // Создание описания соединения для инициатора
    if (isInitiator) {
        const offer = await peerConnection.createOffer();
        await peerConnection.setLocalDescription(offer);
        socket.emit('signal', { to: peerId, signal: peerConnection.localDescription });
    }

    // Сохранение данных пира
    peers[peerId] = { peerConnection, dataChannel };
}

// Функция для подключения к новому пиру
async function connectToPeer(peerId) {
    await createPeerConnection(peerId, true);
}

// Управление микрофоном
toggleAudioButton.addEventListener('click', () => {
    if (!localStream) return;
    const audioTrack = localStream.getAudioTracks()[0];
    if (audioTrack) {
        audioTrack.enabled = !audioTrack.enabled;
        toggleAudioButton.textContent = audioTrack.enabled ? 'Отключить Аудио' : 'Включить Аудио';
    }
});

// Управление видеокамерой
toggleVideoButton.addEventListener('click', () => {
    if (!localStream) return;
    const videoTrack = localStream.getVideoTracks()[0];
    if (videoTrack) {
        videoTrack.enabled = !videoTrack.enabled;
        toggleVideoButton.textContent = videoTrack.enabled ? 'Отключить Видео' : 'Включить Видео';
    }
});

// Демонстрация экрана
shareScreenButton.addEventListener('click', async () => {
    try {
        screenStream = await navigator.mediaDevices.getDisplayMedia({ video: true });
        const screenTrack = screenStream.getVideoTracks()[0];

        for (let peerId in peers) {
            const sender = peers[peerId].peerConnection.getSenders().find(s => s.track.kind === 'video');
            if (sender) {
                await sender.replaceTrack(screenTrack);
            }
        }

        screenTrack.onended = async () => {
            for (let peerId in peers) {
                const sender = peers[peerId].peerConnection.getSenders().find(s => s.track.kind === 'video');
                if (sender) {
                    await sender.replaceTrack(localStream.getVideoTracks()[0]);
                }
            }
        };
    } catch (err) {
        console.error('Ошибка захвата экрана:', err);
        appendMessage(`Ошибка захвата экрана: ${err.message}`);
    }
});
и
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>P2P Чат с Видео и Аудио</title>
    <style>
        body { font-family: Arial, sans-serif; }
        #video-container { display: flex; }
        video { width: 45%; margin: 2.5%; border: 1px solid #ccc; }
        #chat { border: 1px solid #ccc; padding: 10px; height: 300px; overflow-y: scroll; }
        #message-input { width: 80%; }
        #controls { margin-top: 10px; }
        #controls button { margin-right: 5px; }
    </style>
</head>
<body>
    <h1>P2P Чат с Видео и Аудио</h1>
    <div id="video-container">
        <video id="localVideo" autoplay muted></video>
        <video id="remoteVideo" autoplay></video>
    </div>
    <div id="controls">
        <button id="toggleAudio">Отключить Аудио</button>
        <button id="toggleVideo">Отключить Видео</button>
        <button id="shareScreen">Поделиться Экраном</button>
    </div>
    <div id="chat">
        <!-- Сообщения будут отображаться здесь -->
    </div>
    <input type="text" id="message-input" placeholder="Введите сообщение...">
    <button id="send-button">Отправить</button>

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