|  |  |  | 
|---|
|  |  |  | </div> | 
|---|
|  |  |  |  | 
|---|
|  |  |  | <script> | 
|---|
|  |  |  | console.log(RTCRtpReceiver.getCapabilities('video').codecs) | 
|---|
|  |  |  | console.log(RTCRtpReceiver.getCapabilities('audio').codecs) | 
|---|
|  |  |  | //whep操作方法 | 
|---|
|  |  |  | const restartPause = 2000; | 
|---|
|  |  |  | const unquoteCredential = (v) => ( | 
|---|
|  |  |  | JSON.parse(`"${v}"`) | 
|---|
|  |  |  | ); | 
|---|
|  |  |  | const linkToIceServers = (links) => ( | 
|---|
|  |  |  | (links !== null) ? links.split(', ').map((link) => { | 
|---|
|  |  |  | const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i); | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | class WHEPClient { | 
|---|
|  |  |  | constructor(wurl, videoId) { | 
|---|
|  |  |  | constructor(whepUrl, videoId) { | 
|---|
|  |  |  | this.video = videoId; | 
|---|
|  |  |  | this.url = new URL('whep', wurl); | 
|---|
|  |  |  | this.wurl = new URL('whep', whepUrl); | 
|---|
|  |  |  | this.pc = null; | 
|---|
|  |  |  | this.restartTimeout = null; | 
|---|
|  |  |  | this.eTag = ''; | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | start() { | 
|---|
|  |  |  | console.log("requesting ICE servers"); | 
|---|
|  |  |  | fetch(this.url, { | 
|---|
|  |  |  | fetch(this.wurl, { | 
|---|
|  |  |  | method: 'OPTIONS', | 
|---|
|  |  |  | }) | 
|---|
|  |  |  | .then((res) => this.onIceServers(res)) | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | console.log("sending offer"); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | fetch(this.url, { | 
|---|
|  |  |  | fetch(this.wurl, { | 
|---|
|  |  |  | method: 'POST', | 
|---|
|  |  |  | headers: { | 
|---|
|  |  |  | 'Content-Type': 'application/sdp', | 
|---|
|  |  |  | 
|---|
|  |  |  | if (res.status !== 201) { | 
|---|
|  |  |  | throw new Error('bad status code'); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | this.eTag = res.headers.get('E-Tag'); | 
|---|
|  |  |  | // this.eTag = res.headers.get('ETag'); | 
|---|
|  |  |  | this.eTag = res.headers.get("ETag") || res.headers.get('E-Tag'); | 
|---|
|  |  |  | return res.text(); | 
|---|
|  |  |  | }) | 
|---|
|  |  |  | .then((sdp) => this.onRemoteAnswer(new RTCSessionDescription({ | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | sendLocalCandidates(candidates) { | 
|---|
|  |  |  | fetch(this.url, { | 
|---|
|  |  |  | fetch(this.wurl, { | 
|---|
|  |  |  | method: 'PATCH', | 
|---|
|  |  |  | headers: { | 
|---|
|  |  |  | 'Content-Type': 'application/trickle-ice-sdpfrag', | 
|---|
|  |  |  | 'If-Match': this.eTag, | 
|---|
|  |  |  | }, | 
|---|
|  |  |  |  | 
|---|
|  |  |  | body: generateSdpFragment(this.offerData, candidates), | 
|---|
|  |  |  | }) | 
|---|
|  |  |  | .then((res) => { | 
|---|