Discussions

Ask a Question
Back to All

Issue with Real-Time WebRTC Streaming Playback Not Working

Hello D-ID Support Team,

I'm experiencing an issue with the WebRTC streaming functionality where video playback does not start immediately as expected after clicking the microphone button. Here’s a detailed summary of the issue and steps we've already tried:

Issue Description
After successfully establishing a WebRTC connection using D-ID's API, I receive the stream_id, session_id, and sdp_answer. The WebRTC connection is confirmed as established (WebRTC connection established successfully message in the console), and ICE candidates are also exchanged without any issues. However, the video does not start playing automatically as expected.

What We've Observed
Connection Details:

SDP Offer and Answer exchange completes successfully.
All ICE candidates are gathered and exchanged, and the connection state changes to connected.
Video Element:

The ontrack event is triggered, and we set srcObject to the received stream.
Despite this, the video playback does not start. We observe repeated errors like The play() request was interrupted by a new load request.
Browser Policies:

We suspect that browser autoplay policies may be affecting playback. We attempted to mute the video and add autoplay attributes, but this did not resolve the issue.
We also tried manual playback controls, but playback still does not start.
Steps We Have Taken

Tested across different browsers (Chrome, Firefox) and devices.
Added a manual play button to initiate playback, but this was also unsuccessful.
Request
Could you please provide guidance on:

Whether there are any specific settings required in the API to ensure immediate playback on WebRTC streaming.
Additional troubleshooting steps or code adjustments recommended by the D-ID team.
Any known limitations or compatibility issues with specific browsers or devices.
Thank you for your assistance in resolving this issue. I look forward to any insights or suggestions you may have to help get the video playback working smoothly.



// DID API Key와 비디오 요소 참조 설정
const DID_API_KEY = "Basic YOUR_ENCODED_API_KEY";
const videoRef = React.useRef(null);

// D-ID API로부터 SDP Offer와 ICE 서버 정보 요청
async function fetchWebRTCInfo() {
    try {
        const response = await fetch('https://api.d-id.com/talks/streams', {
            method: 'POST',
            headers: {
                "Content-Type": "application/json",
                "Authorization": DID_API_KEY
            },
            body: JSON.stringify({
                source_url: "https://example.com/your-image-url.jpg"
                // 추가적으로 필요한 파라미터가 있다면 여기에 포함
            })
        });

        if (!response.ok) throw new Error("Failed to fetch WebRTC info");

        const { sdp_offer, ice_servers, stream_id, session_id } = await response.json();
        console.log("Received stream_id:", stream_id);
        console.log("Received session_id:", session_id);
        console.log("Received sdp_offer:", sdp_offer);

        // WebRTC 연결 초기화
        initializeWebRTCConnection(sdp_offer, ice_servers, stream_id, session_id);
    } catch (error) {
        console.error("Failed to fetch WebRTC info:", error);
    }
}

// WebRTC 연결 초기화 함수
async function initializeWebRTCConnection(sdpOffer, iceServers, streamId, sessionId) {
    const configuration = { iceServers: iceServers };
    const peerConnection = new RTCPeerConnection(configuration);

    // ICE 후보 수집 및 전송
    peerConnection.onicecandidate = (event) => {
        if (event.candidate) {
            sendIceCandidateToServer(streamId, sessionId, event.candidate);
        }
    };

    // 원격 스트림 수신 후 비디오 요소에 연결
    peerConnection.ontrack = (event) => {
        console.log("Received remote track:", event);

        if (videoRef.current && videoRef.current.srcObject !== event.streams[0]) {
            videoRef.current.srcObject = event.streams[0];
            
            // 비디오 로드가 완료되면 자동 재생
            videoRef.current.onloadedmetadata = () => {
                if (videoRef.current.paused) {
                    videoRef.current.play().catch(error => {
                        console.error("Video play error:", error);
                    });
                }
            };
        }
    };

    // SDP Offer를 원격 설명으로 설정
    await peerConnection.setRemoteDescription(new RTCSessionDescription({ type: 'offer', sdp: sdpOffer }));
    const answer = await peerConnection.createAnswer();
    await peerConnection.setLocalDescription(answer);

    // SDP Answer를 D-ID 서버로 전송
    sendSdpAnswerToServer(streamId, sessionId, answer.sdp);
}

// D-ID 서버에 SDP Answer 전송
async function sendSdpAnswerToServer(streamId, sessionId, sdpAnswer) {
    try {
        const response = await fetch(`https://api.d-id.com/talks/streams/${streamId}/sdp`, {
            method: 'POST',
            headers: {
                "Content-Type": "application/json",
                "Authorization": DID_API_KEY
            },
            body: JSON.stringify({
                session_id: sessionId,
                answer: { type: "answer", sdp: sdpAnswer }
            })
        });

        if (!response.ok) throw new Error("Failed to send SDP answer");

        console.log("SDP answer sent successfully");
    } catch (error) {
        console.error("Failed to send SDP answer:", error);
    }
}

// D-ID 서버에 ICE 후보 전송
async function sendIceCandidateToServer(streamId, sessionId, candidate) {
    try {
        const response = await fetch(`https://api.d-id.com/talks/streams/${streamId}/ice`, {
            method: 'POST',
            headers: {
                "Content-Type": "application/json",
                "Authorization": DID_API_KEY
            },
            body: JSON.stringify({
                session_id: sessionId,
                candidate: {
                    candidate: candidate.candidate,
                    sdpMid: candidate.sdpMid,
                    sdpMLineIndex: candidate.sdpMLineIndex
                }
            })
        });

        if (!response.ok) throw new Error("Failed to send ICE candidate");

        console.log("ICE candidate sent successfully");
    } catch (error) {
        console.error("Failed to send ICE candidate:", error);
    }
}

// 초기 실행 함수 (예: 버튼 클릭 시 실행)
function startStreaming() {
    fetchWebRTCInfo();
}

// JSX에서 비디오 요소와 버튼
return (
    <div>
        <video ref={videoRef} autoPlay playsInline muted style={{ width: "100%", height: "auto" }} />
        <button onClick={startStreaming}>비디오 재생</button>
    </div>
);