@vidtreo/recorder 1.7.0 → 1.7.2
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/dist/index.d.ts +2117 -2098
- package/dist/index.js +108 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1777,6 +1777,12 @@ async function resolveAudioCodecFromPolicy(options) {
|
|
|
1777
1777
|
if (options.bitrate !== undefined) {
|
|
1778
1778
|
audioCodecOptions.bitrate = options.bitrate;
|
|
1779
1779
|
}
|
|
1780
|
+
if (options.numberOfChannels !== undefined) {
|
|
1781
|
+
audioCodecOptions.numberOfChannels = options.numberOfChannels;
|
|
1782
|
+
}
|
|
1783
|
+
if (options.sampleRate !== undefined) {
|
|
1784
|
+
audioCodecOptions.sampleRate = options.sampleRate;
|
|
1785
|
+
}
|
|
1780
1786
|
const probeResults = await Promise.allSettled([
|
|
1781
1787
|
getFirstEncodableAudioCodec(candidates, audioCodecOptions)
|
|
1782
1788
|
]);
|
|
@@ -6299,7 +6305,7 @@ function resolveDeviceError(input) {
|
|
|
6299
6305
|
// package.json
|
|
6300
6306
|
var package_default = {
|
|
6301
6307
|
name: "@vidtreo/recorder",
|
|
6302
|
-
version: "1.7.
|
|
6308
|
+
version: "1.7.2",
|
|
6303
6309
|
type: "module",
|
|
6304
6310
|
description: "Vidtreo SDK for browser-based video recording and transcoding. Features include camera/screen recording, real-time MP4 transcoding, audio level analysis, mute/pause controls, source switching, device selection, and automatic backend uploads. Similar to Ziggeo and Addpipe, Vidtreo provides enterprise-grade video processing capabilities for web applications.",
|
|
6305
6311
|
main: "./dist/index.js",
|
|
@@ -7050,13 +7056,7 @@ class UploadQueueManager {
|
|
|
7050
7056
|
if (!this.storageService.isInitialized()) {
|
|
7051
7057
|
throw new Error("Database not initialized");
|
|
7052
7058
|
}
|
|
7053
|
-
|
|
7054
|
-
const staleUploads = await this.storageService.getPendingUploads("uploading");
|
|
7055
|
-
await Promise.all(staleUploads.map((upload) => this.storageService.updateUploadStatus(upload.id, {
|
|
7056
|
-
status: "pending"
|
|
7057
|
-
})));
|
|
7058
|
-
this.hasRecoveredStaleUploads = true;
|
|
7059
|
-
}
|
|
7059
|
+
await this.recoverStaleUploads();
|
|
7060
7060
|
const pendingUploads = await this.storageService.getPendingUploads("pending");
|
|
7061
7061
|
if (pendingUploads.length > 0) {
|
|
7062
7062
|
const upload = this.getOldestUpload(pendingUploads);
|
|
@@ -7090,6 +7090,27 @@ class UploadQueueManager {
|
|
|
7090
7090
|
getPendingUploads() {
|
|
7091
7091
|
return this.storageService.getPendingUploads();
|
|
7092
7092
|
}
|
|
7093
|
+
async processMatchingUpload(match) {
|
|
7094
|
+
if (this.isProcessing) {
|
|
7095
|
+
return null;
|
|
7096
|
+
}
|
|
7097
|
+
this.isProcessing = true;
|
|
7098
|
+
try {
|
|
7099
|
+
await this.recoverStaleUploads();
|
|
7100
|
+
const uploads = await this.storageService.getPendingUploads();
|
|
7101
|
+
const matchingUpload = this.getOldestMatchingUpload(uploads, match);
|
|
7102
|
+
if (!matchingUpload) {
|
|
7103
|
+
this.isProcessing = false;
|
|
7104
|
+
return null;
|
|
7105
|
+
}
|
|
7106
|
+
const result = await this.processUpload(matchingUpload, true);
|
|
7107
|
+
this.isProcessing = false;
|
|
7108
|
+
return result;
|
|
7109
|
+
} catch (error) {
|
|
7110
|
+
this.isProcessing = false;
|
|
7111
|
+
throw new Error(`Error processing matching upload: ${extractErrorMessage(error)}`);
|
|
7112
|
+
}
|
|
7113
|
+
}
|
|
7093
7114
|
async getStats() {
|
|
7094
7115
|
const all = await this.storageService.getPendingUploads();
|
|
7095
7116
|
const stats = {
|
|
@@ -7121,7 +7142,45 @@ class UploadQueueManager {
|
|
|
7121
7142
|
}
|
|
7122
7143
|
return uploads.sort((a, b) => a.updatedAt - b.updatedAt)[0];
|
|
7123
7144
|
}
|
|
7124
|
-
async
|
|
7145
|
+
async recoverStaleUploads() {
|
|
7146
|
+
if (this.hasRecoveredStaleUploads) {
|
|
7147
|
+
return;
|
|
7148
|
+
}
|
|
7149
|
+
const staleUploads = await this.storageService.getPendingUploads("uploading");
|
|
7150
|
+
await Promise.all(staleUploads.map((upload) => this.storageService.updateUploadStatus(upload.id, {
|
|
7151
|
+
status: "pending"
|
|
7152
|
+
})));
|
|
7153
|
+
this.hasRecoveredStaleUploads = true;
|
|
7154
|
+
}
|
|
7155
|
+
getOldestMatchingUpload(uploads, match) {
|
|
7156
|
+
const matchingUploads = uploads.filter((upload) => this.canProcessMatchingUpload(upload, match));
|
|
7157
|
+
if (matchingUploads.length === 0) {
|
|
7158
|
+
return null;
|
|
7159
|
+
}
|
|
7160
|
+
return matchingUploads.sort((a, b) => a.createdAt - b.createdAt)[0];
|
|
7161
|
+
}
|
|
7162
|
+
canProcessMatchingUpload(upload, match) {
|
|
7163
|
+
if (upload.status === "completed") {
|
|
7164
|
+
return false;
|
|
7165
|
+
}
|
|
7166
|
+
if (upload.status === "failed" && upload.retryCount >= MAX_RETRIES2) {
|
|
7167
|
+
return false;
|
|
7168
|
+
}
|
|
7169
|
+
if (!this.matchesMetadata(upload.metadata, match.metadata)) {
|
|
7170
|
+
return false;
|
|
7171
|
+
}
|
|
7172
|
+
return this.matchesMetadata(upload.userMetadata, match.userMetadata);
|
|
7173
|
+
}
|
|
7174
|
+
matchesMetadata(actual, expected) {
|
|
7175
|
+
if (!expected || Object.keys(expected).length === 0) {
|
|
7176
|
+
return true;
|
|
7177
|
+
}
|
|
7178
|
+
if (!actual) {
|
|
7179
|
+
return false;
|
|
7180
|
+
}
|
|
7181
|
+
return Object.entries(expected).every(([key, value]) => actual[key] === value);
|
|
7182
|
+
}
|
|
7183
|
+
async processUpload(upload, shouldThrowOnError = false) {
|
|
7125
7184
|
try {
|
|
7126
7185
|
await this.storageService.updateUploadStatus(upload.id, {
|
|
7127
7186
|
status: "uploading"
|
|
@@ -7139,6 +7198,7 @@ class UploadQueueManager {
|
|
|
7139
7198
|
});
|
|
7140
7199
|
await this.storageService.deleteUpload(upload.id);
|
|
7141
7200
|
this.callbacks.onUploadComplete?.(upload.id, result);
|
|
7201
|
+
return result;
|
|
7142
7202
|
} catch (error) {
|
|
7143
7203
|
const errorMessage = extractErrorMessage(error);
|
|
7144
7204
|
const retryCount = upload.retryCount + 1;
|
|
@@ -7153,6 +7213,10 @@ class UploadQueueManager {
|
|
|
7153
7213
|
const delay2 = this.calculateRetryDelay(retryCount);
|
|
7154
7214
|
this.scheduleRetry(delay2);
|
|
7155
7215
|
}
|
|
7216
|
+
if (shouldThrowOnError) {
|
|
7217
|
+
throw new Error(errorMessage);
|
|
7218
|
+
}
|
|
7219
|
+
return null;
|
|
7156
7220
|
}
|
|
7157
7221
|
}
|
|
7158
7222
|
calculateRetryDelay(retryCount) {
|
|
@@ -21162,6 +21226,8 @@ var CODEC_CACHE_AUDIO_OVERRIDE = "audioOverride";
|
|
|
21162
21226
|
var CODEC_CACHE_VIDEO_OVERRIDE = "videoOverride";
|
|
21163
21227
|
var CODEC_CACHE_AUDIO_BITRATE = "audioBitrate";
|
|
21164
21228
|
var CODEC_CACHE_VIDEO_BITRATE = "videoBitrate";
|
|
21229
|
+
var CODEC_CACHE_AUDIO_CHANNELS = "audioChannels";
|
|
21230
|
+
var CODEC_CACHE_AUDIO_SAMPLE_RATE = "audioSampleRate";
|
|
21165
21231
|
var CODEC_CACHE_WIDTH = "width";
|
|
21166
21232
|
var CODEC_CACHE_HEIGHT = "height";
|
|
21167
21233
|
var CODEC_CACHE_POLICY_PREFERRED_AUDIO = "policyPreferredAudio";
|
|
@@ -21423,7 +21489,6 @@ class WorkerProcessor {
|
|
|
21423
21489
|
isLinuxPlatform: this.isLinuxPlatformFn()
|
|
21424
21490
|
});
|
|
21425
21491
|
const audioBitrate = this.resolveAudioBitrate(config, format);
|
|
21426
|
-
const audioCodec = await this.resolveAudioCodecWithCache(config, format, policy, audioBitrate);
|
|
21427
21492
|
const codec = await this.resolveVideoCodecWithCache(config, format, policy);
|
|
21428
21493
|
const isScreenCapture = isScreenCaptureStream(stream);
|
|
21429
21494
|
logger.debug("[WorkerProcessor] Starting processing", {
|
|
@@ -21432,7 +21497,6 @@ class WorkerProcessor {
|
|
|
21432
21497
|
codec,
|
|
21433
21498
|
bitrate: config.bitrate
|
|
21434
21499
|
});
|
|
21435
|
-
const workerConfig = this.buildWorkerTranscodeConfig(config, audioCodec, audioBitrate, codec, format);
|
|
21436
21500
|
if (typeof config.fps === "number" && config.fps > 0) {
|
|
21437
21501
|
this.lastConfigFps = config.fps;
|
|
21438
21502
|
}
|
|
@@ -21468,6 +21532,8 @@ class WorkerProcessor {
|
|
|
21468
21532
|
};
|
|
21469
21533
|
}
|
|
21470
21534
|
const { audioConfig, audioStream, shouldStartAudioWorklet } = await this.prepareAudioPipeline(audioTrack, workerProbeResult);
|
|
21535
|
+
const audioCodec = await this.resolveAudioCodecWithCache(config, format, policy, audioBitrate, audioConfig);
|
|
21536
|
+
const workerConfig = this.buildWorkerTranscodeConfig(config, audioCodec, audioBitrate, codec, format);
|
|
21471
21537
|
const overlayConfigToSend = this.buildOverlayConfigToSend();
|
|
21472
21538
|
const message = createStartMessage({
|
|
21473
21539
|
videoTrack: videoInput.videoTrack,
|
|
@@ -21727,12 +21793,14 @@ class WorkerProcessor {
|
|
|
21727
21793
|
}
|
|
21728
21794
|
return getPresetAudioBitrateForFormat(format);
|
|
21729
21795
|
}
|
|
21730
|
-
async resolveAudioCodec(config, format, policy, audioBitrate) {
|
|
21796
|
+
async resolveAudioCodec(config, format, policy, audioBitrate, audioConfig) {
|
|
21731
21797
|
return await resolveAudioCodecFromPolicy({
|
|
21732
21798
|
format,
|
|
21733
21799
|
overrideCodec: config.audioCodec,
|
|
21734
21800
|
policy,
|
|
21735
|
-
bitrate: audioBitrate
|
|
21801
|
+
bitrate: audioBitrate,
|
|
21802
|
+
numberOfChannels: audioConfig?.numberOfChannels,
|
|
21803
|
+
sampleRate: audioConfig?.sampleRate
|
|
21736
21804
|
});
|
|
21737
21805
|
}
|
|
21738
21806
|
async resolveVideoCodec(config, format, policy) {
|
|
@@ -21745,13 +21813,13 @@ class WorkerProcessor {
|
|
|
21745
21813
|
bitrate: config.bitrate
|
|
21746
21814
|
});
|
|
21747
21815
|
}
|
|
21748
|
-
async resolveAudioCodecWithCache(config, format, policy, audioBitrate) {
|
|
21749
|
-
const audioCodecCacheKey = this.buildAudioCodecCacheKey(config, format, policy, audioBitrate);
|
|
21816
|
+
async resolveAudioCodecWithCache(config, format, policy, audioBitrate, audioConfig) {
|
|
21817
|
+
const audioCodecCacheKey = this.buildAudioCodecCacheKey(config, format, policy, audioBitrate, audioConfig);
|
|
21750
21818
|
const cachedAudioCodec = resolvedAudioCodecCache.get(audioCodecCacheKey);
|
|
21751
21819
|
if (cachedAudioCodec) {
|
|
21752
21820
|
return cachedAudioCodec;
|
|
21753
21821
|
}
|
|
21754
|
-
const resolvedAudioCodec = await this.resolveAudioCodec(config, format, policy, audioBitrate);
|
|
21822
|
+
const resolvedAudioCodec = await this.resolveAudioCodec(config, format, policy, audioBitrate, audioConfig);
|
|
21755
21823
|
setCodecCacheValue(resolvedAudioCodecCache, audioCodecCacheKey, resolvedAudioCodec);
|
|
21756
21824
|
return resolvedAudioCodec;
|
|
21757
21825
|
}
|
|
@@ -21765,15 +21833,19 @@ class WorkerProcessor {
|
|
|
21765
21833
|
setCodecCacheValue(resolvedVideoCodecCache, videoCodecCacheKey, resolvedVideoCodec);
|
|
21766
21834
|
return resolvedVideoCodec;
|
|
21767
21835
|
}
|
|
21768
|
-
buildAudioCodecCacheKey(config, format, policy, audioBitrate) {
|
|
21836
|
+
buildAudioCodecCacheKey(config, format, policy, audioBitrate, audioConfig) {
|
|
21769
21837
|
const audioOverride = formatCacheValue(config.audioCodec);
|
|
21770
21838
|
const preferredAudioCodec = formatCacheValue(policy.preferredAudioCodec);
|
|
21771
21839
|
const audioFallbackOrder = formatCacheArray(policy.audioCodecFallbackOrder);
|
|
21772
21840
|
const audioBitrateValue = formatCacheValue(audioBitrate);
|
|
21841
|
+
const audioChannelsValue = formatCacheValue(audioConfig?.numberOfChannels);
|
|
21842
|
+
const audioSampleRateValue = formatCacheValue(audioConfig?.sampleRate);
|
|
21773
21843
|
return [
|
|
21774
21844
|
buildCacheEntry(CODEC_CACHE_FORMAT, formatCacheValue(format)),
|
|
21775
21845
|
buildCacheEntry(CODEC_CACHE_AUDIO_OVERRIDE, audioOverride),
|
|
21776
21846
|
buildCacheEntry(CODEC_CACHE_AUDIO_BITRATE, audioBitrateValue),
|
|
21847
|
+
buildCacheEntry(CODEC_CACHE_AUDIO_CHANNELS, audioChannelsValue),
|
|
21848
|
+
buildCacheEntry(CODEC_CACHE_AUDIO_SAMPLE_RATE, audioSampleRateValue),
|
|
21777
21849
|
buildCacheEntry(CODEC_CACHE_POLICY_PREFERRED_AUDIO, preferredAudioCodec),
|
|
21778
21850
|
buildCacheEntry(CODEC_CACHE_POLICY_AUDIO_FALLBACK, audioFallbackOrder)
|
|
21779
21851
|
].join(CODEC_CACHE_KEY_SEPARATOR);
|
|
@@ -22202,7 +22274,7 @@ class WorkerProcessor {
|
|
|
22202
22274
|
isLinuxPlatform: this.isLinuxPlatformFn()
|
|
22203
22275
|
});
|
|
22204
22276
|
const cacheAudioBitrate = this.resolveAudioBitrate(config, format);
|
|
22205
|
-
this.resolveAudioCodecWithCache(config, format, cachePolicy, cacheAudioBitrate).catch(this.handleWarmupCacheError);
|
|
22277
|
+
this.resolveAudioCodecWithCache(config, format, cachePolicy, cacheAudioBitrate, null).catch(this.handleWarmupCacheError);
|
|
22206
22278
|
this.resolveVideoCodecWithCache(config, format, cachePolicy).catch(this.handleWarmupCacheError);
|
|
22207
22279
|
const workerConfig = this.buildWorkerTranscodeConfig(config, policy.preferredAudioCodec, audioBitrate, codec, format);
|
|
22208
22280
|
const message = {
|
|
@@ -23885,6 +23957,23 @@ class QuotaManager {
|
|
|
23885
23957
|
return quota.percentage >= threshold;
|
|
23886
23958
|
}
|
|
23887
23959
|
}
|
|
23960
|
+
// src/core/upload/pending-upload-recovery.ts
|
|
23961
|
+
async function recoverPendingUpload(options) {
|
|
23962
|
+
const storageService = new VideoStorageService;
|
|
23963
|
+
await storageService.init();
|
|
23964
|
+
const uploadService = new VideoUploadService;
|
|
23965
|
+
const uploadQueueManager = new UploadQueueManager(storageService, uploadService);
|
|
23966
|
+
uploadQueueManager.setCallbacks({
|
|
23967
|
+
onUploadProgress: (_id, progress) => {
|
|
23968
|
+
options.onProgress?.(progress);
|
|
23969
|
+
}
|
|
23970
|
+
});
|
|
23971
|
+
try {
|
|
23972
|
+
return await uploadQueueManager.processMatchingUpload(options.match);
|
|
23973
|
+
} finally {
|
|
23974
|
+
uploadQueueManager.destroy();
|
|
23975
|
+
}
|
|
23976
|
+
}
|
|
23888
23977
|
// src/core/utils/audio-utils.ts
|
|
23889
23978
|
function calculateBarColor(position) {
|
|
23890
23979
|
if (position < 0.25) {
|
|
@@ -24280,6 +24369,7 @@ export {
|
|
|
24280
24369
|
requireInitialized,
|
|
24281
24370
|
requireDefined,
|
|
24282
24371
|
requireActive,
|
|
24372
|
+
recoverPendingUpload,
|
|
24283
24373
|
parseBrowserErrorLinkContent,
|
|
24284
24374
|
mapPresetToConfig,
|
|
24285
24375
|
logger,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vidtreo/recorder",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vidtreo SDK for browser-based video recording and transcoding. Features include camera/screen recording, real-time MP4 transcoding, audio level analysis, mute/pause controls, source switching, device selection, and automatic backend uploads. Similar to Ziggeo and Addpipe, Vidtreo provides enterprise-grade video processing capabilities for web applications.",
|
|
6
6
|
"main": "./dist/index.js",
|