@sorisdk/web-audio 0.6.7 → 0.6.9
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 +68 -12
- package/dist/generated/window_bg.wasm +0 -0
- package/dist/index.d.ts +9 -8
- package/dist/index.js +171 -60
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -13,6 +13,36 @@ Public integration guide: https://docs.soriapi.com/ko/integration/web
|
|
|
13
13
|
- An ephemeral key issued by your server
|
|
14
14
|
- Microphone permission granted by the user
|
|
15
15
|
|
|
16
|
+
## Unreleased: Console-resolved audio marker events
|
|
17
|
+
|
|
18
|
+
The public `audiomarker` event now contains only the marker identity managed in
|
|
19
|
+
SORI Console. The SDK emits it after a successful activity POST or refinement
|
|
20
|
+
PUT returns both a non-blank `audio_marker_id` and `audio_marker_name`:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
recognizer.on("audiomarker", ({ marker }) => {
|
|
24
|
+
console.log(marker.id, marker.name);
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The event is independent from campaign mapping and can be emitted when the
|
|
29
|
+
activity response has no campaign. Repeated responses within one continuous
|
|
30
|
+
material segment emit once; an intervening material, no-match, capture reset,
|
|
31
|
+
or expired continuity gap starts a new segment that may emit again.
|
|
32
|
+
|
|
33
|
+
Local WASM detection and labels such as `code_000` remain private inputs to the
|
|
34
|
+
activity request. They are no longer present on public `audiomarker` or `match`
|
|
35
|
+
events, `campaign.match`, the exported `DetectedMatch`, or the
|
|
36
|
+
`@sorisdk/web-audio` type exports. Custom request and campaign mappers receive
|
|
37
|
+
the public codebook-free match; the SDK adds its private `trait.marker` only to
|
|
38
|
+
the outgoing activity payload after request mapping.
|
|
39
|
+
|
|
40
|
+
This deliberately replaces the 0.6.7-and-earlier event shape. Migrate from
|
|
41
|
+
`event.marker` as a nullable string and `event.detection` as a raw detector
|
|
42
|
+
result to the non-null `event.marker.id` and `event.marker.name` fields above.
|
|
43
|
+
There is no legacy fallback: disabled activity reporting, failed transport, or
|
|
44
|
+
a response with a missing or malformed id/name pair emits no public marker.
|
|
45
|
+
|
|
16
46
|
## Standalone CDN
|
|
17
47
|
|
|
18
48
|
For a browser application that does not use npm or a bundler, import the
|
|
@@ -22,7 +52,7 @@ configuration, or Node-based asset server is required:
|
|
|
22
52
|
```html
|
|
23
53
|
<script type="module">
|
|
24
54
|
import { AudioRecognizer } from
|
|
25
|
-
"https://cdn.iplateia.com/web/sorisdk/v0.6.
|
|
55
|
+
"https://cdn.iplateia.com/web/sorisdk/v0.6.9/sori-web-audio.mjs";
|
|
26
56
|
|
|
27
57
|
const recognizer = new AudioRecognizer({
|
|
28
58
|
appId: "YOUR_APP_ID",
|
|
@@ -49,7 +79,7 @@ configuration, or Node-based asset server is required:
|
|
|
49
79
|
```
|
|
50
80
|
|
|
51
81
|
Static URL imports are valid inside `<script type="module">`. Dynamic
|
|
52
|
-
`await import("https://cdn.iplateia.com/web/sorisdk/v0.6.
|
|
82
|
+
`await import("https://cdn.iplateia.com/web/sorisdk/v0.6.9/sori-web-audio.mjs")`
|
|
53
83
|
is an optional alternative when the SDK should be loaded conditionally.
|
|
54
84
|
|
|
55
85
|
Pin an exact version in production. Do not construct a mutable `latest` URL.
|
|
@@ -119,7 +149,7 @@ An import map can give the standalone URL the npm package name:
|
|
|
119
149
|
<script type="importmap">
|
|
120
150
|
{
|
|
121
151
|
"imports": {
|
|
122
|
-
"@sorisdk/web-audio": "https://cdn.iplateia.com/web/sorisdk/v0.6.
|
|
152
|
+
"@sorisdk/web-audio": "https://cdn.iplateia.com/web/sorisdk/v0.6.9/sori-web-audio.mjs"
|
|
123
153
|
}
|
|
124
154
|
}
|
|
125
155
|
</script>
|
|
@@ -171,6 +201,10 @@ recognizer.on("campaign", (event) => {
|
|
|
171
201
|
console.log(event.activityId, event.campaign);
|
|
172
202
|
});
|
|
173
203
|
|
|
204
|
+
recognizer.on("audiomarker", ({ marker }) => {
|
|
205
|
+
console.log(marker.id, marker.name);
|
|
206
|
+
});
|
|
207
|
+
|
|
174
208
|
recognizer.on("error", ({ error }) => {
|
|
175
209
|
console.error(error);
|
|
176
210
|
});
|
|
@@ -185,6 +219,22 @@ await recognizer.stop();
|
|
|
185
219
|
await recognizer.destroy();
|
|
186
220
|
```
|
|
187
221
|
|
|
222
|
+
## Continuous recognition
|
|
223
|
+
|
|
224
|
+
Continuous observations of one material emit one public `match`. An intervening
|
|
225
|
+
material (A → B → A), two consecutive fingerprint no-match results, or a gap
|
|
226
|
+
greater than 30 seconds since the last successful observation starts a new run.
|
|
227
|
+
The next successful A is delivered immediately. A single fingerprint miss or
|
|
228
|
+
marker miss does not split a run. Successful observations renew continuity even
|
|
229
|
+
when no public `match` event is emitted, in both marker modes.
|
|
230
|
+
|
|
231
|
+
The 30-second boundary also covers capture interruptions with no queries; it is
|
|
232
|
+
checked when querying resumes. Two consecutive misses can confirm a boundary
|
|
233
|
+
sooner. `nomatch` is emitted on an observed boundary, rather than by an idle
|
|
234
|
+
timer. Sequential stop/start, failed-start cleanup, and successful database
|
|
235
|
+
replacement or mutation clear recognition and capture state. Pending queries
|
|
236
|
+
from an older capture cannot restore suppression in the new capture.
|
|
237
|
+
|
|
188
238
|
## Activity refinement
|
|
189
239
|
|
|
190
240
|
The default `AudioRecognizer` activity reporter represents one ordered,
|
|
@@ -200,13 +250,15 @@ server activity:
|
|
|
200
250
|
3. A marker-free match with an active marker-scan request also includes
|
|
201
251
|
top-level `refinement_expected: true`.
|
|
202
252
|
4. The returned `activity_id` is retained for 30 seconds.
|
|
203
|
-
5. If the same recognition gains
|
|
253
|
+
5. If the same recognition gains a private local marker detection, the SDK sends
|
|
204
254
|
`PUT /api/activity/{activity_id}` with the same material and
|
|
205
255
|
`trait.marker`.
|
|
206
|
-
6.
|
|
256
|
+
6. A valid response marker id/name pair emits one public structured
|
|
257
|
+
`audiomarker` event, even when the response has no campaign.
|
|
258
|
+
7. The refined `campaign` event keeps the same non-empty `activityId`, so an
|
|
207
259
|
application can replace the earlier campaign row deterministically.
|
|
208
260
|
|
|
209
|
-
A
|
|
261
|
+
A successful observation for the same material and fingerprint type renews a local
|
|
210
262
|
30-second continuity lease without another POST or campaign event. That local
|
|
211
263
|
lease can keep one segment alive beyond the initial server refinement window,
|
|
212
264
|
but it never extends the original PUT deadline. A marker confirmed anywhere
|
|
@@ -228,10 +280,10 @@ refine the earlier A. Marker evidence arriving after a segment is sealed is
|
|
|
228
280
|
ignored for that segment; create or PUT transport that already started may
|
|
229
281
|
finish under the existing capture, deadline, and cancellation guards.
|
|
230
282
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
283
|
+
Fingerprint `match` events follow the continuous-run rules above and never
|
|
284
|
+
contain the private detector result. Public `audiomarker` delivery is sourced
|
|
285
|
+
only from a completed activity response. It is independent from campaign
|
|
286
|
+
availability but does prove that the server resolved the marker id and name.
|
|
235
287
|
|
|
236
288
|
Recognition timing belongs only to the segment's first material POST. Later
|
|
237
289
|
same-material observations update only the internal `lastObservedAt` lease;
|
|
@@ -273,7 +325,10 @@ Existing `mapMatchToRequest` and `mapResponseToCampaign` hooks continue to
|
|
|
273
325
|
handle POST. Additive refinement hooks can override the PUT payload, response
|
|
274
326
|
mapping, endpoint, headers, fetcher, and retry policy. The stable terminal
|
|
275
327
|
statuses 404, 409, and 410 are never retried even if a custom policy returns
|
|
276
|
-
`true`.
|
|
328
|
+
`true`. Match arguments passed to these hooks omit private detector state. When
|
|
329
|
+
local detection succeeds, the SDK injects its private marker into the outgoing
|
|
330
|
+
`trait.marker` after request mapping, while resolved public identity is parsed
|
|
331
|
+
directly from the unmodified activity response before campaign delivery.
|
|
277
332
|
|
|
278
333
|
`recognized_at` and `position` are optional public request properties for
|
|
279
334
|
source compatibility, but they are SDK-owned transport values. After a custom
|
|
@@ -404,7 +459,8 @@ fingerprint chunks and the existing match-window cadence are unchanged.
|
|
|
404
459
|
|
|
405
460
|
1. Prepare your `appId` and ephemeral key flow.
|
|
406
461
|
2. Create an `AudioRecognizer`.
|
|
407
|
-
3. Subscribe to the events you need, such as `campaign`, `
|
|
462
|
+
3. Subscribe to the events you need, such as `campaign`, `audiomarker`, `match`,
|
|
463
|
+
and `error`.
|
|
408
464
|
4. Call `start()` to begin recognition.
|
|
409
465
|
5. Call `stop()` or `destroy()` when leaving the page or stopping capture.
|
|
410
466
|
|
|
Binary file
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MatcherEphemeralAuthOptions, InitMatcherOptions, MatcherEphemeralAuthResult,
|
|
2
|
-
export { AudioFingerprintType, AudioMarkerConfig,
|
|
1
|
+
import { MatcherEphemeralAuthOptions, InitMatcherOptions, MatcherEphemeralAuthResult, PackSource, MatchResult, MatcherSessionOptions, AudioFingerprintType } from '@sorisdk/matcher';
|
|
2
|
+
export { AudioFingerprintType, AudioMarkerConfig, PackSource } from '@sorisdk/matcher';
|
|
3
3
|
import { InitAfpgenOptions } from '@sorisdk/afpgen';
|
|
4
4
|
|
|
5
5
|
declare const DEFAULT_BROWSER_AUDIOPACK_VERSION = "20220401000000";
|
|
@@ -53,11 +53,14 @@ interface InitMatchWindowWasmOptions {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
interface DetectedMatch extends Pick<MatchResult, "afpType" | "durationMillis" | "name" | "position" | "score"> {
|
|
56
|
-
|
|
56
|
+
}
|
|
57
|
+
/** SORI Console-managed identity resolved from a successful activity response. */
|
|
58
|
+
interface AudioMarkerIdentity {
|
|
59
|
+
readonly id: string;
|
|
60
|
+
readonly name: string;
|
|
57
61
|
}
|
|
58
62
|
interface AudioMarkerEvent {
|
|
59
|
-
marker:
|
|
60
|
-
detection: AudioMarkerDetection;
|
|
63
|
+
readonly marker: AudioMarkerIdentity;
|
|
61
64
|
}
|
|
62
65
|
interface MaterialActivityRequestPayload {
|
|
63
66
|
type: "material";
|
|
@@ -243,7 +246,6 @@ declare class MicrophoneMatcher {
|
|
|
243
246
|
private markerPcmBuffer;
|
|
244
247
|
private resampleBuffer;
|
|
245
248
|
private resampleOffset;
|
|
246
|
-
private latestAudioMarker;
|
|
247
249
|
private latestAudioMarkerDetection;
|
|
248
250
|
private audioMarkerRequestId;
|
|
249
251
|
private activityRecognitionId;
|
|
@@ -281,7 +283,6 @@ declare class MicrophoneMatcher {
|
|
|
281
283
|
private detectAudioMarkerForRequest;
|
|
282
284
|
private matchConfig;
|
|
283
285
|
private withAudioMarkerForRequest;
|
|
284
|
-
private emitAudioMarkerIfChanged;
|
|
285
286
|
private normalizeInputSamples;
|
|
286
287
|
private resampleToTargetRate;
|
|
287
288
|
private cleanupAfterStartFailure;
|
|
@@ -296,4 +297,4 @@ declare function requestMicrophoneStream(mediaDevices: MediaDevices, mediaConstr
|
|
|
296
297
|
preferredSampleRate?: number;
|
|
297
298
|
}): Promise<MediaStream>;
|
|
298
299
|
|
|
299
|
-
export { ACTIVITY_REFINEMENT_WINDOW_MS, type ActivityRefinementFailureContext, type ActivityRefinementRequestContext, type AudioMarkerEvent, AudioRecognizer, type AudioRecognizerAuthOptions, type AudioRecognizerOptions, type AuthenticateAndLoadAudioPackOptions, type AuthenticateAndLoadAudioPackResult, type BrowserAudioPackLoader, type BrowserAudioPackState, type BrowserAudioPackStateStore, type BrowserSessionManager, type CreateLocalStorageAudioPackStoreOptions, type CreateLocalStorageSessionManagerOptions, type CreateMicrophoneMatcherOptions, type CreateMicrophoneMatcherWasmOptions, DEFAULT_BROWSER_AUDIOPACK_VERSION, DEFAULT_SORI_API_ENDPOINT, type DetectedMatch, MAX_API_ENDPOINT_LENGTH, type MaterialActivityRequestPayload, MicrophoneMatcher, type MicrophoneMatcherActivityRefinementOptions, type MicrophoneMatcherActivityReporterOptions, type MicrophoneMatcherCampaignEvent, type MicrophoneMatcherEventMap, type MicrophoneMatcherEventName, type MicrophoneMatcherListener, authenticateAndLoadAudioPack, createLocalStorageAudioPackStore, createLocalStorageSessionManager, createMicrophoneMatcher, requestMicrophoneStream };
|
|
300
|
+
export { ACTIVITY_REFINEMENT_WINDOW_MS, type ActivityRefinementFailureContext, type ActivityRefinementRequestContext, type AudioMarkerEvent, type AudioMarkerIdentity, AudioRecognizer, type AudioRecognizerAuthOptions, type AudioRecognizerOptions, type AuthenticateAndLoadAudioPackOptions, type AuthenticateAndLoadAudioPackResult, type BrowserAudioPackLoader, type BrowserAudioPackState, type BrowserAudioPackStateStore, type BrowserSessionManager, type CreateLocalStorageAudioPackStoreOptions, type CreateLocalStorageSessionManagerOptions, type CreateMicrophoneMatcherOptions, type CreateMicrophoneMatcherWasmOptions, DEFAULT_BROWSER_AUDIOPACK_VERSION, DEFAULT_SORI_API_ENDPOINT, type DetectedMatch, MAX_API_ENDPOINT_LENGTH, type MaterialActivityRequestPayload, MicrophoneMatcher, type MicrophoneMatcherActivityRefinementOptions, type MicrophoneMatcherActivityReporterOptions, type MicrophoneMatcherCampaignEvent, type MicrophoneMatcherEventMap, type MicrophoneMatcherEventName, type MicrophoneMatcherListener, authenticateAndLoadAudioPack, createLocalStorageAudioPackStore, createLocalStorageSessionManager, createMicrophoneMatcher, requestMicrophoneStream };
|
package/dist/index.js
CHANGED
|
@@ -354,6 +354,15 @@ var FingerprintMatchWindow = class {
|
|
|
354
354
|
}
|
|
355
355
|
};
|
|
356
356
|
|
|
357
|
+
// src/activity-refinement.ts
|
|
358
|
+
import { MATCH_CONTINUITY_GAP_MS } from "@sorisdk/matcher";
|
|
359
|
+
|
|
360
|
+
// src/detected-match.ts
|
|
361
|
+
function toPublicDetectedMatch(match) {
|
|
362
|
+
const { audioMarker: _internalAudioMarker, ...publicMatch } = match;
|
|
363
|
+
return publicMatch;
|
|
364
|
+
}
|
|
365
|
+
|
|
357
366
|
// src/activity.ts
|
|
358
367
|
var ActivityReportingError = class extends Error {
|
|
359
368
|
status;
|
|
@@ -417,7 +426,7 @@ function validateRequestPayload(payload) {
|
|
|
417
426
|
}
|
|
418
427
|
async function resolveCreateRequestPayload(reporter, match) {
|
|
419
428
|
const payload = validateRequestPayload(
|
|
420
|
-
reporter.mapMatchToRequest ? await reporter.mapMatchToRequest(match) : defaultRequestPayload(match)
|
|
429
|
+
reporter.mapMatchToRequest ? await reporter.mapMatchToRequest(toPublicDetectedMatch(match)) : defaultRequestPayload(match)
|
|
421
430
|
);
|
|
422
431
|
if (!payload) {
|
|
423
432
|
return null;
|
|
@@ -428,7 +437,7 @@ async function resolveCreateRequestPayload(reporter, match) {
|
|
|
428
437
|
refinement_expected: _ignoredRefinementExpected,
|
|
429
438
|
...requestPayload
|
|
430
439
|
} = payload;
|
|
431
|
-
return requestPayload;
|
|
440
|
+
return withInternalAudioMarker(requestPayload, match);
|
|
432
441
|
}
|
|
433
442
|
async function resolveRefineRequestPayload(reporter, match, context) {
|
|
434
443
|
const refinement = reporter.refinement;
|
|
@@ -436,7 +445,7 @@ async function resolveRefineRequestPayload(reporter, match, context) {
|
|
|
436
445
|
return null;
|
|
437
446
|
}
|
|
438
447
|
const payload = validateRequestPayload(
|
|
439
|
-
refinement.mapMatchToRequest ? await refinement.mapMatchToRequest(match, context) : reporter.mapMatchToRequest ? await reporter.mapMatchToRequest(match) : defaultRequestPayload(match)
|
|
448
|
+
refinement.mapMatchToRequest ? await refinement.mapMatchToRequest(toPublicDetectedMatch(match), context) : reporter.mapMatchToRequest ? await reporter.mapMatchToRequest(toPublicDetectedMatch(match)) : defaultRequestPayload(match)
|
|
440
449
|
);
|
|
441
450
|
if (!payload) {
|
|
442
451
|
return null;
|
|
@@ -447,7 +456,20 @@ async function resolveRefineRequestPayload(reporter, match, context) {
|
|
|
447
456
|
refinement_expected: _ignoredRefinementExpected,
|
|
448
457
|
...requestPayload
|
|
449
458
|
} = payload;
|
|
450
|
-
return requestPayload;
|
|
459
|
+
return withInternalAudioMarker(requestPayload, match);
|
|
460
|
+
}
|
|
461
|
+
function withInternalAudioMarker(payload, match) {
|
|
462
|
+
const marker = match.audioMarker?.code;
|
|
463
|
+
if (typeof marker !== "string" || marker.length === 0) {
|
|
464
|
+
return payload;
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
467
|
+
...payload,
|
|
468
|
+
trait: {
|
|
469
|
+
...payload.trait,
|
|
470
|
+
marker
|
|
471
|
+
}
|
|
472
|
+
};
|
|
451
473
|
}
|
|
452
474
|
function defaultCampaignMapper(payload, match) {
|
|
453
475
|
const campaign = payload.campaign;
|
|
@@ -455,12 +477,23 @@ function defaultCampaignMapper(payload, match) {
|
|
|
455
477
|
return null;
|
|
456
478
|
}
|
|
457
479
|
return {
|
|
458
|
-
match,
|
|
480
|
+
match: toPublicDetectedMatch(match),
|
|
459
481
|
campaign,
|
|
460
482
|
activityId: typeof payload.activity_id === "string" ? payload.activity_id : null,
|
|
461
483
|
raw: payload
|
|
462
484
|
};
|
|
463
485
|
}
|
|
486
|
+
function resolvedAudioMarker(payload) {
|
|
487
|
+
if (!payload) {
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
const id = payload.audio_marker_id;
|
|
491
|
+
const name = payload.audio_marker_name;
|
|
492
|
+
if (typeof id !== "string" || id.trim().length === 0 || typeof name !== "string" || name.trim().length === 0) {
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
return Object.freeze({ id, name });
|
|
496
|
+
}
|
|
464
497
|
async function resolveHeaders(reporter, refinement = false) {
|
|
465
498
|
const refinementHeaders = reporter.refinement && reporter.refinement.headers;
|
|
466
499
|
const baseHeaders = reporter.headers ? typeof reporter.headers === "function" ? await reporter.headers() : reporter.headers : void 0;
|
|
@@ -518,17 +551,28 @@ async function mapCreateResponse(reporter, data, match, refinementExpected) {
|
|
|
518
551
|
if (!data) {
|
|
519
552
|
return {
|
|
520
553
|
activityId: null,
|
|
554
|
+
audioMarker: null,
|
|
521
555
|
campaign: null,
|
|
522
556
|
creationAttempted: true,
|
|
523
557
|
refinementExpected
|
|
524
558
|
};
|
|
525
559
|
}
|
|
526
|
-
const
|
|
560
|
+
const audioMarker = resolvedAudioMarker(data);
|
|
561
|
+
let campaign;
|
|
562
|
+
let campaignMappingFailure;
|
|
563
|
+
try {
|
|
564
|
+
campaign = reporter.mapResponseToCampaign ? await reporter.mapResponseToCampaign(data, toPublicDetectedMatch(match)) : defaultCampaignMapper(data, match);
|
|
565
|
+
} catch (error) {
|
|
566
|
+
campaign = null;
|
|
567
|
+
campaignMappingFailure = { error };
|
|
568
|
+
}
|
|
527
569
|
return {
|
|
528
570
|
activityId: responseActivityId(data, campaign),
|
|
571
|
+
audioMarker,
|
|
529
572
|
campaign,
|
|
530
573
|
creationAttempted: true,
|
|
531
|
-
refinementExpected
|
|
574
|
+
refinementExpected,
|
|
575
|
+
...campaignMappingFailure ? { campaignMappingFailure } : {}
|
|
532
576
|
};
|
|
533
577
|
}
|
|
534
578
|
async function resolveRefinementEndpoint(reporter, activityId) {
|
|
@@ -544,6 +588,7 @@ async function createMatchedMaterialActivity(reporter, match, refinementExpected
|
|
|
544
588
|
if (!payload) {
|
|
545
589
|
return {
|
|
546
590
|
activityId: null,
|
|
591
|
+
audioMarker: null,
|
|
547
592
|
campaign: null,
|
|
548
593
|
creationAttempted: false,
|
|
549
594
|
refinementExpected: false
|
|
@@ -576,11 +621,11 @@ async function createMatchedMaterialActivity(reporter, match, refinementExpected
|
|
|
576
621
|
async function refineMatchedMaterialActivity(reporter, match, context, isActive = () => true) {
|
|
577
622
|
const refinement = reporter.refinement;
|
|
578
623
|
if (!refinement) {
|
|
579
|
-
return { activityId: null, campaign: null };
|
|
624
|
+
return { activityId: null, audioMarker: null, campaign: null };
|
|
580
625
|
}
|
|
581
626
|
const payload = await resolveRefineRequestPayload(reporter, match, context);
|
|
582
627
|
if (!payload) {
|
|
583
|
-
return { activityId: null, campaign: null };
|
|
628
|
+
return { activityId: null, audioMarker: null, campaign: null };
|
|
584
629
|
}
|
|
585
630
|
const endpoint = await resolveRefinementEndpoint(reporter, context.activityId);
|
|
586
631
|
const headers = await resolveHeaders(reporter, true);
|
|
@@ -596,8 +641,16 @@ async function refineMatchedMaterialActivity(reporter, match, context, isActive
|
|
|
596
641
|
if (!data) {
|
|
597
642
|
throw new ActivityReportingError("Activity refine failed: empty response", response.status);
|
|
598
643
|
}
|
|
599
|
-
const
|
|
600
|
-
|
|
644
|
+
const audioMarker = resolvedAudioMarker(data);
|
|
645
|
+
let mappedCampaign;
|
|
646
|
+
let campaignMappingFailure;
|
|
647
|
+
try {
|
|
648
|
+
mappedCampaign = refinement.mapResponseToCampaign ? await refinement.mapResponseToCampaign(data, toPublicDetectedMatch(match), context) : reporter.mapResponseToCampaign ? await reporter.mapResponseToCampaign(data, toPublicDetectedMatch(match)) : defaultCampaignMapper(data, match);
|
|
649
|
+
} catch (error) {
|
|
650
|
+
mappedCampaign = null;
|
|
651
|
+
campaignMappingFailure = { error };
|
|
652
|
+
}
|
|
653
|
+
const activityId = responseActivityId(data, mappedCampaign) ?? (campaignMappingFailure ? context.activityId : null);
|
|
601
654
|
if (activityId !== context.activityId) {
|
|
602
655
|
throw new ActivityReportingError(
|
|
603
656
|
"Activity refine failed: response activity_id does not match the requested activity",
|
|
@@ -605,12 +658,16 @@ async function refineMatchedMaterialActivity(reporter, match, context, isActive
|
|
|
605
658
|
);
|
|
606
659
|
}
|
|
607
660
|
const campaign = mappedCampaign ? { ...mappedCampaign, activityId: context.activityId } : null;
|
|
608
|
-
return {
|
|
661
|
+
return {
|
|
662
|
+
activityId,
|
|
663
|
+
audioMarker,
|
|
664
|
+
campaign,
|
|
665
|
+
...campaignMappingFailure ? { campaignMappingFailure } : {}
|
|
666
|
+
};
|
|
609
667
|
}
|
|
610
668
|
|
|
611
669
|
// src/activity-refinement.ts
|
|
612
670
|
var ACTIVITY_REFINEMENT_WINDOW_MS = 3e4;
|
|
613
|
-
var ACTIVITY_CONTINUITY_GAP_MS = 3e4;
|
|
614
671
|
var DEFAULT_MAX_REFINEMENT_ATTEMPTS = 2;
|
|
615
672
|
var MAX_REFINEMENT_ATTEMPTS = 10;
|
|
616
673
|
function normalizeError(error) {
|
|
@@ -634,6 +691,7 @@ var ActivityRefinementCoordinator = class {
|
|
|
634
691
|
registeredRequests = /* @__PURE__ */ new Set();
|
|
635
692
|
settledRequests = /* @__PURE__ */ new Set();
|
|
636
693
|
activeLifecycle = null;
|
|
694
|
+
activeMarkerSegment = null;
|
|
637
695
|
generation = 0;
|
|
638
696
|
constructor(reporter, callbacks) {
|
|
639
697
|
this.reporter = reporter;
|
|
@@ -644,10 +702,14 @@ var ActivityRefinementCoordinator = class {
|
|
|
644
702
|
this.registeredRequests.add(requestId);
|
|
645
703
|
}
|
|
646
704
|
}
|
|
647
|
-
report(recognitionId, match, captureGeneration, requestId = null) {
|
|
705
|
+
report(recognitionId, match, captureGeneration, requestId = null, distinct = true) {
|
|
648
706
|
const coordinatorGeneration = this.generation;
|
|
707
|
+
const markerSegment = this.resolveMarkerSegment(match, captureGeneration);
|
|
649
708
|
const hasMarker = typeof match.audioMarker?.code === "string" && match.audioMarker.code.length > 0;
|
|
650
709
|
const refinement = this.reporter.refinement;
|
|
710
|
+
if (!refinement && !distinct) {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
651
713
|
const requestCanRefine = requestId !== null && !this.settledRequests.has(requestId);
|
|
652
714
|
const pendingMarker = requestId === null ? void 0 : this.pendingMarkers.get(requestId);
|
|
653
715
|
if (requestId !== null) {
|
|
@@ -690,6 +752,7 @@ var ActivityRefinementCoordinator = class {
|
|
|
690
752
|
activityId: null,
|
|
691
753
|
markerMatch: hasMarker ? match : null,
|
|
692
754
|
markerCode: hasMarker ? match.audioMarker?.code ?? null : null,
|
|
755
|
+
markerSegment,
|
|
693
756
|
refinementTimer: null,
|
|
694
757
|
continuityTimer: null,
|
|
695
758
|
createSettled: false,
|
|
@@ -722,9 +785,15 @@ var ActivityRefinementCoordinator = class {
|
|
|
722
785
|
recognitionTiming
|
|
723
786
|
).then(
|
|
724
787
|
(result) => {
|
|
788
|
+
if (coordinatorGeneration === this.generation && result.audioMarker && this.callbacks.isCurrentCapture(captureGeneration)) {
|
|
789
|
+
this.emitResolvedAudioMarker(markerSegment, result.audioMarker);
|
|
790
|
+
}
|
|
725
791
|
if (coordinatorGeneration === this.generation && result.campaign && this.callbacks.isCurrentCapture(captureGeneration)) {
|
|
726
792
|
this.callbacks.emitCampaign(result.campaign);
|
|
727
793
|
}
|
|
794
|
+
if (coordinatorGeneration === this.generation && result.campaignMappingFailure && this.callbacks.isCurrentCapture(captureGeneration)) {
|
|
795
|
+
this.callbacks.emitError("activity", result.campaignMappingFailure.error);
|
|
796
|
+
}
|
|
728
797
|
if (coordinatorGeneration !== this.generation || !lifecycle || this.lifecycles.get(recognitionId) !== lifecycle) {
|
|
729
798
|
return;
|
|
730
799
|
}
|
|
@@ -803,6 +872,9 @@ var ActivityRefinementCoordinator = class {
|
|
|
803
872
|
if (this.activeLifecycle?.captureGeneration === captureGeneration) {
|
|
804
873
|
this.sealLifecycle(this.activeLifecycle);
|
|
805
874
|
}
|
|
875
|
+
if (this.activeMarkerSegment?.captureGeneration === captureGeneration) {
|
|
876
|
+
this.activeMarkerSegment = null;
|
|
877
|
+
}
|
|
806
878
|
}
|
|
807
879
|
refine(recognitionId, marker, captureGeneration) {
|
|
808
880
|
if (!this.reporter.refinement) {
|
|
@@ -841,6 +913,7 @@ var ActivityRefinementCoordinator = class {
|
|
|
841
913
|
this.registeredRequests.clear();
|
|
842
914
|
this.settledRequests.clear();
|
|
843
915
|
this.activeLifecycle = null;
|
|
916
|
+
this.activeMarkerSegment = null;
|
|
844
917
|
}
|
|
845
918
|
startRefinement(lifecycle) {
|
|
846
919
|
if (lifecycle.refinementStarted || lifecycle.refinementClosed || !lifecycle.activityId || !lifecycle.markerMatch) {
|
|
@@ -901,9 +974,18 @@ var ActivityRefinementCoordinator = class {
|
|
|
901
974
|
return;
|
|
902
975
|
}
|
|
903
976
|
this.closeRefinement(lifecycle);
|
|
977
|
+
if (result.audioMarker) {
|
|
978
|
+
this.emitResolvedAudioMarker(lifecycle.markerSegment, result.audioMarker);
|
|
979
|
+
}
|
|
904
980
|
if (result.campaign) {
|
|
905
981
|
this.callbacks.emitCampaign(result.campaign);
|
|
906
982
|
}
|
|
983
|
+
if (result.campaignMappingFailure) {
|
|
984
|
+
this.callbacks.emitError(
|
|
985
|
+
"activity-refinement",
|
|
986
|
+
result.campaignMappingFailure.error
|
|
987
|
+
);
|
|
988
|
+
}
|
|
907
989
|
return;
|
|
908
990
|
} catch (caught) {
|
|
909
991
|
if (caught instanceof ActivityReportingCancelledError) {
|
|
@@ -977,7 +1059,31 @@ var ActivityRefinementCoordinator = class {
|
|
|
977
1059
|
}
|
|
978
1060
|
}
|
|
979
1061
|
isContinuousMatch(lifecycle, match, captureGeneration, now) {
|
|
980
|
-
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 <=
|
|
1062
|
+
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 <= MATCH_CONTINUITY_GAP_MS;
|
|
1063
|
+
}
|
|
1064
|
+
resolveMarkerSegment(match, captureGeneration) {
|
|
1065
|
+
const now = this.now();
|
|
1066
|
+
const active = this.activeMarkerSegment;
|
|
1067
|
+
if (active && active.captureGeneration === captureGeneration && active.materialName === match.name && active.afpType === match.afpType && now - active.lastObservedAt <= MATCH_CONTINUITY_GAP_MS) {
|
|
1068
|
+
active.lastObservedAt = now;
|
|
1069
|
+
return active;
|
|
1070
|
+
}
|
|
1071
|
+
const segment = {
|
|
1072
|
+
captureGeneration,
|
|
1073
|
+
materialName: match.name,
|
|
1074
|
+
afpType: match.afpType,
|
|
1075
|
+
lastObservedAt: now,
|
|
1076
|
+
emitted: false
|
|
1077
|
+
};
|
|
1078
|
+
this.activeMarkerSegment = segment;
|
|
1079
|
+
return segment;
|
|
1080
|
+
}
|
|
1081
|
+
emitResolvedAudioMarker(segment, marker) {
|
|
1082
|
+
if (segment.emitted) {
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
segment.emitted = true;
|
|
1086
|
+
this.callbacks.emitAudioMarker(Object.freeze({ marker }));
|
|
981
1087
|
}
|
|
982
1088
|
renewContinuity(lifecycle, now) {
|
|
983
1089
|
lifecycle.lastObservedAt = now;
|
|
@@ -987,14 +1093,14 @@ var ActivityRefinementCoordinator = class {
|
|
|
987
1093
|
if (lifecycle.continuityTimer) {
|
|
988
1094
|
clearTimeout(lifecycle.continuityTimer);
|
|
989
1095
|
}
|
|
990
|
-
const remainingMs = lifecycle.lastObservedAt +
|
|
1096
|
+
const remainingMs = lifecycle.lastObservedAt + MATCH_CONTINUITY_GAP_MS - this.now();
|
|
991
1097
|
lifecycle.continuityTimer = setTimeout(() => {
|
|
992
1098
|
lifecycle.continuityTimer = null;
|
|
993
1099
|
if (this.activeLifecycle !== lifecycle || lifecycle.sealed) {
|
|
994
1100
|
return;
|
|
995
1101
|
}
|
|
996
1102
|
const now = this.now();
|
|
997
|
-
if (now - lifecycle.lastObservedAt <=
|
|
1103
|
+
if (now - lifecycle.lastObservedAt <= MATCH_CONTINUITY_GAP_MS) {
|
|
998
1104
|
this.scheduleContinuityExpiry(lifecycle);
|
|
999
1105
|
return;
|
|
1000
1106
|
}
|
|
@@ -1225,7 +1331,6 @@ var MicrophoneMatcher = class {
|
|
|
1225
1331
|
markerPcmBuffer = new Float32Array(0);
|
|
1226
1332
|
resampleBuffer = new Float32Array(0);
|
|
1227
1333
|
resampleOffset = 0;
|
|
1228
|
-
latestAudioMarker = null;
|
|
1229
1334
|
latestAudioMarkerDetection = null;
|
|
1230
1335
|
audioMarkerRequestId = 0;
|
|
1231
1336
|
activityRecognitionId = 0;
|
|
@@ -1252,6 +1357,7 @@ var MicrophoneMatcher = class {
|
|
|
1252
1357
|
this.packSource = options.packSource;
|
|
1253
1358
|
this.activityRefinement = options.activityReporter ? new ActivityRefinementCoordinator(options.activityReporter, {
|
|
1254
1359
|
isCurrentCapture: (captureGeneration) => captureGeneration === this.captureGeneration && this.running,
|
|
1360
|
+
emitAudioMarker: (event) => this.events.emit("audiomarker", event),
|
|
1255
1361
|
emitCampaign: (campaign) => this.events.emit("campaign", campaign),
|
|
1256
1362
|
emitError: (phase, error) => emitError(this.events, phase, error)
|
|
1257
1363
|
}) : null;
|
|
@@ -1280,6 +1386,7 @@ var MicrophoneMatcher = class {
|
|
|
1280
1386
|
}
|
|
1281
1387
|
await this.matcherSession.loadPack(target);
|
|
1282
1388
|
this.loadedPack = true;
|
|
1389
|
+
await this.resetCaptureState();
|
|
1283
1390
|
} catch (error) {
|
|
1284
1391
|
emitAndThrow(this.events, "loadPack", error);
|
|
1285
1392
|
}
|
|
@@ -1321,6 +1428,7 @@ var MicrophoneMatcher = class {
|
|
|
1321
1428
|
this.ensureNotDestroyed();
|
|
1322
1429
|
await this.prepare();
|
|
1323
1430
|
await this.matcherSession.addEntry(name, afpType, fingerprint);
|
|
1431
|
+
await this.resetCaptureState();
|
|
1324
1432
|
} catch (error) {
|
|
1325
1433
|
emitAndThrow(this.events, "addEntry", error);
|
|
1326
1434
|
}
|
|
@@ -1330,6 +1438,7 @@ var MicrophoneMatcher = class {
|
|
|
1330
1438
|
this.ensureNotDestroyed();
|
|
1331
1439
|
await this.prepare();
|
|
1332
1440
|
await this.matcherSession.addOrReplace(name, afpType, fingerprint);
|
|
1441
|
+
await this.resetCaptureState();
|
|
1333
1442
|
} catch (error) {
|
|
1334
1443
|
emitAndThrow(this.events, "addOrReplace", error);
|
|
1335
1444
|
}
|
|
@@ -1338,9 +1447,8 @@ var MicrophoneMatcher = class {
|
|
|
1338
1447
|
try {
|
|
1339
1448
|
this.ensureNotDestroyed();
|
|
1340
1449
|
await this.prepare();
|
|
1341
|
-
this.activityRefinement?.reset();
|
|
1342
|
-
this.matchWindowOrThrow().reset();
|
|
1343
1450
|
await this.matcherSession.clear();
|
|
1451
|
+
await this.resetCaptureState();
|
|
1344
1452
|
} catch (error) {
|
|
1345
1453
|
emitAndThrow(this.events, "clear", error);
|
|
1346
1454
|
}
|
|
@@ -1385,9 +1493,9 @@ var MicrophoneMatcher = class {
|
|
|
1385
1493
|
return;
|
|
1386
1494
|
}
|
|
1387
1495
|
this.running = false;
|
|
1496
|
+
await this.resetCaptureState();
|
|
1388
1497
|
await this.graphController?.stop();
|
|
1389
1498
|
this.graphController = null;
|
|
1390
|
-
await this.resetCaptureState();
|
|
1391
1499
|
if (this.stopTracksOnStop) {
|
|
1392
1500
|
this.stream?.getTracks().forEach((track) => track.stop());
|
|
1393
1501
|
}
|
|
@@ -1477,15 +1585,18 @@ var MicrophoneMatcher = class {
|
|
|
1477
1585
|
let matchedBest = null;
|
|
1478
1586
|
let shouldEmitNoMatch = false;
|
|
1479
1587
|
let audioMarkerRequestId = null;
|
|
1480
|
-
let
|
|
1588
|
+
let observedBest = null;
|
|
1481
1589
|
const handleMatch = (event) => {
|
|
1482
|
-
if (!event.best) {
|
|
1590
|
+
if (!event.best || captureGeneration !== this.captureGeneration || !this.running) {
|
|
1483
1591
|
return;
|
|
1484
1592
|
}
|
|
1485
1593
|
matchedBest = event.best;
|
|
1486
1594
|
shouldEmitNoMatch = false;
|
|
1487
1595
|
};
|
|
1488
1596
|
const handleNoMatch = () => {
|
|
1597
|
+
if (captureGeneration !== this.captureGeneration || !this.running) {
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1489
1600
|
matchedBest = null;
|
|
1490
1601
|
shouldEmitNoMatch = true;
|
|
1491
1602
|
};
|
|
@@ -1495,7 +1606,6 @@ var MicrophoneMatcher = class {
|
|
|
1495
1606
|
this.diagnostics.matchRequests += 1;
|
|
1496
1607
|
const bestMatchPromise = this.matcherSession.bestMatch(query, this.matchConfig());
|
|
1497
1608
|
audioMarkerRequestId = this.beginAudioMarkerDetection(captureGeneration);
|
|
1498
|
-
let observedBest;
|
|
1499
1609
|
try {
|
|
1500
1610
|
observedBest = await bestMatchPromise;
|
|
1501
1611
|
} catch (error) {
|
|
@@ -1504,15 +1614,10 @@ var MicrophoneMatcher = class {
|
|
|
1504
1614
|
}
|
|
1505
1615
|
throw error;
|
|
1506
1616
|
}
|
|
1507
|
-
if (
|
|
1508
|
-
|
|
1509
|
-
audioMarkerRequestId,
|
|
1510
|
-
observedBest,
|
|
1511
|
-
captureGeneration
|
|
1512
|
-
) ?? false;
|
|
1617
|
+
if (captureGeneration !== this.captureGeneration || !this.running) {
|
|
1618
|
+
return;
|
|
1513
1619
|
}
|
|
1514
|
-
|
|
1515
|
-
matchedBest = distinctBest;
|
|
1620
|
+
observedBest = this.withAudioMarkerForRequest(observedBest, audioMarkerRequestId);
|
|
1516
1621
|
} finally {
|
|
1517
1622
|
this.matcherSession.off("match", handleMatch);
|
|
1518
1623
|
this.matcherSession.off("nomatch", handleNoMatch);
|
|
@@ -1520,44 +1625,56 @@ var MicrophoneMatcher = class {
|
|
|
1520
1625
|
if (captureGeneration !== this.captureGeneration || !this.running) {
|
|
1521
1626
|
return;
|
|
1522
1627
|
}
|
|
1523
|
-
if (
|
|
1524
|
-
|
|
1628
|
+
if (observedBest) {
|
|
1629
|
+
const distinct = matchedBest !== null;
|
|
1630
|
+
if (distinct) {
|
|
1631
|
+
this.activityRefinement?.clearActive(captureGeneration);
|
|
1632
|
+
this.events.emit("match", { best: toPublicDetectedMatch(observedBest) });
|
|
1633
|
+
}
|
|
1634
|
+
if (captureGeneration !== this.captureGeneration || !this.running) {
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1525
1637
|
this.activityRecognitionId += 1;
|
|
1526
1638
|
this.reportCampaign(
|
|
1527
1639
|
this.activityRecognitionId,
|
|
1528
|
-
|
|
1640
|
+
observedBest,
|
|
1529
1641
|
captureGeneration,
|
|
1530
|
-
audioMarkerRequestId
|
|
1642
|
+
audioMarkerRequestId,
|
|
1643
|
+
distinct
|
|
1531
1644
|
);
|
|
1532
|
-
} else
|
|
1533
|
-
if (audioMarkerRequestId !== null
|
|
1645
|
+
} else {
|
|
1646
|
+
if (audioMarkerRequestId !== null) {
|
|
1534
1647
|
this.activityRefinement?.discardRequest(audioMarkerRequestId);
|
|
1535
1648
|
}
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1649
|
+
if (shouldEmitNoMatch) {
|
|
1650
|
+
this.activityRefinement?.clearActive(captureGeneration);
|
|
1651
|
+
this.events.emit("nomatch", {});
|
|
1652
|
+
}
|
|
1540
1653
|
}
|
|
1541
1654
|
} while (this.pendingMatch || this.matchWindowOrThrow().hasReadyQuery());
|
|
1542
1655
|
} catch (error) {
|
|
1543
|
-
|
|
1656
|
+
if (captureGeneration === this.captureGeneration && this.running) {
|
|
1657
|
+
emitError(this.events, "match", error);
|
|
1658
|
+
}
|
|
1544
1659
|
} finally {
|
|
1545
|
-
this.
|
|
1660
|
+
if (captureGeneration === this.captureGeneration) {
|
|
1661
|
+
this.matchInFlight = false;
|
|
1662
|
+
}
|
|
1546
1663
|
}
|
|
1547
1664
|
}
|
|
1548
1665
|
async resetCaptureState() {
|
|
1549
1666
|
this.captureGeneration += 1;
|
|
1667
|
+
this.matcherSession.resetRecognitionState();
|
|
1550
1668
|
this.pendingMatch = false;
|
|
1551
1669
|
this.matchInFlight = false;
|
|
1552
1670
|
this.pcmBuffer = new Float32Array(0);
|
|
1553
1671
|
this.markerPcmBuffer = new Float32Array(0);
|
|
1554
1672
|
this.resampleBuffer = new Float32Array(0);
|
|
1555
1673
|
this.resampleOffset = 0;
|
|
1556
|
-
this.latestAudioMarker = null;
|
|
1557
1674
|
this.latestAudioMarkerDetection = null;
|
|
1558
1675
|
this.audioMarkerRequestId += 1;
|
|
1559
1676
|
this.activityRefinement?.reset();
|
|
1560
|
-
this.
|
|
1677
|
+
this.matchWindow?.reset();
|
|
1561
1678
|
await this.extractor?.reset();
|
|
1562
1679
|
}
|
|
1563
1680
|
appendAudioMarkerSamples(samples) {
|
|
@@ -1589,12 +1706,13 @@ var MicrophoneMatcher = class {
|
|
|
1589
1706
|
return null;
|
|
1590
1707
|
}
|
|
1591
1708
|
this.latestAudioMarkerDetection = { requestId, detection };
|
|
1592
|
-
this.emitAudioMarkerIfChanged(detection);
|
|
1593
1709
|
this.activityRefinement?.refine(requestId, detection, captureGeneration);
|
|
1594
1710
|
return detection;
|
|
1595
1711
|
} catch (error) {
|
|
1596
|
-
this.
|
|
1597
|
-
|
|
1712
|
+
if (captureGeneration === this.captureGeneration && this.running) {
|
|
1713
|
+
this.activityRefinement?.settleRequest(requestId);
|
|
1714
|
+
emitError(this.events, "audiomarker", error);
|
|
1715
|
+
}
|
|
1598
1716
|
return null;
|
|
1599
1717
|
}
|
|
1600
1718
|
}
|
|
@@ -1616,14 +1734,6 @@ var MicrophoneMatcher = class {
|
|
|
1616
1734
|
audioMarker: this.latestAudioMarkerDetection.detection
|
|
1617
1735
|
};
|
|
1618
1736
|
}
|
|
1619
|
-
emitAudioMarkerIfChanged(detection) {
|
|
1620
|
-
const marker = detection.code ?? null;
|
|
1621
|
-
if (marker === this.latestAudioMarker) {
|
|
1622
|
-
return;
|
|
1623
|
-
}
|
|
1624
|
-
this.latestAudioMarker = marker;
|
|
1625
|
-
this.events.emit("audiomarker", { marker, detection });
|
|
1626
|
-
}
|
|
1627
1737
|
normalizeInputSamples(samples) {
|
|
1628
1738
|
if (this.audioContext.sampleRate === TARGET_SAMPLE_RATE) {
|
|
1629
1739
|
return samples;
|
|
@@ -1653,9 +1763,9 @@ var MicrophoneMatcher = class {
|
|
|
1653
1763
|
}
|
|
1654
1764
|
async cleanupAfterStartFailure() {
|
|
1655
1765
|
this.running = false;
|
|
1766
|
+
await this.resetCaptureState();
|
|
1656
1767
|
await this.graphController?.stop();
|
|
1657
1768
|
this.graphController = null;
|
|
1658
|
-
await this.resetCaptureState();
|
|
1659
1769
|
if (this.stopTracksOnStop) {
|
|
1660
1770
|
this.stream?.getTracks().forEach((track) => track.stop());
|
|
1661
1771
|
}
|
|
@@ -1686,7 +1796,7 @@ var MicrophoneMatcher = class {
|
|
|
1686
1796
|
}
|
|
1687
1797
|
return this.matchWindow;
|
|
1688
1798
|
}
|
|
1689
|
-
reportCampaign(recognitionId, match, captureGeneration, audioMarkerRequestId) {
|
|
1799
|
+
reportCampaign(recognitionId, match, captureGeneration, audioMarkerRequestId, distinct) {
|
|
1690
1800
|
const reporter = this.options.activityReporter;
|
|
1691
1801
|
if (!reporter) {
|
|
1692
1802
|
return;
|
|
@@ -1695,7 +1805,8 @@ var MicrophoneMatcher = class {
|
|
|
1695
1805
|
recognitionId,
|
|
1696
1806
|
match,
|
|
1697
1807
|
captureGeneration,
|
|
1698
|
-
audioMarkerRequestId
|
|
1808
|
+
audioMarkerRequestId,
|
|
1809
|
+
distinct
|
|
1699
1810
|
);
|
|
1700
1811
|
}
|
|
1701
1812
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sorisdk/web-audio",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.9",
|
|
4
4
|
"description": "Web SDK for browser-based audio recognition with SORI API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
35
35
|
"homepage": "https://docs.soriapi.com/ko/integration/web",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@sorisdk/
|
|
38
|
-
"@sorisdk/
|
|
37
|
+
"@sorisdk/afpgen": "0.6.9",
|
|
38
|
+
"@sorisdk/matcher": "0.6.9"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"tsup": "^8.5.1",
|