@sorisdk/web-audio 0.6.5 → 0.6.8
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/README.md +161 -17
- package/dist/generated/window.d.ts +1 -0
- package/dist/generated/window_bg.js +73 -11
- package/dist/generated/window_bg.wasm +0 -0
- package/dist/generated/window_bg.wasm.d.ts +5 -3
- package/dist/index.d.ts +15 -9
- package/dist/index.js +417 -99
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -181,6 +181,18 @@ function getBrowserMediaDevices() {
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
// src/match-window.ts
|
|
184
|
+
var FINGERPRINT_LEVEL_BYTE_LENGTH = 8;
|
|
185
|
+
function getTypedArrayByteLengthGetter() {
|
|
186
|
+
const getter = Object.getOwnPropertyDescriptor(
|
|
187
|
+
Object.getPrototypeOf(Uint8Array.prototype),
|
|
188
|
+
"byteLength"
|
|
189
|
+
)?.get;
|
|
190
|
+
if (!getter) {
|
|
191
|
+
throw new Error("Uint8Array byteLength intrinsic is unavailable");
|
|
192
|
+
}
|
|
193
|
+
return getter;
|
|
194
|
+
}
|
|
195
|
+
var typedArrayByteLengthGetter = getTypedArrayByteLengthGetter();
|
|
184
196
|
var cachedBindings = null;
|
|
185
197
|
var initPromise = null;
|
|
186
198
|
var testInjectedWasmModule = null;
|
|
@@ -197,18 +209,46 @@ var defaultLoader = async () => {
|
|
|
197
209
|
const loaderModule = await import("./default-loader.js");
|
|
198
210
|
return loaderModule.default();
|
|
199
211
|
};
|
|
212
|
+
function calculateMaxAppendFingerprintByteLength(options) {
|
|
213
|
+
const hopSize = options.afpgenConfig.hopSize ?? 1e3;
|
|
214
|
+
const levelCount = options.afpgenConfig.levelCount ?? 2;
|
|
215
|
+
const hopDurationMs = hopSize / options.sampleRate * 1e3;
|
|
216
|
+
const hopsInWindow = Math.ceil(options.matchWindowMs / hopDurationMs);
|
|
217
|
+
return Math.max(1, hopsInWindow) * levelCount * FINGERPRINT_LEVEL_BYTE_LENGTH;
|
|
218
|
+
}
|
|
219
|
+
function appendLimitError(byteLength, maxByteLength) {
|
|
220
|
+
return new RangeError(
|
|
221
|
+
`Fingerprint append byteLength ${byteLength} exceeds the per-instance limit of ${maxByteLength} bytes`
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
function intrinsicUint8ArrayByteLength(bytes) {
|
|
225
|
+
return typedArrayByteLengthGetter.call(bytes);
|
|
226
|
+
}
|
|
200
227
|
var WrappedFingerprintMatchWindow = class {
|
|
201
|
-
constructor(inner) {
|
|
228
|
+
constructor(inner, options) {
|
|
202
229
|
this.inner = inner;
|
|
230
|
+
const maxLengthFn = getCallable(this.inner, [
|
|
231
|
+
"maxAppendFingerprintByteLength",
|
|
232
|
+
"max_append_fingerprint_byte_length"
|
|
233
|
+
]);
|
|
234
|
+
this.maxAppendByteLength = maxLengthFn ? Number(maxLengthFn.call(this.inner)) : calculateMaxAppendFingerprintByteLength(options);
|
|
203
235
|
}
|
|
204
236
|
inner;
|
|
237
|
+
maxAppendByteLength;
|
|
205
238
|
appendFingerprint(bytes) {
|
|
239
|
+
const byteLength = intrinsicUint8ArrayByteLength(bytes);
|
|
240
|
+
if (byteLength > this.maxAppendByteLength) {
|
|
241
|
+
throw appendLimitError(byteLength, this.maxAppendByteLength);
|
|
242
|
+
}
|
|
206
243
|
const fn = getCallable(this.inner, ["appendFingerprint", "append_fingerprint"]);
|
|
207
244
|
if (!fn) {
|
|
208
245
|
throw new Error("web-audio wasm window is missing appendFingerprint");
|
|
209
246
|
}
|
|
210
247
|
fn.call(this.inner, bytes);
|
|
211
248
|
}
|
|
249
|
+
maxAppendFingerprintByteLength() {
|
|
250
|
+
return this.maxAppendByteLength;
|
|
251
|
+
}
|
|
212
252
|
hasReadyQuery() {
|
|
213
253
|
const fn = getCallable(this.inner, ["hasReadyQuery", "has_ready_query"]);
|
|
214
254
|
if (!fn) {
|
|
@@ -261,7 +301,8 @@ function createBindingsFromModule(moduleLike) {
|
|
|
261
301
|
options.afpgenConfig,
|
|
262
302
|
options.matchWindowMs,
|
|
263
303
|
options.matchStrideMs
|
|
264
|
-
)
|
|
304
|
+
),
|
|
305
|
+
options
|
|
265
306
|
);
|
|
266
307
|
}
|
|
267
308
|
};
|
|
@@ -313,6 +354,12 @@ var FingerprintMatchWindow = class {
|
|
|
313
354
|
}
|
|
314
355
|
};
|
|
315
356
|
|
|
357
|
+
// src/detected-match.ts
|
|
358
|
+
function toPublicDetectedMatch(match) {
|
|
359
|
+
const { audioMarker: _internalAudioMarker, ...publicMatch } = match;
|
|
360
|
+
return publicMatch;
|
|
361
|
+
}
|
|
362
|
+
|
|
316
363
|
// src/activity.ts
|
|
317
364
|
var ActivityReportingError = class extends Error {
|
|
318
365
|
status;
|
|
@@ -357,6 +404,14 @@ function defaultRequestPayload(match) {
|
|
|
357
404
|
...typeof marker === "string" && marker.length > 0 ? { trait: { marker } } : {}
|
|
358
405
|
};
|
|
359
406
|
}
|
|
407
|
+
function captureActivityRecognitionTiming(match) {
|
|
408
|
+
const recognizedAtMillis = Date.now();
|
|
409
|
+
const position = match.position;
|
|
410
|
+
return Object.freeze({
|
|
411
|
+
recognizedAt: new Date(recognizedAtMillis).toISOString(),
|
|
412
|
+
position
|
|
413
|
+
});
|
|
414
|
+
}
|
|
360
415
|
function validateRequestPayload(payload) {
|
|
361
416
|
if (payload === null) {
|
|
362
417
|
return null;
|
|
@@ -368,13 +423,18 @@ function validateRequestPayload(payload) {
|
|
|
368
423
|
}
|
|
369
424
|
async function resolveCreateRequestPayload(reporter, match) {
|
|
370
425
|
const payload = validateRequestPayload(
|
|
371
|
-
reporter.mapMatchToRequest ? await reporter.mapMatchToRequest(match) : defaultRequestPayload(match)
|
|
426
|
+
reporter.mapMatchToRequest ? await reporter.mapMatchToRequest(toPublicDetectedMatch(match)) : defaultRequestPayload(match)
|
|
372
427
|
);
|
|
373
428
|
if (!payload) {
|
|
374
429
|
return null;
|
|
375
430
|
}
|
|
376
|
-
const {
|
|
377
|
-
|
|
431
|
+
const {
|
|
432
|
+
position: _ignoredPosition,
|
|
433
|
+
recognized_at: _ignoredRecognizedAt,
|
|
434
|
+
refinement_expected: _ignoredRefinementExpected,
|
|
435
|
+
...requestPayload
|
|
436
|
+
} = payload;
|
|
437
|
+
return withInternalAudioMarker(requestPayload, match);
|
|
378
438
|
}
|
|
379
439
|
async function resolveRefineRequestPayload(reporter, match, context) {
|
|
380
440
|
const refinement = reporter.refinement;
|
|
@@ -382,13 +442,31 @@ async function resolveRefineRequestPayload(reporter, match, context) {
|
|
|
382
442
|
return null;
|
|
383
443
|
}
|
|
384
444
|
const payload = validateRequestPayload(
|
|
385
|
-
refinement.mapMatchToRequest ? await refinement.mapMatchToRequest(match, context) : reporter.mapMatchToRequest ? await reporter.mapMatchToRequest(match) : defaultRequestPayload(match)
|
|
445
|
+
refinement.mapMatchToRequest ? await refinement.mapMatchToRequest(toPublicDetectedMatch(match), context) : reporter.mapMatchToRequest ? await reporter.mapMatchToRequest(toPublicDetectedMatch(match)) : defaultRequestPayload(match)
|
|
386
446
|
);
|
|
387
447
|
if (!payload) {
|
|
388
448
|
return null;
|
|
389
449
|
}
|
|
390
|
-
const {
|
|
391
|
-
|
|
450
|
+
const {
|
|
451
|
+
position: _ignoredPosition,
|
|
452
|
+
recognized_at: _ignoredRecognizedAt,
|
|
453
|
+
refinement_expected: _ignoredRefinementExpected,
|
|
454
|
+
...requestPayload
|
|
455
|
+
} = payload;
|
|
456
|
+
return withInternalAudioMarker(requestPayload, match);
|
|
457
|
+
}
|
|
458
|
+
function withInternalAudioMarker(payload, match) {
|
|
459
|
+
const marker = match.audioMarker?.code;
|
|
460
|
+
if (typeof marker !== "string" || marker.length === 0) {
|
|
461
|
+
return payload;
|
|
462
|
+
}
|
|
463
|
+
return {
|
|
464
|
+
...payload,
|
|
465
|
+
trait: {
|
|
466
|
+
...payload.trait,
|
|
467
|
+
marker
|
|
468
|
+
}
|
|
469
|
+
};
|
|
392
470
|
}
|
|
393
471
|
function defaultCampaignMapper(payload, match) {
|
|
394
472
|
const campaign = payload.campaign;
|
|
@@ -396,12 +474,23 @@ function defaultCampaignMapper(payload, match) {
|
|
|
396
474
|
return null;
|
|
397
475
|
}
|
|
398
476
|
return {
|
|
399
|
-
match,
|
|
477
|
+
match: toPublicDetectedMatch(match),
|
|
400
478
|
campaign,
|
|
401
479
|
activityId: typeof payload.activity_id === "string" ? payload.activity_id : null,
|
|
402
480
|
raw: payload
|
|
403
481
|
};
|
|
404
482
|
}
|
|
483
|
+
function resolvedAudioMarker(payload) {
|
|
484
|
+
if (!payload) {
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
const id = payload.audio_marker_id;
|
|
488
|
+
const name = payload.audio_marker_name;
|
|
489
|
+
if (typeof id !== "string" || id.trim().length === 0 || typeof name !== "string" || name.trim().length === 0) {
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
return Object.freeze({ id, name });
|
|
493
|
+
}
|
|
405
494
|
async function resolveHeaders(reporter, refinement = false) {
|
|
406
495
|
const refinementHeaders = reporter.refinement && reporter.refinement.headers;
|
|
407
496
|
const baseHeaders = reporter.headers ? typeof reporter.headers === "function" ? await reporter.headers() : reporter.headers : void 0;
|
|
@@ -457,10 +546,31 @@ function responseActivityId(data, campaign) {
|
|
|
457
546
|
}
|
|
458
547
|
async function mapCreateResponse(reporter, data, match, refinementExpected) {
|
|
459
548
|
if (!data) {
|
|
460
|
-
return {
|
|
549
|
+
return {
|
|
550
|
+
activityId: null,
|
|
551
|
+
audioMarker: null,
|
|
552
|
+
campaign: null,
|
|
553
|
+
creationAttempted: true,
|
|
554
|
+
refinementExpected
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
const audioMarker = resolvedAudioMarker(data);
|
|
558
|
+
let campaign;
|
|
559
|
+
let campaignMappingFailure;
|
|
560
|
+
try {
|
|
561
|
+
campaign = reporter.mapResponseToCampaign ? await reporter.mapResponseToCampaign(data, toPublicDetectedMatch(match)) : defaultCampaignMapper(data, match);
|
|
562
|
+
} catch (error) {
|
|
563
|
+
campaign = null;
|
|
564
|
+
campaignMappingFailure = { error };
|
|
461
565
|
}
|
|
462
|
-
|
|
463
|
-
|
|
566
|
+
return {
|
|
567
|
+
activityId: responseActivityId(data, campaign),
|
|
568
|
+
audioMarker,
|
|
569
|
+
campaign,
|
|
570
|
+
creationAttempted: true,
|
|
571
|
+
refinementExpected,
|
|
572
|
+
...campaignMappingFailure ? { campaignMappingFailure } : {}
|
|
573
|
+
};
|
|
464
574
|
}
|
|
465
575
|
async function resolveRefinementEndpoint(reporter, activityId) {
|
|
466
576
|
const configured = reporter.refinement && reporter.refinement.endpoint;
|
|
@@ -470,10 +580,16 @@ async function resolveRefinementEndpoint(reporter, activityId) {
|
|
|
470
580
|
const prefix = String(configured ?? reporter.endpoint);
|
|
471
581
|
return `${prefix.endsWith("/") ? prefix : `${prefix}/`}${encodeURIComponent(activityId)}`;
|
|
472
582
|
}
|
|
473
|
-
async function createMatchedMaterialActivity(reporter, match, refinementExpected = false) {
|
|
583
|
+
async function createMatchedMaterialActivity(reporter, match, refinementExpected = false, recognitionTiming = captureActivityRecognitionTiming(match)) {
|
|
474
584
|
const payload = await resolveCreateRequestPayload(reporter, match);
|
|
475
585
|
if (!payload) {
|
|
476
|
-
return {
|
|
586
|
+
return {
|
|
587
|
+
activityId: null,
|
|
588
|
+
audioMarker: null,
|
|
589
|
+
campaign: null,
|
|
590
|
+
creationAttempted: false,
|
|
591
|
+
refinementExpected: false
|
|
592
|
+
};
|
|
477
593
|
}
|
|
478
594
|
const headers = await resolveHeaders(reporter);
|
|
479
595
|
const actualMarker = match.audioMarker?.code;
|
|
@@ -481,7 +597,12 @@ async function createMatchedMaterialActivity(reporter, match, refinementExpected
|
|
|
481
597
|
const hasMarker = typeof actualMarker === "string" && actualMarker.length > 0 || typeof payloadMarker === "string" && payloadMarker.length > 0;
|
|
482
598
|
const lifecycleOpen = typeof refinementExpected === "function" ? refinementExpected() : refinementExpected;
|
|
483
599
|
const requestRefinementExpected = Boolean(reporter.refinement && lifecycleOpen && !hasMarker);
|
|
484
|
-
const requestPayload =
|
|
600
|
+
const requestPayload = {
|
|
601
|
+
...payload,
|
|
602
|
+
recognized_at: recognitionTiming.recognizedAt,
|
|
603
|
+
position: recognitionTiming.position,
|
|
604
|
+
...requestRefinementExpected ? { refinement_expected: true } : {}
|
|
605
|
+
};
|
|
485
606
|
const response = await resolveFetch(reporter.fetch)(reporter.endpoint, {
|
|
486
607
|
method: "POST",
|
|
487
608
|
headers,
|
|
@@ -497,11 +618,11 @@ async function createMatchedMaterialActivity(reporter, match, refinementExpected
|
|
|
497
618
|
async function refineMatchedMaterialActivity(reporter, match, context, isActive = () => true) {
|
|
498
619
|
const refinement = reporter.refinement;
|
|
499
620
|
if (!refinement) {
|
|
500
|
-
return { activityId: null, campaign: null };
|
|
621
|
+
return { activityId: null, audioMarker: null, campaign: null };
|
|
501
622
|
}
|
|
502
623
|
const payload = await resolveRefineRequestPayload(reporter, match, context);
|
|
503
624
|
if (!payload) {
|
|
504
|
-
return { activityId: null, campaign: null };
|
|
625
|
+
return { activityId: null, audioMarker: null, campaign: null };
|
|
505
626
|
}
|
|
506
627
|
const endpoint = await resolveRefinementEndpoint(reporter, context.activityId);
|
|
507
628
|
const headers = await resolveHeaders(reporter, true);
|
|
@@ -517,8 +638,16 @@ async function refineMatchedMaterialActivity(reporter, match, context, isActive
|
|
|
517
638
|
if (!data) {
|
|
518
639
|
throw new ActivityReportingError("Activity refine failed: empty response", response.status);
|
|
519
640
|
}
|
|
520
|
-
const
|
|
521
|
-
|
|
641
|
+
const audioMarker = resolvedAudioMarker(data);
|
|
642
|
+
let mappedCampaign;
|
|
643
|
+
let campaignMappingFailure;
|
|
644
|
+
try {
|
|
645
|
+
mappedCampaign = refinement.mapResponseToCampaign ? await refinement.mapResponseToCampaign(data, toPublicDetectedMatch(match), context) : reporter.mapResponseToCampaign ? await reporter.mapResponseToCampaign(data, toPublicDetectedMatch(match)) : defaultCampaignMapper(data, match);
|
|
646
|
+
} catch (error) {
|
|
647
|
+
mappedCampaign = null;
|
|
648
|
+
campaignMappingFailure = { error };
|
|
649
|
+
}
|
|
650
|
+
const activityId = responseActivityId(data, mappedCampaign) ?? (campaignMappingFailure ? context.activityId : null);
|
|
522
651
|
if (activityId !== context.activityId) {
|
|
523
652
|
throw new ActivityReportingError(
|
|
524
653
|
"Activity refine failed: response activity_id does not match the requested activity",
|
|
@@ -526,11 +655,17 @@ async function refineMatchedMaterialActivity(reporter, match, context, isActive
|
|
|
526
655
|
);
|
|
527
656
|
}
|
|
528
657
|
const campaign = mappedCampaign ? { ...mappedCampaign, activityId: context.activityId } : null;
|
|
529
|
-
return {
|
|
658
|
+
return {
|
|
659
|
+
activityId,
|
|
660
|
+
audioMarker,
|
|
661
|
+
campaign,
|
|
662
|
+
...campaignMappingFailure ? { campaignMappingFailure } : {}
|
|
663
|
+
};
|
|
530
664
|
}
|
|
531
665
|
|
|
532
666
|
// src/activity-refinement.ts
|
|
533
667
|
var ACTIVITY_REFINEMENT_WINDOW_MS = 3e4;
|
|
668
|
+
var ACTIVITY_CONTINUITY_GAP_MS = 3e4;
|
|
534
669
|
var DEFAULT_MAX_REFINEMENT_ATTEMPTS = 2;
|
|
535
670
|
var MAX_REFINEMENT_ATTEMPTS = 10;
|
|
536
671
|
function normalizeError(error) {
|
|
@@ -554,6 +689,7 @@ var ActivityRefinementCoordinator = class {
|
|
|
554
689
|
registeredRequests = /* @__PURE__ */ new Set();
|
|
555
690
|
settledRequests = /* @__PURE__ */ new Set();
|
|
556
691
|
activeLifecycle = null;
|
|
692
|
+
activeMarkerSegment = null;
|
|
557
693
|
generation = 0;
|
|
558
694
|
constructor(reporter, callbacks) {
|
|
559
695
|
this.reporter = reporter;
|
|
@@ -566,9 +702,7 @@ var ActivityRefinementCoordinator = class {
|
|
|
566
702
|
}
|
|
567
703
|
report(recognitionId, match, captureGeneration, requestId = null) {
|
|
568
704
|
const coordinatorGeneration = this.generation;
|
|
569
|
-
|
|
570
|
-
this.deleteLifecycle(this.activeLifecycle);
|
|
571
|
-
}
|
|
705
|
+
const markerSegment = this.resolveMarkerSegment(match, captureGeneration);
|
|
572
706
|
const hasMarker = typeof match.audioMarker?.code === "string" && match.audioMarker.code.length > 0;
|
|
573
707
|
const refinement = this.reporter.refinement;
|
|
574
708
|
const requestCanRefine = requestId !== null && !this.settledRequests.has(requestId);
|
|
@@ -578,53 +712,97 @@ var ActivityRefinementCoordinator = class {
|
|
|
578
712
|
this.registeredRequests.delete(requestId);
|
|
579
713
|
this.settledRequests.delete(requestId);
|
|
580
714
|
}
|
|
715
|
+
if (refinement && this.activeLifecycle) {
|
|
716
|
+
const now = this.now();
|
|
717
|
+
const activeLifecycle = this.activeLifecycle;
|
|
718
|
+
if (this.isContinuousMatch(activeLifecycle, match, captureGeneration, now)) {
|
|
719
|
+
this.renewContinuity(activeLifecycle, now);
|
|
720
|
+
if (requestId !== null) {
|
|
721
|
+
if (requestCanRefine && this.canAcceptMarker(activeLifecycle)) {
|
|
722
|
+
this.requestLifecycles.set(requestId, activeLifecycle);
|
|
723
|
+
} else {
|
|
724
|
+
this.requestLifecycles.delete(requestId);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
if (pendingMarker) {
|
|
728
|
+
this.claimMarker(activeLifecycle, pendingMarker);
|
|
729
|
+
}
|
|
730
|
+
if (hasMarker && match.audioMarker) {
|
|
731
|
+
this.claimMarker(activeLifecycle, match.audioMarker);
|
|
732
|
+
}
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
this.sealLifecycle(activeLifecycle);
|
|
736
|
+
}
|
|
581
737
|
const refinementExpected = Boolean(refinement && !hasMarker && requestCanRefine);
|
|
582
738
|
let lifecycle = null;
|
|
583
|
-
if (
|
|
584
|
-
const now =
|
|
739
|
+
if (refinement) {
|
|
740
|
+
const now = this.now();
|
|
585
741
|
lifecycle = {
|
|
586
742
|
recognitionId,
|
|
587
743
|
captureGeneration,
|
|
588
744
|
match,
|
|
589
745
|
deadline: now + ACTIVITY_REFINEMENT_WINDOW_MS,
|
|
746
|
+
lastObservedAt: now,
|
|
590
747
|
activityId: null,
|
|
591
|
-
markerMatch: null,
|
|
592
|
-
markerCode: null,
|
|
593
|
-
|
|
748
|
+
markerMatch: hasMarker ? match : null,
|
|
749
|
+
markerCode: hasMarker ? match.audioMarker?.code ?? null : null,
|
|
750
|
+
markerSegment,
|
|
751
|
+
refinementTimer: null,
|
|
752
|
+
continuityTimer: null,
|
|
594
753
|
createSettled: false,
|
|
595
|
-
refinementStarted: false
|
|
754
|
+
refinementStarted: false,
|
|
755
|
+
refinementInFlight: false,
|
|
756
|
+
refinementClosed: !refinementExpected,
|
|
757
|
+
sealed: false
|
|
596
758
|
};
|
|
597
759
|
const createdLifecycle = lifecycle;
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
760
|
+
if (refinementExpected) {
|
|
761
|
+
lifecycle.refinementTimer = setTimeout(() => {
|
|
762
|
+
this.closeRefinement(createdLifecycle);
|
|
763
|
+
}, ACTIVITY_REFINEMENT_WINDOW_MS);
|
|
764
|
+
}
|
|
765
|
+
this.scheduleContinuityExpiry(lifecycle);
|
|
601
766
|
this.lifecycles.set(recognitionId, lifecycle);
|
|
602
|
-
if (requestId !== null) {
|
|
767
|
+
if (requestId !== null && refinementExpected) {
|
|
603
768
|
this.requestLifecycles.set(requestId, lifecycle);
|
|
604
769
|
}
|
|
605
770
|
this.activeLifecycle = lifecycle;
|
|
606
|
-
if (pendingMarker) {
|
|
607
|
-
this.
|
|
771
|
+
if (pendingMarker && refinementExpected) {
|
|
772
|
+
this.claimMarker(lifecycle, pendingMarker);
|
|
608
773
|
}
|
|
609
774
|
}
|
|
775
|
+
const recognitionTiming = captureActivityRecognitionTiming(match);
|
|
610
776
|
void createMatchedMaterialActivity(
|
|
611
777
|
this.reporter,
|
|
612
778
|
match,
|
|
613
|
-
() => Boolean(lifecycle && this.isRefinementActive(lifecycle))
|
|
779
|
+
() => Boolean(lifecycle && this.isRefinementActive(lifecycle)),
|
|
780
|
+
recognitionTiming
|
|
614
781
|
).then(
|
|
615
782
|
(result) => {
|
|
783
|
+
if (coordinatorGeneration === this.generation && result.audioMarker && this.callbacks.isCurrentCapture(captureGeneration)) {
|
|
784
|
+
this.emitResolvedAudioMarker(markerSegment, result.audioMarker);
|
|
785
|
+
}
|
|
616
786
|
if (coordinatorGeneration === this.generation && result.campaign && this.callbacks.isCurrentCapture(captureGeneration)) {
|
|
617
787
|
this.callbacks.emitCampaign(result.campaign);
|
|
618
788
|
}
|
|
789
|
+
if (coordinatorGeneration === this.generation && result.campaignMappingFailure && this.callbacks.isCurrentCapture(captureGeneration)) {
|
|
790
|
+
this.callbacks.emitError("activity", result.campaignMappingFailure.error);
|
|
791
|
+
}
|
|
619
792
|
if (coordinatorGeneration !== this.generation || !lifecycle || this.lifecycles.get(recognitionId) !== lifecycle) {
|
|
620
793
|
return;
|
|
621
794
|
}
|
|
622
|
-
|
|
795
|
+
lifecycle.createSettled = true;
|
|
796
|
+
lifecycle.activityId = result.activityId;
|
|
797
|
+
if (!result.creationAttempted) {
|
|
623
798
|
this.deleteLifecycle(lifecycle);
|
|
624
799
|
return;
|
|
625
800
|
}
|
|
626
|
-
|
|
627
|
-
|
|
801
|
+
if (!result.refinementExpected) {
|
|
802
|
+
this.closeRefinement(lifecycle);
|
|
803
|
+
this.maybeDeleteSealed(lifecycle);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
628
806
|
if (lifecycle.markerMatch) {
|
|
629
807
|
if (lifecycle.activityId) {
|
|
630
808
|
this.startRefinement(lifecycle);
|
|
@@ -632,9 +810,11 @@ var ActivityRefinementCoordinator = class {
|
|
|
632
810
|
this.failMissingActivityId(lifecycle);
|
|
633
811
|
}
|
|
634
812
|
}
|
|
813
|
+
this.maybeDeleteSealed(lifecycle);
|
|
635
814
|
},
|
|
636
815
|
(error) => {
|
|
637
816
|
if (lifecycle) {
|
|
817
|
+
lifecycle.createSettled = true;
|
|
638
818
|
this.deleteLifecycle(lifecycle);
|
|
639
819
|
}
|
|
640
820
|
if (coordinatorGeneration === this.generation && this.callbacks.isCurrentCapture(captureGeneration)) {
|
|
@@ -646,14 +826,26 @@ var ActivityRefinementCoordinator = class {
|
|
|
646
826
|
associate(requestId, match, captureGeneration) {
|
|
647
827
|
const lifecycle = this.activeLifecycle;
|
|
648
828
|
this.registeredRequests.delete(requestId);
|
|
649
|
-
if (!lifecycle || !match
|
|
829
|
+
if (!lifecycle || !match) {
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
const now = this.now();
|
|
833
|
+
if (!this.isContinuousMatch(lifecycle, match, captureGeneration, now)) {
|
|
834
|
+
this.sealLifecycle(lifecycle);
|
|
650
835
|
return false;
|
|
651
836
|
}
|
|
652
|
-
this.
|
|
837
|
+
this.renewContinuity(lifecycle, now);
|
|
653
838
|
const pendingMarker = this.pendingMarkers.get(requestId);
|
|
654
|
-
if (
|
|
839
|
+
if (this.canAcceptMarker(lifecycle)) {
|
|
840
|
+
this.requestLifecycles.set(requestId, lifecycle);
|
|
841
|
+
} else {
|
|
842
|
+
this.requestLifecycles.delete(requestId);
|
|
843
|
+
}
|
|
844
|
+
if (pendingMarker && this.canAcceptMarker(lifecycle)) {
|
|
845
|
+
this.pendingMarkers.delete(requestId);
|
|
846
|
+
this.claimMarker(lifecycle, pendingMarker);
|
|
847
|
+
} else if (pendingMarker) {
|
|
655
848
|
this.pendingMarkers.delete(requestId);
|
|
656
|
-
this.refine(requestId, pendingMarker, captureGeneration);
|
|
657
849
|
}
|
|
658
850
|
return true;
|
|
659
851
|
}
|
|
@@ -666,18 +858,17 @@ var ActivityRefinementCoordinator = class {
|
|
|
666
858
|
settleRequest(requestId) {
|
|
667
859
|
const awaitingAssociation = this.registeredRequests.delete(requestId);
|
|
668
860
|
this.pendingMarkers.delete(requestId);
|
|
669
|
-
|
|
670
|
-
if (lifecycle) {
|
|
671
|
-
this.deleteLifecycle(lifecycle);
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
861
|
+
this.requestLifecycles.delete(requestId);
|
|
674
862
|
if (awaitingAssociation) {
|
|
675
863
|
this.settledRequests.add(requestId);
|
|
676
864
|
}
|
|
677
865
|
}
|
|
678
866
|
clearActive(captureGeneration) {
|
|
679
867
|
if (this.activeLifecycle?.captureGeneration === captureGeneration) {
|
|
680
|
-
this.
|
|
868
|
+
this.sealLifecycle(this.activeLifecycle);
|
|
869
|
+
}
|
|
870
|
+
if (this.activeMarkerSegment?.captureGeneration === captureGeneration) {
|
|
871
|
+
this.activeMarkerSegment = null;
|
|
681
872
|
}
|
|
682
873
|
}
|
|
683
874
|
refine(recognitionId, marker, captureGeneration) {
|
|
@@ -696,24 +887,19 @@ var ActivityRefinementCoordinator = class {
|
|
|
696
887
|
}
|
|
697
888
|
return;
|
|
698
889
|
}
|
|
699
|
-
|
|
700
|
-
if (now > lifecycle.deadline) {
|
|
701
|
-
this.deleteLifecycle(lifecycle);
|
|
890
|
+
if (!this.canAcceptMarker(lifecycle)) {
|
|
702
891
|
return;
|
|
703
892
|
}
|
|
704
|
-
lifecycle
|
|
705
|
-
lifecycle.markerMatch = { ...lifecycle.match, audioMarker: marker };
|
|
706
|
-
if (lifecycle.activityId) {
|
|
707
|
-
this.startRefinement(lifecycle);
|
|
708
|
-
} else if (lifecycle.createSettled) {
|
|
709
|
-
this.failMissingActivityId(lifecycle);
|
|
710
|
-
}
|
|
893
|
+
this.claimMarker(lifecycle, marker);
|
|
711
894
|
}
|
|
712
895
|
reset() {
|
|
713
896
|
this.generation += 1;
|
|
714
897
|
for (const lifecycle of this.lifecycles.values()) {
|
|
715
|
-
if (lifecycle.
|
|
716
|
-
clearTimeout(lifecycle.
|
|
898
|
+
if (lifecycle.refinementTimer) {
|
|
899
|
+
clearTimeout(lifecycle.refinementTimer);
|
|
900
|
+
}
|
|
901
|
+
if (lifecycle.continuityTimer) {
|
|
902
|
+
clearTimeout(lifecycle.continuityTimer);
|
|
717
903
|
}
|
|
718
904
|
}
|
|
719
905
|
this.lifecycles.clear();
|
|
@@ -722,19 +908,24 @@ var ActivityRefinementCoordinator = class {
|
|
|
722
908
|
this.registeredRequests.clear();
|
|
723
909
|
this.settledRequests.clear();
|
|
724
910
|
this.activeLifecycle = null;
|
|
911
|
+
this.activeMarkerSegment = null;
|
|
725
912
|
}
|
|
726
913
|
startRefinement(lifecycle) {
|
|
727
|
-
if (lifecycle.refinementStarted || !lifecycle.activityId || !lifecycle.markerMatch) {
|
|
914
|
+
if (lifecycle.refinementStarted || lifecycle.refinementClosed || !lifecycle.activityId || !lifecycle.markerMatch) {
|
|
728
915
|
return;
|
|
729
916
|
}
|
|
730
917
|
lifecycle.refinementStarted = true;
|
|
731
|
-
|
|
918
|
+
lifecycle.refinementInFlight = true;
|
|
919
|
+
void this.runRefinement(lifecycle).finally(() => {
|
|
920
|
+
lifecycle.refinementInFlight = false;
|
|
921
|
+
this.maybeDeleteSealed(lifecycle);
|
|
922
|
+
});
|
|
732
923
|
}
|
|
733
924
|
failMissingActivityId(lifecycle) {
|
|
734
925
|
if (!this.isRefinementActive(lifecycle)) {
|
|
735
926
|
return;
|
|
736
927
|
}
|
|
737
|
-
this.
|
|
928
|
+
this.closeRefinement(lifecycle);
|
|
738
929
|
this.callbacks.emitError(
|
|
739
930
|
"activity-refinement",
|
|
740
931
|
new Error("Activity refinement requires a non-empty activity_id from the create response")
|
|
@@ -743,7 +934,7 @@ var ActivityRefinementCoordinator = class {
|
|
|
743
934
|
async runRefinement(lifecycle) {
|
|
744
935
|
const refinement = this.reporter.refinement;
|
|
745
936
|
if (!refinement || !lifecycle.activityId || !lifecycle.markerMatch) {
|
|
746
|
-
this.
|
|
937
|
+
this.closeRefinement(lifecycle);
|
|
747
938
|
return;
|
|
748
939
|
}
|
|
749
940
|
const maxAttempts = Math.min(
|
|
@@ -754,12 +945,12 @@ var ActivityRefinementCoordinator = class {
|
|
|
754
945
|
)
|
|
755
946
|
);
|
|
756
947
|
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
757
|
-
if (!this.
|
|
948
|
+
if (!this.isRefinementActive(lifecycle)) {
|
|
758
949
|
return;
|
|
759
950
|
}
|
|
760
|
-
const now =
|
|
951
|
+
const now = this.now();
|
|
761
952
|
if (now > lifecycle.deadline) {
|
|
762
|
-
this.
|
|
953
|
+
this.closeRefinement(lifecycle);
|
|
763
954
|
return;
|
|
764
955
|
}
|
|
765
956
|
try {
|
|
@@ -777,10 +968,19 @@ var ActivityRefinementCoordinator = class {
|
|
|
777
968
|
if (!this.isRefinementActive(lifecycle)) {
|
|
778
969
|
return;
|
|
779
970
|
}
|
|
780
|
-
this.
|
|
971
|
+
this.closeRefinement(lifecycle);
|
|
972
|
+
if (result.audioMarker) {
|
|
973
|
+
this.emitResolvedAudioMarker(lifecycle.markerSegment, result.audioMarker);
|
|
974
|
+
}
|
|
781
975
|
if (result.campaign) {
|
|
782
976
|
this.callbacks.emitCampaign(result.campaign);
|
|
783
977
|
}
|
|
978
|
+
if (result.campaignMappingFailure) {
|
|
979
|
+
this.callbacks.emitError(
|
|
980
|
+
"activity-refinement",
|
|
981
|
+
result.campaignMappingFailure.error
|
|
982
|
+
);
|
|
983
|
+
}
|
|
784
984
|
return;
|
|
785
985
|
} catch (caught) {
|
|
786
986
|
if (caught instanceof ActivityReportingCancelledError) {
|
|
@@ -807,7 +1007,7 @@ var ActivityRefinementCoordinator = class {
|
|
|
807
1007
|
if (!this.isRefinementActive(lifecycle)) {
|
|
808
1008
|
return;
|
|
809
1009
|
}
|
|
810
|
-
this.
|
|
1010
|
+
this.closeRefinement(lifecycle);
|
|
811
1011
|
this.callbacks.emitError("activity-refinement", policyError);
|
|
812
1012
|
return;
|
|
813
1013
|
}
|
|
@@ -817,35 +1017,119 @@ var ActivityRefinementCoordinator = class {
|
|
|
817
1017
|
if (retry) {
|
|
818
1018
|
continue;
|
|
819
1019
|
}
|
|
820
|
-
this.
|
|
1020
|
+
this.closeRefinement(lifecycle);
|
|
821
1021
|
this.callbacks.emitError("activity-refinement", error);
|
|
822
1022
|
return;
|
|
823
1023
|
}
|
|
824
1024
|
}
|
|
825
1025
|
}
|
|
826
|
-
|
|
1026
|
+
isTransportActive(lifecycle) {
|
|
827
1027
|
return this.lifecycles.get(lifecycle.recognitionId) === lifecycle && this.callbacks.isCurrentCapture(lifecycle.captureGeneration);
|
|
828
1028
|
}
|
|
829
1029
|
isRefinementActive(lifecycle) {
|
|
830
|
-
if (!this.
|
|
1030
|
+
if (!this.isTransportActive(lifecycle) || lifecycle.refinementClosed) {
|
|
831
1031
|
return false;
|
|
832
1032
|
}
|
|
833
|
-
const
|
|
834
|
-
const now = refinement && refinement.now ? refinement.now() : Date.now();
|
|
1033
|
+
const now = this.now();
|
|
835
1034
|
if (now > lifecycle.deadline) {
|
|
836
|
-
this.
|
|
1035
|
+
this.closeRefinement(lifecycle);
|
|
837
1036
|
return false;
|
|
838
1037
|
}
|
|
839
1038
|
return true;
|
|
840
1039
|
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
1040
|
+
canAcceptMarker(lifecycle) {
|
|
1041
|
+
return lifecycle.markerCode === null && this.isRefinementActive(lifecycle);
|
|
1042
|
+
}
|
|
1043
|
+
claimMarker(lifecycle, marker) {
|
|
1044
|
+
const markerCode = marker.code;
|
|
1045
|
+
if (typeof markerCode !== "string" || markerCode.length === 0 || !this.canAcceptMarker(lifecycle)) {
|
|
1046
|
+
return;
|
|
845
1047
|
}
|
|
846
|
-
|
|
847
|
-
|
|
1048
|
+
lifecycle.markerCode = markerCode;
|
|
1049
|
+
lifecycle.markerMatch = { ...lifecycle.match, audioMarker: marker };
|
|
1050
|
+
if (lifecycle.activityId) {
|
|
1051
|
+
this.startRefinement(lifecycle);
|
|
1052
|
+
} else if (lifecycle.createSettled) {
|
|
1053
|
+
this.failMissingActivityId(lifecycle);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
isContinuousMatch(lifecycle, match, captureGeneration, now) {
|
|
1057
|
+
return !lifecycle.sealed && this.activeLifecycle === lifecycle && lifecycle.captureGeneration === captureGeneration && lifecycle.match.name === match.name && lifecycle.match.afpType === match.afpType && this.isTransportActive(lifecycle) && now - lifecycle.lastObservedAt <= ACTIVITY_CONTINUITY_GAP_MS;
|
|
1058
|
+
}
|
|
1059
|
+
resolveMarkerSegment(match, captureGeneration) {
|
|
1060
|
+
const now = this.now();
|
|
1061
|
+
const active = this.activeMarkerSegment;
|
|
1062
|
+
if (active && active.captureGeneration === captureGeneration && active.materialName === match.name && active.afpType === match.afpType && now - active.lastObservedAt <= ACTIVITY_CONTINUITY_GAP_MS) {
|
|
1063
|
+
active.lastObservedAt = now;
|
|
1064
|
+
return active;
|
|
1065
|
+
}
|
|
1066
|
+
const segment = {
|
|
1067
|
+
captureGeneration,
|
|
1068
|
+
materialName: match.name,
|
|
1069
|
+
afpType: match.afpType,
|
|
1070
|
+
lastObservedAt: now,
|
|
1071
|
+
emitted: false
|
|
1072
|
+
};
|
|
1073
|
+
this.activeMarkerSegment = segment;
|
|
1074
|
+
return segment;
|
|
1075
|
+
}
|
|
1076
|
+
emitResolvedAudioMarker(segment, marker) {
|
|
1077
|
+
if (segment.emitted) {
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
segment.emitted = true;
|
|
1081
|
+
this.callbacks.emitAudioMarker(Object.freeze({ marker }));
|
|
1082
|
+
}
|
|
1083
|
+
renewContinuity(lifecycle, now) {
|
|
1084
|
+
lifecycle.lastObservedAt = now;
|
|
1085
|
+
this.scheduleContinuityExpiry(lifecycle);
|
|
1086
|
+
}
|
|
1087
|
+
scheduleContinuityExpiry(lifecycle) {
|
|
1088
|
+
if (lifecycle.continuityTimer) {
|
|
1089
|
+
clearTimeout(lifecycle.continuityTimer);
|
|
1090
|
+
}
|
|
1091
|
+
const remainingMs = lifecycle.lastObservedAt + ACTIVITY_CONTINUITY_GAP_MS - this.now();
|
|
1092
|
+
lifecycle.continuityTimer = setTimeout(() => {
|
|
1093
|
+
lifecycle.continuityTimer = null;
|
|
1094
|
+
if (this.activeLifecycle !== lifecycle || lifecycle.sealed) {
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
const now = this.now();
|
|
1098
|
+
if (now - lifecycle.lastObservedAt <= ACTIVITY_CONTINUITY_GAP_MS) {
|
|
1099
|
+
this.scheduleContinuityExpiry(lifecycle);
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
this.sealLifecycle(lifecycle);
|
|
1103
|
+
}, Math.max(1, remainingMs + 1));
|
|
1104
|
+
}
|
|
1105
|
+
sealLifecycle(lifecycle) {
|
|
1106
|
+
if (lifecycle.sealed) {
|
|
1107
|
+
return;
|
|
848
1108
|
}
|
|
1109
|
+
lifecycle.sealed = true;
|
|
1110
|
+
if (lifecycle.continuityTimer) {
|
|
1111
|
+
clearTimeout(lifecycle.continuityTimer);
|
|
1112
|
+
lifecycle.continuityTimer = null;
|
|
1113
|
+
}
|
|
1114
|
+
if (this.activeLifecycle === lifecycle) {
|
|
1115
|
+
this.activeLifecycle = null;
|
|
1116
|
+
}
|
|
1117
|
+
this.removeRequestAssociations(lifecycle);
|
|
1118
|
+
this.maybeDeleteSealed(lifecycle);
|
|
1119
|
+
}
|
|
1120
|
+
closeRefinement(lifecycle) {
|
|
1121
|
+
if (lifecycle.refinementClosed) {
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
lifecycle.refinementClosed = true;
|
|
1125
|
+
if (lifecycle.refinementTimer) {
|
|
1126
|
+
clearTimeout(lifecycle.refinementTimer);
|
|
1127
|
+
lifecycle.refinementTimer = null;
|
|
1128
|
+
}
|
|
1129
|
+
this.removeRequestAssociations(lifecycle);
|
|
1130
|
+
this.maybeDeleteSealed(lifecycle);
|
|
1131
|
+
}
|
|
1132
|
+
removeRequestAssociations(lifecycle) {
|
|
849
1133
|
for (const [requestId, requestLifecycle] of this.requestLifecycles) {
|
|
850
1134
|
if (requestLifecycle === lifecycle) {
|
|
851
1135
|
this.requestLifecycles.delete(requestId);
|
|
@@ -853,6 +1137,28 @@ var ActivityRefinementCoordinator = class {
|
|
|
853
1137
|
this.registeredRequests.delete(requestId);
|
|
854
1138
|
}
|
|
855
1139
|
}
|
|
1140
|
+
}
|
|
1141
|
+
maybeDeleteSealed(lifecycle) {
|
|
1142
|
+
if (lifecycle.sealed && lifecycle.createSettled && !lifecycle.refinementInFlight) {
|
|
1143
|
+
this.deleteLifecycle(lifecycle);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
now() {
|
|
1147
|
+
return this.reporter.refinement && this.reporter.refinement.now ? this.reporter.refinement.now() : Date.now();
|
|
1148
|
+
}
|
|
1149
|
+
deleteLifecycle(lifecycle) {
|
|
1150
|
+
if (lifecycle.refinementTimer) {
|
|
1151
|
+
clearTimeout(lifecycle.refinementTimer);
|
|
1152
|
+
lifecycle.refinementTimer = null;
|
|
1153
|
+
}
|
|
1154
|
+
if (lifecycle.continuityTimer) {
|
|
1155
|
+
clearTimeout(lifecycle.continuityTimer);
|
|
1156
|
+
lifecycle.continuityTimer = null;
|
|
1157
|
+
}
|
|
1158
|
+
if (this.lifecycles.get(lifecycle.recognitionId) === lifecycle) {
|
|
1159
|
+
this.lifecycles.delete(lifecycle.recognitionId);
|
|
1160
|
+
}
|
|
1161
|
+
this.removeRequestAssociations(lifecycle);
|
|
856
1162
|
if (this.activeLifecycle === lifecycle) {
|
|
857
1163
|
this.activeLifecycle = null;
|
|
858
1164
|
}
|
|
@@ -1020,7 +1326,6 @@ var MicrophoneMatcher = class {
|
|
|
1020
1326
|
markerPcmBuffer = new Float32Array(0);
|
|
1021
1327
|
resampleBuffer = new Float32Array(0);
|
|
1022
1328
|
resampleOffset = 0;
|
|
1023
|
-
latestAudioMarker = null;
|
|
1024
1329
|
latestAudioMarkerDetection = null;
|
|
1025
1330
|
audioMarkerRequestId = 0;
|
|
1026
1331
|
activityRecognitionId = 0;
|
|
@@ -1047,6 +1352,7 @@ var MicrophoneMatcher = class {
|
|
|
1047
1352
|
this.packSource = options.packSource;
|
|
1048
1353
|
this.activityRefinement = options.activityReporter ? new ActivityRefinementCoordinator(options.activityReporter, {
|
|
1049
1354
|
isCurrentCapture: (captureGeneration) => captureGeneration === this.captureGeneration && this.running,
|
|
1355
|
+
emitAudioMarker: (event) => this.events.emit("audiomarker", event),
|
|
1050
1356
|
emitCampaign: (campaign) => this.events.emit("campaign", campaign),
|
|
1051
1357
|
emitError: (phase, error) => emitError(this.events, phase, error)
|
|
1052
1358
|
}) : null;
|
|
@@ -1316,7 +1622,7 @@ var MicrophoneMatcher = class {
|
|
|
1316
1622
|
return;
|
|
1317
1623
|
}
|
|
1318
1624
|
if (matchedBest) {
|
|
1319
|
-
this.events.emit("match", { best: matchedBest });
|
|
1625
|
+
this.events.emit("match", { best: toPublicDetectedMatch(matchedBest) });
|
|
1320
1626
|
this.activityRecognitionId += 1;
|
|
1321
1627
|
this.reportCampaign(
|
|
1322
1628
|
this.activityRecognitionId,
|
|
@@ -1348,7 +1654,6 @@ var MicrophoneMatcher = class {
|
|
|
1348
1654
|
this.markerPcmBuffer = new Float32Array(0);
|
|
1349
1655
|
this.resampleBuffer = new Float32Array(0);
|
|
1350
1656
|
this.resampleOffset = 0;
|
|
1351
|
-
this.latestAudioMarker = null;
|
|
1352
1657
|
this.latestAudioMarkerDetection = null;
|
|
1353
1658
|
this.audioMarkerRequestId += 1;
|
|
1354
1659
|
this.activityRefinement?.reset();
|
|
@@ -1384,7 +1689,6 @@ var MicrophoneMatcher = class {
|
|
|
1384
1689
|
return null;
|
|
1385
1690
|
}
|
|
1386
1691
|
this.latestAudioMarkerDetection = { requestId, detection };
|
|
1387
|
-
this.emitAudioMarkerIfChanged(detection);
|
|
1388
1692
|
this.activityRefinement?.refine(requestId, detection, captureGeneration);
|
|
1389
1693
|
return detection;
|
|
1390
1694
|
} catch (error) {
|
|
@@ -1411,14 +1715,6 @@ var MicrophoneMatcher = class {
|
|
|
1411
1715
|
audioMarker: this.latestAudioMarkerDetection.detection
|
|
1412
1716
|
};
|
|
1413
1717
|
}
|
|
1414
|
-
emitAudioMarkerIfChanged(detection) {
|
|
1415
|
-
const marker = detection.code ?? null;
|
|
1416
|
-
if (marker === this.latestAudioMarker) {
|
|
1417
|
-
return;
|
|
1418
|
-
}
|
|
1419
|
-
this.latestAudioMarker = marker;
|
|
1420
|
-
this.events.emit("audiomarker", { marker, detection });
|
|
1421
|
-
}
|
|
1422
1718
|
normalizeInputSamples(samples) {
|
|
1423
1719
|
if (this.audioContext.sampleRate === TARGET_SAMPLE_RATE) {
|
|
1424
1720
|
return samples;
|
|
@@ -1576,6 +1872,8 @@ function createLocalStorageSessionManager(options) {
|
|
|
1576
1872
|
|
|
1577
1873
|
// src/audio-recognizer.ts
|
|
1578
1874
|
var DEFAULT_SORI_API_ENDPOINT = "https://console.soriapi.com/api";
|
|
1875
|
+
var MAX_API_ENDPOINT_LENGTH = 32 * 1024;
|
|
1876
|
+
var ASCII_SLASH_CODE_UNIT = 47;
|
|
1579
1877
|
var FORWARDED_EVENTS = [
|
|
1580
1878
|
"ready",
|
|
1581
1879
|
"microphoneready",
|
|
@@ -1603,12 +1901,24 @@ function ensureNonEmptyString(name, value) {
|
|
|
1603
1901
|
}
|
|
1604
1902
|
return value;
|
|
1605
1903
|
}
|
|
1606
|
-
function
|
|
1607
|
-
const value = String(endpoint)
|
|
1904
|
+
function stringifyAndValidateApiEndpoint(endpoint) {
|
|
1905
|
+
const value = String(endpoint);
|
|
1906
|
+
if (value.length > MAX_API_ENDPOINT_LENGTH) {
|
|
1907
|
+
throw new Error(
|
|
1908
|
+
`AudioRecognizer apiEndpoint exceeds maximum length of ${MAX_API_ENDPOINT_LENGTH} UTF-16 code units`
|
|
1909
|
+
);
|
|
1910
|
+
}
|
|
1608
1911
|
return value;
|
|
1609
1912
|
}
|
|
1913
|
+
function normalizeValidatedEndpointPrefix(value) {
|
|
1914
|
+
let end = value.length;
|
|
1915
|
+
while (end > 0 && value.charCodeAt(end - 1) === ASCII_SLASH_CODE_UNIT) {
|
|
1916
|
+
end -= 1;
|
|
1917
|
+
}
|
|
1918
|
+
return end === value.length ? value : value.slice(0, end);
|
|
1919
|
+
}
|
|
1610
1920
|
function joinEndpoint(prefix, path) {
|
|
1611
|
-
return `${
|
|
1921
|
+
return `${prefix}${path.startsWith("/") ? path : `/${path}`}`;
|
|
1612
1922
|
}
|
|
1613
1923
|
function createEphemeralKeyResolver(endpoint, fetcher, requestInit) {
|
|
1614
1924
|
return async () => {
|
|
@@ -1636,8 +1946,15 @@ function resolveRecognizerOptions(options) {
|
|
|
1636
1946
|
const activityReportingDisabled = options.activityReporter === false;
|
|
1637
1947
|
const customActivityReporter = activityReportingDisabled ? void 0 : options.activityReporter;
|
|
1638
1948
|
const appId = legacyAuth?.appId ?? options.appId;
|
|
1639
|
-
const
|
|
1640
|
-
const
|
|
1949
|
+
const configuredAuthEndpoint = legacyAuth?.endpoint ?? options.authEndpoint;
|
|
1950
|
+
const configuredActivityEndpoint = activityReportingDisabled ? void 0 : customActivityReporter?.endpoint ?? options.activityEndpoint;
|
|
1951
|
+
const derivesAuthEndpoint = configuredAuthEndpoint == null;
|
|
1952
|
+
const derivesActivityEndpoint = !activityReportingDisabled && configuredActivityEndpoint == null;
|
|
1953
|
+
const derivesApiEndpoint = derivesAuthEndpoint || derivesActivityEndpoint;
|
|
1954
|
+
const validatedApiEndpoint = options.apiEndpoint !== void 0 || derivesApiEndpoint ? stringifyAndValidateApiEndpoint(apiEndpoint) : void 0;
|
|
1955
|
+
const normalizedApiEndpoint = derivesApiEndpoint ? normalizeValidatedEndpointPrefix(validatedApiEndpoint) : void 0;
|
|
1956
|
+
const authEndpoint = configuredAuthEndpoint ?? joinEndpoint(normalizedApiEndpoint, "/auth");
|
|
1957
|
+
const activityEndpoint = activityReportingDisabled ? void 0 : configuredActivityEndpoint ?? joinEndpoint(normalizedApiEndpoint, "/activity/");
|
|
1641
1958
|
const ephemeralKey = legacyAuth?.ephemeralKey ?? options.ephemeralKey ?? options.ephemeraKey ?? (legacyAuth?.ephemeralKeyEndpoint ?? options.ephemeralKeyEndpoint ? createEphemeralKeyResolver(
|
|
1642
1959
|
legacyAuth?.ephemeralKeyEndpoint ?? options.ephemeralKeyEndpoint,
|
|
1643
1960
|
legacyAuth?.ephemeralKeyFetch ?? options.ephemeralKeyFetch ?? legacyAuth?.fetch ?? sharedFetch,
|
|
@@ -1825,6 +2142,7 @@ export {
|
|
|
1825
2142
|
AudioRecognizer,
|
|
1826
2143
|
DEFAULT_BROWSER_AUDIOPACK_VERSION,
|
|
1827
2144
|
DEFAULT_SORI_API_ENDPOINT,
|
|
2145
|
+
MAX_API_ENDPOINT_LENGTH,
|
|
1828
2146
|
MicrophoneMatcher,
|
|
1829
2147
|
authenticateAndLoadAudioPack,
|
|
1830
2148
|
createLocalStorageAudioPackStore,
|