janky
Version:
Janus Interface
209 lines (190 loc) • 7.37 kB
text/typescript
import Janus, { JanusJS } from "janus-gateway";
import LocalRTC from "../repositories/LocalRTC";
import PublisherEventsHandler from "../services/PublisherEventsHandler";
import Publisher from "../services/Publisher";
import Videoroom from "./Videoroom";
import SubVideoroom from "./SubVideoroom";
import { RoomExistsResponse, WhatToPublish } from "../types";
import RemoteFeeds from "../repositories/RemoteFeeds";
import eventEmitter from "../repositories/eventEmitter";
import { LOCAL_EVENTS } from "../events";
import { toHaveStyle } from "@testing-library/jest-dom/matchers";
class PubVideoroom extends Videoroom{
protected readonly type = 'publisher';
protected handler: JanusJS.PluginHandle | undefined;
private publisher: Publisher | undefined;
constructor (
public readonly roomID: number,
protected readonly userID: string,
protected readonly janusSession: Janus,
private readonly publishType: WhatToPublish
) {
super();
}
public unpublish() {
return this.publisher?.unpublish();
}
public switchByType(publishType: WhatToPublish) {
this.publisher?.switchByType(publishType);
}
public switchByDevice(
audioDeviceId: string | undefined,
videoDeviceId: string | undefined
) {
return this.publisher?.switchByDevice(audioDeviceId, videoDeviceId);
}
public muteAudio() {
this.handler?.muteAudio();
}
public unmuteAudio() {
this.handler?.unmuteAudio();
}
public muteVideo() {
this.handler?.muteVideo();
}
public unmuteVideo() {
this.handler?.unmuteVideo();
}
public async initiate(): Promise<JanusJS.PluginHandle> {
await this.attachVideoroom();
if( !(await this.checkRoomExists()) ){
await this.createRoom();
}
await this.joinRoom();
LocalRTC.setHandler(this.handler as JanusJS.PluginHandle); //to be removed
return this.handler as JanusJS.PluginHandle;
};
protected attachVideoroom(): Promise<JanusJS.PluginHandle> {
return new Promise<JanusJS.PluginHandle>((resolves: (value: JanusJS.PluginHandle) => void) => {
this.janusSession.attach({
plugin: 'janus.plugin.videoroom',
opaqueId: this.userID.toString(),
success: async (handle: JanusJS.PluginHandle): Promise<JanusJS.PluginCallbacks> => {
this.handler = handle;
eventEmitter.emit(LOCAL_EVENTS.HANDLER, handle);
await this.perpareRTC();
resolves(handle);
return {};
},
onmessage: async (msg: JanusJS.Message, jsep: JanusJS.JSEP) => {
await this.handleMessages(msg, jsep);
},
onlocaltrack(track, on) {
//I don't know if we should use them at all!
eventEmitter.emit(LOCAL_EVENTS.LOCAL_TRACK, track, on);
},
iceState: function(state) {
console.log("ICE state changed to " + state);
},
mediaState: function(medium, on, mid) {
console.log("Janus " + (on ? "started" : "stopped") + " receiving our " + medium + " (mid=" + mid + ")");
},
webrtcState: function(on) {
console.log("Janus says our WebRTC PeerConnection is " + (on ? "up" : "down") + " now");
},
slowLink: function(uplink, lost, mid) {
console.warn("Janus reports problems " + (uplink ? "sending" : "receiving") +
" packets on mid " + mid + " (" + lost + " lost packets)");
},
} as JanusJS.PluginOptions);
});
};
private checkRoomExists(): Promise<boolean> {
return new Promise<boolean>((resolves: (value: boolean)=> void ) => {
const message = {
'request': 'exists',
'room': this.roomID
};
this.handler?.send({
message,
success: ({exists}: RoomExistsResponse) => {
resolves(exists);
}
});
})
}
private createRoom(): Promise<void> {
return new Promise<void>((resolves: ()=> void, rejects: (reason: string) => void) => {
const message = {
"request": "create",
"room": this.roomID,
"permanent": false,
// "fir_freq": 10,
"description": this.roomID.toString(),
"is_private": false,
'publishers': 3,
'audiolevel_event': true,
'notify_joining': true,
'audio_active_packets': 100
};
this.handler?.send({
message,
success: (res) => {
if(res.error_code && res.error) {
rejects(res.error);
return;
}
resolves();
}
});
});
}
private joinRoom(): Promise<void> {
return new Promise<void>((resolve: () => void) => {
const message = {
"request": "join",
"room": this.roomID,
"ptype": this.type,
"display": this.userID,
};
this.handler?.send({
message,
success: () => { resolve()},
});
});
}
protected async perpareRTC(): Promise<void> {
const handler = this.handler as JanusJS.PluginHandle;
this.publisher = new Publisher('publisher_front', handler, this.publishType);
}
protected async handleMessages(msg: JanusJS.Message, jsep: JanusJS.JSEP) : Promise<void> {
new PublisherEventsHandler({
msg,
jsep,
handleRemoteSDP: () => (this.handler as JanusJS.PluginHandle).handleRemoteJsep({jsep}),
sendOffer: () => (this.publisher as Publisher).doOffering(),
handlePublishers: (list: any) => this.handlePublishers(list),
});
}
private async handlePublishers(list: any): Promise<void> {
console.debug("Got a list of available publishers/feeds:", list);
for(let p of list) {
let rid = p.id;
let streams = p.streams;
let display = p.display;
for(let i in streams) {
let stream = streams[i];
stream["id"] = rid;
stream["display"] = display;
}
await this.handleNewRemoteFeed(rid, display, streams);
}
};
private async handleNewRemoteFeed(rid: number, pubID: string, streams: any): Promise<void> {
const subvideoroom = new SubVideoroom(
this.roomID,
pubID,
this.janusSession,
rid,
streams
);
const subHandle = await subvideoroom.initiate();
RemoteFeeds.setFeed({
id: rid,
userID: pubID,
handler: subHandle,
streams: streams
});
}
};
export default PubVideoroom;