Задать вопрос
@Andre548

Можно ли передавать потоковое видео между 2 проектами?

Использовал кто-нибудь webrtc в связке с ларавель?
Есть задача, на одном проекте запускаем стрим, на втором проекте все желающие могут подключится и смотреть.

Для начала пытался на одном проекте запустить и просматривать, но получаю ошибку.

Код:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>WebRTC Receiver</title>
    <script src="https://js.pusher.com/7.0/pusher.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/laravel-echo/dist/echo.iife.min.js"></script>
</head>
<body>
<video id="remoteVideo" playsinline autoplay></video>
<script>
    const remoteVideo = document.getElementById('remoteVideo');

    window.Echo = new Echo({
        broadcaster: 'pusher',
        key: 'ключ',
        cluster: 'eu',
        encrypted: true
    });

    const channel = window.Echo.channel('webrtc-channel');
    let pc;
    let pendingCandidates = [];

    channel.listen('.webrtc-signal', async event => {
        if (event.type === 'offer') {
            pc = createPeerConnection();
            const remoteDesc = new RTCSessionDescription(event.data);
            await pc.setRemoteDescription(remoteDesc);

            const answer = await pc.createAnswer();
            await pc.setLocalDescription(answer);
            sendSignal('answer', pc.localDescription);

            // Обработка всех отложенных ICE кандидатов
            pendingCandidates.forEach(async candidate => {
                await pc.addIceCandidate(candidate);
            });
            pendingCandidates = [];
        } else if (event.type === 'candidate') {
            const candidate = new RTCIceCandidate(event.data);
            if (pc && pc.remoteDescription) {
                await pc.addIceCandidate(candidate);
            } else {
                pendingCandidates.push(candidate);
            }
        }
    });

    function createPeerConnection() {
        const pc = new RTCPeerConnection({
            iceServers: [
                { urls: 'stun:stun.l.google.com:19302' }
            ]
        });

        pc.onicecandidate = event => {
            if (event.candidate) {
                sendSignal('candidate', event.candidate);
            }
        };

        pc.ontrack = event => {
            remoteVideo.srcObject = event.streams[0];
        };

        return pc;
    }

    async function sendSignal(type, data) {
        // Добавление новой строки к SDP
        if (data.sdp) {
            data.sdp += '\n';
        }

        const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
        const response = await fetch('/send-signal', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRF-TOKEN': csrfToken
            },
            body: JSON.stringify({ type, data })
        });
        const result = await response.json();
        console.log(result);
    }
</script>
</body>
</html>


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>WebRTC Sender</title>
    <script src="https://js.pusher.com/7.0/pusher.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/laravel-echo/dist/echo.iife.min.js"></script>
</head>
<body>
<video id="localVideo" playsinline autoplay muted></video>
<button id="startButton">Start Stream</button>
<button id="hangupButton" disabled>Hang Up</button>
<script>
    const startButton = document.getElementById('startButton');
    const hangupButton = document.getElementById('hangupButton');
    const localVideo = document.getElementById('localVideo');

    window.Echo = new Echo({
        broadcaster: 'pusher',
        key: 'ключ',
        cluster: 'eu',
        encrypted: true
    });

    const channel = window.Echo.channel('webrtc-channel');
    let localStream;
    let pc;
    let pendingCandidates = [];

    startButton.onclick = async () => {
        localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
        localVideo.srcObject = localStream;

        pc = createPeerConnection();
        localStream.getTracks().forEach(track => pc.addTrack(track, localStream));

        const offer = await pc.createOffer();
        await pc.setLocalDescription(offer);
        sendSignal('offer', pc.localDescription);

        startButton.disabled = true;
        hangupButton.disabled = false;
    };

    hangupButton.onclick = () => {
        pc.close();
        pc = null;
        localStream.getTracks().forEach(track => track.stop());
        localVideo.srcObject = null;

        startButton.disabled = false;
        hangupButton.disabled = true;
    };

    channel.listen('.webrtc-signal', async event => {
        if (event.type === 'answer') {
            const remoteDesc = new RTCSessionDescription(event.data);
            await pc.setRemoteDescription(remoteDesc);
            // Обработка всех отложенных ICE кандидатов
            pendingCandidates.forEach(async candidate => {
                await pc.addIceCandidate(candidate);
            });
            pendingCandidates = [];
        } else if (event.type === 'candidate') {
            const candidate = new RTCIceCandidate(event.data);
            if (pc.remoteDescription) {
                await pc.addIceCandidate(candidate);
            } else {
                pendingCandidates.push(candidate);
            }
        }
    });

    function createPeerConnection() {
        const pc = new RTCPeerConnection({
            iceServers: [
                { urls: 'stun:stun.l.google.com:19302' }
            ]
        });

        pc.onicecandidate = event => {
            if (event.candidate) {
                sendSignal('candidate', event.candidate);
            }
        };

        return pc;
    }

    async function sendSignal(type, data) {
        // Добавление новой строки к SDP
        if (data.sdp) {
            data.sdp += '\n';
        }

        const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
        const response = await fetch('/send-signal', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRF-TOKEN': csrfToken
            },
            body: JSON.stringify({ type, data })
        });
        const result = await response.json();
        console.log(result);
    }
</script>
</body>
</html>

Ошибка на стороне получателя стриминга:

Uncaught (in promise) DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=ssrc:3152920865 msid:26ea93c0-3d67-45a0-ba6a-00277a7c99fb 4706f36e-605f-4c6c-af9e-6f4feef63463 Invalid SDP line
  • Вопрос задан
  • 109 просмотров
Подписаться 2 Простой Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы