@iam-protocol/pulse-sdk 0.3.3 → 0.3.5
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.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +33 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +33 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/pulse.ts +39 -5
- package/src/sensor/audio.ts +3 -1
- package/src/sensor/motion.ts +1 -1
- package/src/sensor/types.ts +4 -0
package/dist/index.d.mts
CHANGED
|
@@ -54,6 +54,10 @@ interface CaptureOptions {
|
|
|
54
54
|
maxDurationMs?: number;
|
|
55
55
|
/** Called with RMS audio level (0-1) on each buffer during audio capture (~4x per second). */
|
|
56
56
|
onAudioLevel?: (rms: number) => void;
|
|
57
|
+
/** Pre-acquired MediaStream. If provided, captureAudio skips getUserMedia. */
|
|
58
|
+
stream?: MediaStream;
|
|
59
|
+
/** If true, captureMotion skips requestMotionPermission (already acquired). */
|
|
60
|
+
permissionGranted?: boolean;
|
|
57
61
|
}
|
|
58
62
|
/** Stage of a capture session */
|
|
59
63
|
type CaptureStage = "audio" | "motion" | "touch";
|
|
@@ -127,6 +131,7 @@ declare class PulseSession {
|
|
|
127
131
|
startMotion(): Promise<void>;
|
|
128
132
|
stopMotion(): Promise<MotionSample[]>;
|
|
129
133
|
skipMotion(): void;
|
|
134
|
+
isMotionCapturing(): boolean;
|
|
130
135
|
startTouch(): Promise<void>;
|
|
131
136
|
stopTouch(): Promise<TouchSample[]>;
|
|
132
137
|
skipTouch(): void;
|
package/dist/index.d.ts
CHANGED
|
@@ -54,6 +54,10 @@ interface CaptureOptions {
|
|
|
54
54
|
maxDurationMs?: number;
|
|
55
55
|
/** Called with RMS audio level (0-1) on each buffer during audio capture (~4x per second). */
|
|
56
56
|
onAudioLevel?: (rms: number) => void;
|
|
57
|
+
/** Pre-acquired MediaStream. If provided, captureAudio skips getUserMedia. */
|
|
58
|
+
stream?: MediaStream;
|
|
59
|
+
/** If true, captureMotion skips requestMotionPermission (already acquired). */
|
|
60
|
+
permissionGranted?: boolean;
|
|
57
61
|
}
|
|
58
62
|
/** Stage of a capture session */
|
|
59
63
|
type CaptureStage = "audio" | "motion" | "touch";
|
|
@@ -127,6 +131,7 @@ declare class PulseSession {
|
|
|
127
131
|
startMotion(): Promise<void>;
|
|
128
132
|
stopMotion(): Promise<MotionSample[]>;
|
|
129
133
|
skipMotion(): void;
|
|
134
|
+
isMotionCapturing(): boolean;
|
|
130
135
|
startTouch(): Promise<void>;
|
|
131
136
|
stopTouch(): Promise<TouchSample[]>;
|
|
132
137
|
skipTouch(): void;
|
package/dist/index.js
CHANGED
|
@@ -109,9 +109,10 @@ async function captureAudio(options = {}) {
|
|
|
109
109
|
signal,
|
|
110
110
|
minDurationMs = MIN_CAPTURE_MS,
|
|
111
111
|
maxDurationMs = MAX_CAPTURE_MS,
|
|
112
|
-
onAudioLevel
|
|
112
|
+
onAudioLevel,
|
|
113
|
+
stream: preAcquiredStream
|
|
113
114
|
} = options;
|
|
114
|
-
const stream = await navigator.mediaDevices.getUserMedia({
|
|
115
|
+
const stream = preAcquiredStream ?? await navigator.mediaDevices.getUserMedia({
|
|
115
116
|
audio: {
|
|
116
117
|
sampleRate: TARGET_SAMPLE_RATE,
|
|
117
118
|
channelCount: 1,
|
|
@@ -121,6 +122,7 @@ async function captureAudio(options = {}) {
|
|
|
121
122
|
}
|
|
122
123
|
});
|
|
123
124
|
const ctx = new AudioContext({ sampleRate: TARGET_SAMPLE_RATE });
|
|
125
|
+
await ctx.resume();
|
|
124
126
|
const capturedSampleRate = ctx.sampleRate;
|
|
125
127
|
const source = ctx.createMediaStreamSource(stream);
|
|
126
128
|
const chunks = [];
|
|
@@ -197,7 +199,7 @@ async function captureMotion(options = {}) {
|
|
|
197
199
|
minDurationMs = MIN_CAPTURE_MS,
|
|
198
200
|
maxDurationMs = MAX_CAPTURE_MS
|
|
199
201
|
} = options;
|
|
200
|
-
const hasPermission = await requestMotionPermission();
|
|
202
|
+
const hasPermission = options.permissionGranted ?? await requestMotionPermission();
|
|
201
203
|
if (!hasPermission) return [];
|
|
202
204
|
const samples = [];
|
|
203
205
|
const startTime = performance.now();
|
|
@@ -1578,12 +1580,25 @@ var PulseSession = class {
|
|
|
1578
1580
|
async startAudio(onAudioLevel) {
|
|
1579
1581
|
if (this.audioStageState !== "idle")
|
|
1580
1582
|
throw new Error("Audio capture already started");
|
|
1583
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
1584
|
+
audio: {
|
|
1585
|
+
sampleRate: 16e3,
|
|
1586
|
+
channelCount: 1,
|
|
1587
|
+
echoCancellation: false,
|
|
1588
|
+
noiseSuppression: false,
|
|
1589
|
+
autoGainControl: false
|
|
1590
|
+
}
|
|
1591
|
+
});
|
|
1581
1592
|
this.audioStageState = "capturing";
|
|
1582
1593
|
this.audioController = new AbortController();
|
|
1583
1594
|
this.audioPromise = captureAudio({
|
|
1584
1595
|
signal: this.audioController.signal,
|
|
1585
|
-
onAudioLevel
|
|
1586
|
-
|
|
1596
|
+
onAudioLevel,
|
|
1597
|
+
stream
|
|
1598
|
+
}).catch(() => {
|
|
1599
|
+
stream.getTracks().forEach((t) => t.stop());
|
|
1600
|
+
return null;
|
|
1601
|
+
});
|
|
1587
1602
|
}
|
|
1588
1603
|
async stopAudio() {
|
|
1589
1604
|
if (this.audioStageState !== "capturing")
|
|
@@ -1599,10 +1614,16 @@ var PulseSession = class {
|
|
|
1599
1614
|
async startMotion() {
|
|
1600
1615
|
if (this.motionStageState !== "idle")
|
|
1601
1616
|
throw new Error("Motion capture already started");
|
|
1617
|
+
const hasPermission = await requestMotionPermission();
|
|
1618
|
+
if (!hasPermission) {
|
|
1619
|
+
this.motionStageState = "skipped";
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1602
1622
|
this.motionStageState = "capturing";
|
|
1603
1623
|
this.motionController = new AbortController();
|
|
1604
1624
|
this.motionPromise = captureMotion({
|
|
1605
|
-
signal: this.motionController.signal
|
|
1625
|
+
signal: this.motionController.signal,
|
|
1626
|
+
permissionGranted: true
|
|
1606
1627
|
}).catch(() => []);
|
|
1607
1628
|
}
|
|
1608
1629
|
async stopMotion() {
|
|
@@ -1618,6 +1639,9 @@ var PulseSession = class {
|
|
|
1618
1639
|
throw new Error("Motion capture already started");
|
|
1619
1640
|
this.motionStageState = "skipped";
|
|
1620
1641
|
}
|
|
1642
|
+
isMotionCapturing() {
|
|
1643
|
+
return this.motionStageState === "capturing";
|
|
1644
|
+
}
|
|
1621
1645
|
// --- Touch ---
|
|
1622
1646
|
async startTouch() {
|
|
1623
1647
|
if (this.touchStageState !== "idle")
|
|
@@ -1700,12 +1724,13 @@ var PulseSDK = class {
|
|
|
1700
1724
|
}
|
|
1701
1725
|
try {
|
|
1702
1726
|
await session.startMotion();
|
|
1727
|
+
} catch {
|
|
1728
|
+
}
|
|
1729
|
+
if (session.isMotionCapturing()) {
|
|
1703
1730
|
stopPromises.push(
|
|
1704
1731
|
new Promise((r) => setTimeout(r, DEFAULT_CAPTURE_MS)).then(() => session.stopMotion()).then(() => {
|
|
1705
1732
|
})
|
|
1706
1733
|
);
|
|
1707
|
-
} catch {
|
|
1708
|
-
session.skipMotion();
|
|
1709
1734
|
}
|
|
1710
1735
|
if (touchElement) {
|
|
1711
1736
|
try {
|