@simplito/privmx-webendpoint 2.6.5 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +86 -0
- package/README.md +97 -7
- package/assets/driver-web-context.js +1 -1
- package/assets/e2ee-worker.js +1 -1
- package/assets/endpoint-wasm-module.js +2 -2
- package/assets/endpoint-wasm-module.wasm +0 -0
- package/assets/rms-processor.js +1 -0
- package/build-manifest.sh +6 -0
- package/{FinalizationHelper.js → dist/FinalizationHelper.js} +1 -1
- package/dist/ServerTypes.d.ts +7 -0
- package/{Types.d.ts → dist/Types.d.ts} +97 -10
- package/{Types.js → dist/Types.js} +17 -32
- package/{api → dist/api}/Api.d.ts +2 -0
- package/{api → dist/api}/Api.js +18 -1
- package/{api → dist/api}/ConnectionNative.js +1 -1
- package/{api → dist/api}/CryptoApiNative.js +1 -2
- package/{api → dist/api}/InboxApiNative.d.ts +21 -2
- package/{api → dist/api}/KvdbApiNative.d.ts +19 -2
- package/dist/api/NativeError.d.ts +13 -0
- package/dist/api/NativeError.js +20 -0
- package/{api → dist/api}/StoreApiNative.d.ts +19 -2
- package/dist/api/StreamApiNative.d.ts +72 -0
- package/dist/api/StreamApiNative.js +142 -0
- package/{api → dist/api}/ThreadApiNative.d.ts +19 -2
- package/dist/assets/e2ee-worker.js +1 -0
- package/dist/bundle/privmx-endpoint-web.js +2 -0
- package/dist/bundle/privmx-endpoint-web.js.LICENSE.txt +30 -0
- package/dist/bundle/rms-processor.js +1 -0
- package/{extra → dist/extra}/PrivmxClient.d.ts +9 -9
- package/{extra → dist/extra}/PrivmxClient.js +12 -12
- package/{extra → dist/extra}/PublicConnection.d.ts +2 -2
- package/{extra → dist/extra}/PublicConnection.js +2 -2
- package/{extra → dist/extra}/__tests__/connectionEventManager.test.js +1 -3
- package/{extra → dist/extra}/__tests__/customEventManager.test.js +1 -3
- package/{extra → dist/extra}/__tests__/userEventManager.test.js +2 -6
- package/{extra → dist/extra}/__tests__/utils.test.js +18 -18
- package/{extra → dist/extra}/events.js +32 -12
- package/{extra → dist/extra}/files.d.ts +5 -5
- package/{extra → dist/extra}/files.js +11 -11
- package/{extra → dist/extra}/generics.d.ts +1 -1
- package/{extra → dist/extra}/inbox.d.ts +1 -1
- package/{extra → dist/extra}/inbox.js +2 -2
- package/{extra → dist/extra}/index.d.ts +7 -7
- package/{extra → dist/extra}/managers.js +1 -1
- package/{extra → dist/extra}/utils.js +9 -9
- package/{index.d.ts → dist/index.d.ts} +3 -2
- package/{index.js → dist/index.js} +4 -1
- package/{service → dist/service}/Connection.js +13 -6
- package/{service → dist/service}/CryptoApi.js +2 -8
- package/{service → dist/service}/EndpointFactory.d.ts +11 -0
- package/{service → dist/service}/EndpointFactory.js +45 -10
- package/{service → dist/service}/EventApi.js +9 -5
- package/dist/service/EventDispatcher.d.ts +15 -0
- package/dist/service/EventDispatcher.js +25 -0
- package/{service → dist/service}/EventQueue.d.ts +4 -4
- package/{service → dist/service}/EventQueue.js +5 -9
- package/{service → dist/service}/ExtKey.d.ts +10 -10
- package/{service → dist/service}/ExtKey.js +10 -10
- package/{service → dist/service}/InboxApi.js +7 -11
- package/{service → dist/service}/KvdbApi.js +12 -7
- package/{service → dist/service}/StoreApi.js +10 -15
- package/dist/service/StreamApi.d.ts +237 -0
- package/dist/service/StreamApi.js +442 -0
- package/{service → dist/service}/ThreadApi.js +6 -7
- package/{service → dist/service}/UserVerifierInterface.d.ts +2 -2
- package/dist/service/UserVerifierInterface.js +2 -0
- package/dist/service/WebRtcInterface.d.ts +58 -0
- package/dist/service/WebRtcInterface.js +8 -0
- package/{service → dist/service}/index.d.ts +3 -2
- package/{service → dist/service}/index.js +5 -3
- package/dist/webStreams/CryptoUtils.d.ts +24 -0
- package/dist/webStreams/CryptoUtils.js +58 -0
- package/dist/webStreams/KeyStore.d.ts +9 -0
- package/dist/webStreams/KeyStore.js +29 -0
- package/dist/webStreams/Logger.d.ts +7 -0
- package/dist/webStreams/Logger.js +25 -0
- package/dist/webStreams/PeerConnectionsManager.d.ts +20 -0
- package/dist/webStreams/PeerConnectionsManager.js +92 -0
- package/dist/webStreams/Queue.d.ts +19 -0
- package/dist/webStreams/Queue.js +70 -0
- package/dist/webStreams/Utils.d.ts +20 -0
- package/dist/webStreams/Utils.js +211 -0
- package/dist/webStreams/WebRtcClient.d.ts +85 -0
- package/dist/webStreams/WebRtcClient.js +437 -0
- package/dist/webStreams/WebRtcClientTypes.d.ts +64 -0
- package/dist/webStreams/WebRtcClientTypes.js +2 -0
- package/dist/webStreams/WebRtcConfig.d.ts +20 -0
- package/dist/webStreams/WebRtcConfig.js +53 -0
- package/dist/webStreams/WebRtcInterfaceImpl.d.ts +28 -0
- package/dist/webStreams/WebRtcInterfaceImpl.js +85 -0
- package/dist/webStreams/WebWorkerHelper copy.d.ts +0 -0
- package/dist/webStreams/WebWorkerHelper copy.js +17 -0
- package/dist/webStreams/WebWorkerHelper.d.ts +18 -0
- package/dist/webStreams/WebWorkerHelper.js +69 -0
- package/dist/webStreams/audio/ActiveSpeakerDetector.d.ts +38 -0
- package/dist/webStreams/audio/ActiveSpeakerDetector.js +64 -0
- package/dist/webStreams/audio/LocalAudioLevelMeter.d.ts +12 -0
- package/dist/webStreams/audio/LocalAudioLevelMeter.js +101 -0
- package/dist/webStreams/types/ApiTypes.d.ts +74 -0
- package/dist/webStreams/types/ApiTypes.js +2 -0
- package/dist/webStreams/types/BaseServerTypes.d.ts +10 -0
- package/dist/webStreams/types/BaseServerTypes.js +2 -0
- package/dist/webStreams/types/MediaServerWebSocketApiTypes.d.ts +255 -0
- package/dist/webStreams/types/MediaServerWebSocketApiTypes.js +2 -0
- package/dist/webStreams/types/SignalingReceiverTypes.d.ts +13 -0
- package/dist/webStreams/types/SignalingReceiverTypes.js +2 -0
- package/dist/webStreams/types/SignalingSenderTypes.d.ts +24 -0
- package/dist/webStreams/types/SignalingSenderTypes.js +2 -0
- package/dist/webStreams/types/StreamsApiTypes.d.ts +144 -0
- package/dist/webStreams/types/StreamsApiTypes.js +2 -0
- package/dist/webStreams/worker/WorkerEvents.d.ts +11 -0
- package/dist/webStreams/worker/WorkerEvents.js +2 -0
- package/dist/webStreams/worker/worker.d.ts +13 -0
- package/dist/webStreams/worker/worker.js +202 -0
- package/package.json +46 -15
- package/assets/endpoint-wasm-module.worker.js +0 -1
- package/assets/privmx-endpoint-web.js +0 -2
- package/bundle/privmx-endpoint-web.js +0 -2
- package/bundle/privmx-endpoint-web.js.LICENSE.txt +0 -10
- /package/{FinalizationHelper.d.ts → dist/FinalizationHelper.d.ts} +0 -0
- /package/{extra/generics.js → dist/ServerTypes.js} +0 -0
- /package/{api → dist/api}/ApiStatic.d.ts +0 -0
- /package/{api → dist/api}/ApiStatic.js +0 -0
- /package/{api → dist/api}/BaseNative.d.ts +0 -0
- /package/{api → dist/api}/BaseNative.js +0 -0
- /package/{api → dist/api}/ConnectionNative.d.ts +0 -0
- /package/{api → dist/api}/CryptoApiNative.d.ts +0 -0
- /package/{api → dist/api}/EventApiNative.d.ts +0 -0
- /package/{api → dist/api}/EventApiNative.js +0 -0
- /package/{api → dist/api}/EventQueueNative.d.ts +0 -0
- /package/{api → dist/api}/EventQueueNative.js +0 -0
- /package/{api → dist/api}/ExtKeyNative.d.ts +0 -0
- /package/{api → dist/api}/ExtKeyNative.js +0 -0
- /package/{api → dist/api}/IdGenerator.d.ts +0 -0
- /package/{api → dist/api}/IdGenerator.js +0 -0
- /package/{api → dist/api}/InboxApiNative.js +0 -0
- /package/{api → dist/api}/KvdbApiNative.js +0 -0
- /package/{api → dist/api}/StoreApiNative.js +0 -0
- /package/{api → dist/api}/ThreadApiNative.js +0 -0
- /package/{bundle.d.ts → dist/bundle.d.ts} +0 -0
- /package/{bundle.js → dist/bundle.js} +0 -0
- /package/{extra → dist/extra}/__mocks__/constants.d.ts +0 -0
- /package/{extra → dist/extra}/__mocks__/constants.js +0 -0
- /package/{extra → dist/extra}/__mocks__/mockContainerSubscriber.d.ts +0 -0
- /package/{extra → dist/extra}/__mocks__/mockContainerSubscriber.js +0 -0
- /package/{extra → dist/extra}/__mocks__/mockEventQueue.d.ts +0 -0
- /package/{extra → dist/extra}/__mocks__/mockEventQueue.js +0 -0
- /package/{extra → dist/extra}/__mocks__/utils.d.ts +0 -0
- /package/{extra → dist/extra}/__mocks__/utils.js +0 -0
- /package/{extra → dist/extra}/__tests__/connectionEventManager.test.d.ts +0 -0
- /package/{extra → dist/extra}/__tests__/customEventManager.test.d.ts +0 -0
- /package/{extra → dist/extra}/__tests__/eventsManager.test.d.ts +0 -0
- /package/{extra → dist/extra}/__tests__/eventsManager.test.js +0 -0
- /package/{extra → dist/extra}/__tests__/inboxEventManager.d.ts +0 -0
- /package/{extra → dist/extra}/__tests__/inboxEventManager.js +0 -0
- /package/{extra → dist/extra}/__tests__/storeEventManager.test.d.ts +0 -0
- /package/{extra → dist/extra}/__tests__/storeEventManager.test.js +0 -0
- /package/{extra → dist/extra}/__tests__/threadEventManager.test.d.ts +0 -0
- /package/{extra → dist/extra}/__tests__/threadEventManager.test.js +0 -0
- /package/{extra → dist/extra}/__tests__/userEventManager.test.d.ts +0 -0
- /package/{extra → dist/extra}/__tests__/utils.test.d.ts +0 -0
- /package/{extra → dist/extra}/events.d.ts +0 -0
- /package/{service/UserVerifierInterface.js → dist/extra/generics.js} +0 -0
- /package/{extra → dist/extra}/index.js +0 -0
- /package/{extra → dist/extra}/managers.d.ts +0 -0
- /package/{extra → dist/extra}/subscriptions.d.ts +0 -0
- /package/{extra → dist/extra}/subscriptions.js +0 -0
- /package/{extra → dist/extra}/utils.d.ts +0 -0
- /package/{service → dist/service}/BaseApi.d.ts +0 -0
- /package/{service → dist/service}/BaseApi.js +0 -0
- /package/{service → dist/service}/Connection.d.ts +0 -0
- /package/{service → dist/service}/CryptoApi.d.ts +0 -0
- /package/{service → dist/service}/EventApi.d.ts +0 -0
- /package/{service → dist/service}/InboxApi.d.ts +0 -0
- /package/{service → dist/service}/KvdbApi.d.ts +0 -0
- /package/{service → dist/service}/StoreApi.d.ts +0 -0
- /package/{service → dist/service}/ThreadApi.d.ts +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
PrivMX Endpoint.
|
|
4
|
+
Copyright © 2024 Simplito sp. z o.o.
|
|
5
|
+
|
|
6
|
+
This file is part of the PrivMX Platform (https://privmx.dev).
|
|
7
|
+
This software is Licensed under the PrivMX Free License.
|
|
8
|
+
|
|
9
|
+
See the License for the specific language governing permissions and
|
|
10
|
+
limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.WebRtcInterfaceImpl = void 0;
|
|
14
|
+
class WebRtcInterfaceImpl {
|
|
15
|
+
webRtcClient;
|
|
16
|
+
constructor(webRtcClient) {
|
|
17
|
+
this.webRtcClient = webRtcClient;
|
|
18
|
+
}
|
|
19
|
+
methodsMap = {
|
|
20
|
+
createOfferAndSetLocalDescription: this.createOfferAndSetLocalDescription,
|
|
21
|
+
createAnswerAndSetDescriptions: this.createAnswerAndSetDescriptions,
|
|
22
|
+
setAnswerAndSetRemoteDescription: this.setAnswerAndSetRemoteDescription,
|
|
23
|
+
updateSessionId: this.updateSessionId,
|
|
24
|
+
close: this.close,
|
|
25
|
+
updateKeys: this.updateKeys,
|
|
26
|
+
};
|
|
27
|
+
isMainThread() {
|
|
28
|
+
return typeof window !== "undefined";
|
|
29
|
+
}
|
|
30
|
+
getClient() {
|
|
31
|
+
if (!this.webRtcClient) {
|
|
32
|
+
throw new Error("WebRtcClient not initialized. Aborting...");
|
|
33
|
+
}
|
|
34
|
+
return this.webRtcClient;
|
|
35
|
+
}
|
|
36
|
+
async methodCall(name, params) {
|
|
37
|
+
if (this.methodsMap[name]) {
|
|
38
|
+
const method = this.methodsMap[name];
|
|
39
|
+
if (typeof method === "function") {
|
|
40
|
+
return this.methodsMap[name].call(this, params);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
throw new Error(`Method '${name}' is not implemented.`);
|
|
44
|
+
}
|
|
45
|
+
async createOfferAndSetLocalDescription(model) {
|
|
46
|
+
const peerConnection = this.getClient()
|
|
47
|
+
.getConnectionManager()
|
|
48
|
+
.getConnectionWithSession(model.roomId, "publisher").pc;
|
|
49
|
+
const offer = await peerConnection.createOffer();
|
|
50
|
+
await peerConnection.setLocalDescription(offer);
|
|
51
|
+
return offer.sdp; // sdp
|
|
52
|
+
}
|
|
53
|
+
async createAnswerAndSetDescriptions(model) {
|
|
54
|
+
const offer = { sdp: model.sdp, type: model.type };
|
|
55
|
+
await this.getClient().onSubscriptionUpdated(model.roomId, offer);
|
|
56
|
+
return this.webRtcClient.lastProcessedAnswer[model.roomId].sdp;
|
|
57
|
+
}
|
|
58
|
+
async setAnswerAndSetRemoteDescription(model) {
|
|
59
|
+
const janusSession = this.getClient()
|
|
60
|
+
.getConnectionManager()
|
|
61
|
+
.getConnectionWithSession(model.roomId, "publisher");
|
|
62
|
+
if (!("pc" in janusSession)) {
|
|
63
|
+
throw new Error("WebRtcInterfaceImpl: No peerConnection available on setAnswerAndSetRemoteDescription");
|
|
64
|
+
}
|
|
65
|
+
const peerConnection = janusSession.pc;
|
|
66
|
+
await peerConnection.setRemoteDescription(new RTCSessionDescription({ sdp: model.sdp, type: model.type }));
|
|
67
|
+
}
|
|
68
|
+
async close(roomId) {
|
|
69
|
+
this.getClient()
|
|
70
|
+
.getConnectionManager()
|
|
71
|
+
.closePeerConnectionBySessionIfExists(roomId, "subscriber");
|
|
72
|
+
this.getClient()
|
|
73
|
+
.getConnectionManager()
|
|
74
|
+
.closePeerConnectionBySessionIfExists(roomId, "publisher");
|
|
75
|
+
}
|
|
76
|
+
async updateKeys(model) {
|
|
77
|
+
return this.getClient().updateKeys(model.streamRoomId, model.keys);
|
|
78
|
+
}
|
|
79
|
+
async updateSessionId(streamRoomId, sessionId, connectionType) {
|
|
80
|
+
this.getClient()
|
|
81
|
+
.getConnectionManager()
|
|
82
|
+
.updateSessionForConnection(streamRoomId, connectionType, sessionId);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.WebRtcInterfaceImpl = WebRtcInterfaceImpl;
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// import { EncKey } from "./WebRtcClientTypes";
|
|
3
|
+
// export class WebWorker {
|
|
4
|
+
// worker: Worker | undefined;
|
|
5
|
+
// constructor(private encKey: EncKey) {
|
|
6
|
+
// // this.worker = new Worker(new URL("./worker/worker.ts", import.meta.url), {name: "worker"});
|
|
7
|
+
// this.worker = new Worker(new URL("worker.js", import.meta.url), {name: "worker"});
|
|
8
|
+
// this.worker.onerror = e => console.error(e);
|
|
9
|
+
// this.worker.postMessage({
|
|
10
|
+
// operation: 'initialize',
|
|
11
|
+
// key: encKey.key, iv: encKey.iv
|
|
12
|
+
// });
|
|
13
|
+
// }
|
|
14
|
+
// getWorker() {
|
|
15
|
+
// return this.worker;
|
|
16
|
+
// }
|
|
17
|
+
// }
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Key } from "../Types";
|
|
2
|
+
export interface FrameInfo {
|
|
3
|
+
rms: number;
|
|
4
|
+
kind: "audio";
|
|
5
|
+
receiverId: number;
|
|
6
|
+
publisherId: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class WebWorker {
|
|
9
|
+
private assetsDir;
|
|
10
|
+
private onFrame;
|
|
11
|
+
worker: Worker | undefined;
|
|
12
|
+
constructor(assetsDir: string, onFrame: (frameInfo: FrameInfo) => void);
|
|
13
|
+
init_e2ee(): Promise<void>;
|
|
14
|
+
getWorker(): Worker;
|
|
15
|
+
setKeys(keys: Key[]): void;
|
|
16
|
+
createWorkerFromFunction(workerFunction: Function): Worker;
|
|
17
|
+
createWorkerFromScript(scriptUrl: string): Promise<Worker>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebWorker = void 0;
|
|
4
|
+
class WebWorker {
|
|
5
|
+
assetsDir;
|
|
6
|
+
onFrame;
|
|
7
|
+
worker;
|
|
8
|
+
constructor(assetsDir, onFrame) {
|
|
9
|
+
this.assetsDir = assetsDir;
|
|
10
|
+
this.onFrame = onFrame;
|
|
11
|
+
}
|
|
12
|
+
async init_e2ee() {
|
|
13
|
+
this.worker = new Worker(this.assetsDir + "/e2ee-worker.js");
|
|
14
|
+
this.worker.onmessage = (event) => {
|
|
15
|
+
try {
|
|
16
|
+
if (event.data.type === "rms") {
|
|
17
|
+
if (this.onFrame !== undefined && typeof this.onFrame === "function") {
|
|
18
|
+
this.onFrame({
|
|
19
|
+
rms: event.data.rms,
|
|
20
|
+
kind: "audio",
|
|
21
|
+
receiverId: event.data.receiverId,
|
|
22
|
+
publisherId: event.data.publisherId,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
console.error("[Worker]: invalid event");
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
this.worker.onerror = (e) => console.error(e);
|
|
32
|
+
this.worker.postMessage({
|
|
33
|
+
operation: "initialize",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
getWorker() {
|
|
37
|
+
return this.worker;
|
|
38
|
+
}
|
|
39
|
+
setKeys(keys) {
|
|
40
|
+
if (!this.worker) {
|
|
41
|
+
console.warn("Cannot pass keys to e2ee worker as it is not initialized yet.");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
this.worker.postMessage({
|
|
45
|
+
operation: "setKeys",
|
|
46
|
+
keys,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
createWorkerFromFunction(workerFunction) {
|
|
50
|
+
const blob = new Blob([`(${workerFunction.toString()})()`], {
|
|
51
|
+
type: "application/javascript",
|
|
52
|
+
});
|
|
53
|
+
return new Worker(URL.createObjectURL(blob));
|
|
54
|
+
}
|
|
55
|
+
async createWorkerFromScript(scriptUrl) {
|
|
56
|
+
const scriptContent = await fetch(scriptUrl).then((r) => r.text());
|
|
57
|
+
const blob = new Blob([scriptContent], { type: "application/javascript" });
|
|
58
|
+
const workerUrl = URL.createObjectURL(blob);
|
|
59
|
+
const worker = new Worker(workerUrl);
|
|
60
|
+
return worker;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.WebWorker = WebWorker;
|
|
64
|
+
// function workerScript() {
|
|
65
|
+
// self.onmessage = WorkerSpec.onmessage;
|
|
66
|
+
// }
|
|
67
|
+
function workerScript() {
|
|
68
|
+
return "";
|
|
69
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare const DEFAULTS: {
|
|
2
|
+
rmsEmaAlpha: number;
|
|
3
|
+
noiseEmaAlpha: number;
|
|
4
|
+
thresholdOffset: number;
|
|
5
|
+
activityWindowMs: number;
|
|
6
|
+
holdMs: number;
|
|
7
|
+
};
|
|
8
|
+
type SpeakerId = number;
|
|
9
|
+
interface FrameInput {
|
|
10
|
+
id: SpeakerId;
|
|
11
|
+
rms: number;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
}
|
|
14
|
+
export interface SpeakerState {
|
|
15
|
+
streamId: number;
|
|
16
|
+
emaRms: number;
|
|
17
|
+
noiseFloor: number;
|
|
18
|
+
lastAboveThresholdTs: number;
|
|
19
|
+
activeSince: number;
|
|
20
|
+
active: boolean;
|
|
21
|
+
}
|
|
22
|
+
interface ActiveSpeakerDetectorOptions {
|
|
23
|
+
rmsEmaAlpha: number;
|
|
24
|
+
noiseEmaAlpha: number;
|
|
25
|
+
thresholdOffset: number;
|
|
26
|
+
activityWindowMs: number;
|
|
27
|
+
holdMs: number;
|
|
28
|
+
}
|
|
29
|
+
export declare class ActiveSpeakerDetector {
|
|
30
|
+
private opts;
|
|
31
|
+
private speakers;
|
|
32
|
+
private activeSpeaker;
|
|
33
|
+
constructor(opts: ActiveSpeakerDetectorOptions);
|
|
34
|
+
onFrame({ id, rms, timestamp }: FrameInput): SpeakerState[];
|
|
35
|
+
private selectActiveSpeakers;
|
|
36
|
+
private getOrCreateState;
|
|
37
|
+
}
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ActiveSpeakerDetector = exports.DEFAULTS = void 0;
|
|
4
|
+
exports.DEFAULTS = {
|
|
5
|
+
rmsEmaAlpha: 0.2, // szybka reakcja na mowę
|
|
6
|
+
noiseEmaAlpha: 0.02, // wolna adaptacja tła
|
|
7
|
+
thresholdOffset: 6, // dB (jeśli RMS w dB)
|
|
8
|
+
activityWindowMs: 400,
|
|
9
|
+
holdMs: 200,
|
|
10
|
+
};
|
|
11
|
+
class ActiveSpeakerDetector {
|
|
12
|
+
opts;
|
|
13
|
+
speakers = new Map();
|
|
14
|
+
activeSpeaker = null;
|
|
15
|
+
constructor(opts) {
|
|
16
|
+
this.opts = opts;
|
|
17
|
+
}
|
|
18
|
+
onFrame({ id, rms, timestamp }) {
|
|
19
|
+
const state = this.getOrCreateState(id, rms);
|
|
20
|
+
state.emaRms = this.opts.rmsEmaAlpha * rms + (1 - this.opts.rmsEmaAlpha) * state.emaRms;
|
|
21
|
+
if (state.emaRms < state.noiseFloor + this.opts.thresholdOffset) {
|
|
22
|
+
state.noiseFloor =
|
|
23
|
+
this.opts.noiseEmaAlpha * state.emaRms +
|
|
24
|
+
(1 - this.opts.noiseEmaAlpha) * state.noiseFloor;
|
|
25
|
+
}
|
|
26
|
+
const adaptiveThreshold = state.noiseFloor + this.opts.thresholdOffset;
|
|
27
|
+
if (state.emaRms >= adaptiveThreshold) {
|
|
28
|
+
state.lastAboveThresholdTs = timestamp;
|
|
29
|
+
state.activeSince = timestamp;
|
|
30
|
+
state.active = true;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
state.active = false;
|
|
34
|
+
state.activeSince = 0;
|
|
35
|
+
}
|
|
36
|
+
return this.selectActiveSpeakers(timestamp);
|
|
37
|
+
}
|
|
38
|
+
selectActiveSpeakers(now) {
|
|
39
|
+
let bestId = null;
|
|
40
|
+
let bestRms = -Infinity;
|
|
41
|
+
for (const [id, state] of this.speakers.entries()) {
|
|
42
|
+
state.active =
|
|
43
|
+
now - state.lastAboveThresholdTs <= this.opts.activityWindowMs &&
|
|
44
|
+
now - state.activeSince < this.opts.holdMs;
|
|
45
|
+
}
|
|
46
|
+
return Array.from(this.speakers.values());
|
|
47
|
+
}
|
|
48
|
+
getOrCreateState(id, rms) {
|
|
49
|
+
let state = this.speakers.get(id);
|
|
50
|
+
if (!state) {
|
|
51
|
+
state = {
|
|
52
|
+
streamId: id,
|
|
53
|
+
emaRms: rms,
|
|
54
|
+
noiseFloor: rms,
|
|
55
|
+
lastAboveThresholdTs: -Infinity,
|
|
56
|
+
active: false,
|
|
57
|
+
activeSince: 0,
|
|
58
|
+
};
|
|
59
|
+
this.speakers.set(id, state);
|
|
60
|
+
}
|
|
61
|
+
return state;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.ActiveSpeakerDetector = ActiveSpeakerDetector;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class LocalAudioLevelMeter {
|
|
2
|
+
private track;
|
|
3
|
+
private onLevel;
|
|
4
|
+
private ctx;
|
|
5
|
+
private node;
|
|
6
|
+
private source;
|
|
7
|
+
private keepAliveGain;
|
|
8
|
+
private stopped;
|
|
9
|
+
constructor(track: MediaStreamTrack, onLevel: (rmsDb: number) => void);
|
|
10
|
+
init(workletUrl: string): Promise<void>;
|
|
11
|
+
stop(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalAudioLevelMeter = void 0;
|
|
4
|
+
class LocalAudioLevelMeter {
|
|
5
|
+
track;
|
|
6
|
+
onLevel;
|
|
7
|
+
ctx;
|
|
8
|
+
node;
|
|
9
|
+
source;
|
|
10
|
+
keepAliveGain;
|
|
11
|
+
stopped = false;
|
|
12
|
+
constructor(track, onLevel) {
|
|
13
|
+
this.track = track;
|
|
14
|
+
this.onLevel = onLevel;
|
|
15
|
+
}
|
|
16
|
+
async init(workletUrl) {
|
|
17
|
+
const candidateSampleRates = [];
|
|
18
|
+
try {
|
|
19
|
+
const settings = this.track.getSettings?.();
|
|
20
|
+
if (typeof settings?.sampleRate === "number") {
|
|
21
|
+
candidateSampleRates.push(settings.sampleRate);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// ignore
|
|
26
|
+
}
|
|
27
|
+
candidateSampleRates.push(undefined);
|
|
28
|
+
let lastErr;
|
|
29
|
+
for (const sampleRate of candidateSampleRates) {
|
|
30
|
+
if (this.stopped) {
|
|
31
|
+
throw new Error("LocalAudioLevelMeter stopped during init");
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
this.ctx = sampleRate ? new AudioContext({ sampleRate }) : new AudioContext();
|
|
35
|
+
await this.ctx.audioWorklet.addModule(workletUrl);
|
|
36
|
+
try {
|
|
37
|
+
await this.ctx.resume();
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// ignore (can be blocked until user gesture)
|
|
41
|
+
}
|
|
42
|
+
this.source = this.ctx.createMediaStreamSource(new MediaStream([this.track]));
|
|
43
|
+
this.node = new AudioWorkletNode(this.ctx, "rms-processor");
|
|
44
|
+
this.node.port.onmessage = (e) => this.onLevel(e.data.rmsDb);
|
|
45
|
+
this.keepAliveGain = this.ctx.createGain();
|
|
46
|
+
this.keepAliveGain.gain.value = 0;
|
|
47
|
+
this.source.connect(this.node);
|
|
48
|
+
this.node.connect(this.keepAliveGain);
|
|
49
|
+
this.keepAliveGain.connect(this.ctx.destination);
|
|
50
|
+
lastErr = undefined;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
lastErr = e;
|
|
55
|
+
try {
|
|
56
|
+
this.ctx?.close();
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// ignore
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (lastErr) {
|
|
64
|
+
throw lastErr;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
stop() {
|
|
68
|
+
this.stopped = true;
|
|
69
|
+
try {
|
|
70
|
+
this.node?.port?.close();
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// ignore
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
this.source?.disconnect();
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// ignore
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
this.node?.disconnect();
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// ignore
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
this.keepAliveGain?.disconnect();
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// ignore
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
this.ctx?.close();
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// ignore
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
exports.LocalAudioLevelMeter = LocalAudioLevelMeter;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { StreamHandle } from "../../Types";
|
|
2
|
+
import * as MediaServerTypes from "./MediaServerWebSocketApiTypes";
|
|
3
|
+
export interface UserWithPubKey {
|
|
4
|
+
userId: string;
|
|
5
|
+
key: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ListQuery {
|
|
8
|
+
skip?: number;
|
|
9
|
+
limit?: number;
|
|
10
|
+
order?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface StreamCreateMeta {
|
|
13
|
+
mid?: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
p2p?: boolean;
|
|
16
|
+
tracks?: StreamTrackCreateMeta[];
|
|
17
|
+
}
|
|
18
|
+
export interface StreamTrackCreateMeta {
|
|
19
|
+
mid?: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface StreamRemoteInfo {
|
|
23
|
+
id: StreamId;
|
|
24
|
+
tracks?: TrackInfo[];
|
|
25
|
+
}
|
|
26
|
+
export interface StreamAndTracksSelector {
|
|
27
|
+
streamRoomId: StreamRoomId;
|
|
28
|
+
streamId: StreamId;
|
|
29
|
+
tracks?: StreamTrackId[];
|
|
30
|
+
}
|
|
31
|
+
export interface Stream {
|
|
32
|
+
handle: StreamHandle;
|
|
33
|
+
streamRoomId: StreamRoomId;
|
|
34
|
+
remote: boolean;
|
|
35
|
+
createStreamMeta?: StreamCreateMeta;
|
|
36
|
+
remoteStreamInfo?: StreamRemoteInfo;
|
|
37
|
+
localMediaStream?: MediaStream;
|
|
38
|
+
}
|
|
39
|
+
export interface StreamList {
|
|
40
|
+
list: Stream[];
|
|
41
|
+
}
|
|
42
|
+
export type StreamId = number & {
|
|
43
|
+
__streamId: never;
|
|
44
|
+
};
|
|
45
|
+
export interface DataChannelMeta {
|
|
46
|
+
name: string;
|
|
47
|
+
}
|
|
48
|
+
export interface StreamTrackMeta {
|
|
49
|
+
track?: MediaStreamTrack;
|
|
50
|
+
dataChannel?: DataChannelMeta;
|
|
51
|
+
}
|
|
52
|
+
export interface StreamTrackList {
|
|
53
|
+
list: TrackInfo[];
|
|
54
|
+
}
|
|
55
|
+
export type StreamTrackId = string & {
|
|
56
|
+
__streamTrackId: never;
|
|
57
|
+
};
|
|
58
|
+
export interface PublishMeta {
|
|
59
|
+
bitrate?: number;
|
|
60
|
+
display?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface TrackInfo extends MediaServerTypes.VideoRoomStreamTrack {
|
|
63
|
+
type: string;
|
|
64
|
+
streamRoomId: StreamRoomId;
|
|
65
|
+
streamId: StreamId;
|
|
66
|
+
meta?: DataChannelMeta;
|
|
67
|
+
dataTrackId?: StreamTrackId;
|
|
68
|
+
}
|
|
69
|
+
export type StreamRoomInfo = MediaServerTypes.VideoRoom;
|
|
70
|
+
export type StreamRoomList = MediaServerTypes.RoomListResult;
|
|
71
|
+
export type StreamRoomId = string & {
|
|
72
|
+
__streamRoomId: never;
|
|
73
|
+
};
|
|
74
|
+
export type TrackType = "audio" | "video" | "data";
|