UNPKG

@livekit/components-core

Version:

This package is a wrapper around the [livekit/client-sdk-js](https://github.com/livekit/client-sdk-js) package. It transforms the event based logic into simple to use observable state and component level APIs. This package is the core for all framework sp

1,316 lines (1,284 loc) 89.1 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name); 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 __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from3, except, desc) => { if (from3 && typeof from3 === "object" || typeof from3 === "function") { for (let key of __getOwnPropNames(from3)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from3[key], enumerable: !(desc = __getOwnPropDesc(from3, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); 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()); }); }; var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it); // src/index.ts var index_exports = {}; __export(index_exports, { DataTopic: () => DataTopic, GRID_LAYOUTS: () => GRID_LAYOUTS, LegacyDataTopic: () => LegacyDataTopic, PIN_DEFAULT_STATE: () => PIN_DEFAULT_STATE, ParticipantAgentAttributes: () => ParticipantAgentAttributes, WIDGET_DEFAULT_STATE: () => WIDGET_DEFAULT_STATE, activeSpeakerObserver: () => activeSpeakerObserver, addMediaTimestampToTranscription: () => addMediaTimestampToTranscription, allParticipantEvents: () => allParticipantEvents, allParticipantRoomEvents: () => allParticipantRoomEvents, allRemoteParticipantEvents: () => allRemoteParticipantEvents, allRemoteParticipantRoomEvents: () => allRemoteParticipantRoomEvents, attachIfSubscribed: () => attachIfSubscribed, computeMenuPosition: () => computeMenuPosition, connectedParticipantObserver: () => connectedParticipantObserver, connectedParticipantsObserver: () => connectedParticipantsObserver, connectionStateObserver: () => connectionStateObserver, createActiveDeviceObservable: () => createActiveDeviceObservable, createChatObserver: () => createChatObserver, createConnectionQualityObserver: () => createConnectionQualityObserver, createDataObserver: () => createDataObserver, createDefaultGrammar: () => createDefaultGrammar, createEmailRegExp: () => createEmailRegExp, createInteractingObservable: () => createInteractingObservable, createIsSpeakingObserver: () => createIsSpeakingObserver, createMediaDeviceObserver: () => createMediaDeviceObserver, createTrackObserver: () => createTrackObserver, createUrlRegExp: () => createUrlRegExp, cssPrefix: () => cssPrefix, dedupeSegments: () => dedupeSegments, defaultUserChoices: () => defaultUserChoices, didActiveSegmentsChange: () => didActiveSegmentsChange, encryptionStatusObservable: () => encryptionStatusObservable, getActiveTranscriptionSegments: () => getActiveTranscriptionSegments, getScrollBarWidth: () => getScrollBarWidth, getTrackByIdentifier: () => getTrackByIdentifier, getTrackReferenceId: () => getTrackReferenceId, getTrackReferenceSource: () => getTrackReferenceSource, isEqualTrackRef: () => isEqualTrackRef, isLocal: () => isLocal, isMobileBrowser: () => isMobileBrowser, isParticipantTrackReferencePinned: () => isParticipantTrackReferencePinned, isPlaceholderReplacement: () => isPlaceholderReplacement, isRemote: () => isRemote, isSourceWitOptions: () => isSourceWitOptions, isSourcesWithOptions: () => isSourcesWithOptions, isTrackReference: () => isTrackReference, isTrackReferencePinned: () => isTrackReferencePinned, isTrackReferencePlaceholder: () => isTrackReferencePlaceholder, isWeb: () => isWeb, loadUserChoices: () => loadUserChoices, log: () => log, mutedObserver: () => mutedObserver, observeParticipantEvents: () => observeParticipantEvents, observeParticipantMedia: () => observeParticipantMedia, observeRoomEvents: () => observeRoomEvents, observeTrackEvents: () => observeTrackEvents, participantAttributesObserver: () => participantAttributesObserver, participantByIdentifierObserver: () => participantByIdentifierObserver, participantEventSelector: () => participantEventSelector, participantInfoObserver: () => participantInfoObserver, participantPermissionObserver: () => participantPermissionObserver, participantTrackEvents: () => participantTrackEvents, participantTracksObservable: () => participantTracksObservable, recordingStatusObservable: () => recordingStatusObservable, roomAudioPlaybackAllowedObservable: () => roomAudioPlaybackAllowedObservable, roomEventSelector: () => roomEventSelector, roomInfoObserver: () => roomInfoObserver, roomObserver: () => roomObserver, roomVideoPlaybackAllowedObservable: () => roomVideoPlaybackAllowedObservable, saveUserChoices: () => saveUserChoices, screenShareObserver: () => screenShareObserver, selectGridLayout: () => selectGridLayout, sendMessage: () => sendMessage, setDifference: () => setDifference, setLogExtension: () => setLogExtension, setLogLevel: () => setLogLevel, setupChat: () => setupChat, setupChatMessageHandler: () => setupChatMessageHandler, setupChatToggle: () => setupChatToggle, setupClearPinButton: () => setupClearPinButton, setupConnectionQualityIndicator: () => setupConnectionQualityIndicator, setupDataMessageHandler: () => setupDataMessageHandler, setupDeviceSelector: () => setupDeviceSelector, setupDisconnectButton: () => setupDisconnectButton, setupFocusToggle: () => setupFocusToggle, setupLiveKitRoom: () => setupLiveKitRoom, setupManualToggle: () => setupManualToggle, setupMediaToggle: () => setupMediaToggle, setupMediaTrack: () => setupMediaTrack, setupParticipantName: () => setupParticipantName, setupParticipantTile: () => setupParticipantTile, setupStartAudio: () => setupStartAudio, setupStartVideo: () => setupStartVideo, setupTextStream: () => setupTextStream, setupTrackMutedIndicator: () => setupTrackMutedIndicator, sortParticipants: () => sortParticipants, sortTrackReferences: () => sortTrackReferences, supportsScreenSharing: () => supportsScreenSharing, tokenize: () => tokenize, trackEventSelector: () => trackEventSelector, trackObservable: () => trackObservable, trackReferencesObservable: () => trackReferencesObservable, trackSyncTimeObserver: () => trackSyncTimeObserver, trackTranscriptionObserver: () => trackTranscriptionObserver, updatePages: () => updatePages, wasClickOutside: () => wasClickOutside }); module.exports = __toCommonJS(index_exports); // src/constants.ts var cssPrefix = "lk"; // src/track-reference/track-reference.types.ts function isTrackReference(trackReference) { if (typeof trackReference === "undefined") { return false; } return isTrackReferenceSubscribed(trackReference) || isTrackReferencePublished(trackReference); } function isTrackReferenceSubscribed(trackReference) { var _a; if (!trackReference) { return false; } return trackReference.hasOwnProperty("participant") && trackReference.hasOwnProperty("source") && trackReference.hasOwnProperty("track") && typeof ((_a = trackReference.publication) == null ? void 0 : _a.track) !== "undefined"; } function isTrackReferencePublished(trackReference) { if (!trackReference) { return false; } return trackReference.hasOwnProperty("participant") && trackReference.hasOwnProperty("source") && trackReference.hasOwnProperty("publication") && typeof trackReference.publication !== "undefined"; } function isTrackReferencePlaceholder(trackReference) { if (!trackReference) { return false; } return trackReference.hasOwnProperty("participant") && trackReference.hasOwnProperty("source") && typeof trackReference.publication === "undefined"; } // src/track-reference/track-reference.utils.ts function getTrackReferenceId(trackReference) { if (typeof trackReference === "string" || typeof trackReference === "number") { return `${trackReference}`; } else if (isTrackReferencePlaceholder(trackReference)) { return `${trackReference.participant.identity}_${trackReference.source}_placeholder`; } else if (isTrackReference(trackReference)) { return `${trackReference.participant.identity}_${trackReference.publication.source}_${trackReference.publication.trackSid}`; } else { throw new Error(`Can't generate a id for the given track reference: ${trackReference}`); } } function getTrackReferenceSource(trackReference) { if (isTrackReference(trackReference)) { return trackReference.publication.source; } else { return trackReference.source; } } function isEqualTrackRef(a, b) { if (a === void 0 || b === void 0) { return false; } if (isTrackReference(a) && isTrackReference(b)) { return a.publication.trackSid === b.publication.trackSid; } else { return getTrackReferenceId(a) === getTrackReferenceId(b); } } function isTrackReferencePinned(trackReference, pinState) { if (typeof pinState === "undefined") { return false; } if (isTrackReference(trackReference)) { return pinState.some( (pinnedTrackReference) => pinnedTrackReference.participant.identity === trackReference.participant.identity && isTrackReference(pinnedTrackReference) && pinnedTrackReference.publication.trackSid === trackReference.publication.trackSid ); } else if (isTrackReferencePlaceholder(trackReference)) { return pinState.some( (pinnedTrackReference) => pinnedTrackReference.participant.identity === trackReference.participant.identity && isTrackReferencePlaceholder(pinnedTrackReference) && pinnedTrackReference.source === trackReference.source ); } else { return false; } } function isPlaceholderReplacement(currentTrackRef, nextTrackRef) { return isTrackReferencePlaceholder(currentTrackRef) && isTrackReference(nextTrackRef) && nextTrackRef.participant.identity === currentTrackRef.participant.identity && nextTrackRef.source === currentTrackRef.source; } // src/utils.ts function isLocal(p) { return p.isLocal; } function isRemote(p) { return !p.isLocal; } var attachIfSubscribed = (publication, element) => { if (!publication) return; const { isSubscribed, track } = publication; if (element && track) { if (isSubscribed) { track.attach(element); } else { track.detach(element); } } }; function isParticipantTrackReferencePinned(trackRef, pinState) { if (pinState === void 0) { return false; } return pinState.some((pinnedTrackRef) => isEqualTrackRef(pinnedTrackRef, trackRef)); } function getScrollBarWidth() { const inner = document.createElement("p"); inner.style.width = "100%"; inner.style.height = "200px"; const outer = document.createElement("div"); outer.style.position = "absolute"; outer.style.top = "0px"; outer.style.left = "0px"; outer.style.visibility = "hidden"; outer.style.width = "200px"; outer.style.height = "150px"; outer.style.overflow = "hidden"; outer.appendChild(inner); document.body.appendChild(outer); const w1 = inner.offsetWidth; outer.style.overflow = "scroll"; let w2 = inner.offsetWidth; if (w1 === w2) { w2 = outer.clientWidth; } document.body.removeChild(outer); const scrollBarWidth = w1 - w2; return scrollBarWidth; } // src/helper/detectMobileBrowser.ts function isWeb() { return typeof document !== "undefined"; } function isMobileBrowser() { return isWeb() ? /Mobi/i.test(window.navigator.userAgent) : false; } // src/helper/url-regex.ts function createUrlRegExp(options) { options = __spreadValues({}, options); const protocol = `(?:(?:[a-z]+:)?//)?`; const auth = "(?:\\S+(?::\\S*)?@)?"; const ip = new RegExp( "(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}", "g" ).source; const host = "(?:(?:[a-z\\u00a1-\\uffff0-9][-_]*)*[a-z\\u00a1-\\uffff0-9]+)"; const domain = "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*"; const tld = `(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))\\.?`; const port = "(?::\\d{2,5})?"; const path = '(?:[/?#][^\\s"]*)?'; const regex2 = `(?:${protocol}|www\\.)${auth}(?:localhost|${ip}|${host}${domain}${tld})${port}${path}`; return options.exact ? new RegExp(`(?:^${regex2}$)`, "i") : new RegExp(regex2, "ig"); } // src/helper/emailRegex.ts var regex = "[^\\.\\s@:](?:[^\\s@:]*[^\\s@:\\.])?@[^\\.\\s@]+(?:\\.[^\\.\\s@]+)*"; function createEmailRegExp({ exact } = {}) { return exact ? new RegExp(`^${regex}$`) : new RegExp(regex, "g"); } // src/helper/floating-menu.ts var import_dom = require("@floating-ui/dom"); function computeMenuPosition(button, menu, onUpdate) { const cleanup = (0, import_dom.autoUpdate)(button, menu, () => __async(this, null, function* () { const { x, y } = yield (0, import_dom.computePosition)(button, menu, { placement: "top", middleware: [(0, import_dom.offset)(6), (0, import_dom.flip)(), (0, import_dom.shift)({ padding: 5 })] }); onUpdate == null ? void 0 : onUpdate(x, y); })); return cleanup; } function wasClickOutside(insideElement, event) { const isOutside = !insideElement.contains(event.target); return isOutside; } // src/helper/tokenizer.ts var createDefaultGrammar = () => { return { email: createEmailRegExp(), url: createUrlRegExp({}) }; }; function tokenize(input, grammar) { const matches = Object.entries(grammar).map( ([type, rx], weight) => Array.from(input.matchAll(rx)).map(({ index, 0: content }) => ({ type, weight, content, index: index != null ? index : 0 })) ).flat().sort((a, b) => { const d = a.index - b.index; return d !== 0 ? d : a.weight - b.weight; }).filter(({ index }, i, arr) => { if (i === 0) return true; const prev = arr[i - 1]; return prev.index + prev.content.length <= index; }); const tokens = []; let pos = 0; for (const { type, content, index } of matches) { if (index > pos) tokens.push(input.substring(pos, index)); tokens.push({ type, content }); pos = index + content.length; } if (input.length > pos) tokens.push(input.substring(pos)); return tokens; } // src/helper/eventGroups.ts var import_livekit_client = require("livekit-client"); var allRemoteParticipantRoomEvents = [ import_livekit_client.RoomEvent.ConnectionStateChanged, import_livekit_client.RoomEvent.RoomMetadataChanged, import_livekit_client.RoomEvent.ActiveSpeakersChanged, import_livekit_client.RoomEvent.ConnectionQualityChanged, import_livekit_client.RoomEvent.ParticipantConnected, import_livekit_client.RoomEvent.ParticipantDisconnected, import_livekit_client.RoomEvent.ParticipantPermissionsChanged, import_livekit_client.RoomEvent.ParticipantMetadataChanged, import_livekit_client.RoomEvent.ParticipantNameChanged, import_livekit_client.RoomEvent.ParticipantAttributesChanged, import_livekit_client.RoomEvent.TrackMuted, import_livekit_client.RoomEvent.TrackUnmuted, import_livekit_client.RoomEvent.TrackPublished, import_livekit_client.RoomEvent.TrackUnpublished, import_livekit_client.RoomEvent.TrackStreamStateChanged, import_livekit_client.RoomEvent.TrackSubscriptionFailed, import_livekit_client.RoomEvent.TrackSubscriptionPermissionChanged, import_livekit_client.RoomEvent.TrackSubscriptionStatusChanged ]; var allParticipantRoomEvents = [ ...allRemoteParticipantRoomEvents, import_livekit_client.RoomEvent.LocalTrackPublished, import_livekit_client.RoomEvent.LocalTrackUnpublished ]; var participantTrackEvents = [ import_livekit_client.ParticipantEvent.TrackPublished, import_livekit_client.ParticipantEvent.TrackUnpublished, import_livekit_client.ParticipantEvent.TrackMuted, import_livekit_client.ParticipantEvent.TrackUnmuted, import_livekit_client.ParticipantEvent.TrackStreamStateChanged, import_livekit_client.ParticipantEvent.TrackSubscribed, import_livekit_client.ParticipantEvent.TrackUnsubscribed, import_livekit_client.ParticipantEvent.TrackSubscriptionPermissionChanged, import_livekit_client.ParticipantEvent.TrackSubscriptionFailed, import_livekit_client.ParticipantEvent.LocalTrackPublished, import_livekit_client.ParticipantEvent.LocalTrackUnpublished ]; var allRemoteParticipantEvents = [ import_livekit_client.ParticipantEvent.ConnectionQualityChanged, import_livekit_client.ParticipantEvent.IsSpeakingChanged, import_livekit_client.ParticipantEvent.ParticipantMetadataChanged, import_livekit_client.ParticipantEvent.ParticipantPermissionsChanged, import_livekit_client.ParticipantEvent.TrackMuted, import_livekit_client.ParticipantEvent.TrackUnmuted, import_livekit_client.ParticipantEvent.TrackPublished, import_livekit_client.ParticipantEvent.TrackUnpublished, import_livekit_client.ParticipantEvent.TrackStreamStateChanged, import_livekit_client.ParticipantEvent.TrackSubscriptionFailed, import_livekit_client.ParticipantEvent.TrackSubscriptionPermissionChanged, import_livekit_client.ParticipantEvent.TrackSubscriptionStatusChanged ]; var allParticipantEvents = [ ...allRemoteParticipantEvents, import_livekit_client.ParticipantEvent.LocalTrackPublished, import_livekit_client.ParticipantEvent.LocalTrackUnpublished ]; // src/logger.ts var import_livekit_client2 = require("livekit-client"); var import_loglevel = __toESM(require("loglevel")); var log = import_loglevel.default.getLogger("lk-components-js"); log.setDefaultLevel("WARN"); function setLogLevel(level, options = {}) { var _a; log.setLevel(level); (0, import_livekit_client2.setLogLevel)((_a = options.liveKitClientLogLevel) != null ? _a : level); } function setLogExtension(extension, options = {}) { var _a; const originalFactory = log.methodFactory; log.methodFactory = (methodName, configLevel, loggerName) => { const rawMethod = originalFactory(methodName, configLevel, loggerName); const logLevel = import_livekit_client2.LogLevel[methodName]; const needLog = logLevel >= configLevel && logLevel < import_livekit_client2.LogLevel.silent; return (msg, context) => { if (context) rawMethod(msg, context); else rawMethod(msg); if (needLog) { extension(logLevel, msg, context); } }; }; log.setLevel(log.getLevel()); (0, import_livekit_client2.setLogExtension)((_a = options.liveKitClientLogExtension) != null ? _a : extension); } // src/helper/grid-layouts.ts var GRID_LAYOUTS = [ { columns: 1, rows: 1 }, { columns: 1, rows: 2, orientation: "portrait" }, { columns: 2, rows: 1, orientation: "landscape" }, { columns: 2, rows: 2, minWidth: 560 }, { columns: 3, rows: 3, minWidth: 700 }, { columns: 4, rows: 4, minWidth: 960 }, { columns: 5, rows: 5, minWidth: 1100 } ]; function selectGridLayout(layoutDefinitions, participantCount, width, height) { if (layoutDefinitions.length < 1) { throw new Error("At least one grid layout definition must be provided."); } const layouts = expandAndSortLayoutDefinitions(layoutDefinitions); if (width <= 0 || height <= 0) { return layouts[0]; } let currentLayoutIndex = 0; const containerOrientation = width / height > 1 ? "landscape" : "portrait"; let layout = layouts.find((layout_, index, allLayouts) => { currentLayoutIndex = index; const isBiggerLayoutAvailable = allLayouts.findIndex((l, i) => { const fitsOrientation = !l.orientation || l.orientation === containerOrientation; const layoutIsBiggerThanCurrent = i > index; const layoutFitsSameAmountOfParticipants = l.maxTiles === layout_.maxTiles; return layoutIsBiggerThanCurrent && layoutFitsSameAmountOfParticipants && fitsOrientation; }) !== -1; return layout_.maxTiles >= participantCount && !isBiggerLayoutAvailable; }); if (layout === void 0) { layout = layouts[layouts.length - 1]; if (layout) { log.warn( `No layout found for: participantCount: ${participantCount}, width/height: ${width}/${height} fallback to biggest available layout (${layout}).` ); } else { throw new Error(`No layout or fallback layout found.`); } } if (width < layout.minWidth || height < layout.minHeight) { if (currentLayoutIndex > 0) { const smallerLayout = layouts[currentLayoutIndex - 1]; layout = selectGridLayout( layouts.slice(0, currentLayoutIndex), smallerLayout.maxTiles, width, height ); } } return layout; } function expandAndSortLayoutDefinitions(layouts) { return [...layouts].map((layout) => { var _a, _b; return { name: `${layout.columns}x${layout.rows}`, columns: layout.columns, rows: layout.rows, maxTiles: layout.columns * layout.rows, minWidth: (_a = layout.minWidth) != null ? _a : 0, minHeight: (_b = layout.minHeight) != null ? _b : 0, orientation: layout.orientation }; }).sort((a, b) => { if (a.maxTiles !== b.maxTiles) { return a.maxTiles - b.maxTiles; } else if (a.minWidth !== 0 || b.minWidth !== 0) { return a.minWidth - b.minWidth; } else if (a.minHeight !== 0 || b.minHeight !== 0) { return a.minHeight - b.minHeight; } else { return 0; } }); } // src/helper/set-helper.ts function setDifference(setA, setB) { const _difference = new Set(setA); for (const elem of setB) { _difference.delete(elem); } return _difference; } // src/helper/featureDetection.ts function supportsScreenSharing() { return typeof navigator !== "undefined" && navigator.mediaDevices && !!navigator.mediaDevices.getDisplayMedia; } // src/helper/transcriptions.ts function getActiveTranscriptionSegments(segments, syncTimes, maxAge = 0) { return segments.filter((segment) => { var _a; const hasTrackSync = !!syncTimes.rtpTimestamp; const currentTrackTime = (_a = syncTimes.rtpTimestamp) != null ? _a : performance.timeOrigin + performance.now(); const displayStartTime = hasTrackSync ? Math.max(segment.receivedAtMediaTimestamp, segment.startTime) : segment.receivedAt; const segmentDuration = maxAge + segment.endTime - segment.startTime; return currentTrackTime >= displayStartTime && currentTrackTime <= displayStartTime + segmentDuration; }); } function addMediaTimestampToTranscription(segment, timestamps) { var _a; return __spreadProps(__spreadValues({}, segment), { receivedAtMediaTimestamp: (_a = timestamps.rtpTimestamp) != null ? _a : 0, receivedAt: timestamps.timestamp }); } function dedupeSegments(prevSegments, newSegments, windowSize) { return [...prevSegments, ...newSegments].reduceRight((acc, segment) => { if (!acc.find((val) => val.id === segment.id)) { acc.unshift(segment); } return acc; }, []).slice(0 - windowSize); } function didActiveSegmentsChange(prevActive, newActive) { if (newActive.length !== prevActive.length) { return true; } return !newActive.every((newSegment) => { return prevActive.find( (prevSegment) => prevSegment.id === newSegment.id && prevSegment.text === newSegment.text && prevSegment.final === newSegment.final && prevSegment.language === newSegment.language && prevSegment.startTime === newSegment.startTime && prevSegment.endTime === newSegment.endTime ); }); } // src/helper/participant-attributes.ts var ParticipantAgentAttributes = /* @__PURE__ */ ((ParticipantAgentAttributes2) => { ParticipantAgentAttributes2["AgentState"] = "lk.agent.state"; ParticipantAgentAttributes2["PublishOnBehalf"] = "lk.publish_on_behalf"; ParticipantAgentAttributes2["TranscriptionFinal"] = "lk.transcription_final"; ParticipantAgentAttributes2["TranscriptionSegmentId"] = "lk.segment_id"; ParticipantAgentAttributes2["TranscribedTrackId"] = "lk.transcribed_track_id"; return ParticipantAgentAttributes2; })(ParticipantAgentAttributes || {}); // src/types.ts var PIN_DEFAULT_STATE = []; var WIDGET_DEFAULT_STATE = { showChat: false, unreadMessages: 0, showSettings: false }; function isSourceWitOptions(source) { return typeof source === "object"; } function isSourcesWithOptions(sources) { return Array.isArray(sources) && sources.filter(isSourceWitOptions).length > 0; } // src/sorting/sort-track-bundles.ts var import_livekit_client4 = require("livekit-client"); // src/sorting/base-sort-functions.ts var import_livekit_client3 = require("livekit-client"); function sortParticipantsByAudioLevel(a, b) { return b.audioLevel - a.audioLevel; } function sortParticipantsByIsSpeaking(a, b) { if (a.isSpeaking === b.isSpeaking) { return 0; } else { return a.isSpeaking ? -1 : 1; } } function sortParticipantsByLastSpokenAT(a, b) { var _a, _b, _c, _d; if (a.lastSpokeAt !== void 0 || b.lastSpokeAt !== void 0) { return ((_b = (_a = b.lastSpokeAt) == null ? void 0 : _a.getTime()) != null ? _b : 0) - ((_d = (_c = a.lastSpokeAt) == null ? void 0 : _c.getTime()) != null ? _d : 0); } else { return 0; } } function sortParticipantsByJoinedAt(a, b) { var _a, _b, _c, _d; return ((_b = (_a = a.joinedAt) == null ? void 0 : _a.getTime()) != null ? _b : 0) - ((_d = (_c = b.joinedAt) == null ? void 0 : _c.getTime()) != null ? _d : 0); } function sortTrackReferencesByType(a, b) { if (isTrackReference(a)) { if (isTrackReference(b)) { return 0; } else { return -1; } } else if (isTrackReference(b)) { return 1; } else { return 0; } } function sortTrackRefsByIsCameraEnabled(a, b) { const aVideo = a.participant.isCameraEnabled; const bVideo = b.participant.isCameraEnabled; if (aVideo !== bVideo) { if (aVideo) { return -1; } else { return 1; } } else { return 0; } } // src/sorting/sort-track-bundles.ts function sortTrackReferences(tracks) { const localTracks = []; const screenShareTracks = []; const cameraTracks = []; const undefinedTracks = []; tracks.forEach((trackRef) => { if (trackRef.participant.isLocal && trackRef.source === import_livekit_client4.Track.Source.Camera) { localTracks.push(trackRef); } else if (trackRef.source === import_livekit_client4.Track.Source.ScreenShare) { screenShareTracks.push(trackRef); } else if (trackRef.source === import_livekit_client4.Track.Source.Camera) { cameraTracks.push(trackRef); } else { undefinedTracks.push(trackRef); } }); const sortedScreenShareTracks = sortScreenShareTracks(screenShareTracks); const sortedCameraTracks = sortCameraTracks(cameraTracks); return [...localTracks, ...sortedScreenShareTracks, ...sortedCameraTracks, ...undefinedTracks]; } function sortScreenShareTracks(screenShareTracks) { const localScreenShares = []; const remoteScreenShares = []; screenShareTracks.forEach((trackRef) => { if (trackRef.participant.isLocal) { localScreenShares.push(trackRef); } else { remoteScreenShares.push(trackRef); } }); localScreenShares.sort((a, b) => sortParticipantsByJoinedAt(a.participant, b.participant)); remoteScreenShares.sort((a, b) => sortParticipantsByJoinedAt(a.participant, b.participant)); const sortedScreenShareTrackRefs = [...remoteScreenShares, ...localScreenShares]; return sortedScreenShareTrackRefs; } function sortCameraTracks(cameraTrackReferences) { const localCameraTracks = []; const remoteCameraTracks = []; cameraTrackReferences.forEach((trackRef) => { if (trackRef.participant.isLocal) { localCameraTracks.push(trackRef); } else { remoteCameraTracks.push(trackRef); } }); remoteCameraTracks.sort((a, b) => { if (a.participant.isSpeaking && b.participant.isSpeaking) { return sortParticipantsByAudioLevel(a.participant, b.participant); } if (a.participant.isSpeaking !== b.participant.isSpeaking) { return sortParticipantsByIsSpeaking(a.participant, b.participant); } if (a.participant.lastSpokeAt !== b.participant.lastSpokeAt) { return sortParticipantsByLastSpokenAT(a.participant, b.participant); } if (isTrackReference(a) !== isTrackReference(b)) { return sortTrackReferencesByType(a, b); } if (a.participant.isCameraEnabled !== b.participant.isCameraEnabled) { return sortTrackRefsByIsCameraEnabled(a, b); } return sortParticipantsByJoinedAt(a.participant, b.participant); }); return [...localCameraTracks, ...remoteCameraTracks]; } // src/sorting/sort-participants.ts function sortParticipants(participants) { const sortedParticipants = [...participants]; sortedParticipants.sort((a, b) => { if (a.isSpeaking && b.isSpeaking) { return sortParticipantsByAudioLevel(a, b); } if (a.isSpeaking !== b.isSpeaking) { return sortParticipantsByIsSpeaking(a, b); } if (a.lastSpokeAt !== b.lastSpokeAt) { return sortParticipantsByLastSpokenAT(a, b); } const aVideo = a.videoTrackPublications.size > 0; const bVideo = b.videoTrackPublications.size > 0; if (aVideo !== bVideo) { if (aVideo) { return -1; } else { return 1; } } return sortParticipantsByJoinedAt(a, b); }); const localParticipant = sortedParticipants.find((p) => p.isLocal); if (localParticipant) { const localIdx = sortedParticipants.indexOf(localParticipant); if (localIdx >= 0) { sortedParticipants.splice(localIdx, 1); if (sortedParticipants.length > 0) { sortedParticipants.splice(0, 0, localParticipant); } else { sortedParticipants.push(localParticipant); } } } return sortedParticipants; } // src/helper/array-helper.ts function chunk(input, size) { return input.reduce( (arr, item, idx) => { return idx % size === 0 ? [...arr, [item]] : [...arr.slice(0, -1), [...arr.slice(-1)[0], item]]; }, [] ); } function zip(a1, a2) { const resultLength = Math.max(a1.length, a2.length); return new Array(resultLength).fill([]).map((_val, idx) => [a1[idx], a2[idx]]); } function differenceBy(a1, a2, by) { return a1.filter((c) => !a2.map((v) => by(v)).includes(by(c))); } // src/track-reference/test-utils.ts var import_livekit_client5 = require("livekit-client"); function flatTrackReferenceArray(list) { return list.map((item) => { if (typeof item === "string" || typeof item === "number") { return `${item}`; } else { return getTrackReferenceId(item); } }); } // src/sorting/tile-array-update.ts function visualPageChange(state, next) { return { dropped: differenceBy(state, next, getTrackReferenceId), added: differenceBy(next, state, getTrackReferenceId) }; } function listNeedsUpdating(changes) { return changes.added.length !== 0 || changes.dropped.length !== 0; } function findIndex(trackReference, trackReferences) { const indexToReplace = trackReferences.findIndex( (trackReference_) => getTrackReferenceId(trackReference_) === getTrackReferenceId(trackReference) ); if (indexToReplace === -1) { throw new Error( `Element not part of the array: ${getTrackReferenceId( trackReference )} not in ${flatTrackReferenceArray(trackReferences)}` ); } return indexToReplace; } function swapItems(moveForward, moveBack, trackReferences) { const indexToReplace = findIndex(moveForward, trackReferences); const indexReplaceWith = findIndex(moveBack, trackReferences); trackReferences.splice(indexToReplace, 1, moveBack); trackReferences.splice(indexReplaceWith, 1, moveForward); return trackReferences; } function dropItem(itemToDrop, list) { const indexOfElementToDrop = findIndex(itemToDrop, list); list.splice(indexOfElementToDrop, 1); return list; } function addItem(itemToAdd, list) { return [...list, itemToAdd]; } function divideIntoPages(list, maxElementsOnPage) { const pages = chunk(list, maxElementsOnPage); return pages; } function updatePages(currentList, nextList, maxItemsOnPage) { let updatedList = refreshList(currentList, nextList); if (updatedList.length < nextList.length) { const addedItems = differenceBy(nextList, updatedList, getTrackReferenceId); updatedList = [...updatedList, ...addedItems]; } const currentPages = divideIntoPages(updatedList, maxItemsOnPage); const nextPages = divideIntoPages(nextList, maxItemsOnPage); zip(currentPages, nextPages).forEach(([currentPage, nextPage], pageIndex) => { if (currentPage && nextPage) { const updatedPage = divideIntoPages(updatedList, maxItemsOnPage)[pageIndex]; const changes = visualPageChange(updatedPage, nextPage); if (listNeedsUpdating(changes)) { log.debug( `Detected visual changes on page: ${pageIndex}, current: ${flatTrackReferenceArray( currentPage )}, next: ${flatTrackReferenceArray(nextPage)}`, { changes } ); if (changes.added.length === changes.dropped.length) { zip(changes.added, changes.dropped).forEach(([added, dropped]) => { if (added && dropped) { updatedList = swapItems(added, dropped, updatedList); } else { throw new Error( `For a swap action we need a addition and a removal one is missing: ${added}, ${dropped}` ); } }); } if (changes.added.length === 0 && changes.dropped.length > 0) { changes.dropped.forEach((item) => { updatedList = dropItem(item, updatedList); }); } if (changes.added.length > 0 && changes.dropped.length === 0) { changes.added.forEach((item) => { updatedList = addItem(item, updatedList); }); } } } }); if (updatedList.length > nextList.length) { const missingItems = differenceBy(updatedList, nextList, getTrackReferenceId); updatedList = updatedList.filter( (item) => !missingItems.map(getTrackReferenceId).includes(getTrackReferenceId(item)) ); } return updatedList; } function refreshList(currentList, nextList) { return currentList.map((currentItem) => { const updateForCurrentItem = nextList.find( (newItem_) => ( // If the IDs match or .. getTrackReferenceId(currentItem) === getTrackReferenceId(newItem_) || // ... if the current item is a placeholder and the new item is the track reference can replace it. typeof currentItem !== "number" && isTrackReferencePlaceholder(currentItem) && isTrackReference(newItem_) && isPlaceholderReplacement(currentItem, newItem_) ) ); return updateForCurrentItem != null ? updateForCurrentItem : currentItem; }); } // src/components/mediaToggle.ts var import_livekit_client9 = require("livekit-client"); var import_rxjs4 = require("rxjs"); // src/observables/participant.ts var import_livekit_client8 = require("livekit-client"); var import_rxjs3 = require("rxjs"); // src/components/mediaTrack.ts var import_livekit_client6 = require("livekit-client"); var import_rxjs = require("rxjs"); // src/styles-interface/class-prefixer.ts function prefixClass(unprefixedClassName) { return `${cssPrefix}-${unprefixedClassName}`; } // src/components/mediaTrack.ts function setupMediaTrack(trackIdentifier) { const initialPub = getTrackByIdentifier(trackIdentifier); const trackObserver = observeParticipantMedia(trackIdentifier.participant).pipe( (0, import_rxjs.map)(() => { return getTrackByIdentifier(trackIdentifier); }), (0, import_rxjs.startWith)(initialPub) ); const className = prefixClass( trackIdentifier.source === import_livekit_client6.Track.Source.Camera || trackIdentifier.source === import_livekit_client6.Track.Source.ScreenShare ? "participant-media-video" : "participant-media-audio" ); return { className, trackObserver }; } function getTrackByIdentifier(options) { if (isTrackReference(options)) { return options.publication; } else { const { source, name, participant } = options; if (source && name) { return participant.getTrackPublications().find((pub) => pub.source === source && pub.trackName === name); } else if (name) { return participant.getTrackPublicationByName(name); } else if (source) { return participant.getTrackPublication(source); } else { throw new Error("At least one of source and name needs to be defined"); } } } // src/observables/room.ts var import_livekit_client7 = require("livekit-client"); var import_rxjs2 = require("rxjs"); function observeRoomEvents(room, ...events) { const observable = new import_rxjs2.Observable((subscribe) => { const onRoomUpdate = () => { subscribe.next(room); }; events.forEach((evt) => { room.on(evt, onRoomUpdate); }); const unsubscribe = () => { events.forEach((evt) => { room.off(evt, onRoomUpdate); }); }; return unsubscribe; }).pipe((0, import_rxjs2.startWith)(room)); return observable; } function roomEventSelector(room, event) { const observable = new import_rxjs2.Observable((subscribe) => { const update = (...params) => { subscribe.next(params); }; room.on(event, update); const unsubscribe = () => { room.off(event, update); }; return unsubscribe; }); return observable; } function roomObserver(room) { const observable = observeRoomEvents( room, import_livekit_client7.RoomEvent.ParticipantConnected, import_livekit_client7.RoomEvent.ParticipantDisconnected, import_livekit_client7.RoomEvent.ActiveSpeakersChanged, import_livekit_client7.RoomEvent.TrackSubscribed, import_livekit_client7.RoomEvent.TrackUnsubscribed, import_livekit_client7.RoomEvent.LocalTrackPublished, import_livekit_client7.RoomEvent.LocalTrackUnpublished, import_livekit_client7.RoomEvent.AudioPlaybackStatusChanged, import_livekit_client7.RoomEvent.ConnectionStateChanged ); return observable; } function connectionStateObserver(room) { return roomEventSelector(room, import_livekit_client7.RoomEvent.ConnectionStateChanged).pipe( (0, import_rxjs2.map)(([connectionState]) => connectionState), (0, import_rxjs2.startWith)(room.state) ); } function screenShareObserver(room) { let screenShareSubscriber; const observers = []; const observable = new import_rxjs2.Observable((subscriber) => { screenShareSubscriber = subscriber; return () => { observers.forEach((observer) => { observer.unsubscribe(); }); }; }); const screenShareTracks = []; const handleSub = (publication, participant) => { if (publication.source !== import_livekit_client7.Track.Source.ScreenShare && publication.source !== import_livekit_client7.Track.Source.ScreenShareAudio) { return; } let trackMap = screenShareTracks.find((tr) => tr.participant.identity === participant.identity); const getScreenShareTracks = (participant2) => { return participant2.getTrackPublications().filter( (track) => (track.source === import_livekit_client7.Track.Source.ScreenShare || track.source === import_livekit_client7.Track.Source.ScreenShareAudio) && track.track ); }; if (!trackMap) { trackMap = { participant, tracks: getScreenShareTracks(participant) }; } else { const index = screenShareTracks.indexOf(trackMap); screenShareTracks.splice(index, 1); trackMap.tracks = getScreenShareTracks(participant); } if (trackMap.tracks.length > 0) { screenShareTracks.push(trackMap); } screenShareSubscriber.next(screenShareTracks); }; observers.push( roomEventSelector(room, import_livekit_client7.RoomEvent.TrackSubscribed).subscribe( ([, ...args]) => handleSub(...args) ) ); observers.push( roomEventSelector(room, import_livekit_client7.RoomEvent.TrackUnsubscribed).subscribe( ([, ...args]) => handleSub(...args) ) ); observers.push( roomEventSelector(room, import_livekit_client7.RoomEvent.LocalTrackPublished).subscribe((args) => handleSub(...args)) ); observers.push( roomEventSelector(room, import_livekit_client7.RoomEvent.LocalTrackUnpublished).subscribe((args) => { handleSub(...args); }) ); observers.push( roomEventSelector(room, import_livekit_client7.RoomEvent.TrackMuted).subscribe((args) => { handleSub(...args); }) ); observers.push( roomEventSelector(room, import_livekit_client7.RoomEvent.TrackUnmuted).subscribe((args) => { handleSub(...args); }) ); setTimeout(() => { for (const p of room.remoteParticipants.values()) { p.getTrackPublications().forEach((track) => { handleSub(track, p); }); } }, 1); return observable; } function roomInfoObserver(room) { const observer = observeRoomEvents( room, import_livekit_client7.RoomEvent.RoomMetadataChanged, import_livekit_client7.RoomEvent.ConnectionStateChanged ).pipe( (0, import_rxjs2.map)((r) => { return { name: r.name, metadata: r.metadata }; }) ); return observer; } function activeSpeakerObserver(room) { return roomEventSelector(room, import_livekit_client7.RoomEvent.ActiveSpeakersChanged).pipe( (0, import_rxjs2.map)(([speakers]) => speakers) ); } function createMediaDeviceObserver(kind, onError, requestPermissions = true) { const initialDevices$ = new import_rxjs2.Observable((subscriber) => { import_livekit_client7.Room.getLocalDevices(kind, requestPermissions).then((devices) => { subscriber.next(devices); subscriber.complete(); }).catch((e) => { onError == null ? void 0 : onError(e); subscriber.next([]); subscriber.complete(); }); }); const deviceChanges$ = new import_rxjs2.Observable((subscriber) => { var _a; const onDeviceChange = () => __async(this, null, function* () { try { const newDevices = yield import_livekit_client7.Room.getLocalDevices(kind, requestPermissions); subscriber.next(newDevices); } catch (e) { onError == null ? void 0 : onError(e); } }); if (typeof window !== "undefined") { if (!window.isSecureContext) { throw new Error( `Accessing media devices is available only in secure contexts (HTTPS and localhost), in some or all supporting browsers. See: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/mediaDevices` ); } (_a = navigator == null ? void 0 : navigator.mediaDevices) == null ? void 0 : _a.addEventListener("devicechange", onDeviceChange); } return () => { var _a2; (_a2 = navigator == null ? void 0 : navigator.mediaDevices) == null ? void 0 : _a2.removeEventListener("devicechange", onDeviceChange); }; }); return (0, import_rxjs2.concat)(initialDevices$, deviceChanges$); } function createDataObserver(room) { return roomEventSelector(room, import_livekit_client7.RoomEvent.DataReceived); } function createChatObserver(room) { return roomEventSelector(room, import_livekit_client7.RoomEvent.ChatMessage); } function roomAudioPlaybackAllowedObservable(room) { const observable = observeRoomEvents(room, import_livekit_client7.RoomEvent.AudioPlaybackStatusChanged).pipe( (0, import_rxjs2.map)((room2) => { return { canPlayAudio: room2.canPlaybackAudio }; }) ); return observable; } function roomVideoPlaybackAllowedObservable(room) { const observable = observeRoomEvents(room, import_livekit_client7.RoomEvent.VideoPlaybackStatusChanged).pipe( (0, import_rxjs2.map)((room2) => { return { canPlayVideo: room2.canPlaybackVideo }; }) ); return observable; } function createActiveDeviceObservable(room, kind) { return roomEventSelector(room, import_livekit_client7.RoomEvent.ActiveDeviceChanged).pipe( (0, import_rxjs2.filter)(([kindOfDevice]) => kindOfDevice === kind), (0, import_rxjs2.map)(([kind2, deviceId]) => { log.debug("activeDeviceObservable | RoomEvent.ActiveDeviceChanged", { kind: kind2, deviceId }); return deviceId; }) ); } function encryptionStatusObservable(room, participant) { return roomEventSelector(room, import_livekit_client7.RoomEvent.ParticipantEncryptionStatusChanged).pipe( (0, import_rxjs2.filter)( ([, p]) => (participant == null ? void 0 : participant.identity) === (p == null ? void 0 : p.identity) || !p && (participant == null ? void 0 : participant.identity) === room.localParticipant.identity ), (0, import_rxjs2.map)(([encrypted]) => encrypted), (0, import_rxjs2.startWith)( (participant == null ? void 0 : participant.isLocal) ? participant.isE2EEEnabled : !!(participant == null ? void 0 : participant.isEncrypted) ) ); } function recordingStatusObservable(room) { return roomEventSelector(room, import_livekit_client7.RoomEvent.RecordingStatusChanged).pipe( (0, import_rxjs2.map)(([recording]) => recording), (0, import_rxjs2.startWith)(room.isRecording) ); } // src/observables/participant.ts function observeParticipantEvents(participant, ...events) { const observable = new import_rxjs3.Observable((subscribe) => { const onParticipantUpdate = () => { subscribe.next(participant); }; events.forEach((evt) => { participant.on(evt, onParticipantUpdate); }); const unsubscribe = () => { events.forEach((evt) => { participant.off(evt, onParticipantUpdate); }); }; return unsubscribe; }).pipe((0, import_rxjs3.startWith)(participant)); return observable; } function observeParticipantMedia(participant) { const participantObserver = observeParticipantEvents( participant, import_livekit_client8.ParticipantEvent.TrackMuted, import_livekit_client8.ParticipantEvent.TrackUnmuted, import_livekit_client8.ParticipantEvent.ParticipantPermissionsChanged, // ParticipantEvent.IsSpeakingChanged, import_livekit_client8.ParticipantEvent.TrackPublished, import_livekit_client8.ParticipantEvent.TrackUnpublished, import_livekit_client8.ParticipantEvent.LocalTrackPublished, import_livekit_client8.ParticipantEvent.LocalTrackUnpublished, import_livekit_client8.ParticipantEvent.MediaDevicesError, import_livekit_client8.ParticipantEvent.TrackSubscriptionStatusChanged // ParticipantEvent.ConnectionQualityChanged, ).pipe( (0, import_rxjs3.map)((p) => { const { isMicrophoneEnabled, isCameraEnabled, isScreenShareEnabled } = p; const microphoneTrack = p.getTrackPublication(import_livekit_client8.Track.Source.Microphone); const cameraTrack = p.getTrackPublication(import_livekit_client8.Track.Source.Camera); const participantMedia = { isCameraEnabled, isMicrophoneEnabled, isScreenShareEnabled, cameraTrack, microphoneTrack, participant: p }; return participantMedia; }) ); return participantObserver; } function createTrackObserver(participant, options) { return observeParticipantMedia(participant).pipe( (0, import_rxjs3.map)(() => { return { publication: getTrackByIdentifier(options) }; }) ); } function participantInfoObserver(participant) { if (!participant) { return void 0; } const observer = observeParticipantEvents( participant, import_livekit_client8.ParticipantEvent.ParticipantMetadataChanged, import_livekit_client8.ParticipantEvent.ParticipantNameChanged ).pipe( (0, import_rxjs3.map)(({ name, identity, metadata }) => { return { name, identity, metadata }; }), (0, import_rxjs3.startWith)({ name: participant.name, identity: participant.identity, metadata: participant.metadata }) ); return observer; } function createConnection