seepur/resources/scripts/applications/home/scripts/call.service.ts
2020-04-12 10:25:42 -04:00

166 lines
5 KiB
TypeScript

export default class CallService {
private callId: string;
private inCall: boolean;
private peerId: number;
private subscription;
private localStream: MediaStream;
private remoteStream: MediaStream;
private needToAddStream: boolean = true;
private pc: RTCPeerConnection;
constructor(private ws) {
this.callId = null;
this.inCall = false;
this.peerId = -1;
this.subscription = null;
this.pc = null;
this.localStream = null;
this.remoteStream = null;
this.remoteStream = new MediaStream();
}
async connectToCall(callId: string): Promise<boolean> {
if (this.inCall) throw new Error('Already connected to call');
this.subscription = this.ws.subscribe(`call:${callId}`);
const subscription = this.subscription;
const self = this;
return new Promise((resolve, reject) => {
subscription.on('error', (e) => {
console.error(e);
resolve(false)
});
subscription.on('ready', () => {
this.callId = callId;
this.inCall = true;
resolve(true)
});
subscription.on('close', self.close.bind(this));
subscription.on('call:start', self.onCallStart.bind(this));
subscription.on('call:standby', self.onCallStandby.bind(this));
subscription.on('wrtc:sdp:offer', self.onRemoteOffer.bind(this));
subscription.on('wrtc:sdp:answer', self.onRemoteAnswer.bind(this));
subscription.on('wrtc:ice', self.onRemoteIce.bind(this));
});
}
private send(event: string, payload: { [key: string]: any }) {
this.subscription.emit(event, {
id: this.peerId,
...payload
})
}
async onCallStart(payload: { iceServers: RTCIceServer[], id: number }) {
console.log(payload);
this.peerId = payload.id;
this.pc = new RTCPeerConnection({ iceServers: payload.iceServers });
console.log('Created PeerConnection');
this.setupPeerConnectionListeners();
const sdp = await this.pc.createOffer();
await this.pc.setLocalDescription(sdp);
console.log('Local description Set');
this.send('wrtc:sdp:offer', {
sdp
});
return true;
}
async onCallStandby(payload: { iceServers: RTCIceServer[], id: number }) {
console.log(payload);
this.peerId = payload.id;
this.pc = new RTCPeerConnection({ iceServers: payload.iceServers });
console.log('Created PeerConnection');
this.setupPeerConnectionListeners();
return true;
}
setupPeerConnectionListeners() {
this.pc.addEventListener("icecandidate", this.onLocalIce.bind(this));
this.pc.addEventListener('connectionstatechange', event => {
console.log(`PC Connection state: ${this.pc.connectionState}`);
// if (this.pc.connectionState === 'connected') {
// // Peers connected!
// }
});
this.pc.addEventListener('iceconnectionstatechange', event => {
console.log('iceconnectionstatechange');
console.log(this.pc.iceConnectionState);
})
this.pc.addEventListener('track', async (event) => {
console.log('On remote track!');
this.remoteStream.addTrack(event.track);
});
this.pc.addEventListener('icegatheringstatechange', event => {
console.log('icegatheringstatechange', this.pc.iceGatheringState);
});
if (this.needToAddStream && this.localStream) {
this.localStream.getTracks().forEach(t => {
console.log('adding track to pc - in the event list');
console.log(t);
this.pc.addTrack(t, this.localStream);
});
this.needToAddStream = false;
}
}
onLocalIce(event) {
if (event.candidate) {
console.log('Sending candidate');
this.send('wrtc:ice', {
ice: event.candidate
});
}
}
async onRemoteOffer(payload) {
const offer = new RTCSessionDescription(payload.sdp);
await this.pc.setRemoteDescription(offer);
console.log('Remote offer Set');
const sdp = await this.pc.createAnswer();
this.send('wrtc:sdp:answer', {
sdp
});
await this.pc.setLocalDescription(sdp);
console.log('Local answer Set');
return true;
}
async onRemoteAnswer(payload) {
const answer = new RTCSessionDescription(payload.sdp);
await this.pc.setRemoteDescription(answer);
console.log('Remote answer Set');
return true;
}
async onRemoteIce(payload) {
const ice = payload.ice;
await this.pc.addIceCandidate(ice);
return true;
}
async getUserMedia(constraints: MediaStreamConstraints = { video: false, audio: true }) {
if (this.localStream) return this.localStream;
this.localStream = await navigator.mediaDevices.getUserMedia(constraints);
if (this.pc) {
if (this.needToAddStream && this.localStream) {
this.localStream.getTracks().forEach(t => {
console.log('adding track to pc - in get user media');
this.pc.addTrack(t, this.localStream);
});
this.needToAddStream = false;
}
}
return this.localStream;
}
getRemoteStream() {
return this.remoteStream;
}
close() {
if (this.subscription) this.subscription.close();
this.subscription = null;
this.inCall = false;
}
}