@spatius/avatarkit 1.3.1-beta.7 → 1.3.1
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/CHANGELOG.md +22 -0
- package/dist/{AvatarDownloader-B1tJTnIb.js → AvatarDownloader-DyhenPKd.js} +98 -43
- package/dist/{AvatarSDK-CTprrfJk.js → AvatarSDK-DgPvHU4L.js} +162 -2560
- package/dist/{OpusCodec-PWv7ynPp.js → OpusCodec-CXU7ysrU.js} +43 -9
- package/dist/{OpusDecoderProxy-m0fVN_M2.js → OpusDecoderProxy-Cq8Z_MZY.js} +19 -6
- package/dist/{OpusEncoderProxy-DiW21sBK.js → OpusEncoderProxy-CzY-VckE.js} +42 -7
- package/dist/{StreamingAudioPlayer-C6hgkvbK.js → StreamingAudioPlayer-CIJmBp3z.js} +2 -2
- package/dist/assets/{AvatarDownloader-LO9uuYvm.js → AvatarDownloader-G5FO1bVl.js} +96 -41
- package/dist/assets/{AvatarSDK-CPEeTeLT.js → AvatarSDK-C_Anluwp.js} +149 -12
- package/dist/assets/{OpusDecoderWorker.worker-CSSWn75M.js → OpusDecoderWorker.worker-C2T0afkj.js} +21 -5
- package/dist/assets/{OpusEncoderWorker.worker-q4TdCVDZ.js → OpusEncoderWorker.worker-DLYO9vPK.js} +53 -11
- package/dist/assets/{logger-DCzHWd4N.js → logger-YPooEAbA.js} +319 -126
- package/dist/core/AvatarController.d.ts +10 -0
- package/dist/{error-utils-BCZDCrc6.js → error-utils-BogEllAd.js} +1 -1
- package/dist/index.js +274 -43
- package/dist/internal-telemetry.d.ts +45 -20
- package/dist/internal-telemetry.js +27 -2
- package/dist/{logger-DdmfSEn-.js → logger-BOpQ7u0w.js} +336 -126
- package/dist/otel-trace-Ct4T48nC.js +2565 -0
- package/dist/{pwa-cache-manager-BMKyJWXI.js → pwa-cache-manager-C7NbU52Q.js} +1 -1
- package/dist/types/index.d.ts +30 -4
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as __exportAll } from "./rolldown-runtime-B-1-B7_t.js";
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as ContextAPI, A as addHrTimes, B as ATTR_SERVICE_NAME, C as createResource, D as resourceFromAttributes, E as defaultResource, F as millisToHrTime, G as suppressTracing, H as getStringFromEnv, I as otperformance, J as context, K as trace, L as ATTR_EXCEPTION_MESSAGE, M as hrTimeDuration, N as isTimeInput, O as BindOnceFuture, P as isTimeInputHrTime, Q as TraceFlags, R as ATTR_EXCEPTION_STACKTRACE, S as createInstrumentationScope, T as OTLPExporterBase, U as globalErrorHandler, V as getNumberFromEnv, W as isTracingSuppressed, X as isValidTraceId, Y as isSpanContextValid, Z as INVALID_SPAN_CONTEXT, _ as cleanupOtelMetrics, a as clientContextFields, at as registerGlobal, b as createLegacyOtlpBrowserExportDelegate, c as logEvent, ct as OTEL_PASSWORD, d as cleanupOtel, dt as OTEL_TRACES_STREAM_NAME, et as createNoopMeter, f as initializeOtel, ft as OTEL_USERNAME, g as observeExporter, i as cleanupPostHog, it as getGlobal, j as hrTime, k as ExportResultCode, lt as OTEL_STREAM_NAME, m as fetchBootstrap, mt as idManager, n as setLogLevel, nt as createContextKey, o as getLogsFeatureFlag, ot as unregisterGlobal, p as clockSync, q as diag$1, r as logSink, rt as DiagAPI, s as initializePostHog, st as OTEL_LOGS_ENDPOINT, t as logger, tt as ROOT_CONTEXT, u as updatePostHogPersonPropertiesForFlags, ut as OTEL_TRACES_ENDPOINT, v as initializeOtelMetrics, w as toAttributes, x as JSON_ENCODER, xt as LogLevel, yt as DrivingServiceMode, z as ATTR_EXCEPTION_TYPE } from "./logger-YPooEAbA.js";
|
|
3
3
|
//#region node_modules/.pnpm/@opentelemetry+api@1.9.1/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js
|
|
4
4
|
var BaggageImpl = class BaggageImpl {
|
|
5
5
|
constructor(entries) {
|
|
@@ -1040,13 +1040,20 @@ const avatarViewRegistry = new AvatarViewRegistry();
|
|
|
1040
1040
|
//#endregion
|
|
1041
1041
|
//#region utils/region-resolver.ts
|
|
1042
1042
|
/**
|
|
1043
|
-
* Region
|
|
1043
|
+
* Region 解析(区域自动调度)—— stale-while-revalidate
|
|
1044
1044
|
*
|
|
1045
|
-
* - region 为 'auto':调一次 bootstrap,用后台推荐的 region.current。
|
|
1046
1045
|
* - region 为具体值(用户手动指定):直接用,跳过调度。
|
|
1047
|
-
* - auto
|
|
1046
|
+
* - region 为 'auto' 且**有缓存**:立即返回缓存值,bootstrap 转后台异步跑、只更新缓存。
|
|
1047
|
+
* - region 为 'auto' 且**无缓存**(首次启动):同步等 bootstrap,拿到即用并写缓存。
|
|
1048
|
+
* - auto 无缓存且 bootstrap 失败:降级到默认 region(us-west),并上报一条 error 埋点
|
|
1048
1049
|
* (严重事件,供监控观测),不阻断初始化。
|
|
1049
1050
|
*
|
|
1051
|
+
* 为什么缓存优先:bootstrap 是一次网络往返,此前每次 init 都要等它(弱网下最多 5s
|
|
1052
|
+
* 超时)才能继续。实际上用户的接入区极少变动,用上次结果几乎总是对的。
|
|
1053
|
+
*
|
|
1054
|
+
* **后台刷新到的新值不影响本次会话**,只写缓存、下次启动生效。会话中途换接入域名
|
|
1055
|
+
* 会让已建立的 WS / 下到一半的资产指向另一个接入点,风险远大于「晚一次启动才切区」。
|
|
1056
|
+
*
|
|
1050
1057
|
* 与时钟校准(clock-sync)解耦:各自独立调 bootstrap,互不影响。
|
|
1051
1058
|
* @internal
|
|
1052
1059
|
*/
|
|
@@ -1071,6 +1078,32 @@ function readRegionCache() {
|
|
|
1071
1078
|
}
|
|
1072
1079
|
}
|
|
1073
1080
|
/**
|
|
1081
|
+
* 后台刷新 region 缓存:缓存命中时发起,**结果只写缓存、不影响本次会话**(见文件头)。
|
|
1082
|
+
*
|
|
1083
|
+
* 失败一律静默:本次会话已经拿着缓存值正常跑了,这条刷新失败不构成用户可见问题,
|
|
1084
|
+
* 报 error 埋点只会污染 `region_resolve_failed` 的告警语义(那条是「真的没 region 可用」)。
|
|
1085
|
+
* @internal
|
|
1086
|
+
*/
|
|
1087
|
+
async function refreshRegionCache(opts) {
|
|
1088
|
+
const controller = new AbortController();
|
|
1089
|
+
const timer = setTimeout(() => controller.abort(), RESOLVE_TIMEOUT_MS);
|
|
1090
|
+
try {
|
|
1091
|
+
const current = (await fetchBootstrap({
|
|
1092
|
+
appId: opts.appId,
|
|
1093
|
+
sdkVersion: opts.sdkVersion,
|
|
1094
|
+
region: "auto"
|
|
1095
|
+
}, controller.signal)).region?.current;
|
|
1096
|
+
if (typeof current === "string" && current.length > 0) {
|
|
1097
|
+
writeRegionCache(current);
|
|
1098
|
+
logger.log(`[RegionResolver] background refresh → ${current} (applies next launch)`);
|
|
1099
|
+
}
|
|
1100
|
+
} catch (error) {
|
|
1101
|
+
logger.log(`[RegionResolver] background refresh failed (cached value stays): ${error instanceof Error ? error.message : String(error)}`);
|
|
1102
|
+
} finally {
|
|
1103
|
+
clearTimeout(timer);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1074
1107
|
* 把请求的 region 解析成实际接入 region。
|
|
1075
1108
|
* @param requestedRegion 用户传入的 region('auto' 或具体值)
|
|
1076
1109
|
* @returns 实际接入 region(always a concrete value,不会是 'auto')
|
|
@@ -1079,6 +1112,15 @@ function readRegionCache() {
|
|
|
1079
1112
|
async function resolveRegion(opts) {
|
|
1080
1113
|
const { appId, sdkVersion, requestedRegion } = opts;
|
|
1081
1114
|
if (requestedRegion !== "auto") return requestedRegion;
|
|
1115
|
+
const cachedRegion = readRegionCache();
|
|
1116
|
+
if (cachedRegion !== null) {
|
|
1117
|
+
logger.log(`[RegionResolver] auto → ${cachedRegion} (cached, refreshing in background)`);
|
|
1118
|
+
refreshRegionCache({
|
|
1119
|
+
appId,
|
|
1120
|
+
sdkVersion
|
|
1121
|
+
});
|
|
1122
|
+
return cachedRegion;
|
|
1123
|
+
}
|
|
1082
1124
|
const controller = new AbortController();
|
|
1083
1125
|
const timer = setTimeout(() => controller.abort(), RESOLVE_TIMEOUT_MS);
|
|
1084
1126
|
try {
|
|
@@ -2318,6 +2360,7 @@ const OTEL_TRACER_NAME = "spatius-avatarkit";
|
|
|
2318
2360
|
let sdkVersion = "1.0.0";
|
|
2319
2361
|
let isInitialized = false;
|
|
2320
2362
|
let tracerProvider = null;
|
|
2363
|
+
let tracer = null;
|
|
2321
2364
|
const idGenerator = new PinnableIdGenerator();
|
|
2322
2365
|
function buildBasicAuthHeader() {
|
|
2323
2366
|
const credentials = `${OTEL_USERNAME}:${OTEL_PASSWORD}`;
|
|
@@ -2347,23 +2390,93 @@ function initializeOtelTrace(version, resourceAttrs) {
|
|
|
2347
2390
|
"dsm": resourceAttrs.dsm,
|
|
2348
2391
|
...clientContextFields()
|
|
2349
2392
|
}),
|
|
2350
|
-
spanProcessors: [new BatchSpanProcessor(new OTLPTraceExporter({
|
|
2393
|
+
spanProcessors: [new BatchSpanProcessor(observeExporter(new OTLPTraceExporter({
|
|
2351
2394
|
url: OTEL_TRACES_ENDPOINT,
|
|
2352
2395
|
headers: {
|
|
2353
2396
|
"Authorization": buildBasicAuthHeader(),
|
|
2354
2397
|
"stream-name": OTEL_TRACES_STREAM_NAME
|
|
2355
2398
|
}
|
|
2356
|
-
}))],
|
|
2399
|
+
}), "/v1/traces", OTEL_TRACES_ENDPOINT))],
|
|
2357
2400
|
idGenerator
|
|
2358
2401
|
});
|
|
2359
2402
|
trace.setGlobalTracerProvider(tracerProvider);
|
|
2360
|
-
trace.getTracer(OTEL_TRACER_NAME, sdkVersion);
|
|
2403
|
+
tracer = trace.getTracer(OTEL_TRACER_NAME, sdkVersion);
|
|
2361
2404
|
isInitialized = true;
|
|
2362
2405
|
logger.log(`[OTel-Trace] Initialized - endpoint: ${OTEL_TRACES_ENDPOINT}, stream: ${OTEL_TRACES_STREAM_NAME}`);
|
|
2363
2406
|
} catch (error) {
|
|
2364
2407
|
logger.warn("[OTel-Trace] Failed to initialize:", error instanceof Error ? error.message : String(error));
|
|
2365
2408
|
}
|
|
2366
2409
|
}
|
|
2410
|
+
/** 空实现:未初始化 / 被门禁拦截时返回,调用方无需判空。 */
|
|
2411
|
+
const NOOP_GROUP = {
|
|
2412
|
+
span: () => {},
|
|
2413
|
+
end: () => {}
|
|
2414
|
+
};
|
|
2415
|
+
const NOOP_TRACE = {
|
|
2416
|
+
span: () => {},
|
|
2417
|
+
group: () => NOOP_GROUP,
|
|
2418
|
+
end: () => {}
|
|
2419
|
+
};
|
|
2420
|
+
/**
|
|
2421
|
+
* 开一条**加载角色**的 trace。root span 名 `load_avatar`,覆盖 `AvatarManager` 加载
|
|
2422
|
+
* 全过程,内部按四段切子 span(见调用处)。
|
|
2423
|
+
*
|
|
2424
|
+
* 与播放 trace 的两点不同:
|
|
2425
|
+
* - **trace_id 随机**,不从业务 id 派生。加载链路上后端只参与元数据接口一处,串联需求
|
|
2426
|
+
* 弱;而按 avatar_id 派生会让同一角色的多次加载撞进同一条 trace,在 viewer 里叠成
|
|
2427
|
+
* 一条、时间轴错乱。avatar_id 作 span 属性照样能筛。
|
|
2428
|
+
* - **无 anchor / 不钉 span_id**:那两样是为了匹配已在线上的 traceparent,加载没有这个约束。
|
|
2429
|
+
*
|
|
2430
|
+
* 量级上远小于播放 trace:一次会话通常只加载一次角色,而对话是几十轮。
|
|
2431
|
+
* @internal
|
|
2432
|
+
*/
|
|
2433
|
+
/**
|
|
2434
|
+
* 开一条 **SDK 初始化** 的 trace。root span 名 `sdk_init`。
|
|
2435
|
+
*
|
|
2436
|
+
* 与 load / playback 是三条**独立** trace:它们本就是独立流程(初始化一次、加载可多次、
|
|
2437
|
+
* 对话更多次),硬串成一条会得到横跨整个 app 生命周期的怪 waterfall。三者靠 `session_id`
|
|
2438
|
+
* 关联——后台按它一查就能还原「这次启动做了什么」。
|
|
2439
|
+
*
|
|
2440
|
+
* 注意调用时机:trace 通道本身要到 `initializeOtelTrace` 之后才就绪,所以初始化早期
|
|
2441
|
+
* 阶段(region 解析等)只能先记时刻、等通道起来再用历史时间戳补发 span。
|
|
2442
|
+
* @internal
|
|
2443
|
+
*/
|
|
2444
|
+
function startInitTrace(sessionId, startTimeMs, attrs = {}) {
|
|
2445
|
+
if (!tracer || !tracerProvider) return NOOP_TRACE;
|
|
2446
|
+
try {
|
|
2447
|
+
const root = tracer.startSpan("sdk_init", {
|
|
2448
|
+
startTime: startTimeMs,
|
|
2449
|
+
attributes: {
|
|
2450
|
+
session_id: sessionId,
|
|
2451
|
+
...attrs
|
|
2452
|
+
}
|
|
2453
|
+
}, ROOT_CONTEXT);
|
|
2454
|
+
const rootCtx = trace.setSpan(ROOT_CONTEXT, root);
|
|
2455
|
+
return {
|
|
2456
|
+
span(name, startMs, endMs, spanAttrs = {}, isError = false) {
|
|
2457
|
+
try {
|
|
2458
|
+
const sp = tracer.startSpan(name, {
|
|
2459
|
+
startTime: startMs,
|
|
2460
|
+
attributes: spanAttrs
|
|
2461
|
+
}, rootCtx);
|
|
2462
|
+
if (isError) sp.setStatus({ code: SpanStatusCode.ERROR });
|
|
2463
|
+
sp.end(endMs);
|
|
2464
|
+
} catch {}
|
|
2465
|
+
},
|
|
2466
|
+
group: () => NOOP_GROUP,
|
|
2467
|
+
end(ok = true, endTimeMs, endAttrs = {}) {
|
|
2468
|
+
try {
|
|
2469
|
+
for (const [k, v] of Object.entries(endAttrs)) root.setAttribute(k, v);
|
|
2470
|
+
root.setStatus({ code: ok ? SpanStatusCode.OK : SpanStatusCode.ERROR });
|
|
2471
|
+
root.end(endTimeMs);
|
|
2472
|
+
} catch {}
|
|
2473
|
+
}
|
|
2474
|
+
};
|
|
2475
|
+
} catch (error) {
|
|
2476
|
+
logger.warn("[OTel-Trace] Failed to start init trace:", error instanceof Error ? error.message : String(error));
|
|
2477
|
+
return NOOP_TRACE;
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2367
2480
|
/**
|
|
2368
2481
|
* Cleanup:flush 剩余 span 并关闭 provider。
|
|
2369
2482
|
* @internal
|
|
@@ -2380,6 +2493,7 @@ function cleanupOtelTrace() {
|
|
|
2380
2493
|
} finally {
|
|
2381
2494
|
isInitialized = false;
|
|
2382
2495
|
tracerProvider = null;
|
|
2496
|
+
tracer = null;
|
|
2383
2497
|
}
|
|
2384
2498
|
}
|
|
2385
2499
|
//#endregion
|
|
@@ -6109,7 +6223,7 @@ var AvatarSDK = class {
|
|
|
6109
6223
|
static _initializationState = "uninitialized";
|
|
6110
6224
|
static _initializingPromise = null;
|
|
6111
6225
|
static _configuration = null;
|
|
6112
|
-
static _version = "1.3.1
|
|
6226
|
+
static _version = "1.3.1";
|
|
6113
6227
|
static _avatarCore = null;
|
|
6114
6228
|
static _cachedDeviceScore = null;
|
|
6115
6229
|
static _rendererBackend = null;
|
|
@@ -6157,8 +6271,9 @@ var AvatarSDK = class {
|
|
|
6157
6271
|
return this._initializingPromise;
|
|
6158
6272
|
}
|
|
6159
6273
|
static async _initializeInternal(appId, configuration) {
|
|
6274
|
+
const initStart = Date.now();
|
|
6275
|
+
const requestedRegion = configuration.region || "auto";
|
|
6160
6276
|
try {
|
|
6161
|
-
const requestedRegion = configuration.region || "auto";
|
|
6162
6277
|
logger.log(`[AvatarSDK] Initializing with appId: ${appId}, region: ${requestedRegion}`);
|
|
6163
6278
|
resetDeprecationWarnings();
|
|
6164
6279
|
setLogLevel(configuration.logLevel ?? LogLevel.off);
|
|
@@ -6166,6 +6281,7 @@ var AvatarSDK = class {
|
|
|
6166
6281
|
logger.log(`[AvatarSDK] Client ID: ${idManager.getClientId()}`);
|
|
6167
6282
|
const dsm = configuration.drivingServiceMode || DrivingServiceMode.direct;
|
|
6168
6283
|
const appIdValue = idManager.getAppId() || "";
|
|
6284
|
+
const regionStart = Date.now();
|
|
6169
6285
|
const region = await resolveRegion({
|
|
6170
6286
|
appId: appIdValue,
|
|
6171
6287
|
sdkVersion: this._version,
|
|
@@ -6176,8 +6292,8 @@ var AvatarSDK = class {
|
|
|
6176
6292
|
region
|
|
6177
6293
|
};
|
|
6178
6294
|
const af = this._configuration.audioFormat;
|
|
6179
|
-
if (af
|
|
6180
|
-
logger.warn(`[AvatarSDK]
|
|
6295
|
+
if (af && af.opusUplinkEnabled !== false && af.inputAudioFormat !== "opus" && !OPUS_UPLINK_SAMPLE_RATES.includes(af.sampleRate)) {
|
|
6296
|
+
logger.warn(`[AvatarSDK] Opus uplink is on but sampleRate=${af.sampleRate} is not Opus-compatible (supported: ${OPUS_UPLINK_SAMPLE_RATES}); disabling Opus uplink, sending raw PCM.`);
|
|
6181
6297
|
this._configuration = {
|
|
6182
6298
|
...this._configuration,
|
|
6183
6299
|
audioFormat: {
|
|
@@ -6190,6 +6306,7 @@ var AvatarSDK = class {
|
|
|
6190
6306
|
supported_rates: OPUS_UPLINK_SAMPLE_RATES.join(",")
|
|
6191
6307
|
});
|
|
6192
6308
|
}
|
|
6309
|
+
const regionEnd = Date.now();
|
|
6193
6310
|
initializePostHog(this._version, {
|
|
6194
6311
|
region,
|
|
6195
6312
|
dsm
|
|
@@ -6213,9 +6330,22 @@ var AvatarSDK = class {
|
|
|
6213
6330
|
appId: appIdValue,
|
|
6214
6331
|
sdkVersion: this._version
|
|
6215
6332
|
});
|
|
6333
|
+
const wasmStart = Date.now();
|
|
6216
6334
|
await this.initializeWASMModule();
|
|
6335
|
+
const templateStart = Date.now();
|
|
6217
6336
|
await this.initializeTemplateResources();
|
|
6218
6337
|
this._initializationState = "initialized";
|
|
6338
|
+
const initEnd = Date.now();
|
|
6339
|
+
const initTrace = startInitTrace(idManager.getSessionId(), initStart, {
|
|
6340
|
+
region,
|
|
6341
|
+
dsm
|
|
6342
|
+
});
|
|
6343
|
+
initTrace.span("prepare", initStart, regionStart);
|
|
6344
|
+
initTrace.span("resolve_region", regionStart, regionEnd);
|
|
6345
|
+
initTrace.span("init_telemetry", regionEnd, wasmStart);
|
|
6346
|
+
initTrace.span("init_wasm", wasmStart, templateStart);
|
|
6347
|
+
initTrace.span("load_template", templateStart, initEnd);
|
|
6348
|
+
initTrace.end(true, initEnd);
|
|
6219
6349
|
logEvent("sdk_initialized", "info", {});
|
|
6220
6350
|
logger.log(`[AvatarSDK] Successfully initialized`);
|
|
6221
6351
|
this._ensureDeviceScoreCached();
|
|
@@ -6224,6 +6354,13 @@ var AvatarSDK = class {
|
|
|
6224
6354
|
}, 0);
|
|
6225
6355
|
} catch (error) {
|
|
6226
6356
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6357
|
+
try {
|
|
6358
|
+
const failEnd = Date.now();
|
|
6359
|
+
startInitTrace(idManager.getSessionId(), initStart, {
|
|
6360
|
+
region: requestedRegion,
|
|
6361
|
+
dsm: configuration.drivingServiceMode || DrivingServiceMode.direct
|
|
6362
|
+
}).end(false, failEnd, { error: errorMessage });
|
|
6363
|
+
} catch {}
|
|
6227
6364
|
logger.error("Failed to initialize AvatarSDK:", errorMessage);
|
|
6228
6365
|
logEvent("sdk_startup", "error", { reason: errorMessage });
|
|
6229
6366
|
this._initializationState = "uninitialized";
|
|
@@ -6275,7 +6412,7 @@ var AvatarSDK = class {
|
|
|
6275
6412
|
logger.log("[AvatarSDK] Loading template resources...");
|
|
6276
6413
|
logEvent("template_init_start", "info", { stage: "sdk_init" });
|
|
6277
6414
|
try {
|
|
6278
|
-
const { AvatarDownloader } = await import("./AvatarDownloader-
|
|
6415
|
+
const { AvatarDownloader } = await import("./AvatarDownloader-G5FO1bVl.js");
|
|
6279
6416
|
const templateResources = await new AvatarDownloader().loadUnifiedTemplate();
|
|
6280
6417
|
if (await this._avatarCore.loadTemplateResourcesFromBuffers(templateResources)) logger.log("[AvatarSDK] Template resources initialized successfully");
|
|
6281
6418
|
else logger.log("[AvatarSDK] Template resources already initialized, skipping...");
|
package/dist/assets/{OpusDecoderWorker.worker-CSSWn75M.js → OpusDecoderWorker.worker-C2T0afkj.js}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as __toESM, t as __commonJSMin } from "./rolldown-runtime-B-1-B7_t.js";
|
|
2
|
-
import { t as logger } from "./logger-
|
|
2
|
+
import { t as logger } from "./logger-YPooEAbA.js";
|
|
3
3
|
//#region __vite-browser-external
|
|
4
4
|
var require___vite_browser_external = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
5
5
|
module.exports = {};
|
|
@@ -41185,9 +41185,15 @@ var OggOpusDecoder = class {
|
|
|
41185
41185
|
* trailing page is buffered until the rest arrives.
|
|
41186
41186
|
*
|
|
41187
41187
|
* @param oggBytes raw Ogg stream bytes (any slice boundary).
|
|
41188
|
+
* @param onSegment 可选:每解出一个 packet 就回调一次那一段 PCM。
|
|
41189
|
+
*
|
|
41190
|
+
* 给延迟打点用。`tap_N` 的语义是「第 N 秒音频进入播放链路的时刻」,若只在
|
|
41191
|
+
* decode 返回后按整块累计,宿主一次性喂进整段 Ogg 时所有 tap 会挤在同一个
|
|
41192
|
+
* 时刻(实测 tap_1/2/4 三条同值),送入节奏这个信息就没了。解码本来就是逐包
|
|
41193
|
+
* 进行的,把分段暴露出来,打点才能落在真实的音频时间轴上。
|
|
41188
41194
|
* @returns decoded PCM16 bytes, possibly empty.
|
|
41189
41195
|
*/
|
|
41190
|
-
decode(oggBytes) {
|
|
41196
|
+
decode(oggBytes, onSegment) {
|
|
41191
41197
|
const incoming = oggBytes instanceof Uint8Array ? oggBytes : new Uint8Array(oggBytes);
|
|
41192
41198
|
let buf;
|
|
41193
41199
|
if (this.carry.length > 0) {
|
|
@@ -41203,7 +41209,10 @@ var OggOpusDecoder = class {
|
|
|
41203
41209
|
offset = page.nextOffset;
|
|
41204
41210
|
for (const packet of page.packets) {
|
|
41205
41211
|
const pcm = this.decodePacket(packet);
|
|
41206
|
-
if (pcm.length > 0)
|
|
41212
|
+
if (pcm.length > 0) {
|
|
41213
|
+
pcmChunks.push(pcm);
|
|
41214
|
+
onSegment?.(pcm);
|
|
41215
|
+
}
|
|
41207
41216
|
}
|
|
41208
41217
|
}
|
|
41209
41218
|
this.carry = offset < buf.length ? buf.slice(offset) : /* @__PURE__ */ new Uint8Array(0);
|
|
@@ -41347,11 +41356,18 @@ self.onmessage = (e) => {
|
|
|
41347
41356
|
});
|
|
41348
41357
|
return;
|
|
41349
41358
|
}
|
|
41350
|
-
const
|
|
41359
|
+
const segments = [];
|
|
41360
|
+
const segmentTs = [];
|
|
41361
|
+
const pcm = decoder.decode(msg.ogg, (seg) => {
|
|
41362
|
+
segments.push(seg.length);
|
|
41363
|
+
segmentTs.push(performance.timeOrigin + performance.now());
|
|
41364
|
+
});
|
|
41351
41365
|
post({
|
|
41352
41366
|
type: "pcm",
|
|
41353
41367
|
seq: msg.seq,
|
|
41354
|
-
pcm: pcm.buffer
|
|
41368
|
+
pcm: pcm.buffer,
|
|
41369
|
+
segments,
|
|
41370
|
+
segmentTs
|
|
41355
41371
|
}, [pcm.buffer]);
|
|
41356
41372
|
break;
|
|
41357
41373
|
}
|
package/dist/assets/{OpusEncoderWorker.worker-q4TdCVDZ.js → OpusEncoderWorker.worker-DLYO9vPK.js}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as __toESM, t as __commonJSMin } from "./rolldown-runtime-B-1-B7_t.js";
|
|
2
|
-
import { t as logger } from "./logger-
|
|
2
|
+
import { t as logger } from "./logger-YPooEAbA.js";
|
|
3
3
|
//#region __vite-browser-external
|
|
4
4
|
var require___vite_browser_external = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
5
5
|
module.exports = {};
|
|
@@ -41423,12 +41423,26 @@ var OggOpusEncoder = class {
|
|
|
41423
41423
|
* @param end true on the final chunk of the req_id; flushes the tail and emits the EOS page.
|
|
41424
41424
|
* @returns Ogg page byte arrays to send over the socket, in order.
|
|
41425
41425
|
*/
|
|
41426
|
-
|
|
41426
|
+
/**
|
|
41427
|
+
* @param onFrame 可选:每编完一帧(20ms)回调一次,参数是这帧的 PCM 字节数。
|
|
41428
|
+
* 给延迟打点用——编码内部逐帧进行,但结果打成页一起返回;只按整批记时会把
|
|
41429
|
+
* 一次调用的全部耗时算成一段(实测 1068ms 一条),看不出编码速率是否稳定。
|
|
41430
|
+
* @param onPages 可选:**每凑满 1 秒音频就吐一批页**,让调用方边编边发。
|
|
41431
|
+
*
|
|
41432
|
+
* 不给这个回调时退化为老行为(全部编完一次性返回)。宿主一次性灌入整段音频时,
|
|
41433
|
+
* 老行为要等全部编完才发出第一个包——实测 12 秒音频编码 1105ms,首包上行就白等
|
|
41434
|
+
* 这 1105ms(起播 startup_buffering 1804ms 里大半是它)。编 1 秒发 1 秒后,
|
|
41435
|
+
* 首包在几十毫秒内就能上线。
|
|
41436
|
+
*/
|
|
41437
|
+
encode(reqId, pcm, end, onFrame, onPages) {
|
|
41427
41438
|
const pages = [];
|
|
41439
|
+
const emit = onPages ?? ((built) => {
|
|
41440
|
+
pages.push(...built);
|
|
41441
|
+
});
|
|
41428
41442
|
if (reqId !== this.currentReqId) {
|
|
41429
41443
|
this.currentReqId = reqId;
|
|
41430
41444
|
this.pcmRemainder = /* @__PURE__ */ new Int16Array(0);
|
|
41431
|
-
|
|
41445
|
+
emit(this.muxer.startStream(reqId));
|
|
41432
41446
|
}
|
|
41433
41447
|
const incoming = this.bytesToInt16(pcm);
|
|
41434
41448
|
let samples = incoming;
|
|
@@ -41438,18 +41452,29 @@ var OggOpusEncoder = class {
|
|
|
41438
41452
|
samples.set(incoming, this.pcmRemainder.length);
|
|
41439
41453
|
}
|
|
41440
41454
|
const frameGranule = this.muxer.toGranule(this.frameSamples);
|
|
41441
|
-
const
|
|
41455
|
+
const FRAMES_PER_SECOND = Math.round(1e3 / FRAME_MS);
|
|
41456
|
+
let packets = [];
|
|
41442
41457
|
let offset = 0;
|
|
41458
|
+
const flushPackets = () => {
|
|
41459
|
+
if (packets.length === 0) return;
|
|
41460
|
+
const built = this.muxer.addPackets(packets, frameGranule);
|
|
41461
|
+
packets = [];
|
|
41462
|
+
emit(built);
|
|
41463
|
+
};
|
|
41443
41464
|
while (samples.length - offset >= this.frameSamples) {
|
|
41444
41465
|
const frame = samples.subarray(offset, offset + this.frameSamples);
|
|
41445
41466
|
offset += this.frameSamples;
|
|
41446
41467
|
const packet = this.encodeFrame(frame);
|
|
41447
|
-
if (packet)
|
|
41468
|
+
if (packet) {
|
|
41469
|
+
packets.push(packet);
|
|
41470
|
+
onFrame?.(frame.length * 2);
|
|
41471
|
+
}
|
|
41472
|
+
if (onPages && packets.length >= FRAMES_PER_SECOND) flushPackets();
|
|
41448
41473
|
}
|
|
41449
|
-
|
|
41474
|
+
flushPackets();
|
|
41450
41475
|
this.pcmRemainder = samples.slice(offset);
|
|
41451
41476
|
if (end) {
|
|
41452
|
-
|
|
41477
|
+
emit(this.flush());
|
|
41453
41478
|
this.currentReqId = null;
|
|
41454
41479
|
}
|
|
41455
41480
|
return pages;
|
|
@@ -41538,15 +41563,32 @@ self.onmessage = (e) => {
|
|
|
41538
41563
|
});
|
|
41539
41564
|
return;
|
|
41540
41565
|
}
|
|
41541
|
-
const
|
|
41542
|
-
const
|
|
41566
|
+
const frames = [];
|
|
41567
|
+
const frameTs = [];
|
|
41568
|
+
encoder.encode(msg.reqId, msg.pcm, msg.end, (pcmBytes) => {
|
|
41569
|
+
frames.push(pcmBytes);
|
|
41570
|
+
frameTs.push(performance.timeOrigin + performance.now());
|
|
41571
|
+
}, (batch) => {
|
|
41572
|
+
const transfer = batch.map((p) => p.buffer);
|
|
41573
|
+
post({
|
|
41574
|
+
type: "pages",
|
|
41575
|
+
reqId: msg.reqId,
|
|
41576
|
+
seq: msg.seq,
|
|
41577
|
+
end: msg.end,
|
|
41578
|
+
pages: batch,
|
|
41579
|
+
last: false
|
|
41580
|
+
}, transfer);
|
|
41581
|
+
});
|
|
41543
41582
|
post({
|
|
41544
41583
|
type: "pages",
|
|
41545
41584
|
reqId: msg.reqId,
|
|
41546
41585
|
seq: msg.seq,
|
|
41547
41586
|
end: msg.end,
|
|
41548
|
-
pages
|
|
41549
|
-
|
|
41587
|
+
pages: [],
|
|
41588
|
+
frames,
|
|
41589
|
+
frameTs,
|
|
41590
|
+
last: true
|
|
41591
|
+
});
|
|
41550
41592
|
break;
|
|
41551
41593
|
}
|
|
41552
41594
|
case "destroy":
|