@spatialwalk/avatarkit 1.0.0-beta.51 → 1.0.0-beta.53
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
CHANGED
|
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.0-beta.53] - 2025-01-05
|
|
9
|
+
|
|
10
|
+
### 🐛 Bugfix
|
|
11
|
+
- **Race Condition Fix** - Fixed race condition where `startStreamingPlaybackInternal()` could be called multiple times when `yieldKeyframes` received data rapidly, causing audio chunks to be cleared and playback to freeze after transition animations. Added `isStartingPlayback` flag to prevent concurrent execution.
|
|
12
|
+
|
|
13
|
+
## [1.0.0-beta.52] - 2025-01-05
|
|
14
|
+
|
|
15
|
+
### 🔧 Performance Improvements
|
|
16
|
+
- **Telemetry Optimization** - Consolidated resource download telemetry: removed individual `resource_download` events and added cache information (`cache_hit`, `cache_type`) to total duration metrics (`template_resources_load_measure` and `download_avatar_assets_total_measure`). This enables analysis of download times for cache misses while reducing telemetry overhead.
|
|
17
|
+
|
|
8
18
|
## [1.0.0-beta.51] - 2025-01-05
|
|
9
19
|
|
|
10
20
|
### 🐛 Bugfix
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import { A as APP_CONFIG, e as errorToMessage, l as logEvent, a as logger } from "./index-
|
|
4
|
+
import { A as APP_CONFIG, e as errorToMessage, l as logEvent, a as logger } from "./index-CLKS00Ly.js";
|
|
5
5
|
class StreamingAudioPlayer {
|
|
6
6
|
constructor(options) {
|
|
7
7
|
__publicField(this, "audioContext", null);
|
|
@@ -7579,7 +7579,7 @@ const _AnimationPlayer = class _AnimationPlayer {
|
|
|
7579
7579
|
if (this.streamingPlayer) {
|
|
7580
7580
|
return;
|
|
7581
7581
|
}
|
|
7582
|
-
const { StreamingAudioPlayer } = await import("./StreamingAudioPlayer-
|
|
7582
|
+
const { StreamingAudioPlayer } = await import("./StreamingAudioPlayer-DNLrXB1O.js");
|
|
7583
7583
|
const { AvatarSDK: AvatarSDK2 } = await Promise.resolve().then(() => AvatarSDK$1);
|
|
7584
7584
|
const audioFormat = AvatarSDK2.getAudioFormat();
|
|
7585
7585
|
this.streamingPlayer = new StreamingAudioPlayer({
|
|
@@ -8969,7 +8969,7 @@ class AvatarSDK {
|
|
|
8969
8969
|
}
|
|
8970
8970
|
__publicField(AvatarSDK, "_isInitialized", false);
|
|
8971
8971
|
__publicField(AvatarSDK, "_configuration", null);
|
|
8972
|
-
__publicField(AvatarSDK, "_version", "1.0.0-beta.
|
|
8972
|
+
__publicField(AvatarSDK, "_version", "1.0.0-beta.53");
|
|
8973
8973
|
__publicField(AvatarSDK, "_avatarCore", null);
|
|
8974
8974
|
__publicField(AvatarSDK, "_dynamicSdkConfig", null);
|
|
8975
8975
|
const AvatarSDK$1 = Object.freeze(Object.defineProperty({
|
|
@@ -10619,6 +10619,7 @@ class AvatarController {
|
|
|
10619
10619
|
__publicField(this, "currentKeyframes", []);
|
|
10620
10620
|
__publicField(this, "pendingAudioChunks", []);
|
|
10621
10621
|
__publicField(this, "isPlaying", false);
|
|
10622
|
+
__publicField(this, "isStartingPlayback", false);
|
|
10622
10623
|
__publicField(this, "isConnected", false);
|
|
10623
10624
|
__publicField(this, "currentState", AvatarState.idle);
|
|
10624
10625
|
__publicField(this, "currentConversationId", null);
|
|
@@ -10960,9 +10961,10 @@ class AvatarController {
|
|
|
10960
10961
|
this.currentKeyframes.push(...keyframes);
|
|
10961
10962
|
}
|
|
10962
10963
|
this.emit("keyframesUpdate", this.currentKeyframes);
|
|
10963
|
-
if (!this.isPlaying && this.pendingAudioChunks.length > 0 && this.currentKeyframes.length > 0) {
|
|
10964
|
+
if (!this.isPlaying && !this.isStartingPlayback && this.pendingAudioChunks.length > 0 && this.currentKeyframes.length > 0) {
|
|
10964
10965
|
this.startStreamingPlayback().catch((error) => {
|
|
10965
10966
|
var _a;
|
|
10967
|
+
this.isStartingPlayback = false;
|
|
10966
10968
|
logger.error("[AvatarController] Failed to auto-start playback:", error);
|
|
10967
10969
|
(_a = this.onError) == null ? void 0 : _a.call(this, new SPAvatarError("Failed to start playback", "PLAYBACK_START_FAILED"));
|
|
10968
10970
|
});
|
|
@@ -11185,6 +11187,14 @@ class AvatarController {
|
|
|
11185
11187
|
}
|
|
11186
11188
|
async startStreamingPlaybackInternal() {
|
|
11187
11189
|
var _a, _b, _c;
|
|
11190
|
+
if (this.isPlaying) {
|
|
11191
|
+
this.isStartingPlayback = false;
|
|
11192
|
+
return;
|
|
11193
|
+
}
|
|
11194
|
+
if (this.isStartingPlayback) {
|
|
11195
|
+
return;
|
|
11196
|
+
}
|
|
11197
|
+
this.isStartingPlayback = true;
|
|
11188
11198
|
if (!this.animationPlayer) {
|
|
11189
11199
|
this.animationPlayer = new AnimationPlayer();
|
|
11190
11200
|
}
|
|
@@ -11192,6 +11202,7 @@ class AvatarController {
|
|
|
11192
11202
|
try {
|
|
11193
11203
|
await this.animationPlayer.createAndInitializeStreamingPlayer();
|
|
11194
11204
|
} catch (error) {
|
|
11205
|
+
this.isStartingPlayback = false;
|
|
11195
11206
|
const message = error instanceof Error ? error.message : String(error);
|
|
11196
11207
|
logger.error("[AvatarController] Failed to create streaming player:", message);
|
|
11197
11208
|
logEvent("character_player", "error", {
|
|
@@ -11203,6 +11214,7 @@ class AvatarController {
|
|
|
11203
11214
|
}
|
|
11204
11215
|
}
|
|
11205
11216
|
if (!this.currentKeyframes || this.currentKeyframes.length === 0) {
|
|
11217
|
+
this.isStartingPlayback = false;
|
|
11206
11218
|
logger.warn("[AvatarController] No animation data to play");
|
|
11207
11219
|
return;
|
|
11208
11220
|
}
|
|
@@ -11240,6 +11252,7 @@ class AvatarController {
|
|
|
11240
11252
|
this.currentState = AvatarState.playing;
|
|
11241
11253
|
(_a = this.onConversationState) == null ? void 0 : _a.call(this, this.mapToConversationState(AvatarState.playing));
|
|
11242
11254
|
this.startPlaybackLoop();
|
|
11255
|
+
this.isStartingPlayback = false;
|
|
11243
11256
|
logEvent("character_player", "info", {
|
|
11244
11257
|
avatar_id: this.avatar.id,
|
|
11245
11258
|
event: "playback_started",
|
|
@@ -11250,6 +11263,7 @@ class AvatarController {
|
|
|
11250
11263
|
logger.error("[AvatarController] Failed to start streaming playback:", message);
|
|
11251
11264
|
(_c = this.onError) == null ? void 0 : _c.call(this, new SPAvatarError("Failed to start streaming playback", "INIT_FAILED"));
|
|
11252
11265
|
this.isPlaying = false;
|
|
11266
|
+
this.isStartingPlayback = false;
|
|
11253
11267
|
}
|
|
11254
11268
|
}
|
|
11255
11269
|
checkPlaybackStuck(audioTime) {
|
|
@@ -11506,6 +11520,7 @@ class AvatarController {
|
|
|
11506
11520
|
stopPlayback() {
|
|
11507
11521
|
var _a;
|
|
11508
11522
|
this.stopPlaybackLoop();
|
|
11523
|
+
this.isStartingPlayback = false;
|
|
11509
11524
|
if (this.animationPlayer) {
|
|
11510
11525
|
this.animationPlayer.stop();
|
|
11511
11526
|
const streamingPlayer = this.animationPlayer.getStreamingPlayer();
|
|
@@ -11915,24 +11930,16 @@ class AvatarDownloader {
|
|
|
11915
11930
|
}
|
|
11916
11931
|
updateProgress(resourceName, false);
|
|
11917
11932
|
logger.log(`📥 Loading ${key} from API CDN: ${url}`);
|
|
11918
|
-
const { data: buffer
|
|
11933
|
+
const { data: buffer } = await downloadResource(url, { resourceType: "template" });
|
|
11919
11934
|
logger.log(`✅ ${key} loaded: ${buffer.byteLength} bytes`);
|
|
11920
11935
|
templateResources[key] = buffer;
|
|
11921
11936
|
updateProgress(resourceName, true);
|
|
11922
|
-
logEvent("resource_download", "info", {
|
|
11923
|
-
resource_type: "template",
|
|
11924
|
-
resource_name: resourceName,
|
|
11925
|
-
cache_hit: cacheInfo.cacheHit,
|
|
11926
|
-
cache_type: cacheInfo.cacheType,
|
|
11927
|
-
pwa_cache_subtype: cacheInfo.pwaCacheSubtype,
|
|
11928
|
-
transfer_size: cacheInfo.transferSize,
|
|
11929
|
-
cdn_cache_status: cacheInfo.cdnCacheStatus
|
|
11930
|
-
});
|
|
11931
11937
|
});
|
|
11932
11938
|
await Promise.all(promises);
|
|
11933
11939
|
return templateResources;
|
|
11934
11940
|
}
|
|
11935
11941
|
async loadGlobalFlameResources(progressCallback = null) {
|
|
11942
|
+
var _a;
|
|
11936
11943
|
await PwaCacheManager.checkTemplateCacheVersion();
|
|
11937
11944
|
const startTime = Date.now();
|
|
11938
11945
|
const { cdnBaseUrl, resources } = APP_CONFIG.flame;
|
|
@@ -11970,6 +11977,7 @@ class AvatarDownloader {
|
|
|
11970
11977
|
}
|
|
11971
11978
|
};
|
|
11972
11979
|
const templateResources = {};
|
|
11980
|
+
const cacheInfos = [];
|
|
11973
11981
|
try {
|
|
11974
11982
|
const promises = Object.entries(templateFiles).map(async ([key, { url, resourceName }]) => {
|
|
11975
11983
|
updateProgress(resourceName, false);
|
|
@@ -11977,22 +11985,18 @@ class AvatarDownloader {
|
|
|
11977
11985
|
const { data: buffer, cacheInfo } = await downloadResource(url, { resourceType: "template" });
|
|
11978
11986
|
logger.log(`✅ ${key} loaded: ${buffer.byteLength} bytes`);
|
|
11979
11987
|
templateResources[key] = buffer;
|
|
11988
|
+
cacheInfos.push(cacheInfo);
|
|
11980
11989
|
updateProgress(resourceName, true);
|
|
11981
|
-
logEvent("resource_download", "info", {
|
|
11982
|
-
resource_type: "template",
|
|
11983
|
-
resource_name: resourceName,
|
|
11984
|
-
cache_hit: cacheInfo.cacheHit,
|
|
11985
|
-
cache_type: cacheInfo.cacheType,
|
|
11986
|
-
pwa_cache_subtype: cacheInfo.pwaCacheSubtype,
|
|
11987
|
-
transfer_size: cacheInfo.transferSize,
|
|
11988
|
-
cdn_cache_status: cacheInfo.cdnCacheStatus
|
|
11989
|
-
});
|
|
11990
11990
|
});
|
|
11991
11991
|
await Promise.all(promises);
|
|
11992
|
+
const cacheHit = cacheInfos.length > 0 && cacheInfos.every((info) => info.cacheHit);
|
|
11993
|
+
const cacheType = ((_a = cacheInfos[0]) == null ? void 0 : _a.cacheType) || "none";
|
|
11992
11994
|
const duration = Date.now() - startTime;
|
|
11993
11995
|
logEvent("template_resources_load_measure", "info", {
|
|
11994
11996
|
duration,
|
|
11995
|
-
file_count: totalFiles
|
|
11997
|
+
file_count: totalFiles,
|
|
11998
|
+
cache_hit: cacheHit,
|
|
11999
|
+
cache_type: cacheType
|
|
11996
12000
|
});
|
|
11997
12001
|
return templateResources;
|
|
11998
12002
|
} catch (error) {
|
|
@@ -12008,21 +12012,12 @@ class AvatarDownloader {
|
|
|
12008
12012
|
}
|
|
12009
12013
|
try {
|
|
12010
12014
|
logger.log(`📥 Loading camera info from: ${cameraUrl}`);
|
|
12011
|
-
const { data: arrayBuffer
|
|
12015
|
+
const { data: arrayBuffer } = await downloadResource(cameraUrl, {
|
|
12012
12016
|
characterId: characterMeta.characterId ?? void 0,
|
|
12013
12017
|
resourceType: "character"
|
|
12014
12018
|
});
|
|
12015
12019
|
const text = new TextDecoder().decode(arrayBuffer);
|
|
12016
12020
|
const cameraSettings = JSON.parse(text);
|
|
12017
|
-
logEvent("resource_download", "info", {
|
|
12018
|
-
resource_type: "camera_settings",
|
|
12019
|
-
resource_name: "camera.json",
|
|
12020
|
-
cache_hit: cacheInfo.cacheHit,
|
|
12021
|
-
cache_type: cacheInfo.cacheType,
|
|
12022
|
-
pwa_cache_subtype: cacheInfo.pwaCacheSubtype,
|
|
12023
|
-
transfer_size: cacheInfo.transferSize,
|
|
12024
|
-
cdn_cache_status: cacheInfo.cdnCacheStatus
|
|
12025
|
-
});
|
|
12026
12021
|
logger.log("✅ Camera info loaded:", cameraSettings);
|
|
12027
12022
|
return cameraSettings;
|
|
12028
12023
|
} catch (error) {
|
|
@@ -12031,7 +12026,7 @@ class AvatarDownloader {
|
|
|
12031
12026
|
}
|
|
12032
12027
|
}
|
|
12033
12028
|
async loadCharacterData(characterMeta, options) {
|
|
12034
|
-
var _a, _b, _c, _d, _e2, _f, _g, _h, _i2;
|
|
12029
|
+
var _a, _b, _c, _d, _e2, _f, _g, _h, _i2, _j;
|
|
12035
12030
|
const { progressCallback = null } = options || {};
|
|
12036
12031
|
const totalStartTime = Date.now();
|
|
12037
12032
|
const shapeUrl = (_c = (_b = (_a = characterMeta.models) == null ? void 0 : _a.shape) == null ? void 0 : _b.resource) == null ? void 0 : _c.remote;
|
|
@@ -12068,6 +12063,7 @@ class AvatarDownloader {
|
|
|
12068
12063
|
}
|
|
12069
12064
|
};
|
|
12070
12065
|
const characterData = {};
|
|
12066
|
+
const cacheInfos = [];
|
|
12071
12067
|
const parallelStartTime = Date.now();
|
|
12072
12068
|
const downloadPromises = filesToLoad.map(async ({ key, url, filename, optional }) => {
|
|
12073
12069
|
updateProgress(filename, false);
|
|
@@ -12083,16 +12079,8 @@ class AvatarDownloader {
|
|
|
12083
12079
|
} else if (key === "idleAnimation") {
|
|
12084
12080
|
characterData.idleAnimation = arrayBuffer;
|
|
12085
12081
|
}
|
|
12082
|
+
cacheInfos.push(cacheInfo);
|
|
12086
12083
|
updateProgress(filename, true);
|
|
12087
|
-
logEvent("resource_download", "info", {
|
|
12088
|
-
resource_type: "character_asset",
|
|
12089
|
-
resource_name: filename,
|
|
12090
|
-
cache_hit: cacheInfo.cacheHit,
|
|
12091
|
-
cache_type: cacheInfo.cacheType,
|
|
12092
|
-
pwa_cache_subtype: cacheInfo.pwaCacheSubtype,
|
|
12093
|
-
transfer_size: cacheInfo.transferSize,
|
|
12094
|
-
cdn_cache_status: cacheInfo.cdnCacheStatus
|
|
12095
|
-
});
|
|
12096
12084
|
return { key, success: true, size: arrayBuffer.byteLength };
|
|
12097
12085
|
} catch (error) {
|
|
12098
12086
|
if (!optional) {
|
|
@@ -12114,6 +12102,8 @@ class AvatarDownloader {
|
|
|
12114
12102
|
});
|
|
12115
12103
|
throw new Error(reason);
|
|
12116
12104
|
}
|
|
12105
|
+
const cacheHit = cacheInfos.length > 0 && cacheInfos.every((info) => info.cacheHit);
|
|
12106
|
+
const cacheType = ((_j = cacheInfos[0]) == null ? void 0 : _j.cacheType) || "none";
|
|
12117
12107
|
const totalSize = Object.values(characterData).reduce((sum, buffer) => {
|
|
12118
12108
|
return sum + (buffer ? buffer.byteLength : 0);
|
|
12119
12109
|
}, 0);
|
|
@@ -12122,7 +12112,9 @@ class AvatarDownloader {
|
|
|
12122
12112
|
total_duration: totalDuration,
|
|
12123
12113
|
parallel_duration: parallelDuration,
|
|
12124
12114
|
total_size: totalSize,
|
|
12125
|
-
file_count: filesToLoad.length
|
|
12115
|
+
file_count: filesToLoad.length,
|
|
12116
|
+
cache_hit: cacheHit,
|
|
12117
|
+
cache_type: cacheType
|
|
12126
12118
|
});
|
|
12127
12119
|
return characterData;
|
|
12128
12120
|
}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED