janky
Version:
Janus Interface
240 lines (218 loc) • 7.32 kB
text/typescript
import { JanusJS } from "janus-gateway";
import LocalRTC from "../repositories/LocalRTC";
import { ParticipantType, WhatToPublish } from "../types";
import eventEmitter from "../repositories/eventEmitter";
import { LOCAL_EVENTS } from "../events";
interface CaptureByID {
deviceId: { exact: string}
}
interface OfferTrackType {
type: 'audio' | 'video' | 'screen';
capture: boolean | 'screen' | CaptureByID;
recv: false;
simulcast?: boolean;
svc?: null,
}
type MobileFacingMode = 'user' | 'environment';
interface MediaMobileVideo {
facingMode: {
exact: MobileFacingMode
}
}
interface MediaConstraints {
audio: boolean;
video: boolean | MediaMobileVideo
}
class Publisher {
public localStream: MediaStream | undefined;
constructor(
protected type: ParticipantType,
private readonly handler: JanusJS.PluginHandle,
private publishType: WhatToPublish
) {}
public setMobileFacingMode (facingMode: MobileFacingMode): void {
window.localStorage.setItem('mobile-camera-facing-mode', facingMode);
}
public getMobileFacingMode (): MobileFacingMode {
return (window.localStorage.getItem('mobile-camera-facing-mode') || 'user') as MobileFacingMode;
}
public async doOffering(): Promise<void> {
const jsep = await this.generateOffer();
this.sendJsep(jsep);
}
public unpublish(): Promise<void> {
return new Promise<void>((resolves: () => void) => {
this.handler.send({
message: {
request: 'unpublish',
},
success: () => {
resolves();
}
});
// clearing data (unset)
eventEmitter.emit(LOCAL_EVENTS.NULL_STREAM);
LocalRTC.setStream(null);
LocalRTC.setIDs(undefined, undefined); // undefined to make it obvious we are cleaning the old data here
})
}
private generateOffer(): Promise<JanusJS.JSEP> {
return new Promise<JanusJS.JSEP>((resolves: (jsep: JanusJS.JSEP) => void, rejects: (reason: string)=> void ) => {
const tracks: OfferTrackType[] = this.mapTypeToTracks();
this.handler.createOffer({
tracks,
iceRestart: true,
trickle: true,
success: async (jsep: JanusJS.JSEP) => {
await this.sendPublishCommand(jsep);
resolves(jsep);
},
error: (error: string) => {
console.log('Error On Creating Offer', error);
rejects(error)
}
} as JanusJS.OfferParams);
});
}
private mapTypeToCommand(): MediaConstraints {
switch(this.publishType) {
case "audio":
return {audio: true, video: false};
case "video":
return {audio: true, video: true};
case "video_environment":
return {
audio: true,
video: {
facingMode: {
exact: 'environment'
}
}
};
case "video_user":
return {
audio: true,
video: {
facingMode: {
exact: 'user'
}
}
};
case 'screen':
return {
audio: true,
video: true
};
default:
return {audio: false, video: false};
}
}
public switchByType(publishType: WhatToPublish): Promise<void> {
return new Promise<void>((resolves: () => void, rejects: (reason: string) => void) => {
this.publishType = publishType;
const tracks = this.mapTypeToTracks();
this.handler.replaceTracks({
tracks: tracks as unknown as JanusJS.TrackOption[],
success: () => resolves(),
error: err => rejects(err)
});
});
}
public switchByDevice(
audioDeviceId: string | undefined,
videoDeviceId: string | undefined
) {
const tracks: OfferTrackType[] = [];
if(audioDeviceId) {
tracks.push({
type: 'audio',
capture: { deviceId: { exact: audioDeviceId } },
recv: false
});
}
if(videoDeviceId) {
tracks.push({
type: 'video',
capture: { deviceId: { exact: videoDeviceId } },
recv: false
});
}
}
private mapTypeToTracks() {
const tracks: OfferTrackType[] = [];
const addAudio = ['video_environment', 'video_user', 'video', 'screen', 'audio'];
const addVideo = ['video_environment', 'video_user', 'video'];
if(addAudio.includes(this.publishType)) {
tracks.push({
recv: false,
type: 'audio',
capture: true
});
}
if(addVideo.includes(this.publishType)) {
tracks.push({
type: 'video',
capture: true,
simulcast: true,
svc: null,
recv: false,
});
}
if(this.publishType === 'screen') {
tracks.push({ type: 'screen', capture: true, recv: false });
}
return tracks;
}
private sendPublishCommand(jsep: JanusJS.JSEP): Promise<void> {
return new Promise<void>((resolves,rejects) => {
const mediaConstraints: MediaConstraints = this.mapTypeToCommand();
const message = { request: "publish", ...mediaConstraints };
this.handler.send({
message,
jsep,
success: data => {
if(data && data.error) {
console.log(data.error);
rejects(data.error);
return;
}
resolves();
},
error: err => {
console.log(err);
rejects(err);
}
});
});
}
private sendJsep(jsep: JanusJS.JSEP): Promise<void> {
return new Promise<void>((resolves, rejects) => {
const message = { request: "configure", audio: true, video: true }; // TO BE CHANGED
this.handler.send({
message,
"jsep": jsep,
success: (res) => {
if(res && res.error) {
rejects(res.error);
return;
}
resolves();
}
});
});
}
// private mapTypeToConstraints () {
// switch(this.type) {
// case 'publisher_audio':
// return {
// };
// case 'publisher_back':
// return {
// };
// case 'publisher_front':
// return {
// }
// }
// }
};
export default Publisher;