@ateam-ai-mobile/expo 0.1.20 → 0.1.22
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/aiLive/provider.d.mts +26 -0
- package/dist/aiLive/provider.d.ts +26 -0
- package/dist/aiLive/provider.js +476 -0
- package/dist/aiLive/provider.js.map +1 -0
- package/dist/aiLive/provider.mjs +17 -0
- package/dist/aiLive/provider.mjs.map +1 -0
- package/dist/bootstrap.js +428 -7
- package/dist/bootstrap.js.map +1 -1
- package/dist/bootstrap.mjs +12 -8
- package/dist/bootstrap.mjs.map +1 -1
- package/dist/capabilities/index.d.mts +40 -1
- package/dist/capabilities/index.d.ts +40 -1
- package/dist/capabilities/index.js +49 -1
- package/dist/capabilities/index.js.map +1 -1
- package/dist/capabilities/index.mjs +54 -6
- package/dist/capabilities/index.mjs.map +1 -1
- package/dist/{chunk-42FP5DTO.mjs → chunk-2ZQEQJQ6.mjs} +1 -1
- package/dist/chunk-2ZQEQJQ6.mjs.map +1 -0
- package/dist/{chunk-KRGCWVDJ.mjs → chunk-4HJ5FO3S.mjs} +2 -2
- package/dist/{chunk-RZDAY2GS.mjs → chunk-GGEFDRQQ.mjs} +5 -5
- package/dist/chunk-GGEFDRQQ.mjs.map +1 -0
- package/dist/{chunk-SOUNJY7R.mjs → chunk-NH3CHSLR.mjs} +10 -10
- package/dist/chunk-PV2EHH2P.mjs +426 -0
- package/dist/chunk-PV2EHH2P.mjs.map +1 -0
- package/dist/{chunk-6JX222YX.mjs → chunk-WQK6PUBN.mjs} +9 -2
- package/dist/chunk-WQK6PUBN.mjs.map +1 -0
- package/dist/device/createDeviceProvider.js.map +1 -1
- package/dist/device/createDeviceProvider.mjs +6 -6
- package/dist/device-bridge/index.js +1 -1
- package/dist/device-bridge/index.js.map +1 -1
- package/dist/device-bridge/index.mjs +3 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/push/silentSync.js.map +1 -1
- package/dist/push/silentSync.mjs +5 -5
- package/dist/vision/index.d.mts +7 -1
- package/dist/vision/index.d.ts +7 -1
- package/dist/vision/index.js +8 -0
- package/dist/vision/index.js.map +1 -1
- package/dist/vision/index.mjs +3 -1
- package/ios/AdaVisionModule.swift +44 -1
- package/package.json +10 -4
- package/src/aiLive/provider.ts +331 -0
- package/src/aiLive/streamProtocol.ts +90 -0
- package/src/bootstrap.ts +7 -1
- package/src/capabilities/index.ts +2 -0
- package/src/capabilities/picturesToAi.ts +40 -0
- package/src/capabilities/store.ts +50 -0
- package/src/device-bridge/capabilities.ts +2 -1
- package/src/index.ts +3 -0
- package/src/vision/index.ts +14 -0
- package/dist/chunk-42FP5DTO.mjs.map +0 -1
- package/dist/chunk-6JX222YX.mjs.map +0 -1
- package/dist/chunk-RZDAY2GS.mjs.map +0 -1
- /package/dist/{chunk-KRGCWVDJ.mjs.map → chunk-4HJ5FO3S.mjs.map} +0 -0
- /package/dist/{chunk-SOUNJY7R.mjs.map → chunk-NH3CHSLR.mjs.map} +0 -0
package/dist/bootstrap.js
CHANGED
|
@@ -175,8 +175,8 @@ __export(bootstrap_exports, {
|
|
|
175
175
|
bootstrapExpoAdas: () => bootstrapExpoAdas
|
|
176
176
|
});
|
|
177
177
|
module.exports = __toCommonJS(bootstrap_exports);
|
|
178
|
-
var
|
|
179
|
-
var
|
|
178
|
+
var import_core3 = require("@ateam-ai-mobile/core");
|
|
179
|
+
var import_plugin_runtime4 = require("@ateam-ai-mobile/plugin-runtime");
|
|
180
180
|
var import_ui2 = require("@ateam-ai-mobile/ui");
|
|
181
181
|
|
|
182
182
|
// src/audio/index.ts
|
|
@@ -1901,6 +1901,12 @@ async function describe(id, maxLabels = 5) {
|
|
|
1901
1901
|
async function detectObjects(id, maxItems = 10, minConfidence = 0.25) {
|
|
1902
1902
|
return verb("detectObjects")(id, maxItems, minConfidence);
|
|
1903
1903
|
}
|
|
1904
|
+
async function jpegById(id, maxSide = 768, quality = 0.7) {
|
|
1905
|
+
if (native2 && typeof native2.jpegById !== "function") {
|
|
1906
|
+
throw new Error("sending pictures to AI needs a newer app build \u2014 this one cannot make a picture from a camera frame");
|
|
1907
|
+
}
|
|
1908
|
+
return verb("jpegById")(id, maxSide, quality);
|
|
1909
|
+
}
|
|
1904
1910
|
|
|
1905
1911
|
// src/maps/index.ts
|
|
1906
1912
|
var import_react_native3 = require("react-native");
|
|
@@ -2917,6 +2923,420 @@ function createDeviceProvider(config2) {
|
|
|
2917
2923
|
};
|
|
2918
2924
|
}
|
|
2919
2925
|
|
|
2926
|
+
// src/aiLive/provider.ts
|
|
2927
|
+
var import_core2 = require("@ateam-ai-mobile/core");
|
|
2928
|
+
var import_plugin_runtime3 = require("@ateam-ai-mobile/plugin-runtime");
|
|
2929
|
+
|
|
2930
|
+
// src/aiLive/streamProtocol.ts
|
|
2931
|
+
var STREAM_PATH = "/ws/stream";
|
|
2932
|
+
var SUBPROTOCOL = "adas.v1";
|
|
2933
|
+
var HEADER_BYTES = 14;
|
|
2934
|
+
var ENVELOPE_VERSION = 1;
|
|
2935
|
+
var CLOSE = Object.freeze({
|
|
2936
|
+
AUTH_MISSING: 4001,
|
|
2937
|
+
AUTH_FAILED: 4002,
|
|
2938
|
+
NO_SUCH_WORKSPACE: 4003,
|
|
2939
|
+
NOT_ENTITLED: 4004,
|
|
2940
|
+
BAD_REQUEST: 4400,
|
|
2941
|
+
UNKNOWN_KIND: 4404,
|
|
2942
|
+
TIMEOUT: 4408,
|
|
2943
|
+
OVER_LIMIT: 4429,
|
|
2944
|
+
TOO_BIG: 1009,
|
|
2945
|
+
CONSUMER_FAILING: 1011
|
|
2946
|
+
});
|
|
2947
|
+
function encodeFrame({ seq, tCapture, payload }) {
|
|
2948
|
+
const out = new Uint8Array(HEADER_BYTES + payload.length);
|
|
2949
|
+
const v = new DataView(out.buffer);
|
|
2950
|
+
v.setUint8(0, ENVELOPE_VERSION);
|
|
2951
|
+
v.setUint8(1, 0);
|
|
2952
|
+
v.setUint32(2, seq >>> 0, false);
|
|
2953
|
+
v.setFloat64(6, tCapture, false);
|
|
2954
|
+
out.set(payload, HEADER_BYTES);
|
|
2955
|
+
return out;
|
|
2956
|
+
}
|
|
2957
|
+
function openMessage(kind, params) {
|
|
2958
|
+
return JSON.stringify(params ? { type: "open", kind, params } : { type: "open", kind });
|
|
2959
|
+
}
|
|
2960
|
+
var CLOSE_MESSAGE = JSON.stringify({ type: "close" });
|
|
2961
|
+
function parseServerEvent(text2) {
|
|
2962
|
+
if (typeof text2 !== "string") return null;
|
|
2963
|
+
try {
|
|
2964
|
+
const m = JSON.parse(text2);
|
|
2965
|
+
return m && typeof m.event === "string" ? { event: m.event, data: m.data } : null;
|
|
2966
|
+
} catch {
|
|
2967
|
+
return null;
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
var WHY = {
|
|
2971
|
+
[CLOSE.AUTH_MISSING]: "The login or the workspace was missing. Sign in again and try once more.",
|
|
2972
|
+
[CLOSE.AUTH_FAILED]: "The login was refused. Sign in again and try once more.",
|
|
2973
|
+
[CLOSE.NO_SUCH_WORKSPACE]: "This workspace was not found.",
|
|
2974
|
+
[CLOSE.NOT_ENTITLED]: "This workspace may not stream right now.",
|
|
2975
|
+
[CLOSE.TIMEOUT]: "The connection to the AI timed out.",
|
|
2976
|
+
[CLOSE.OVER_LIMIT]: "Too many cameras are sending to this workspace. Stop another one first.",
|
|
2977
|
+
[CLOSE.TOO_BIG]: "A picture was too big to send.",
|
|
2978
|
+
[CLOSE.CONSUMER_FAILING]: "The AI stopped taking pictures. Check the live session in AI Models."
|
|
2979
|
+
};
|
|
2980
|
+
function describeClose(code, reason) {
|
|
2981
|
+
if (code === CLOSE.BAD_REQUEST && reason) return reason;
|
|
2982
|
+
return WHY[code] || (reason ? reason : `The connection to the AI closed (${code}).`);
|
|
2983
|
+
}
|
|
2984
|
+
var B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
2985
|
+
var B64_INDEX = (() => {
|
|
2986
|
+
const t = new Int16Array(256).fill(-1);
|
|
2987
|
+
for (let i = 0; i < 64; i++) t[B64.charCodeAt(i)] = i;
|
|
2988
|
+
return t;
|
|
2989
|
+
})();
|
|
2990
|
+
function base64ToBytes(b64) {
|
|
2991
|
+
const clean = b64.replace(/[^A-Za-z0-9+/]/g, "");
|
|
2992
|
+
const out = new Uint8Array(Math.floor(clean.length * 3 / 4));
|
|
2993
|
+
let o = 0, acc = 0, bits = 0;
|
|
2994
|
+
for (let i = 0; i < clean.length; i++) {
|
|
2995
|
+
acc = acc << 6 | B64_INDEX[clean.charCodeAt(i)];
|
|
2996
|
+
bits += 6;
|
|
2997
|
+
if (bits >= 8) {
|
|
2998
|
+
bits -= 8;
|
|
2999
|
+
out[o++] = acc >> bits & 255;
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
return o === out.length ? out : out.subarray(0, o);
|
|
3003
|
+
}
|
|
3004
|
+
|
|
3005
|
+
// src/aiLive/provider.ts
|
|
3006
|
+
var LIVE_KIND = "ai-models.live";
|
|
3007
|
+
var FRESH_MS2 = 3e3;
|
|
3008
|
+
var MAX_BUFFERED = 512 * 1024;
|
|
3009
|
+
var DEFAULT_CAMERA = { fps: 1, maxPx: 768 };
|
|
3010
|
+
var OPEN_TIMEOUT_MS = 2e4;
|
|
3011
|
+
var CLOSE_WAIT_MS = 3e3;
|
|
3012
|
+
var isEpisode = (d) => !!d && typeof d === "object" && typeof d.type === "string" && typeof d.class === "string" && typeof d.episodeId === "string" && typeof d.actorId === "string" && d.actorId.length > 0 && Number.isFinite(d.at);
|
|
3013
|
+
var defaultAiLiveDeps = () => ({
|
|
3014
|
+
WebSocketImpl: globalThis.WebSocket,
|
|
3015
|
+
wsBase: import_core2.getCoreWsUrl,
|
|
3016
|
+
token: import_core2.getToken,
|
|
3017
|
+
tenant: import_core2.getTenant,
|
|
3018
|
+
jpegById,
|
|
3019
|
+
now: Date.now,
|
|
3020
|
+
setInterval: (fn, ms) => setInterval(fn, ms),
|
|
3021
|
+
clearInterval: (h) => clearInterval(h),
|
|
3022
|
+
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
3023
|
+
clearTimeout: (h) => clearTimeout(h)
|
|
3024
|
+
});
|
|
3025
|
+
var idle = () => ({ state: "idle", camera: null, sent: 0, skipped: 0, lastEpisode: null, lastError: null });
|
|
3026
|
+
function createAiLiveProvider(overrides = {}) {
|
|
3027
|
+
const deps = { ...defaultAiLiveDeps(), ...overrides };
|
|
3028
|
+
let owner = null;
|
|
3029
|
+
let snap = idle();
|
|
3030
|
+
let ws = null;
|
|
3031
|
+
let loop = null;
|
|
3032
|
+
let visual = null;
|
|
3033
|
+
let allowed = () => false;
|
|
3034
|
+
let stopReason = null;
|
|
3035
|
+
let tearingDown = null;
|
|
3036
|
+
const waitingToStart = /* @__PURE__ */ new Map();
|
|
3037
|
+
const closedOf = /* @__PURE__ */ new WeakMap();
|
|
3038
|
+
let closingOnPurpose = false;
|
|
3039
|
+
let seq = 0;
|
|
3040
|
+
let busy = false;
|
|
3041
|
+
let gen = 0;
|
|
3042
|
+
let lastFrameId = null;
|
|
3043
|
+
let camera = DEFAULT_CAMERA;
|
|
3044
|
+
let lastOwner = null;
|
|
3045
|
+
const episodeCbs = /* @__PURE__ */ new Map();
|
|
3046
|
+
const snapCbs = /* @__PURE__ */ new Map();
|
|
3047
|
+
const sendingCbs = /* @__PURE__ */ new Set();
|
|
3048
|
+
let wasSending = false;
|
|
3049
|
+
const add = (m, who, cb) => {
|
|
3050
|
+
let set3 = m.get(who);
|
|
3051
|
+
if (!set3) {
|
|
3052
|
+
set3 = /* @__PURE__ */ new Set();
|
|
3053
|
+
m.set(who, set3);
|
|
3054
|
+
}
|
|
3055
|
+
set3.add(cb);
|
|
3056
|
+
return { unsubscribe: () => {
|
|
3057
|
+
set3.delete(cb);
|
|
3058
|
+
} };
|
|
3059
|
+
};
|
|
3060
|
+
const set2 = (patch) => {
|
|
3061
|
+
snap = { ...snap, ...patch };
|
|
3062
|
+
for (const cb of lastOwner && snapCbs.get(lastOwner) || []) {
|
|
3063
|
+
try {
|
|
3064
|
+
cb(snap);
|
|
3065
|
+
} catch {
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
const sending = snap.state === "starting" || snap.state === "sending";
|
|
3069
|
+
if (sending !== wasSending) {
|
|
3070
|
+
wasSending = sending;
|
|
3071
|
+
for (const cb of sendingCbs) {
|
|
3072
|
+
try {
|
|
3073
|
+
cb();
|
|
3074
|
+
} catch {
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
};
|
|
3079
|
+
function stopTimers() {
|
|
3080
|
+
if (loop != null) {
|
|
3081
|
+
deps.clearInterval(loop);
|
|
3082
|
+
loop = null;
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
async function slot() {
|
|
3086
|
+
const mySeq = seq++;
|
|
3087
|
+
const g = gen;
|
|
3088
|
+
const sock = ws;
|
|
3089
|
+
const current = () => g === gen && ws === sock && sock?.readyState === 1;
|
|
3090
|
+
const consentGone = () => {
|
|
3091
|
+
if (allowed()) return false;
|
|
3092
|
+
if (g === gen) void teardown("stopped", import_plugin_runtime3.CONSENT_TAKEN_BACK);
|
|
3093
|
+
return true;
|
|
3094
|
+
};
|
|
3095
|
+
if (consentGone()) return;
|
|
3096
|
+
if (busy || !current()) {
|
|
3097
|
+
set2({ skipped: snap.skipped + 1 });
|
|
3098
|
+
return;
|
|
3099
|
+
}
|
|
3100
|
+
if ((sock.bufferedAmount || 0) > MAX_BUFFERED) {
|
|
3101
|
+
set2({ skipped: snap.skipped + 1 });
|
|
3102
|
+
return;
|
|
3103
|
+
}
|
|
3104
|
+
busy = true;
|
|
3105
|
+
try {
|
|
3106
|
+
const v = await visual.getSnapshot();
|
|
3107
|
+
if (!current()) return;
|
|
3108
|
+
const f = v?.latest;
|
|
3109
|
+
const id = f?.handle?.id;
|
|
3110
|
+
const t = Number(f?.timestamp);
|
|
3111
|
+
if (!id || id === lastFrameId || !(deps.now() - t < FRESH_MS2)) {
|
|
3112
|
+
set2({ skipped: snap.skipped + 1 });
|
|
3113
|
+
return;
|
|
3114
|
+
}
|
|
3115
|
+
const b64 = await deps.jpegById(id, camera.maxPx, 0.7);
|
|
3116
|
+
if (!current() || consentGone()) return;
|
|
3117
|
+
const frame = encodeFrame({ seq: mySeq, tCapture: t, payload: base64ToBytes(b64) });
|
|
3118
|
+
sock.send(frame.buffer);
|
|
3119
|
+
lastFrameId = id;
|
|
3120
|
+
set2({ sent: snap.sent + 1 });
|
|
3121
|
+
} catch (e) {
|
|
3122
|
+
if (g === gen) set2({ skipped: snap.skipped + 1, lastError: String(e?.message || e) });
|
|
3123
|
+
} finally {
|
|
3124
|
+
if (g === gen) busy = false;
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
function openSocket() {
|
|
3128
|
+
return new Promise((resolve, reject) => {
|
|
3129
|
+
const token = deps.token();
|
|
3130
|
+
const tenant = deps.tenant();
|
|
3131
|
+
if (!token || !tenant) {
|
|
3132
|
+
reject(new Error("not signed in to a workspace"));
|
|
3133
|
+
return;
|
|
3134
|
+
}
|
|
3135
|
+
const url = `${deps.wsBase()}${STREAM_PATH}?tenant=${encodeURIComponent(tenant)}`;
|
|
3136
|
+
let opened = false;
|
|
3137
|
+
const sock = new deps.WebSocketImpl(url, [SUBPROTOCOL, `adas.bearer.${token}`]);
|
|
3138
|
+
ws = sock;
|
|
3139
|
+
sock.binaryType = "arraybuffer";
|
|
3140
|
+
let markClosed = () => {
|
|
3141
|
+
};
|
|
3142
|
+
closedOf.set(sock, new Promise((r) => {
|
|
3143
|
+
markClosed = r;
|
|
3144
|
+
}));
|
|
3145
|
+
const gaveUp = deps.setTimeout(() => {
|
|
3146
|
+
if (opened) return;
|
|
3147
|
+
reject(new Error("Core did not answer in time. Try again."));
|
|
3148
|
+
try {
|
|
3149
|
+
sock.close();
|
|
3150
|
+
} catch {
|
|
3151
|
+
}
|
|
3152
|
+
}, OPEN_TIMEOUT_MS);
|
|
3153
|
+
sock.onopen = () => {
|
|
3154
|
+
try {
|
|
3155
|
+
sock.send(openMessage(LIVE_KIND, { session: "own", source: "phone" }));
|
|
3156
|
+
} catch (e) {
|
|
3157
|
+
reject(e);
|
|
3158
|
+
}
|
|
3159
|
+
};
|
|
3160
|
+
sock.onmessage = (m) => {
|
|
3161
|
+
if (ws !== sock) return;
|
|
3162
|
+
const ev = parseServerEvent(m?.data);
|
|
3163
|
+
if (!ev) return;
|
|
3164
|
+
if (ev.event === "session" && !opened) {
|
|
3165
|
+
const c = ev.data?.camera;
|
|
3166
|
+
camera = c && Number(c.fps) > 0 && Number(c.maxPx) > 0 ? { fps: Number(c.fps), maxPx: Number(c.maxPx) } : DEFAULT_CAMERA;
|
|
3167
|
+
return;
|
|
3168
|
+
}
|
|
3169
|
+
if (ev.event === "opened" && !opened) {
|
|
3170
|
+
opened = true;
|
|
3171
|
+
deps.clearTimeout(gaveUp);
|
|
3172
|
+
resolve();
|
|
3173
|
+
return;
|
|
3174
|
+
}
|
|
3175
|
+
if (ev.event === "episode" && isEpisode(ev.data)) {
|
|
3176
|
+
const episode = ev.data;
|
|
3177
|
+
set2({ lastEpisode: episode });
|
|
3178
|
+
for (const cb of owner && episodeCbs.get(owner) || []) {
|
|
3179
|
+
try {
|
|
3180
|
+
cb(episode);
|
|
3181
|
+
} catch {
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
3185
|
+
};
|
|
3186
|
+
sock.onerror = () => {
|
|
3187
|
+
};
|
|
3188
|
+
sock.onclose = (c) => {
|
|
3189
|
+
markClosed();
|
|
3190
|
+
const why = describeClose(Number(c?.code), c?.reason);
|
|
3191
|
+
if (!opened) {
|
|
3192
|
+
deps.clearTimeout(gaveUp);
|
|
3193
|
+
reject(new Error(why));
|
|
3194
|
+
return;
|
|
3195
|
+
}
|
|
3196
|
+
if (closingOnPurpose || ws !== sock) return;
|
|
3197
|
+
void teardown("error", why);
|
|
3198
|
+
};
|
|
3199
|
+
});
|
|
3200
|
+
}
|
|
3201
|
+
function teardown(state, lastError) {
|
|
3202
|
+
if (tearingDown) return tearingDown;
|
|
3203
|
+
const p = teardownNow(state, lastError);
|
|
3204
|
+
tearingDown = p;
|
|
3205
|
+
void p.then(() => {
|
|
3206
|
+
}, () => {
|
|
3207
|
+
}).then(() => {
|
|
3208
|
+
if (tearingDown === p) tearingDown = null;
|
|
3209
|
+
});
|
|
3210
|
+
return p;
|
|
3211
|
+
}
|
|
3212
|
+
async function teardownNow(state, lastError) {
|
|
3213
|
+
stopReason = lastError;
|
|
3214
|
+
allowed = () => false;
|
|
3215
|
+
gen++;
|
|
3216
|
+
stopTimers();
|
|
3217
|
+
const sock = ws;
|
|
3218
|
+
ws = null;
|
|
3219
|
+
closingOnPurpose = true;
|
|
3220
|
+
try {
|
|
3221
|
+
if (sock && sock.readyState === 1) sock.send(CLOSE_MESSAGE);
|
|
3222
|
+
} catch {
|
|
3223
|
+
}
|
|
3224
|
+
try {
|
|
3225
|
+
sock?.close?.();
|
|
3226
|
+
} catch {
|
|
3227
|
+
}
|
|
3228
|
+
closingOnPurpose = false;
|
|
3229
|
+
const v = visual;
|
|
3230
|
+
visual = null;
|
|
3231
|
+
let gaveUp = null;
|
|
3232
|
+
const closed = sock && closedOf.get(sock);
|
|
3233
|
+
await Promise.all([
|
|
3234
|
+
(async () => {
|
|
3235
|
+
try {
|
|
3236
|
+
await v?.stop?.();
|
|
3237
|
+
} catch {
|
|
3238
|
+
}
|
|
3239
|
+
})(),
|
|
3240
|
+
closed ? Promise.race([closed, new Promise((r) => {
|
|
3241
|
+
gaveUp = deps.setTimeout(r, CLOSE_WAIT_MS);
|
|
3242
|
+
})]) : Promise.resolve()
|
|
3243
|
+
]);
|
|
3244
|
+
if (gaveUp != null) deps.clearTimeout(gaveUp);
|
|
3245
|
+
owner = null;
|
|
3246
|
+
set2({ state, lastError });
|
|
3247
|
+
}
|
|
3248
|
+
return {
|
|
3249
|
+
async start(opts, who, ctx) {
|
|
3250
|
+
if (tearingDown) {
|
|
3251
|
+
const wait = { cancelled: false };
|
|
3252
|
+
waitingToStart.set(who, wait);
|
|
3253
|
+
try {
|
|
3254
|
+
while (tearingDown) {
|
|
3255
|
+
try {
|
|
3256
|
+
await tearingDown;
|
|
3257
|
+
} catch {
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
} finally {
|
|
3261
|
+
if (waitingToStart.get(who) === wait) waitingToStart.delete(who);
|
|
3262
|
+
}
|
|
3263
|
+
if (wait.cancelled) throw Object.assign(new Error("aiLive: stopped before it started."), { code: "STOPPED" });
|
|
3264
|
+
}
|
|
3265
|
+
if (owner && owner !== who) throw Object.assign(new Error("aiLive: another screen is sending to AI right now. Close it first."), { code: "CONFLICT" });
|
|
3266
|
+
if (owner === who) return snap;
|
|
3267
|
+
const cam = opts?.camera === "front" ? "front" : "back";
|
|
3268
|
+
if (opts?.camera && opts.camera !== "front" && opts.camera !== "back") throw new Error(`aiLive: unknown camera "${String(opts.camera)}" \u2014 use "front" or "back"`);
|
|
3269
|
+
owner = who;
|
|
3270
|
+
lastOwner = who;
|
|
3271
|
+
visual = ctx.visual;
|
|
3272
|
+
allowed = typeof ctx.allowed === "function" ? ctx.allowed : () => false;
|
|
3273
|
+
gen++;
|
|
3274
|
+
seq = 0;
|
|
3275
|
+
lastFrameId = null;
|
|
3276
|
+
busy = false;
|
|
3277
|
+
const g = gen;
|
|
3278
|
+
const cameraOfScreen = ctx.visual;
|
|
3279
|
+
snap = { ...idle(), camera: cam };
|
|
3280
|
+
set2({ state: "starting" });
|
|
3281
|
+
const stillStarting = async () => {
|
|
3282
|
+
if (g === gen && !allowed()) await teardown("stopped", import_plugin_runtime3.CONSENT_TAKEN_BACK);
|
|
3283
|
+
if (g !== gen) throw Object.assign(new Error(stopReason || "aiLive: stopped before it started sending."), { code: "STOPPED" });
|
|
3284
|
+
};
|
|
3285
|
+
try {
|
|
3286
|
+
await stillStarting();
|
|
3287
|
+
camera = DEFAULT_CAMERA;
|
|
3288
|
+
if (g !== gen) throw Object.assign(new Error(stopReason || "aiLive: stopped before it started sending."), { code: "STOPPED" });
|
|
3289
|
+
await openSocket();
|
|
3290
|
+
await stillStarting();
|
|
3291
|
+
await cameraOfScreen.start({ intent: "stream", facing: cam });
|
|
3292
|
+
if (g !== gen) {
|
|
3293
|
+
try {
|
|
3294
|
+
await cameraOfScreen.stop?.();
|
|
3295
|
+
} catch {
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
await stillStarting();
|
|
3299
|
+
if (g !== gen) throw Object.assign(new Error(stopReason || "aiLive: stopped before it started sending."), { code: "STOPPED" });
|
|
3300
|
+
loop = deps.setInterval(() => {
|
|
3301
|
+
void slot();
|
|
3302
|
+
}, Math.max(200, Math.round(1e3 / camera.fps)));
|
|
3303
|
+
set2({ state: "sending" });
|
|
3304
|
+
return snap;
|
|
3305
|
+
} catch (e) {
|
|
3306
|
+
if (g !== gen) {
|
|
3307
|
+
throw e?.code === "STOPPED" ? e : Object.assign(new Error(stopReason || "aiLive: stopped before it started sending."), { code: "STOPPED" });
|
|
3308
|
+
}
|
|
3309
|
+
await teardown("error", String(e?.message || e));
|
|
3310
|
+
throw e;
|
|
3311
|
+
}
|
|
3312
|
+
},
|
|
3313
|
+
async stop(who, why) {
|
|
3314
|
+
const waiting = waitingToStart.get(who);
|
|
3315
|
+
if (waiting) waiting.cancelled = true;
|
|
3316
|
+
if (owner !== who) return;
|
|
3317
|
+
await teardown("stopped", why ?? null);
|
|
3318
|
+
},
|
|
3319
|
+
getSnapshot: (who) => lastOwner === who ? snap : idle(),
|
|
3320
|
+
onEpisode: (cb, who) => add(episodeCbs, who, cb),
|
|
3321
|
+
subscribe: (cb, who) => add(snapCbs, who, cb),
|
|
3322
|
+
forget(who) {
|
|
3323
|
+
episodeCbs.delete(who);
|
|
3324
|
+
snapCbs.delete(who);
|
|
3325
|
+
if (lastOwner === who && owner === null) {
|
|
3326
|
+
lastOwner = null;
|
|
3327
|
+
snap = idle();
|
|
3328
|
+
}
|
|
3329
|
+
},
|
|
3330
|
+
isSending: () => snap.state === "starting" || snap.state === "sending",
|
|
3331
|
+
subscribeSending(cb) {
|
|
3332
|
+
sendingCbs.add(cb);
|
|
3333
|
+
return { unsubscribe: () => {
|
|
3334
|
+
sendingCbs.delete(cb);
|
|
3335
|
+
} };
|
|
3336
|
+
}
|
|
3337
|
+
};
|
|
3338
|
+
}
|
|
3339
|
+
|
|
2920
3340
|
// src/oauth/expoOAuth.tsx
|
|
2921
3341
|
var import_react_native7 = require("react-native");
|
|
2922
3342
|
var import_google_signin = require("@react-native-google-signin/google-signin");
|
|
@@ -2996,7 +3416,7 @@ function bootstrapExpoAdas(opts) {
|
|
|
2996
3416
|
deviceProvider: createDeviceProvider({ reachabilityUrl: opts.reachabilityUrl })
|
|
2997
3417
|
});
|
|
2998
3418
|
for (const plugin of opts.nativePlugins ?? []) {
|
|
2999
|
-
for (const id of plugin.ids) (0,
|
|
3419
|
+
for (const id of plugin.ids) (0, import_plugin_runtime4.registerNativePlugin)(id, plugin.resolver);
|
|
3000
3420
|
}
|
|
3001
3421
|
const relay = opts.urls.relay;
|
|
3002
3422
|
(0, import_ui2.setPluginWebViewExtraHosts)(() => relay ? [relay()] : []);
|
|
@@ -3008,14 +3428,15 @@ function bootstrapExpoAdas(opts) {
|
|
|
3008
3428
|
(0, import_ui2.setCallAudioProvider)(createCallAudioProvider());
|
|
3009
3429
|
if (opts.onReachabilityChange) {
|
|
3010
3430
|
const onReach = opts.onReachabilityChange;
|
|
3011
|
-
(0,
|
|
3431
|
+
(0, import_core3.setAcsReachabilityReporter)({ up: () => onReach(true), down: () => onReach(false) });
|
|
3012
3432
|
}
|
|
3013
|
-
(0,
|
|
3433
|
+
(0, import_plugin_runtime4.setDeviceStateProvider)(
|
|
3014
3434
|
createDeviceState({ connectivity: connectivity_exports, location: location_exports })
|
|
3015
3435
|
);
|
|
3016
|
-
(0,
|
|
3436
|
+
(0, import_plugin_runtime4.setAiLiveProvider)(createAiLiveProvider());
|
|
3437
|
+
(0, import_plugin_runtime4.registerPlatformDeviceTools)();
|
|
3017
3438
|
(0, import_ui2.setUIActionNavigator)(opts.navigateToPlugin);
|
|
3018
|
-
(0,
|
|
3439
|
+
(0, import_core3.initAdas)({
|
|
3019
3440
|
coreUrl: opts.urls.core,
|
|
3020
3441
|
...opts.urls.voice ? { voiceUrl: opts.urls.voice } : {},
|
|
3021
3442
|
...opts.urls.consumerAuth ? { consumerAuthUrl: opts.urls.consumerAuth } : {},
|