💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ## code <details> <summary>index.html</summary> ``` <!DOCTYPE html> <html lang="zh-cmn-Hans"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>Title</title> <style> video{ width: 300px; height: 300px; } </style> </head> <body> <div> <button id="start">start</button> <button id="call">call</button> <button id="hangup">hangup</button> </div> <div> <video playsinline id="local"></video> <video playsinline autoplay id="remote"></video> </div> <script src="//raw.githubusercontent.com/webrtcHacks/adapter/master/release/adapter.js"></script> <script> // init 'use strict'; /** * * @type RTCPeerConnection */ let pc1 = null; /** * @type RTCPeerConnection */ let pc2 = null; let localVideo = null; let remoteVideo = null; /** * * @type MediaStream */ let localStream=null; let btn_start=null; let btn_call=null; let btn_hangup=null; const constraints = { video: true, audio: true } btn_start=document.querySelector("#start") btn_start.addEventListener("click",start) btn_call=document.querySelector("#call") btn_call.addEventListener("click",call) btn_hangup=document.querySelector("#hangup") btn_hangup.addEventListener("click",hangup) localVideo=document.querySelector("#local") remoteVideo=document.querySelector("#remote") function start() { navigator.mediaDevices.getUserMedia(constraints) .then(stream=>{ localStream=stream; localVideo.srcObject=stream; localVideo.play(); }) .catch(e=>{ console.log(e); }) } async function call() { // const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]} const configuration = {} pc1 = new RTCPeerConnection(configuration) pc1.onicecandidate=handle_icecandidate.bind(pc1) pc1.oniceconnectionstatechange=handle_iceconnectionstatechange pc2=new RTCPeerConnection(configuration) pc2.onicecandidate=handle_icecandidate.bind(pc2) pc2.oniceconnectionstatechange=handle_iceconnectionstatechange pc2.ontrack=handle_track //添加流 pc1 localStream.getTracks().forEach(track => pc1.addTrack(track, localStream)); // 创建 offer const offerOptions = { offerToReceiveAudio: 1, offerToReceiveVideo: 1 }; const offer = await pc1.createOffer(offerOptions) createSession(offer,pc1,pc2) // 创建 answer let answer = await pc2.createAnswer(); createSession(answer,pc2,pc1) } function handle_icecandidate(e) { if (e.candidate){ getOtherPc(this).addIceCandidate(e.candidate).catch(err=>{ console.log(err); }) } } function handle_iceconnectionstatechange(e) { // this 可能为 pc1 或pc2 console.log(getPcName(this) + " event " + e.iceConnectionState); } function handle_track(e) { if (remoteVideo.srcObject !== e.streams[0]) { remoteVideo.srcObject = e.streams[0]; remoteVideo.play(); console.log('pc2 received remote stream'); } } function createSession(session,pc_1,pc_2){ pc_1.setLocalDescription(session).catch(e=>{ console.log(e); }) pc_2.setRemoteDescription(session).catch(e=>{ console.log(e); }) } function getOtherPc(pc){ return (pc===pc1)?pc2:pc1; } function getPcName(pc){ return (pc===pc1)?"pc1":"pc1"; } function hangup() { pc1.close() pc2.close() pc1 = null; pc2 = null; } </script> </body> </html> ``` </details> <br/> 效果 ![](https://img.kancloud.cn/88/c3/88c3308a7b2eb8348d12fa023ac8872d_604x302.png)