@jellyfish-dev/react-client-sdk
Version:
React client library for Jellyfish.
135 lines (134 loc) • 4.63 kB
JavaScript
import EventEmitter from "events";
import { parseError } from "./types";
export class ScreenShareManager extends EventEmitter {
defaultConfig;
config;
data = {
audioMedia: null,
videoMedia: null,
status: "Not requested",
error: null,
};
// todo add nested read only
getSnapshot() {
return this.data;
}
constructor(defaultConfig) {
super();
this.defaultConfig = defaultConfig;
}
setConfig(config) {
this.config = config;
}
getType(options) {
if (options.audio && options.video)
return "audiovideo";
if (options.audio)
return "audio";
if (options.video)
return "video";
return null;
}
async start(config) {
const options = {
video: config?.videoTrackConstraints ??
this.config?.videoTrackConstraints ??
this.defaultConfig?.videoTrackConstraints,
audio: config?.audioTrackConstraints ??
this.config?.audioTrackConstraints ??
this.defaultConfig?.audioTrackConstraints,
};
const type = this.getType(options);
if (!type)
return;
try {
const newStream = await navigator.mediaDevices.getDisplayMedia(options);
this.data = {
error: null,
videoMedia: {
enabled: true,
stream: newStream,
track: newStream?.getVideoTracks()[0] ?? null,
},
audioMedia: {
enabled: true,
stream: newStream,
track: newStream?.getAudioTracks()[0] ?? null,
},
status: "OK",
};
this.setupOnEndedCallback();
this.emit("deviceReady", { type: type }, this.data);
}
catch (error) {
const parsedError = parseError(error);
this.emit("error", { type, error: parsedError, rawError: error }, this.data);
}
}
setupOnEndedCallback() {
if (this.data.videoMedia?.track) {
this.data.videoMedia.track.addEventListener("ended", async (event) => await this.onTrackEnded("video", event.target.id));
}
if (this.data.audioMedia?.track) {
this.data.audioMedia.track.addEventListener("ended", async (event) => await this.onTrackEnded("audio", event.target.id));
}
}
onTrackEnded = async (type, trackId) => {
const mediaType = type === "video" ? "videoMedia" : "audioMedia";
if (trackId === this?.data[mediaType]?.track?.id) {
await this.stop("audiovideo");
}
};
async stop(type) {
if (type === "video") {
for (const track of this.data?.videoMedia?.stream?.getTracks() ?? []) {
track.stop();
}
this.data.videoMedia = null;
}
else if (type === "audio") {
// todo test it
for (const track of this.data?.audioMedia?.stream?.getTracks() ?? []) {
track.stop();
}
this.data.audioMedia = null;
}
else {
for (const track of this.data?.videoMedia?.stream?.getTracks() ?? []) {
track.stop();
}
this.data.videoMedia = null;
for (const track of this.data?.audioMedia?.stream?.getTracks() ?? []) {
track.stop();
}
this.data.audioMedia = null;
}
this.emit("deviceStopped", { type }, this.data);
}
setEnable(type, value) {
if (type === "video" && this.data.videoMedia?.track) {
this.data.videoMedia.track.enabled = value;
this.data.videoMedia.enabled = value;
}
else if (type === "audio" && this.data.audioMedia?.track) {
this.data.audioMedia.track.enabled = value;
this.data.audioMedia.enabled = value;
}
else {
if (this.data.videoMedia?.track) {
this.data.videoMedia.track.enabled = value;
this.data.videoMedia.enabled = value;
}
if (this.data.audioMedia?.track) {
this.data.audioMedia.track.enabled = value;
this.data.audioMedia.enabled = value;
}
}
if (value) {
this.emit("deviceEnabled", { type }, this.data);
}
else {
this.emit("deviceDisabled", { type }, this.data);
}
}
}