client.js 6.48 KB
var pc = null;

function negotiate() {
    pc.addTransceiver('video', { direction: 'recvonly' });
    pc.addTransceiver('audio', { direction: 'recvonly' });
    return pc.createOffer().then((offer) => {
        return pc.setLocalDescription(offer);
    }).then(() => {
        // wait for ICE gathering to complete with timeout
        return new Promise((resolve) => {
            if (pc.iceGatheringState === 'complete') {
                resolve();
            } else {
                let resolved = false;
                
                // ICE收集超时机制:3秒后强制继续
                const timeout = setTimeout(() => {
                    if (!resolved) {
                        console.warn('ICE gathering timeout after 3 seconds, proceeding with available candidates');
                        resolved = true;
                        resolve();
                    }
                }, 3000);
                
                const checkState = () => {
                    if (pc.iceGatheringState === 'complete' && !resolved) {
                        clearTimeout(timeout);
                        resolved = true;
                        pc.removeEventListener('icegatheringstatechange', checkState);
                        console.log('ICE gathering completed successfully');
                        resolve();
                    }
                };
                pc.addEventListener('icegatheringstatechange', checkState);
            }
        });
    }).then(() => {
        var offer = pc.localDescription;
        return fetch('/offer', {
            body: JSON.stringify({
                sdp: offer.sdp,
                type: offer.type,
            }),
            headers: {
                'Content-Type': 'application/json'
            },
            method: 'POST'
        });
    }).then((response) => {
        console.log('收到/offer接口响应,状态:', response.status);
        if (!response.ok) {
            throw new Error(`HTTP错误: ${response.status} ${response.statusText}`);
        }
        return response.json();
    }).then((answer) => {
        console.log('解析/offer接口响应:', answer);
        if(answer.code == -1){
            throw new Error(answer.msg);
        }


        if (!answer.sessionid) {
            throw new Error('服务器响应中缺少sessionid字段');
        }
        
        document.getElementById('sessionid').value = answer.sessionid;
        console.log('SessionID已设置:', answer.sessionid);
        console.log('sessionid元素当前值:', document.getElementById('sessionid').value);
        
        // 保存sessionId到本地存储(如果saveSessionId函数存在)
        saveSessionId(answer.sessionid);
        
        
        // 触发WebSocket连接(如果connectWebSocket函数存在)
        if (typeof connectWebSocket === 'function') {
            console.log('触发WebSocket连接...');
            connectWebSocket();
        }
        
        return pc.setRemoteDescription(answer);
    }).catch((e) => {
        console.error('WebRTC连接失败:', e);
        console.error('错误详情:', e.message);
        
        // 设置sessionid为0,表示连接失败
        document.getElementById('sessionid').value = '0';
        
        // 显示更详细的错误信息
        const errorMsg = `WebRTC连接失败: ${e.message}`;
        alert(errorMsg);
        
        // 如果存在状态显示元素,更新状态
        const statusElement = document.getElementById('overall-status');
        if (statusElement) {
            statusElement.textContent = `连接失败: ${e.message}`;
        }
    });
}

function start() {
    // 更新连接状态
    if (typeof updateConnectionStatus === 'function') {
        updateConnectionStatus('connecting', '正在建立WebRTC连接...');
    }
    
    var config = {
        sdpSemantics: 'unified-plan'
    };

    if (document.getElementById('use-stun').checked) {
        // 优化STUN服务器配置:使用多个快速STUN服务器
        config.iceServers = [
            { urls: ['stun:stun.l.google.com:19302'] },
            { urls: ['stun:stun1.l.google.com:19302'] },
            { urls: ['stun:stun2.l.google.com:19302'] }
        ];
        // ICE传输策略和候选者池大小优化
        config.iceTransportPolicy = 'all';
        config.iceCandidatePoolSize = 10;
    }

    pc = new RTCPeerConnection(config);

    // 添加ICE连接状态监控
    pc.addEventListener('iceconnectionstatechange', () => {
        console.log('ICE connection state:', pc.iceConnectionState);
        const statusElement = document.getElementById('connection-status');
        if (statusElement) {
            statusElement.textContent = `ICE状态: ${pc.iceConnectionState}`;
        }
    });

    // 添加ICE候选者收集状态监控
    pc.addEventListener('icegatheringstatechange', () => {
        console.log('ICE gathering state:', pc.iceGatheringState);
        const statusElement = document.getElementById('gathering-status');
        if (statusElement) {
            statusElement.textContent = `ICE收集: ${pc.iceGatheringState}`;
        }
    });

    // 添加连接状态监控
    pc.addEventListener('connectionstatechange', () => {
        console.log('Connection state:', pc.connectionState);
        const statusElement = document.getElementById('overall-status');
        if (statusElement) {
            statusElement.textContent = `连接状态: ${pc.connectionState}`;
        }
    });

    // connect audio / video
    pc.addEventListener('track', (evt) => {
        if (evt.track.kind == 'video') {
            document.getElementById('video').srcObject = evt.streams[0];
        } else {
            document.getElementById('audio').srcObject = evt.streams[0];
        }
    });

    document.getElementById('start').style.display = 'none';
    negotiate();
    document.getElementById('stop').style.display = 'inline-block';
}

function stop() {
    document.getElementById('stop').style.display = 'none';

    // close peer connection
    setTimeout(() => {
        pc.close();
    }, 500);
}

window.onunload = function(event) {
    // 在这里执行你想要的操作
    setTimeout(() => {
        pc.close();
    }, 500);
};

window.onbeforeunload = function (e) {
        setTimeout(() => {
                pc.close();
            }, 500);
        e = e || window.event
        // 兼容IE8和Firefox 4之前的版本
        if (e) {
          e.returnValue = '关闭提示'
        }
        // Chrome, Safari, Firefox 4+, Opera 12+ , IE 9+
        return '关闭提示'
      }