You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
3.9 KiB
TypeScript
139 lines
3.9 KiB
TypeScript
|
3 years ago
|
// WebRTC Sdp Player
|
||
|
|
export default class sdpPlayer {
|
||
|
|
private pc: any;
|
||
|
|
public player: any;
|
||
|
|
private statsTimeoutHandler: any;
|
||
|
|
private statsFun: Function = new Function();
|
||
|
|
private startFun: Function = new Function();
|
||
|
|
private errorFun: Function = (e)=>{
|
||
|
|
clearInterval(this.statsTimeoutHandler);
|
||
|
|
};
|
||
|
|
|
||
|
|
public setView(id: string): void {
|
||
|
|
this.player = document.getElementById(id);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* video play
|
||
|
|
* @param url .sdp video url
|
||
|
|
*/
|
||
|
|
public start(url: string): void {
|
||
|
|
if (url === '' && !this.player) {
|
||
|
|
cc.error("need url and set player ID");
|
||
|
|
this.errorFun(`need url and set player ID`); // cahnge to error Fun
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
// cc.log('Start play');
|
||
|
|
const offerSdpOption = {
|
||
|
|
offerToReceiveAudio: true,
|
||
|
|
offerToReceiveVideo: true
|
||
|
|
};
|
||
|
|
this.pc = new RTCPeerConnection();
|
||
|
|
this.pc.addTransceiver("audio", { direction: "recvonly" });
|
||
|
|
this.pc.addTransceiver("video", { direction: "recvonly" });
|
||
|
|
this.pc.oniceconnectionstatechange = this.onIceStateChange(this.pc);
|
||
|
|
this.pc.stream = new MediaStream();
|
||
|
|
this.pc.ontrack = this.gotRemoteStream.bind(this);
|
||
|
|
this.pc.createOffer(offerSdpOption).then((offer) => {
|
||
|
|
this.pc.setLocalDescription(offer);
|
||
|
|
const xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
|
||
|
|
xmlhttp.timeout = 6000;
|
||
|
|
xmlhttp.onerror = this.errorFun.bind(this); // xmlerror to error Fun
|
||
|
|
xmlhttp.ontimeout = this.errorFun.bind(this); // timeout to error Fun
|
||
|
|
xmlhttp.onload = () => {
|
||
|
|
if (xmlhttp.status == 200) {
|
||
|
|
const data = JSON.parse(xmlhttp.responseText);
|
||
|
|
const remoteSdp = data.remoteSdp;
|
||
|
|
this.pc.setRemoteDescription(
|
||
|
|
new RTCSessionDescription(remoteSdp),
|
||
|
|
() => {
|
||
|
|
cc.log("setRemoteDescription success!");
|
||
|
|
},
|
||
|
|
(e) => {
|
||
|
|
stop();
|
||
|
|
this.errorFun(e.message); // cahnge to error Fun
|
||
|
|
cc.log("setRemoteDescription failed, message:" + e.message);
|
||
|
|
}
|
||
|
|
);
|
||
|
|
this.startFun();
|
||
|
|
this.onStatus();
|
||
|
|
} else {
|
||
|
|
this.errorFun(`xml status: ${xmlhttp.status}`); // cahnge to error Fun
|
||
|
|
}
|
||
|
|
};
|
||
|
|
xmlhttp.open("POST", url);
|
||
|
|
xmlhttp.send(JSON.stringify({ localSdp: offer }));
|
||
|
|
}).catch((reason) => {
|
||
|
|
this.errorFun(reason); // cahnge to error Fun
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private onIceStateChange(pc): void {
|
||
|
|
if (pc) {
|
||
|
|
if (pc.iceConnectionState == 'disconnected') stop();
|
||
|
|
cc.log('ICE state: ' + pc.iceConnectionState);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private gotRemoteStream(m): void {
|
||
|
|
cc.log("ontrack, kind:" + m.track.kind);
|
||
|
|
this.pc.stream.addTrack(m.track);
|
||
|
|
this.player.srcObject = this.pc.stream;
|
||
|
|
}
|
||
|
|
|
||
|
|
// video status event timer
|
||
|
|
private onStatus(): void {
|
||
|
|
var checkInterval = 1000; // check every 1s (do not use lower values)
|
||
|
|
this.statsTimeoutHandler = setInterval(this.statsFun, checkInterval)
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* video event listener
|
||
|
|
* @param event start,stats,error
|
||
|
|
* @param fn listener callback function
|
||
|
|
*/
|
||
|
|
public on(event: "start" | "stats" | "error", fn: Function): void {
|
||
|
|
this[event + "Fun"] = (event === "error") ? (e) => {
|
||
|
|
clearInterval(this.statsTimeoutHandler);
|
||
|
|
fn(e);
|
||
|
|
} : fn;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** video voice (support max and min voice only) */
|
||
|
|
public setVolume(num: Number): void {
|
||
|
|
if (this.player) {
|
||
|
|
if (num == 0) this.player.muted = true;
|
||
|
|
else this.player.muted = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** video stop */
|
||
|
|
public stop(): void {
|
||
|
|
clearInterval(this.statsTimeoutHandler);
|
||
|
|
try {
|
||
|
|
if (this.player) {
|
||
|
|
const tracks = this.player.srcObject?.getTracks();
|
||
|
|
this.player.load();
|
||
|
|
if (tracks) {
|
||
|
|
tracks.forEach(track => track.stop());
|
||
|
|
this.pc?.removeStream(this.player.srcObject);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} catch(ex) {
|
||
|
|
cc.log(ex);
|
||
|
|
}
|
||
|
|
this.pc?.close();
|
||
|
|
this.pc = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** auto play active (need user touch active) */
|
||
|
|
public autoPlayActive(): void {
|
||
|
|
if (this.player) {
|
||
|
|
this.player.muted = false;
|
||
|
|
this.player.controls = false;
|
||
|
|
this.player.autoplay = true;
|
||
|
|
this.player.playsinline = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|