UNPKG

vroom-web-sdk-beta

Version:

VROOM SDK (beta) by True Virtual World

276 lines (218 loc) 6.92 kB
import { get } from 'lodash' import VroomPlugin from './vroom.plugin' import VroomSession from '../session/vroom.session' import { keepAlivePeriod, VROOM_COMMAND_STATUS } from '../constants' import { JoinResponseType } from '../types/message' import VroomParticipant from '../types/publisher' class PublisherPlugin extends VroomPlugin { keepAliveTimeoutID: any userId: number | undefined privateId: number | undefined roomId: number | undefined onPublisherJoined: Function = () => {} onPublisherSJoined: Function = () => {} onPublisherMuteAudio: Function = () => {} onPublisherMuteVideo: Function = () => {} onLeave: Function = () => {} isCreateOffer: boolean = false stream!: MediaStream constructor(session: VroomSession, id: number) { super(session, id) this.setKeepAliveTimeout() } public async joinRoom( stream: MediaStream, roomId: number, display: string, muteAudio = false, muteVideo = false, ): Promise<JoinResponseType> { try { this.roomId = roomId this.stream = stream let joinResponse: any = await this.sendMessage({ request: 'join', room: roomId, display, ptype: 'publisher', mute_audio: muteAudio, mute_video: muteVideo, }) if (joinResponse.janus === 'event' && get(joinResponse, 'plugindata.data', false)) { const data = joinResponse.plugindata.data if (data.videoroom === 'joined') { this.userId = data.id this.privateId = data.private_id // add localStream to peerConnection stream.getTracks().forEach((track: MediaStreamTrack) => { this.pc.addTrack(track) }) await this.createOffer(100000, !muteAudio, !muteVideo) } const mapPublisher = data.publishers.map((d: any) => new VroomParticipant(d)) return { status: data.videoroom, success: true, publisher: mapPublisher || [], attendees: data.attendees || [] } as JoinResponseType } return { status: 'errors', success: false, publisher: [], attendees: [], } as JoinResponseType } catch (e) { return { status: e, success: false, publisher: [], attendees: [], } as JoinResponseType } } async onMessage(message: any) { const { janus } = message switch (janus) { case VROOM_COMMAND_STATUS.TRICKLE: { if (this.isRemoteDescriptionSet && message.candidate.sdpMid) { if (!message?.candidate?.completed) { await this.pc.addIceCandidate( new RTCIceCandidate({ candidate: message.candidate.candidate, sdpMid: message.candidate.sdpMid, sdpMLineIndex: message.candidate.sdpMLineIndex, }), ) } } if (!message?.candidate.completed) { this.cachedCandidates.push( new RTCIceCandidate({ candidate: message.candidate.candidate, sdpMid: message.candidate.sdpMid, sdpMLineIndex: message.candidate.sdpMLineIndex, }), ) } return } case VROOM_COMMAND_STATUS.EVENT: { if (get(message, 'plugindata.data.videoroom') === VROOM_COMMAND_STATUS.EVENT) { const data = get(message, 'plugindata.data') if (get(data, 'publishers', false)) { const publisher = get(data, 'publishers') publisher .map((data: any) => new VroomParticipant(data)) .forEach((p: VroomParticipant) => this.onPublisherJoined(p)) } else if (get(data, 'leaving', false)) { const leavingPublisherID = get(data, 'leaving') this.onLeave({ id: leavingPublisherID }) } } if (get(message, 'plugindata.data.videoroom') === VROOM_COMMAND_STATUS.S_JOIN) { this.onPublisherSJoined(get(message, 'plugindata.data')) } return } case VROOM_COMMAND_STATUS.MUTE_AUDIO: { const data = get(message, 'plugindata.data') this.onPublisherMuteAudio(data) return } } if (message['jsep']) { const answerRes = await this.createAnswer(message['jsep']) await this.sendMessage( { request: 'start', room: this.roomId, }, answerRes, ) } } public isAudioMuted() { return !this.stream.getAudioTracks()[0].enabled } public muteAudio() { this.stream.getAudioTracks()[0].enabled = false } public unmuteAudio() { this.stream.getAudioTracks()[0].enabled = true } public isVideoMuted() { return !this.stream.getVideoTracks()[0].enabled } public muteVideo() { this.stream.getVideoTracks()[0].enabled = false } public unmuteVideo() { this.stream.getVideoTracks()[0].enabled = true } private keepAlive() { if (this.connected) { this.setKeepAliveTimeout() this .send({ janus: 'keepalive', session_id: this.sessionId, }) .catch(console.error) } } private setKeepAliveTimeout() { if (this.connected) { this.keepAliveTimeoutID = setTimeout(() => this.keepAlive(), keepAlivePeriod) } } private async createOffer(bitrate: number, audio: boolean, video: boolean) { const offerObj = { offerToReceiveAudio: true, offerToReceiveVideo: true, } const _offer = await this.pc.createOffer(offerObj) await this.pc.setLocalDescription(_offer) const configObj = { request: 'configure', audio, video, bitrate, } const offerResponse: any = await this.sendMessage(configObj, _offer) await this.pc.setRemoteDescription( new RTCSessionDescription({ sdp: offerResponse.jsep.sdp, type: offerResponse.jsep.type, }), ) this.isRemoteDescriptionSet = true this.cachedCandidates.forEach((candidate: RTCIceCandidate) => { this.pc.addIceCandidate(candidate) }) this.cachedCandidates = [] as RTCIceCandidate[] this.isCreateOffer = true } private async createAnswer(jsep: any) { await this.pc.setRemoteDescription( new RTCSessionDescription({ sdp: jsep.sdp, type: jsep.type, }), ) this.isRemoteDescriptionSet = true // TODO async could not use in loop this.cachedCandidates.forEach(async (candidate: RTCIceCandidate) => { await this.pc.addIceCandidate(candidate) }) this.cachedCandidates = [] as RTCIceCandidate[] const answerRes = await this.pc.createAnswer({ offerToReceiveAudio: true, offerToReceiveVideo: true, }) await this.pc.setLocalDescription(answerRes) return answerRes } } export default PublisherPlugin