@wcstack/camera 4.6.2 → 4.8.0
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.ja.md +2 -1
- package/README.md +2 -1
- package/dist/auto.min.js +1 -1
- package/dist/auto.min.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.esm.js +95 -24
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -347,6 +347,9 @@ declare class WcsCamera extends HTMLElement {
|
|
|
347
347
|
private _core;
|
|
348
348
|
private _video;
|
|
349
349
|
private _connectedCallbackPromise;
|
|
350
|
+
private _connectResolve;
|
|
351
|
+
private _acquirePending;
|
|
352
|
+
private _autostartCancelled;
|
|
350
353
|
private _connected;
|
|
351
354
|
private _batchingAttrs;
|
|
352
355
|
private _internals;
|
|
@@ -396,6 +399,7 @@ declare class WcsCamera extends HTMLElement {
|
|
|
396
399
|
private _constraints;
|
|
397
400
|
private _onStreamReady;
|
|
398
401
|
private _onActiveChanged;
|
|
402
|
+
private _scheduleAcquire;
|
|
399
403
|
connectedCallback(): void;
|
|
400
404
|
disconnectedCallback(): void;
|
|
401
405
|
attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null): void;
|
|
@@ -445,9 +449,11 @@ declare class RecorderCore extends EventTarget {
|
|
|
445
449
|
private _closing;
|
|
446
450
|
private _ready;
|
|
447
451
|
/**
|
|
448
|
-
* Whether `[wcs/command-not-ready]` was said
|
|
452
|
+
* Whether `[wcs/command-not-ready]` was said in this outage: a `start()` refused because the
|
|
449
453
|
* element is not ready loses what it carried, and `error` alone told only a page that binds it.
|
|
450
|
-
* Said once per
|
|
454
|
+
* Said once per outage (docs/v4-direction-2026-10.md, the I/O command policy): a stream arriving
|
|
455
|
+
* resets it. Once per element was once per page life — a route puts the same element back on
|
|
456
|
+
* every entry, so the next outage's lost recording went unsaid (docs/seam-apps.md, shift-desk).
|
|
451
457
|
*/
|
|
452
458
|
private _toldNotReady;
|
|
453
459
|
constructor(target?: EventTarget);
|
package/dist/index.esm.js
CHANGED
|
@@ -647,6 +647,12 @@ class CameraCore extends EventTarget {
|
|
|
647
647
|
if (this._constraints.audio) {
|
|
648
648
|
tasks.push(this._watchMicrophone());
|
|
649
649
|
}
|
|
650
|
+
else {
|
|
651
|
+
// A re-observe after dispose() without audio: the microphone state the last
|
|
652
|
+
// subscription left is not what this one asks about (null = audio not requested),
|
|
653
|
+
// as _reconcileAudioWatcher clears it on a live Core.
|
|
654
|
+
this._setAudioPermission(null);
|
|
655
|
+
}
|
|
650
656
|
// Track hot-plug: refresh the device list when a camera is added/removed.
|
|
651
657
|
if (typeof navigator.mediaDevices.addEventListener === "function") {
|
|
652
658
|
navigator.mediaDevices.addEventListener("devicechange", this._onDeviceChange);
|
|
@@ -951,14 +957,23 @@ class WcsCamera extends HTMLElement {
|
|
|
951
957
|
commands: CameraCore.wcBindable.commands,
|
|
952
958
|
};
|
|
953
959
|
// `autostart` and `keep-alive` are intentionally NOT observed: `autostart` is a
|
|
954
|
-
// connect-time-only acquire trigger (read once
|
|
955
|
-
// later is meaningless), and `keep-alive`
|
|
956
|
-
// (_onVisibilityChange), so it never needs
|
|
957
|
-
// is exactly the constraints that reshape
|
|
960
|
+
// connect-time-only acquire trigger (read once by the connect-time decision in
|
|
961
|
+
// _scheduleAcquire's microtask; flipping it later is meaningless), and `keep-alive`
|
|
962
|
+
// is read fresh on every visibilitychange (_onVisibilityChange), so it never needs
|
|
963
|
+
// to drive a re-acquire. The observed set is exactly the constraints that reshape
|
|
964
|
+
// the requested track.
|
|
958
965
|
static observedAttributes = ["facing-mode", "device-id", "audio", "width", "height"];
|
|
959
966
|
_core;
|
|
960
967
|
_video;
|
|
961
968
|
_connectedCallbackPromise = Promise.resolve();
|
|
969
|
+
// connectedCallback が張った connectedCallbackPromise を解く関数。接続時の判断を下す
|
|
970
|
+
// _scheduleAcquire のマイクロタスクが(その前に外れたときは disconnectedCallback が)呼ぶ。
|
|
971
|
+
// null でないあいだは「接続時の判断待ち」でもある。
|
|
972
|
+
_connectResolve = null;
|
|
973
|
+
// _scheduleAcquire のマイクロタスクが待っている間 true
|
|
974
|
+
_acquirePending = false;
|
|
975
|
+
// 接続時の判断待ちに stop() が呼ばれたら true — その判断は autostart でも取得しない
|
|
976
|
+
_autostartCancelled = false;
|
|
962
977
|
_connected = false;
|
|
963
978
|
// True while switchCamera() rewrites several attributes at once. Each setAttribute /
|
|
964
979
|
// removeAttribute fires its own attributeChangedCallback synchronously; without this
|
|
@@ -1081,8 +1096,21 @@ class WcsCamera extends HTMLElement {
|
|
|
1081
1096
|
get errorInfo() { return this._core.errorInfo; }
|
|
1082
1097
|
get connectedCallbackPromise() { return this._connectedCallbackPromise; }
|
|
1083
1098
|
// --- Commands ---
|
|
1084
|
-
start() {
|
|
1085
|
-
|
|
1099
|
+
start() {
|
|
1100
|
+
// 制約は属性が正本。接続時の判断・属性の変化はマイクロタスクで Core に渡るので
|
|
1101
|
+
// (_scheduleAcquire)、それより先の start() でも、いまの属性の制約で取得するよう渡しておく
|
|
1102
|
+
if (this._connected)
|
|
1103
|
+
this._core.observe(this._constraints());
|
|
1104
|
+
this._core.start();
|
|
1105
|
+
}
|
|
1106
|
+
stop() {
|
|
1107
|
+
// 接続時の判断待ちなら、その autostart を取り消す — 同じタスクの append → stop() で、後の
|
|
1108
|
+
// マイクロタスクが取得を始めないように(判断が同期だった頃は、始めた取得を stop() が止めて
|
|
1109
|
+
// いた)。権限の監視(observe)は取り消さない。入れ直せば、次の判断は autostart に従う
|
|
1110
|
+
if (this._connectResolve !== null)
|
|
1111
|
+
this._autostartCancelled = true;
|
|
1112
|
+
this._core.stop();
|
|
1113
|
+
}
|
|
1086
1114
|
/**
|
|
1087
1115
|
* Toggle the front/back camera by updating the DOM attributes (the single source
|
|
1088
1116
|
* of truth), not just the Core's internal constraints. Deliberately does NOT call
|
|
@@ -1142,18 +1170,63 @@ class WcsCamera extends HTMLElement {
|
|
|
1142
1170
|
}
|
|
1143
1171
|
};
|
|
1144
1172
|
// --- Lifecycle ---
|
|
1173
|
+
// 取得の判断はマイクロタスクで、そのときの属性(制約と autostart)で 1 回だけ行う
|
|
1174
|
+
// (timing-and-firing-contract §23)。router は遷移で同じノードを入れ直し、新しいルートの
|
|
1175
|
+
// params から state が device-id などを書くのはマイクロタスク — その場で取得すると、前の
|
|
1176
|
+
// 制約で getUserMedia を起こし、取得中は active が偽なので新しい制約での取り直しも起きず、
|
|
1177
|
+
// 前の制約のストリームが残っていた(docs/seam-apps.md、shift-desk)。同じタスクの制約の
|
|
1178
|
+
// 変化もここへまとまる。
|
|
1179
|
+
_scheduleAcquire() {
|
|
1180
|
+
if (this._acquirePending)
|
|
1181
|
+
return;
|
|
1182
|
+
this._acquirePending = true;
|
|
1183
|
+
queueMicrotask(() => {
|
|
1184
|
+
this._acquirePending = false;
|
|
1185
|
+
const resolveConnect = this._connectResolve;
|
|
1186
|
+
this._connectResolve = null;
|
|
1187
|
+
// 判断の前に外れた要素は何もしない(disconnectedCallback が dispose 済み)
|
|
1188
|
+
if (!this._connected)
|
|
1189
|
+
return;
|
|
1190
|
+
// Track the constraints (and reconcile the microphone watcher).
|
|
1191
|
+
const ready = this._core.observe(this._constraints());
|
|
1192
|
+
if (resolveConnect !== null) {
|
|
1193
|
+
// 接続時の判断: autostart なら取得する(判断待ちに stop() が呼ばれていなければ)
|
|
1194
|
+
if (this.autostart && !this._autostartCancelled) {
|
|
1195
|
+
this._core.start();
|
|
1196
|
+
}
|
|
1197
|
+
this._autostartCancelled = false;
|
|
1198
|
+
resolveConnect(ready);
|
|
1199
|
+
}
|
|
1200
|
+
else if (this._core.active) {
|
|
1201
|
+
// A constraints change re-acquires (switchMap-style restart) only when a stream
|
|
1202
|
+
// is actually live. `active` is the deliberate guard (not `desired`): `active`
|
|
1203
|
+
// implies `desired` (a stream only goes live under desired), so re-acquiring
|
|
1204
|
+
// cannot spuriously re-`desired` a stopped camera. Guarding on `active` rather
|
|
1205
|
+
// than `desired` also avoids force-acquiring while suspended/hidden (desired but
|
|
1206
|
+
// not active) — the visibility handler owns resume there.
|
|
1207
|
+
this._core.start();
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1145
1211
|
connectedCallback() {
|
|
1146
1212
|
// upgrade 前に代入された input を取り込み直す(doc 13 §1.2 / Phase A1)
|
|
1147
1213
|
upgradeProperties(this);
|
|
1148
1214
|
this._connected = true;
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1215
|
+
// connectedCallbackPromise は接続時の observe(権限の初期状態)が済むまでを表す。
|
|
1216
|
+
// observe は判断と同じマイクロタスクで走るので、ここで張ってそこで解く
|
|
1217
|
+
this._connectedCallbackPromise = new Promise((resolve) => {
|
|
1218
|
+
this._connectResolve = resolve;
|
|
1219
|
+
});
|
|
1220
|
+
this._scheduleAcquire();
|
|
1153
1221
|
document.addEventListener("visibilitychange", this._onVisibilityChange);
|
|
1154
1222
|
}
|
|
1155
1223
|
disconnectedCallback() {
|
|
1156
1224
|
this._connected = false;
|
|
1225
|
+
// 判断の前に外れたら、張った connectedCallbackPromise をここで解く — 同じタスクで
|
|
1226
|
+
// 入れ直されると次の connectedCallback が張り替えるので、待つ側が取り残されないように
|
|
1227
|
+
this._connectResolve?.();
|
|
1228
|
+
this._connectResolve = null;
|
|
1229
|
+
this._autostartCancelled = false;
|
|
1157
1230
|
document.removeEventListener("visibilitychange", this._onVisibilityChange);
|
|
1158
1231
|
this._core.dispose();
|
|
1159
1232
|
}
|
|
@@ -1165,17 +1238,9 @@ class WcsCamera extends HTMLElement {
|
|
|
1165
1238
|
// constraints (see `_batchingAttrs`).
|
|
1166
1239
|
if (this._batchingAttrs)
|
|
1167
1240
|
return;
|
|
1168
|
-
//
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
// is actually live. `active` is the deliberate guard (not `desired`): `active`
|
|
1172
|
-
// implies `desired` (a stream only goes live under desired), so re-acquiring
|
|
1173
|
-
// cannot spuriously re-`desired` a stopped camera. Guarding on `active` rather
|
|
1174
|
-
// than `desired` also avoids force-acquiring while suspended/hidden (desired but
|
|
1175
|
-
// not active) — the visibility handler owns resume there.
|
|
1176
|
-
if (this._core.active) {
|
|
1177
|
-
this._core.start();
|
|
1178
|
-
}
|
|
1241
|
+
// 制約の変化は取得の判断(_scheduleAcquire)へまとめる: 接続時の判断待ちならそれが
|
|
1242
|
+
// 新しい制約を読み、その後ならストリームが生きているときだけ取り直す
|
|
1243
|
+
this._scheduleAcquire();
|
|
1179
1244
|
}
|
|
1180
1245
|
_onVisibilityChange = () => {
|
|
1181
1246
|
if (this.keepAlive)
|
|
@@ -1270,9 +1335,11 @@ class RecorderCore extends EventTarget {
|
|
|
1270
1335
|
// asynchronous probe to await — readiness is immediate.
|
|
1271
1336
|
_ready = Promise.resolve();
|
|
1272
1337
|
/**
|
|
1273
|
-
* Whether `[wcs/command-not-ready]` was said
|
|
1338
|
+
* Whether `[wcs/command-not-ready]` was said in this outage: a `start()` refused because the
|
|
1274
1339
|
* element is not ready loses what it carried, and `error` alone told only a page that binds it.
|
|
1275
|
-
* Said once per
|
|
1340
|
+
* Said once per outage (docs/v4-direction-2026-10.md, the I/O command policy): a stream arriving
|
|
1341
|
+
* resets it. Once per element was once per page life — a route puts the same element back on
|
|
1342
|
+
* every entry, so the next outage's lost recording went unsaid (docs/seam-apps.md, shift-desk).
|
|
1276
1343
|
*/
|
|
1277
1344
|
_toldNotReady = false;
|
|
1278
1345
|
constructor(target) {
|
|
@@ -1358,6 +1425,9 @@ class RecorderCore extends EventTarget {
|
|
|
1358
1425
|
*/
|
|
1359
1426
|
attachStream(stream) {
|
|
1360
1427
|
this._stream = stream;
|
|
1428
|
+
// ready again: a start refused in the next outage is said again
|
|
1429
|
+
if (stream)
|
|
1430
|
+
this._toldNotReady = false;
|
|
1361
1431
|
}
|
|
1362
1432
|
/** Start recording the borrowed stream. Never throws — surfaces `error`. */
|
|
1363
1433
|
start(options = {}) {
|
|
@@ -1470,7 +1540,8 @@ class RecorderCore extends EventTarget {
|
|
|
1470
1540
|
return;
|
|
1471
1541
|
this._toldNotReady = true;
|
|
1472
1542
|
console.warn("[@wcstack/camera] [wcs/command-not-ready] start() was refused: no stream is attached, so nothing is recorded. " +
|
|
1473
|
-
"It goes to `error` too. Wire a camera's stream to the recorder first.
|
|
1543
|
+
"It goes to `error` too. Wire a camera's stream to the recorder first. " +
|
|
1544
|
+
"(Said once until a stream is attached again.)", this._target);
|
|
1474
1545
|
}
|
|
1475
1546
|
/** Stop recording; the assembled Blob is published from the recorder's onstop. */
|
|
1476
1547
|
stop() {
|