@snap/camera-kit
Version:
Camera Kit Web
260 lines • 15.2 kB
JavaScript
import { __awaiter, __esDecorate, __runInitializers } from "tslib";
import { filter, firstValueFrom, map, of, takeUntil, tap } from "rxjs";
import { dispatch, forActions, inStates, isAction, isState } from "@snap/state-management";
import { Injectable } from "@snap/ts-inject";
import { isLens } from "../lens/Lens";
import { lensCoreFactory } from "../lens-core-module/loader/lensCoreFactory";
import { isLensLaunchDataOrUndefined } from "../lens/LensLaunchData";
import { getTypeName, validate } from "../common/validate";
import { TypedEventTarget } from "../events/TypedEventTarget";
import { TypedCustomEvent } from "../events/TypedCustomEvent";
import { isCameraKitSource } from "../media-sources/CameraKitSource";
import { isPartialCameraKitDeviceOptionsOrUndefined } from "../media-sources/CameraKitSource";
import { cameraKitSourceError } from "../namedErrors";
import { createMediaStreamSource } from "../media-sources/MediaStreamSource";
import { createVideoSource } from "../media-sources/VideoSource";
import { getLogger } from "../logger/logger";
import { errorLoggingDecorator } from "../logger/errorLoggingDecorator";
import { logEntriesFactory } from "../logger/logEntries";
import { pageVisibilityFactory } from "../common/pageVisibility";
import { isUndefined, isValidNumber } from "../common/typeguards";
import { LensPerformanceMetrics } from "./LensPerformanceMetrics";
import { lensStateFactory } from "./lensState";
import { sessionStateFactory } from "./sessionState";
import { lensKeyboardFactory } from "./LensKeyboard";
import { isPublicLensError } from "./CameraKitSessionEvents";
import { frameEventsFactory } from "./frameEvents";
import { prepareScreenRegionsUpdate, isScreenRegions } from "./screenRegions";
const logger = getLogger("CameraKitSession");
function isAllowedSource(value) {
return isCameraKitSource(value) || isMediaStream(value) || isHTMLVideoElement(value);
}
function isMediaStream(value) {
return value instanceof MediaStream;
}
function isHTMLVideoElement(value) {
return value instanceof HTMLVideoElement;
}
function isRenderTargetOrUndefined(value) {
return isUndefined(value) || value === "live" || value === "capture";
}
let CameraKitSession = (() => {
var _a;
let _instanceExtraInitializers = [];
let _applyLens_decorators;
let _removeLens_decorators;
let _play_decorators;
let _pause_decorators;
let _mute_decorators;
let _unmute_decorators;
let _setSource_decorators;
let _setFPSLimit_decorators;
let _setScreenRegions_decorators;
let _destroy_decorators;
return _a = class CameraKitSession {
constructor(innerKeyboard, lensCore, sessionState, lensState, logEntries, pageVisibility, frameEvents) {
this.innerKeyboard = (__runInitializers(this, _instanceExtraInitializers), innerKeyboard);
this.lensCore = lensCore;
this.sessionState = sessionState;
this.lensState = lensState;
this.frameEvents = frameEvents;
this.events = new TypedEventTarget();
this.keyboard = innerKeyboard.toPublicInterface();
const outputs = this.lensCore.getOutputCanvases();
this.output = {
live: outputs[this.lensCore.CanvasType.Preview.value],
capture: outputs[this.lensCore.CanvasType.Capture.value],
};
this.playing = {
live: false,
capture: false,
};
this.metrics = new LensPerformanceMetrics(frameEvents);
const removeOnHidden = pageVisibility.onPageHidden(() => this.sessionState.dispatch("suspend", this));
const removeOnVisible = pageVisibility.onPageVisible(() => this.sessionState.dispatch("resume", this));
this.removePageVisibilityHandlers = () => {
removeOnHidden();
removeOnVisible();
};
this.subscriptions = [
lensCore.errors
.pipe(filter((error) => error.name === "LensCoreAbortError"))
.subscribe(() => this.destroy()),
lensCore.errors
.pipe(filter((error) => error.name !== "LensCoreAbortError" && error.isFrameError))
.subscribe(() => this.removeLens()),
logEntries
.pipe(filter((entry) => entry.level === "error"), map((entry) => entry.messages.find((e) => e instanceof Error)), filter(isPublicLensError))
.subscribe((error) => {
const state = lensState.getState();
if (!isState(state, "noLensApplied")) {
this.events.dispatchEvent(new TypedCustomEvent("error", { error, lens: state.data }));
}
else {
logger.warn("Lens error occurred even though there is no active lens.", error);
}
}),
];
}
applyLens(lens, launchData) {
return __awaiter(this, void 0, void 0, function* () {
const action = this.lensState.actions.applyLens({ lens, launchData });
return firstValueFrom(of(action).pipe(dispatch(this.lensState), takeUntil(this.lensState.events.pipe(forActions("applyLens"), filter(([a]) => a !== action))), tap(([a]) => {
if (isAction(a, "applyLensFailed") && a.data.lens.id === lens.id)
throw a.data.error;
}), inStates("lensApplied"), map(() => true)), { defaultValue: false });
});
}
removeLens() {
return __awaiter(this, void 0, void 0, function* () {
if (isState(this.lensState.getState(), "noLensApplied"))
return true;
return firstValueFrom(of(this.lensState.actions.removeLens()).pipe(dispatch(this.lensState), tap(([a]) => {
if (isAction(a, "removeLensFailed"))
throw a.data;
}), inStates("noLensApplied"), takeUntil(this.lensState.events.pipe(forActions("applyLens"))), map(() => true)), { defaultValue: false });
});
}
play(target = "live") {
return __awaiter(this, void 0, void 0, function* () {
if (this.playing[target])
return;
this.playing[target] = true;
const type = this.renderTargetToCanvasType(target);
return this.lensCore.playCanvas({ type }).catch((error) => {
this.playing[target] = false;
throw error;
});
});
}
pause(target = "live") {
return __awaiter(this, void 0, void 0, function* () {
if (this.playing[target] === false)
return;
this.playing[target] = false;
const type = this.renderTargetToCanvasType(target);
return this.lensCore.pauseCanvas({ type }).catch((error) => {
this.playing[target] = true;
throw error;
});
});
}
mute(fade = false) {
this.lensCore.setAllSoundsMuted({
muted: true,
fade,
});
}
unmute(fade = false) {
this.lensCore.setAllSoundsMuted({
muted: false,
fade,
});
}
setSource(source, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
yield this.safelyDetachSource();
const cameraKitSource = isMediaStream(source)
? createMediaStreamSource(source, options)
: isHTMLVideoElement(source)
? createVideoSource(source, options)
: source;
const priorPlayingState = this.playing;
this.playing = {
live: false,
capture: false,
};
yield cameraKitSource.attach(this.lensCore, this.frameEvents, (error) => {
logger.error(cameraKitSourceError("Error occurred during source attachment.", error));
});
this.source = cameraKitSource;
if (priorPlayingState.live)
yield this.play("live");
if (priorPlayingState.capture)
yield this.play("capture");
return cameraKitSource;
});
}
setFPSLimit(fpsLimit) {
return __awaiter(this, void 0, void 0, function* () {
const fps = fpsLimit < Number.POSITIVE_INFINITY ? fpsLimit : 0;
return this.lensCore.setFPSLimit({ fps });
});
}
setScreenRegions(regions) {
return __awaiter(this, void 0, void 0, function* () {
yield this.lensCore.setScreenRegions({
regions: prepareScreenRegionsUpdate(regions),
});
});
}
destroy() {
return __awaiter(this, void 0, void 0, function* () {
try {
yield this.lensCore.clearAllLenses();
yield this.lensCore.teardown();
}
catch (error) {
logger.warn("An error occurred in LensCore during the session termination process.", error);
}
this.subscriptions.forEach((sub) => sub.unsubscribe());
yield this.safelyDetachSource();
this.removePageVisibilityHandlers();
this.sessionState.dispatch("destroy", undefined);
this.innerKeyboard.destroy();
this.metrics.destroy();
});
}
renderTargetToCanvasType(target) {
return target === "capture" ? this.lensCore.CanvasType.Capture : this.lensCore.CanvasType.Preview;
}
safelyDetachSource() {
return __awaiter(this, void 0, void 0, function* () {
if (this.source) {
try {
yield this.source.detach((error) => {
logger.error(cameraKitSourceError("Error occurred during source detachment.", error));
});
}
catch (error) {
logger.error(cameraKitSourceError(`Detaching prior source of type ${getTypeName(this.source)} failed.`, error));
}
}
});
}
},
(() => {
_applyLens_decorators = [validate(isLens, isLensLaunchDataOrUndefined), errorLoggingDecorator(logger)];
_removeLens_decorators = [errorLoggingDecorator(logger)];
_play_decorators = [validate(isRenderTargetOrUndefined), errorLoggingDecorator(logger)];
_pause_decorators = [validate(isRenderTargetOrUndefined), errorLoggingDecorator(logger)];
_mute_decorators = [errorLoggingDecorator(logger)];
_unmute_decorators = [errorLoggingDecorator(logger)];
_setSource_decorators = [validate(isAllowedSource, isPartialCameraKitDeviceOptionsOrUndefined), errorLoggingDecorator(logger)];
_setFPSLimit_decorators = [validate(isValidNumber), errorLoggingDecorator(logger)];
_setScreenRegions_decorators = [validate(isScreenRegions), errorLoggingDecorator(logger)];
_destroy_decorators = [errorLoggingDecorator(logger)];
__esDecorate(_a, null, _applyLens_decorators, { kind: "method", name: "applyLens", static: false, private: false, access: { has: obj => "applyLens" in obj, get: obj => obj.applyLens } }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _removeLens_decorators, { kind: "method", name: "removeLens", static: false, private: false, access: { has: obj => "removeLens" in obj, get: obj => obj.removeLens } }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _play_decorators, { kind: "method", name: "play", static: false, private: false, access: { has: obj => "play" in obj, get: obj => obj.play } }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _pause_decorators, { kind: "method", name: "pause", static: false, private: false, access: { has: obj => "pause" in obj, get: obj => obj.pause } }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _mute_decorators, { kind: "method", name: "mute", static: false, private: false, access: { has: obj => "mute" in obj, get: obj => obj.mute } }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _unmute_decorators, { kind: "method", name: "unmute", static: false, private: false, access: { has: obj => "unmute" in obj, get: obj => obj.unmute } }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _setSource_decorators, { kind: "method", name: "setSource", static: false, private: false, access: { has: obj => "setSource" in obj, get: obj => obj.setSource } }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _setFPSLimit_decorators, { kind: "method", name: "setFPSLimit", static: false, private: false, access: { has: obj => "setFPSLimit" in obj, get: obj => obj.setFPSLimit } }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _setScreenRegions_decorators, { kind: "method", name: "setScreenRegions", static: false, private: false, access: { has: obj => "setScreenRegions" in obj, get: obj => obj.setScreenRegions } }, null, _instanceExtraInitializers);
__esDecorate(_a, null, _destroy_decorators, { kind: "method", name: "destroy", static: false, private: false, access: { has: obj => "destroy" in obj, get: obj => obj.destroy } }, null, _instanceExtraInitializers);
})(),
_a;
})();
export { CameraKitSession };
export const cameraKitSessionFactory = Injectable("CameraKitSession", [
lensCoreFactory.token,
logEntriesFactory.token,
lensKeyboardFactory.token,
sessionStateFactory.token,
lensStateFactory.token,
pageVisibilityFactory.token,
frameEventsFactory.token,
], (lensCore, logEntries, keyboard, sessionState, lensState, pageVisibility, frameEvents) => new CameraKitSession(keyboard, lensCore, sessionState, lensState, logEntries, pageVisibility, frameEvents));
//# sourceMappingURL=CameraKitSession.js.map