callskit
Version:
A toolkit for building call experience using Cloudflare Realtime
1,114 lines (1,102 loc) • 39.2 kB
JavaScript
import { setLogLevel, PartyTracks, getMic, getCamera, devices$, getScreenshare } from 'partytracks/client';
import { Observable, BehaviorSubject, of, filter, switchMap } from 'rxjs';
import invariant from 'tiny-invariant';
import PartySocket from 'partysocket';
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __typeError = (msg) => {
throw TypeError(msg);
};
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
target[prop] = source[prop];
}
return target;
};
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/utils/events-handler.ts
var _callbacksMap, _globalCallbacks;
var EventsHandler = class {
constructor() {
__privateAdd(this, _callbacksMap);
__privateAdd(this, _globalCallbacks);
__privateSet(this, _callbacksMap, /* @__PURE__ */ new Map());
__privateSet(this, _globalCallbacks, /* @__PURE__ */ new Set());
}
emit(event, ...args) {
var _a;
(_a = __privateGet(this, _callbacksMap).get(event)) == null ? void 0 : _a.forEach((callback) => callback(...args));
__privateGet(this, _globalCallbacks).forEach((callback) => callback(event, ...args));
}
addEventListener(event, callback) {
if (!__privateGet(this, _callbacksMap).has(event)) {
__privateGet(this, _callbacksMap).set(event, /* @__PURE__ */ new Set());
}
__privateGet(this, _callbacksMap).get(event).add(callback);
}
removeEventListener(event, callback) {
var _a;
(_a = __privateGet(this, _callbacksMap).get(event)) == null ? void 0 : _a.delete(callback);
}
subscribe(event, callback) {
this.addEventListener(event, callback);
return () => this.removeEventListener(event, callback);
}
subscribeAll(callback) {
__privateGet(this, _globalCallbacks).add(callback);
return () => {
__privateGet(this, _globalCallbacks).delete(callback);
};
}
unsubscribeAll(callback) {
__privateGet(this, _globalCallbacks).delete(callback);
}
once(event, callback) {
const wrapper = (...args) => {
this.removeEventListener(event, wrapper);
callback(...args);
};
this.addEventListener(event, wrapper);
return () => {
this.removeEventListener(event, wrapper);
};
}
clearAll() {
__privateGet(this, _callbacksMap).clear();
__privateGet(this, _globalCallbacks).clear();
}
};
_callbacksMap = new WeakMap();
_globalCallbacks = new WeakMap();
// src/utils/logger.ts
var _Logger = class _Logger {
constructor(options = {}) {
var _a, _b, _c;
this.level = (_a = options.level) != null ? _a : "info";
this.prefix = (_b = options.prefix) != null ? _b : "";
this.enabled = (_c = options.enabled) != null ? _c : true;
}
shouldLog(level) {
return this.enabled && _Logger.levels[level] >= _Logger.levels[this.level];
}
formatMessage(level, args) {
const prefix = this.prefix ? `[${this.prefix}]` : "";
return [prefix, ...args];
}
debug(...args) {
if (this.shouldLog("debug")) {
console.debug(...this.formatMessage("debug", args));
}
}
info(...args) {
if (this.shouldLog("info")) {
console.info(...this.formatMessage("info", args));
}
}
warn(...args) {
if (this.shouldLog("warn")) {
console.warn(...this.formatMessage("warn", args));
}
}
error(...args) {
if (this.shouldLog("error")) {
console.error(...this.formatMessage("error", args));
}
}
setLevel(level) {
this.level = level;
}
enable() {
this.enabled = true;
}
disable() {
this.enabled = false;
}
};
_Logger.levels = {
debug: 0,
info: 1,
warn: 2,
error: 3
};
var Logger = _Logger;
var contextStack = [];
function runWithContext(context, fn) {
contextStack.push(context);
try {
return fn();
} finally {
contextStack.pop();
}
}
function getCurrentCallContext() {
const ctx = contextStack[contextStack.length - 1];
invariant(ctx, "No active CallContext");
return ctx;
}
// src/lib/call-chat/call-chat.ts
var _ctx, _CallChat_instances, sendMessage_fn;
var CallChat = class extends EventsHandler {
constructor() {
super();
__privateAdd(this, _CallChat_instances);
this.messages = [];
__privateAdd(this, _ctx);
__privateSet(this, _ctx, getCurrentCallContext());
}
sendTextMessage(message) {
__privateMethod(this, _CallChat_instances, sendMessage_fn).call(this, { type: "text", message: message.trim() });
}
addMessage(message) {
const parsedMessage = __spreadProps(__spreadValues({}, message), {
created_at: new Date(message.created_at)
});
this.messages = [...this.messages, parsedMessage];
this.emit("message", parsedMessage);
}
addMessagesInBulk(messages) {
const parsed = messages.map((message) => __spreadProps(__spreadValues({}, message), {
created_at: new Date(message.created_at)
}));
this.messages = [...this.messages, ...parsed];
this.emit("loaded", parsed);
}
};
_ctx = new WeakMap();
_CallChat_instances = new WeakSet();
sendMessage_fn = function(message) {
__privateGet(this, _ctx).socket.sendAction({ action: "chat/message", message });
};
new Observable(
(subscriber) => {
const canvas = document.createElement("canvas");
canvas.height = 720;
canvas.width = 1280;
const ctx = canvas.getContext("2d");
invariant(ctx);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
const interval = setInterval(() => {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
}, 1e3);
subscriber.next(canvas.captureStream().getVideoTracks()[0]);
return () => {
clearInterval(interval);
};
}
);
function getInaudibleTrack() {
const audioContext = new AudioContext();
audioContext.resume();
const oscillator = audioContext.createOscillator();
oscillator.type = "triangle";
oscillator.frequency.setValueAtTime(20, audioContext.currentTime);
const gainNode = audioContext.createGain();
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
oscillator.connect(gainNode);
const destination = audioContext.createMediaStreamDestination();
gainNode.connect(destination);
oscillator.start();
const track = destination.stream.getAudioTracks()[0];
return { track, audioContext };
}
new Observable(
(subscriber) => {
const { audioContext, track } = getInaudibleTrack();
subscriber.next(track);
return () => {
track.stop();
audioContext.close();
};
}
);
function createTrackId(metadata) {
return `${metadata.sessionId}/${metadata.trackName}`;
}
function parseTrackId(trackId) {
const [sessionId, trackName] = trackId.split("/");
return { sessionId, trackName };
}
// src/lib/call-participant/call-participant.ts
var _ctx2, _micEnabled$, _micTrackId$, _micEnabled, _micTrack, _cameraEnabled$, _cameraTrackId$, _cameraEnabled, _cameraTrack, _screenshareEnabled$, _screenshareVideoTrackId$, _screenshareAudioTrackId$, _screenshareEnabled, _screenshareVideoTrack, _screenshareAudioTrack;
var _CallParticipant = class _CallParticipant extends EventsHandler {
constructor(options) {
super();
__privateAdd(this, _ctx2);
__privateAdd(this, _micEnabled$);
__privateAdd(this, _micTrackId$);
__privateAdd(this, _micEnabled, false);
__privateAdd(this, _micTrack);
__privateAdd(this, _cameraEnabled$);
__privateAdd(this, _cameraTrackId$);
__privateAdd(this, _cameraEnabled, false);
__privateAdd(this, _cameraTrack);
__privateAdd(this, _screenshareEnabled$, new BehaviorSubject(false));
__privateAdd(this, _screenshareVideoTrackId$);
__privateAdd(this, _screenshareAudioTrackId$);
__privateAdd(this, _screenshareEnabled, false);
__privateAdd(this, _screenshareVideoTrack);
__privateAdd(this, _screenshareAudioTrack);
this.id = options.id;
this.name = options.name;
__privateSet(this, _ctx2, getCurrentCallContext());
__privateSet(this, _micEnabled$, new BehaviorSubject(
options.micEnabled || false
));
__privateSet(this, _micTrackId$, new BehaviorSubject(
options.micEnabled ? options.micTrackId : void 0
));
__privateSet(this, _cameraEnabled$, new BehaviorSubject(
options.cameraEnabled || false
));
__privateSet(this, _cameraTrackId$, new BehaviorSubject(
options.cameraEnabled ? options.cameraTrackId : void 0
));
__privateSet(this, _screenshareEnabled, options.screenshareEnabled || false);
__privateSet(this, _screenshareVideoTrackId$, new BehaviorSubject(
options.screenshareEnabled ? options.screenshareVideoTrackId : void 0
));
__privateSet(this, _screenshareAudioTrackId$, new BehaviorSubject(
options.screenshareEnabled ? options.screenshareAudioTrackId : void 0
));
__privateGet(this, _micEnabled$).subscribe((enabled) => {
if (!enabled) {
__privateSet(this, _micEnabled, false);
this.emit("micUpdate", { micEnabled: false });
__privateGet(this, _ctx2).call.participants.joined.emit("micUpdate", this);
} else if (enabled && __privateGet(this, _micTrack)) {
__privateSet(this, _micEnabled, true);
this.emit("micUpdate", {
micEnabled: true,
micTrack: __privateGet(this, _micTrack)
});
__privateGet(this, _ctx2).call.participants.joined.emit("micUpdate", this);
__privateGet(this, _ctx2).call.participants.emit("micUpdate", this);
}
});
const micMetadata$ = __privateGet(this, _micTrackId$).pipe(
filter((id) => typeof id === "string"),
switchMap((id) => {
const { sessionId, trackName } = parseTrackId(id);
return of({
sessionId,
trackName,
location: "remote"
});
})
);
const micTrack$ = __privateGet(this, _ctx2).partyTracks.pull(micMetadata$);
micTrack$.subscribe((track) => {
__privateSet(this, _micEnabled, true);
__privateSet(this, _micTrack, track);
this.emit("micUpdate", { micEnabled: true, micTrack: track });
__privateGet(this, _ctx2).call.participants.joined.emit("micUpdate", this);
__privateGet(this, _ctx2).call.participants.emit("micUpdate", this);
});
__privateGet(this, _cameraEnabled$).subscribe((enabled) => {
if (!enabled) {
__privateSet(this, _cameraEnabled, false);
this.emit("cameraUpdate", { cameraEnabled: false });
__privateGet(this, _ctx2).call.participants.joined.emit("cameraUpdate", this);
__privateGet(this, _ctx2).call.participants.emit("cameraUpdate", this);
} else if (enabled && __privateGet(this, _cameraTrack)) {
__privateSet(this, _cameraEnabled, true);
this.emit("cameraUpdate", {
cameraEnabled: true,
cameraTrack: __privateGet(this, _cameraTrack)
});
__privateGet(this, _ctx2).call.participants.joined.emit("cameraUpdate", this);
__privateGet(this, _ctx2).call.participants.emit("cameraUpdate", this);
}
});
const cameraMetadata$ = __privateGet(this, _cameraTrackId$).pipe(
filter((id) => typeof id === "string"),
switchMap((id) => {
const { sessionId, trackName } = parseTrackId(id);
return of({
sessionId,
trackName,
location: "remote"
});
})
);
const cameraTrack$ = __privateGet(this, _ctx2).partyTracks.pull(cameraMetadata$, {
simulcast: { preferredRid$: __privateGet(this, _ctx2).cameraRid$ }
});
cameraTrack$.subscribe((track) => {
__privateSet(this, _cameraEnabled, true);
__privateSet(this, _cameraTrack, track);
this.emit("cameraUpdate", { cameraEnabled: true, cameraTrack: track });
__privateGet(this, _ctx2).call.participants.joined.emit("cameraUpdate", this);
__privateGet(this, _ctx2).call.participants.emit("cameraUpdate", this);
});
const screenshareVideoMetadata$ = __privateGet(this, _screenshareVideoTrackId$).pipe(
filter((id) => typeof id === "string"),
switchMap((id) => {
const { sessionId, trackName } = parseTrackId(id);
return of({
sessionId,
trackName,
location: "remote"
});
})
);
const screenshareVideoTrack$ = __privateGet(this, _ctx2).partyTracks.pull(
screenshareVideoMetadata$
);
screenshareVideoTrack$.subscribe((track) => {
__privateSet(this, _screenshareVideoTrack, track);
this.emit("screenshareUpdate", {
screenshareEnabled: true,
screenshareVideoTrack: track,
screenshareAudioTrack: __privateGet(this, _screenshareAudioTrack)
});
__privateGet(this, _ctx2).call.participants.joined.emit("screenshareUpdate", this);
__privateGet(this, _ctx2).call.participants.emit("screenshareUpdate", this);
});
const screenshareAudioMetadata$ = __privateGet(this, _screenshareAudioTrackId$).pipe(
filter((id) => typeof id === "string"),
switchMap((id) => {
const { sessionId, trackName } = parseTrackId(id);
return of({
sessionId,
trackName,
location: "remote"
});
})
);
const screenshareAudioTrack$ = __privateGet(this, _ctx2).partyTracks.pull(
screenshareAudioMetadata$
);
screenshareAudioTrack$.subscribe((track) => {
__privateSet(this, _screenshareAudioTrack, track);
this.emit("screenshareUpdate", {
screenshareEnabled: true,
screenshareVideoTrack: __privateGet(this, _screenshareVideoTrack),
screenshareAudioTrack: track
});
__privateGet(this, _ctx2).call.participants.joined.emit("screenshareUpdate", this);
__privateGet(this, _ctx2).call.participants.emit("screenshareUpdate", this);
});
}
updateMicState(updates) {
__privateGet(this, _ctx2).logger.debug("\u{1F399}\uFE0F participant mic state updated", updates);
if (updates.micEnabled && updates.micTrackId) {
__privateGet(this, _micTrackId$).next(updates.micTrackId);
__privateGet(this, _micEnabled$).next(true);
} else {
__privateGet(this, _micEnabled$).next(false);
}
}
updateCameraState(updates) {
__privateGet(this, _ctx2).logger.debug("\u{1F3A5} participant camera state updated", updates);
if (updates.cameraEnabled && updates.cameraTrackId) {
__privateGet(this, _cameraTrackId$).next(updates.cameraTrackId);
__privateGet(this, _cameraEnabled$).next(true);
} else {
__privateGet(this, _cameraEnabled$).next(false);
}
}
updateScreenshareState(updates) {
__privateGet(this, _ctx2).logger.debug("\u{1F5A5}\uFE0F participant screenshare state updated", updates);
if (updates.screenshareEnabled) {
if (updates.screenshareVideoTrackId) {
__privateGet(this, _screenshareVideoTrackId$).next(updates.screenshareVideoTrackId);
}
if (updates.screenshareAudioTrackId) {
__privateGet(this, _screenshareAudioTrackId$).next(updates.screenshareAudioTrackId);
}
__privateGet(this, _screenshareEnabled$).next(true);
__privateSet(this, _screenshareEnabled, true);
} else {
__privateGet(this, _screenshareEnabled$).next(false);
__privateGet(this, _screenshareVideoTrackId$).next(void 0);
__privateGet(this, _screenshareAudioTrackId$).next(void 0);
__privateSet(this, _screenshareEnabled, false);
this.emit("screenshareUpdate", { screenshareEnabled: false });
__privateGet(this, _ctx2).call.participants.joined.emit("screenshareUpdate", this);
__privateGet(this, _ctx2).call.participants.emit("screenshareUpdate", this);
}
}
get micEnabled() {
return __privateGet(this, _micEnabled);
}
get micTrack() {
return __privateGet(this, _micEnabled) ? __privateGet(this, _micTrack) : void 0;
}
get cameraEnabled() {
return __privateGet(this, _cameraEnabled);
}
get cameraTrack() {
return __privateGet(this, _cameraEnabled) ? __privateGet(this, _cameraTrack) : void 0;
}
get screenshareEnabled() {
return __privateGet(this, _screenshareEnabled);
}
get screenshareTracks() {
if (!this.screenshareEnabled) {
return void 0;
}
return {
video: __privateGet(this, _screenshareVideoTrack),
audio: __privateGet(this, _screenshareAudioTrack)
};
}
toString() {
return `CallParticipant::${this.id}::${this.name}`;
}
static fromJSON(obj) {
return new _CallParticipant(obj);
}
};
_ctx2 = new WeakMap();
_micEnabled$ = new WeakMap();
_micTrackId$ = new WeakMap();
_micEnabled = new WeakMap();
_micTrack = new WeakMap();
_cameraEnabled$ = new WeakMap();
_cameraTrackId$ = new WeakMap();
_cameraEnabled = new WeakMap();
_cameraTrack = new WeakMap();
_screenshareEnabled$ = new WeakMap();
_screenshareVideoTrackId$ = new WeakMap();
_screenshareAudioTrackId$ = new WeakMap();
_screenshareEnabled = new WeakMap();
_screenshareVideoTrack = new WeakMap();
_screenshareAudioTrack = new WeakMap();
var CallParticipant = _CallParticipant;
// src/lib/call-participant-map/call-participant-map.ts
var _participants;
var CallParticipantMap = class extends EventsHandler {
constructor() {
super();
__privateAdd(this, _participants, /* @__PURE__ */ new Map());
}
get(id) {
return __privateGet(this, _participants).get(id);
}
set(id, participant) {
const isUpdate = __privateGet(this, _participants).has(id);
__privateGet(this, _participants).set(id, participant);
this.emit(isUpdate ? "updated" : "added", participant);
return this;
}
delete(id) {
const removed = __privateGet(this, _participants).get(id);
const didDelete = __privateGet(this, _participants).delete(id);
if (didDelete && removed) {
this.emit("removed", removed);
}
return didDelete;
}
has(id) {
return __privateGet(this, _participants).has(id);
}
values() {
return __privateGet(this, _participants).values();
}
keys() {
return __privateGet(this, _participants).keys();
}
entries() {
return __privateGet(this, _participants).entries();
}
forEach(callbackfn, thisArg) {
return __privateGet(this, _participants).forEach(callbackfn, thisArg);
}
get size() {
return __privateGet(this, _participants).size;
}
clear() {
__privateGet(this, _participants).clear();
this.emit("cleared");
}
toArray() {
return Array.from(__privateGet(this, _participants).values());
}
[Symbol.iterator]() {
return __privateGet(this, _participants)[Symbol.iterator]();
}
get [Symbol.toStringTag]() {
return "CallParticipantMap";
}
};
_participants = new WeakMap();
// src/lib/participants-controller/participants-controller.ts
var ParticipantsController = class extends EventsHandler {
constructor() {
super();
this.joined = new CallParticipantMap();
}
addParticipant(participant) {
this.joined.set(participant.id, participant);
}
removeParticipantById(participantId) {
this.joined.delete(participantId);
}
};
var _ctx3, _mic, _camera, _screenshare, _micEnabled2, _micTrackId, _micTrack2, _cameraEnabled2, _cameraTrackId, _cameraTrack2, _screenshareEnabled2, _screenshareVideoTrackId, _screenshareVideoTrack2, _screenshareAudioTrackId, _screenshareAudioTrack2, _micDevice, _cameraDevice, _devices;
var CallSelf = class extends EventsHandler {
constructor(options) {
var _a, _b;
super();
this.id = crypto.randomUUID();
__privateAdd(this, _ctx3);
__privateAdd(this, _mic);
__privateAdd(this, _camera);
__privateAdd(this, _screenshare);
__privateAdd(this, _micEnabled2, false);
__privateAdd(this, _micTrackId);
__privateAdd(this, _micTrack2);
__privateAdd(this, _cameraEnabled2, false);
__privateAdd(this, _cameraTrackId);
__privateAdd(this, _cameraTrack2);
__privateAdd(this, _screenshareEnabled2, false);
__privateAdd(this, _screenshareVideoTrackId);
__privateAdd(this, _screenshareVideoTrack2);
__privateAdd(this, _screenshareAudioTrackId);
__privateAdd(this, _screenshareAudioTrack2);
__privateAdd(this, _micDevice);
__privateAdd(this, _cameraDevice);
__privateAdd(this, _devices);
this.name = options.name;
__privateSet(this, _ctx3, getCurrentCallContext());
__privateSet(this, _mic, getMic());
__privateSet(this, _camera, getCamera());
__privateGet(this, _mic).isBroadcasting$.subscribe((enabled) => {
__privateSet(this, _micEnabled2, enabled);
});
__privateGet(this, _mic).broadcastTrack$.subscribe((track) => {
__privateSet(this, _micTrack2, track);
});
__privateGet(this, _camera).isBroadcasting$.subscribe((enabled) => {
__privateSet(this, _cameraEnabled2, enabled);
});
__privateGet(this, _camera).broadcastTrack$.subscribe((track) => {
__privateSet(this, _cameraTrack2, track);
});
__privateGet(this, _mic).activeDevice$.subscribe((device) => {
__privateSet(this, _micDevice, device);
this.emit("activeDeviceUpdate", "mic", device);
});
__privateGet(this, _camera).activeDevice$.subscribe((device) => {
__privateSet(this, _cameraDevice, device);
this.emit("activeDeviceUpdate", "camera", device);
});
devices$.subscribe((devices) => {
__privateSet(this, _devices, devices);
this.emit("devicesUpdate", devices);
});
const micMetadata$ = __privateGet(this, _ctx3).partyTracks.push(__privateGet(this, _mic).broadcastTrack$, {
sendEncodings$: of([
{ networkPriority: "high" }
])
});
micMetadata$.subscribe((metadata) => {
if (__privateGet(this, _micEnabled2) && __privateGet(this, _micTrack2)) {
const micTrackId = createTrackId(metadata);
__privateSet(this, _micTrackId, micTrackId);
__privateGet(this, _ctx3).socket.sendAction({
action: "self/mic-update",
updates: {
micEnabled: true,
micTrackId
}
});
this.emit("micUpdate", {
micEnabled: true,
micTrack: __privateGet(this, _micTrack2)
});
} else if (!__privateGet(this, _micEnabled2)) {
__privateGet(this, _ctx3).socket.sendAction({
action: "self/mic-update",
updates: { micEnabled: false }
});
this.emit("micUpdate", { micEnabled: false });
}
});
const cameraMetadata$ = __privateGet(this, _ctx3).partyTracks.push(
__privateGet(this, _camera).broadcastTrack$,
{
sendEncodings$: __privateGet(this, _ctx3).cameraEncodings$
}
);
cameraMetadata$.subscribe((metadata) => {
if (__privateGet(this, _cameraEnabled2) && __privateGet(this, _cameraTrack2)) {
const cameraTrackId = createTrackId(metadata);
__privateSet(this, _cameraTrackId, cameraTrackId);
__privateGet(this, _ctx3).socket.sendAction({
action: "self/camera-update",
updates: {
cameraEnabled: true,
cameraTrackId
}
});
this.emit("cameraUpdate", {
cameraEnabled: true,
cameraTrack: __privateGet(this, _cameraTrack2)
});
} else if (!__privateGet(this, _cameraEnabled2)) {
__privateSet(this, _cameraTrackId, void 0);
__privateGet(this, _ctx3).socket.sendAction({
action: "self/camera-update",
updates: { cameraEnabled: false }
});
this.emit("cameraUpdate", { cameraEnabled: false });
}
});
if ((_a = options.defaults) == null ? void 0 : _a.audio) {
this.startMic();
}
if ((_b = options.defaults) == null ? void 0 : _b.video) {
this.startCamera();
}
__privateSet(this, _screenshare, getScreenshare({ audio: true }));
__privateGet(this, _screenshare).video.isBroadcasting$.subscribe((enabled) => {
__privateSet(this, _screenshareEnabled2, enabled);
});
__privateGet(this, _screenshare).video.broadcastTrack$.subscribe((track) => {
__privateSet(this, _screenshareVideoTrack2, track);
});
__privateGet(this, _screenshare).audio.broadcastTrack$.subscribe((track) => {
__privateSet(this, _screenshareAudioTrack2, track);
});
const screenshareVideoMetadata$ = __privateGet(this, _ctx3).partyTracks.push(
__privateGet(this, _screenshare).video.broadcastTrack$
);
const screenshareAudioMetadata$ = __privateGet(this, _ctx3).partyTracks.push(
__privateGet(this, _screenshare).audio.broadcastTrack$
);
screenshareVideoMetadata$.subscribe((metadata) => {
if (!__privateGet(this, _screenshareEnabled2)) {
__privateGet(this, _ctx3).socket.sendAction({
action: "self/screenshare-update",
updates: {
screenshareEnabled: false
}
});
this.emit("screenshareUpdate", { screenshareEnabled: false });
} else {
__privateSet(this, _screenshareVideoTrackId, createTrackId(metadata));
__privateGet(this, _ctx3).socket.sendAction({
action: "self/screenshare-update",
updates: {
screenshareEnabled: true,
screenshareVideoTrackId: __privateGet(this, _screenshareVideoTrackId)
}
});
this.emit("screenshareUpdate", {
screenshareEnabled: true,
screenshareVideoTrack: __privateGet(this, _screenshareVideoTrack2)
});
}
});
screenshareAudioMetadata$.subscribe((metadata) => {
if (!__privateGet(this, _screenshareEnabled2)) {
__privateGet(this, _ctx3).socket.sendAction({
action: "self/screenshare-update",
updates: {
screenshareEnabled: false
}
});
this.emit("screenshareUpdate", { screenshareEnabled: false });
} else {
__privateSet(this, _screenshareAudioTrackId, createTrackId(metadata));
__privateGet(this, _ctx3).socket.sendAction({
action: "self/screenshare-update",
updates: {
screenshareEnabled: true,
screenshareAudioTrackId: __privateGet(this, _screenshareAudioTrackId)
}
});
this.emit("screenshareUpdate", {
screenshareEnabled: true,
screenshareAudioTrack: __privateGet(this, _screenshareAudioTrack2)
});
}
});
}
startMic() {
__privateGet(this, _mic).startBroadcasting();
}
stopMic() {
__privateGet(this, _mic).stopBroadcasting();
}
startCamera() {
__privateGet(this, _camera).startBroadcasting();
}
stopCamera() {
__privateGet(this, _camera).stopBroadcasting();
}
startScreenshare() {
__privateGet(this, _screenshare).startBroadcasting();
}
stopScreenshare() {
__privateGet(this, _screenshare).stopBroadcasting();
}
setCameraDevice(deviceId) {
return __async(this, null, function* () {
const devices = this.devices;
const device = devices == null ? void 0 : devices.find((d) => d.deviceId === deviceId);
if (!device) {
throw new Error(`Camera device not found: ${deviceId}`);
}
__privateGet(this, _camera).setPreferredDevice(device);
});
}
setMicDevice(deviceId) {
return __async(this, null, function* () {
const devices = this.devices;
const device = devices == null ? void 0 : devices.find((d) => d.deviceId === deviceId);
if (!device) {
throw new Error(`Microphone device not found: ${deviceId}`);
}
__privateGet(this, _mic).setPreferredDevice(device);
});
}
get micEnabled() {
return __privateGet(this, _micEnabled2);
}
get micTrack() {
return __privateGet(this, _micEnabled2) ? __privateGet(this, _micTrack2) : void 0;
}
get cameraEnabled() {
return __privateGet(this, _cameraEnabled2);
}
get cameraTrack() {
return __privateGet(this, _cameraEnabled2) ? __privateGet(this, _cameraTrack2) : void 0;
}
get screenshareEnabled() {
return __privateGet(this, _screenshareEnabled2);
}
get screenshareTracks() {
if (!this.screenshareEnabled) {
return void 0;
}
return {
video: __privateGet(this, _screenshareVideoTrack2),
audio: __privateGet(this, _screenshareAudioTrack2)
};
}
get devices() {
return __privateGet(this, _devices);
}
get activeDevices() {
var _a, _b, _c, _d;
return {
mic: (_b = __privateGet(this, _micDevice)) != null ? _b : (_a = this.devices) == null ? void 0 : _a.find(
(d) => d.deviceId === "default" && d.kind === "audioinput"
),
camera: (_d = __privateGet(this, _cameraDevice)) != null ? _d : (_c = this.devices) == null ? void 0 : _c.find(
(d) => d.deviceId === "default" && d.kind === "videoinput"
)
};
}
setName(name) {
const oldName = this.name;
this.name = name;
this.emit("nameChange", this.name, oldName);
}
toJSON() {
return {
id: this.id,
name: this.name,
micEnabled: this.micEnabled,
micTrackId: __privateGet(this, _micTrackId),
cameraEnabled: this.cameraEnabled,
cameraTrackId: __privateGet(this, _cameraTrackId),
screenshareEnabled: this.screenshareEnabled,
screenshareVideoTrackId: __privateGet(this, _screenshareVideoTrackId),
screenshareAudioTrackId: __privateGet(this, _screenshareAudioTrackId)
};
}
toString() {
return `CallSelf::${this.id}::${this.name}`;
}
};
_ctx3 = new WeakMap();
_mic = new WeakMap();
_camera = new WeakMap();
_screenshare = new WeakMap();
_micEnabled2 = new WeakMap();
_micTrackId = new WeakMap();
_micTrack2 = new WeakMap();
_cameraEnabled2 = new WeakMap();
_cameraTrackId = new WeakMap();
_cameraTrack2 = new WeakMap();
_screenshareEnabled2 = new WeakMap();
_screenshareVideoTrackId = new WeakMap();
_screenshareVideoTrack2 = new WeakMap();
_screenshareAudioTrackId = new WeakMap();
_screenshareAudioTrack2 = new WeakMap();
_micDevice = new WeakMap();
_cameraDevice = new WeakMap();
_devices = new WeakMap();
var _logger;
var CallSocket = class extends PartySocket {
constructor(options) {
super(options);
__privateAdd(this, _logger);
__privateSet(this, _logger, options.logger);
}
sendAction(action) {
__privateGet(this, _logger).debug("CallSocket:sendAction", action);
return this.send(JSON.stringify(action));
}
};
_logger = new WeakMap();
// src/lib/call-self/call-self-data.ts
var cameraEncodings = [
{
rid: "a",
maxBitrate: 13e5,
maxFramerate: 30,
active: true
},
{
rid: "b",
scaleResolutionDownBy: 2,
maxBitrate: 5e5,
maxFramerate: 24,
active: true
}
];
// src/lib/call-client/call-client.ts
setLogLevel("debug");
var _ctx4, _logger2, _autoJoin, _CallClient_instances, onMessage_fn;
var CallClient = class extends EventsHandler {
constructor(options) {
var _a, _b, _c;
super();
__privateAdd(this, _CallClient_instances);
this.state = void 0;
__privateAdd(this, _ctx4);
__privateAdd(this, _logger2);
__privateAdd(this, _autoJoin);
this.room = options.room;
__privateSet(this, _autoJoin, options.autoJoin || false);
__privateSet(this, _logger2, new Logger({
level: (_a = options.logLevel) != null ? _a : "warn"
// prefix: 'callskit',
}));
const socket = new CallSocket({
room: this.room,
host: options.socketBaseUrl,
logger: __privateGet(this, _logger2)
});
socket.addEventListener("message", __privateMethod(this, _CallClient_instances, onMessage_fn).bind(this));
if (options.onError) {
const onError = options.onError;
socket.addEventListener("error", (e) => {
onError(new Error("Error while connecting to server"));
});
}
const partyTracks = new PartyTracks({
prefix: options.apiBaseUrl + "/partytracks",
headers: options.apiHeaders
});
let unsubSession = partyTracks.session$.subscribe(
() => {
this.emit("mediaConnected");
unsubSession.unsubscribe();
unsubSession = void 0;
}
);
__privateSet(this, _ctx4, {
socket,
partyTracks,
call: this,
logger: __privateGet(this, _logger2),
cameraRid$: new BehaviorSubject(
(_c = (_b = options.config) == null ? void 0 : _b.preferredCameraQuality) != null ? _c : "a"
),
cameraEncodings$: new BehaviorSubject(
cameraEncodings
),
onError: options.onError
});
this.self = runWithContext(
__privateGet(this, _ctx4),
() => new CallSelf({ name: options.displayName, defaults: options.defaults })
);
this.participants = runWithContext(
__privateGet(this, _ctx4),
() => new ParticipantsController()
);
this.chat = runWithContext(__privateGet(this, _ctx4), () => new CallChat());
}
join() {
if (this.state !== "connected") return;
__privateGet(this, _ctx4).socket.sendAction({ action: "join", self: this.self.toJSON() });
}
leave() {
__privateGet(this, _ctx4).socket.close();
this.state = "left";
this.emit("left");
}
get cameraTrackQuality() {
return __privateGet(this, _ctx4).cameraRid$.value;
}
/**
* Set the remote camera track quality.
* - `f` - full quality
* - `h` - half quality
*/
setRemoteCameraTrackQuality(quality) {
const qualities = ["a", "b"];
if (qualities.includes(quality)) {
const oldQuality = __privateGet(this, _ctx4).cameraRid$.value;
__privateGet(this, _ctx4).cameraRid$.next(quality);
this.emit("cameraQualityChanged", quality, oldQuality);
}
}
};
_ctx4 = new WeakMap();
_logger2 = new WeakMap();
_autoJoin = new WeakMap();
_CallClient_instances = new WeakSet();
onMessage_fn = function(event) {
const ev = JSON.parse(event.data);
__privateGet(this, _logger2).debug("\u{1F4E9} CallSocket:Event", ev);
switch (ev.event) {
case "connected":
this.state = "connected";
this.emit("connected");
if (__privateGet(this, _autoJoin)) {
this.join();
}
break;
case "room/init": {
if (this.state !== "connected") return;
const user_objects = ev.participants;
runWithContext(
__privateGet(this, _ctx4),
() => user_objects.map((obj) => CallParticipant.fromJSON(obj))
).forEach((participant) => {
this.participants.addParticipant(participant);
});
this.started_at = new Date(ev.started_at);
this.chat.addMessagesInBulk(ev.chatMessages);
this.state = "joined";
this.emit("joined");
break;
}
case "participant/joined": {
const participant = runWithContext(
__privateGet(this, _ctx4),
() => CallParticipant.fromJSON(ev.participant)
);
this.participants.addParticipant(participant);
break;
}
case "participant/left": {
this.participants.removeParticipantById(ev.participantId);
break;
}
case "participant/mic-update": {
const _a = ev.data, { participantId } = _a, updates = __objRest(_a, ["participantId"]);
const participant = this.participants.joined.get(participantId);
participant == null ? void 0 : participant.updateMicState(updates);
break;
}
case "participant/camera-update": {
const _b = ev.data, { participantId } = _b, updates = __objRest(_b, ["participantId"]);
const participant = this.participants.joined.get(participantId);
participant == null ? void 0 : participant.updateCameraState(updates);
break;
}
case "participant/screenshare-update": {
const _c = ev.data, { participantId } = _c, updates = __objRest(_c, ["participantId"]);
const participant = this.participants.joined.get(participantId);
participant == null ? void 0 : participant.updateScreenshareState(updates);
break;
}
case "chat/new-message": {
this.chat.addMessage(ev.message);
break;
}
default:
__privateGet(this, _logger2).info("Received unknown event:", ev);
break;
}
};
// src/index.ts
function createCallClient(options) {
return __async(this, null, function* () {
return new Promise((resolve, reject) => {
const client = new CallClient(options);
let socketConnected = false, mediaConnected = false;
const checkConnection = () => {
if (socketConnected && mediaConnected) {
resolve(client);
}
};
client.once("connected", () => {
socketConnected = true;
checkConnection();
});
client.once("mediaConnected", () => {
mediaConnected = true;
checkConnection();
});
setTimeout(() => {
if (!socketConnected && !mediaConnected) {
reject(new Error("Both socket and media connections timed out"));
} else if (!socketConnected) {
reject(new Error("Socket connection timed out"));
} else if (!mediaConnected) {
reject(new Error("Media connection timed out"));
}
}, 1e4);
});
});
}
export { EventsHandler, __async, createCallClient };