@spatialwalk/avatarkit 1.0.0-beta.98 → 1.0.0-beta.99
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 +6 -0
- package/README.md +3 -3
- package/dist/{StreamingAudioPlayer-DEELveJ_.js → StreamingAudioPlayer-CLmftu1c.js} +6 -1
- package/dist/core/AvatarController.d.ts +11 -7
- package/dist/{index-DfE9mnfH.js → index-CnV_uOSq.js} +50 -25
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ 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.99]
|
|
9
|
+
|
|
10
|
+
### ✨ Features
|
|
11
|
+
|
|
12
|
+
- **Playback diagnostics** — Added telemetry events for audio buffer stall and frame starvation detection, improving visibility into playback interruption issues.
|
|
13
|
+
|
|
8
14
|
## [1.0.0-beta.98]
|
|
9
15
|
|
|
10
16
|
### 🐛 Bugfixes
|
package/README.md
CHANGED
|
@@ -716,8 +716,8 @@ const conversationId = avatarView.controller.getCurrentConversationId()
|
|
|
716
716
|
// Returns: Current conversationId for the active audio session, or null if no active session
|
|
717
717
|
|
|
718
718
|
// Volume control (affects only avatar audio player, not system volume)
|
|
719
|
-
avatarView.controller.
|
|
720
|
-
const currentVolume = avatarView.controller.
|
|
719
|
+
avatarView.controller.setVolume(0.5) // Set volume to 50% (0.0 to 1.0)
|
|
720
|
+
const currentVolume = avatarView.controller.getVolume() // Get current volume (0.0 to 1.0)
|
|
721
721
|
|
|
722
722
|
// Set event callbacks
|
|
723
723
|
avatarView.controller.onConnectionState = (state: ConnectionState) => {} // SDK mode only
|
|
@@ -745,7 +745,7 @@ avatarView.avatarTransform = { x: 0.5, y: 0, scale: 2.0 } // Right half, double
|
|
|
745
745
|
**Important Notes:**
|
|
746
746
|
- `start()` and `close()` are only available in SDK mode
|
|
747
747
|
- `yieldAudioData()` and `yieldFramesData()` are only available in Host mode
|
|
748
|
-
- `pause()`, `resume()`, `interrupt()`, `clear()`, `getCurrentConversationId()`, and `
|
|
748
|
+
- `pause()`, `resume()`, `interrupt()`, `clear()`, `getCurrentConversationId()`, `setVolume()`, and `getVolume()` are available in both modes
|
|
749
749
|
- The playback mode is determined when creating `AvatarView` and cannot be changed
|
|
750
750
|
|
|
751
751
|
## 🔧 Configuration
|
|
@@ -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, l as logger, e as errorToMessage, a as logEvent } from "./index-
|
|
4
|
+
import { A as APP_CONFIG, l as logger, e as errorToMessage, a as logEvent } from "./index-CnV_uOSq.js";
|
|
5
5
|
class StreamingAudioPlayer {
|
|
6
6
|
// Mark if AudioContext is being resumed, avoid concurrent resume requests
|
|
7
7
|
constructor(options) {
|
|
@@ -305,6 +305,11 @@ class StreamingAudioPlayer {
|
|
|
305
305
|
const lastChunk = this.audioChunks[this.scheduledChunks - 1];
|
|
306
306
|
if (lastChunk && !lastChunk.isLast) {
|
|
307
307
|
this.log("All audio chunks ended but end=false, pausing and setting autoContinue");
|
|
308
|
+
logEvent("character_player", "warning", {
|
|
309
|
+
event: "audio_buffer_stall",
|
|
310
|
+
scheduled_chunks: this.scheduledChunks,
|
|
311
|
+
audio_time: this.getCurrentTime()
|
|
312
|
+
});
|
|
308
313
|
this.autoContinue = true;
|
|
309
314
|
this.pause();
|
|
310
315
|
} else if (isLast) {
|
|
@@ -31,6 +31,8 @@ export declare class AvatarController {
|
|
|
31
31
|
private lastSyncLogTime;
|
|
32
32
|
private lastOutOfBoundsState;
|
|
33
33
|
private isFallbackMode;
|
|
34
|
+
private frameStarvationEvents;
|
|
35
|
+
private isFrameStarved;
|
|
34
36
|
private playbackStuckCheckState;
|
|
35
37
|
private readonly MAX_AUDIO_TIME_ZERO_COUNT;
|
|
36
38
|
private readonly MAX_AUDIO_TIME_STUCK_COUNT;
|
|
@@ -138,12 +140,14 @@ export declare class AvatarController {
|
|
|
138
140
|
*/
|
|
139
141
|
setPostProcessingConfig(config: PostProcessingConfig | null): void;
|
|
140
142
|
/**
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* @
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
* Set audio playback volume
|
|
144
|
+
* Note: This only controls the avatar audio player volume, not the system volume
|
|
145
|
+
* @param volume Volume value, range from 0.0 to 1.0 (0.0 = mute, 1.0 = max volume)
|
|
146
|
+
*/
|
|
147
|
+
setVolume(volume: number): void;
|
|
148
|
+
/**
|
|
149
|
+
* Get current audio playback volume
|
|
150
|
+
* @returns Current volume value (0.0 - 1.0)
|
|
146
151
|
*/
|
|
147
|
-
|
|
148
|
-
set volume(value: number);
|
|
152
|
+
getVolume(): number;
|
|
149
153
|
}
|
|
@@ -9510,7 +9510,7 @@ const _AnimationPlayer = class _AnimationPlayer {
|
|
|
9510
9510
|
if (this.streamingPlayer) {
|
|
9511
9511
|
return;
|
|
9512
9512
|
}
|
|
9513
|
-
const { StreamingAudioPlayer } = await import("./StreamingAudioPlayer-
|
|
9513
|
+
const { StreamingAudioPlayer } = await import("./StreamingAudioPlayer-CLmftu1c.js");
|
|
9514
9514
|
const { AvatarSDK: AvatarSDK2 } = await Promise.resolve().then(() => AvatarSDK$1);
|
|
9515
9515
|
const audioFormat = AvatarSDK2.getAudioFormat();
|
|
9516
9516
|
this.streamingPlayer = new StreamingAudioPlayer({
|
|
@@ -11531,7 +11531,7 @@ class AvatarSDK {
|
|
|
11531
11531
|
__publicField(AvatarSDK, "_initializationState", "uninitialized");
|
|
11532
11532
|
__publicField(AvatarSDK, "_initializingPromise", null);
|
|
11533
11533
|
__publicField(AvatarSDK, "_configuration", null);
|
|
11534
|
-
__publicField(AvatarSDK, "_version", "1.0.0-beta.
|
|
11534
|
+
__publicField(AvatarSDK, "_version", "1.0.0-beta.99");
|
|
11535
11535
|
__publicField(AvatarSDK, "_avatarCore", null);
|
|
11536
11536
|
__publicField(AvatarSDK, "_dynamicSdkConfig", null);
|
|
11537
11537
|
__publicField(AvatarSDK, "_cachedDeviceScore", null);
|
|
@@ -12626,6 +12626,9 @@ class AvatarController {
|
|
|
12626
12626
|
// ========== Fallback Mode ==========
|
|
12627
12627
|
__publicField(this, "isFallbackMode", false);
|
|
12628
12628
|
// 降级模式标志
|
|
12629
|
+
// ========== Frame Starvation Tracking ==========
|
|
12630
|
+
__publicField(this, "frameStarvationEvents", []);
|
|
12631
|
+
__publicField(this, "isFrameStarved", false);
|
|
12629
12632
|
// ========== Playback Stuck Detection ==========
|
|
12630
12633
|
__publicField(this, "playbackStuckCheckState", {
|
|
12631
12634
|
audioTimeZeroCount: 0,
|
|
@@ -13426,29 +13429,31 @@ class AvatarController {
|
|
|
13426
13429
|
}
|
|
13427
13430
|
}
|
|
13428
13431
|
/**
|
|
13429
|
-
*
|
|
13430
|
-
*
|
|
13431
|
-
* @
|
|
13432
|
-
* avatarView.controller.volume = 0.5
|
|
13433
|
-
* const current = avatarView.controller.volume
|
|
13432
|
+
* Set audio playback volume
|
|
13433
|
+
* Note: This only controls the avatar audio player volume, not the system volume
|
|
13434
|
+
* @param volume Volume value, range from 0.0 to 1.0 (0.0 = mute, 1.0 = max volume)
|
|
13434
13435
|
*/
|
|
13435
|
-
|
|
13436
|
-
var _a;
|
|
13437
|
-
return ((_a = this.animationPlayer) == null ? void 0 : _a.getVolume()) ?? 1;
|
|
13438
|
-
}
|
|
13439
|
-
set volume(value) {
|
|
13436
|
+
setVolume(volume) {
|
|
13440
13437
|
var _a;
|
|
13441
|
-
if (
|
|
13442
|
-
logger.warn(`[AvatarController] Volume out of range: ${
|
|
13443
|
-
|
|
13438
|
+
if (volume < 0 || volume > 1) {
|
|
13439
|
+
logger.warn(`[AvatarController] Volume out of range: ${volume}, clamping to [0, 1]`);
|
|
13440
|
+
volume = Math.max(0, Math.min(1, volume));
|
|
13444
13441
|
}
|
|
13445
|
-
(_a = this.animationPlayer) == null ? void 0 : _a.setVolume(
|
|
13442
|
+
(_a = this.animationPlayer) == null ? void 0 : _a.setVolume(volume);
|
|
13446
13443
|
logEvent("character_player", "info", {
|
|
13447
13444
|
avatar_id: this.avatar.id,
|
|
13448
13445
|
event: "volume_changed",
|
|
13449
|
-
volume
|
|
13446
|
+
volume
|
|
13450
13447
|
});
|
|
13451
13448
|
}
|
|
13449
|
+
/**
|
|
13450
|
+
* Get current audio playback volume
|
|
13451
|
+
* @returns Current volume value (0.0 - 1.0)
|
|
13452
|
+
*/
|
|
13453
|
+
getVolume() {
|
|
13454
|
+
var _a;
|
|
13455
|
+
return ((_a = this.animationPlayer) == null ? void 0 : _a.getVolume()) ?? 1;
|
|
13456
|
+
}
|
|
13452
13457
|
/**
|
|
13453
13458
|
* Provide interface for AvatarView to register internal events
|
|
13454
13459
|
* @internal
|
|
@@ -13493,11 +13498,27 @@ class AvatarController {
|
|
|
13493
13498
|
throw new AvatarError("Animation player not initialized", ErrorCode.animationPlayerNotInitialized);
|
|
13494
13499
|
}
|
|
13495
13500
|
await this.animationPlayer.prepareStreamingPlayer(() => {
|
|
13496
|
-
var _a2;
|
|
13501
|
+
var _a2, _b2;
|
|
13497
13502
|
this.isPlaying = false;
|
|
13498
13503
|
this.currentState = AvatarState.idle;
|
|
13499
13504
|
this.notifyConversationState(AvatarState.idle);
|
|
13500
13505
|
this.emit("stopRendering");
|
|
13506
|
+
if (this.frameStarvationEvents.length > 0) {
|
|
13507
|
+
logEvent("character_player", "warning", {
|
|
13508
|
+
event: "frame_starvation",
|
|
13509
|
+
avatar_id: this.avatar.id,
|
|
13510
|
+
conversationId: ((_a2 = this.networkLayer) == null ? void 0 : _a2.getCurrentConversationId()) || void 0,
|
|
13511
|
+
starvation_count: this.frameStarvationEvents.length,
|
|
13512
|
+
starvation_times: this.frameStarvationEvents.map((e2) => Number(e2.audioTime.toFixed(3)))
|
|
13513
|
+
});
|
|
13514
|
+
}
|
|
13515
|
+
this.frameStarvationEvents = [];
|
|
13516
|
+
this.isFrameStarved = false;
|
|
13517
|
+
logEvent("character_player", "info", {
|
|
13518
|
+
avatar_id: this.avatar.id,
|
|
13519
|
+
event: "playback_ended",
|
|
13520
|
+
conversationId: ((_b2 = this.networkLayer) == null ? void 0 : _b2.getCurrentConversationId()) || void 0
|
|
13521
|
+
});
|
|
13501
13522
|
this.clearPlaybackData();
|
|
13502
13523
|
if (this.networkLayer) {
|
|
13503
13524
|
this.networkLayer.resetConversationId();
|
|
@@ -13506,11 +13527,6 @@ class AvatarController {
|
|
|
13506
13527
|
}
|
|
13507
13528
|
this.reqEnd = false;
|
|
13508
13529
|
this.isFallbackMode = false;
|
|
13509
|
-
logEvent("character_player", "info", {
|
|
13510
|
-
avatar_id: this.avatar.id,
|
|
13511
|
-
event: "playback_ended",
|
|
13512
|
-
conversationId: ((_a2 = this.networkLayer) == null ? void 0 : _a2.getCurrentConversationId()) || void 0
|
|
13513
|
-
});
|
|
13514
13530
|
});
|
|
13515
13531
|
this.emit("startRendering");
|
|
13516
13532
|
const streamingPlayer = this.animationPlayer.getStreamingPlayer();
|
|
@@ -13628,6 +13644,7 @@ class AvatarController {
|
|
|
13628
13644
|
* @internal
|
|
13629
13645
|
*/
|
|
13630
13646
|
async computeAndRenderFrame(frameIndex, loopGeneration) {
|
|
13647
|
+
var _a;
|
|
13631
13648
|
let arrayIndex = frameIndex - this.keyframesOffset;
|
|
13632
13649
|
if (arrayIndex < 0) {
|
|
13633
13650
|
arrayIndex = 0;
|
|
@@ -13643,8 +13660,16 @@ class AvatarController {
|
|
|
13643
13660
|
this.lastSyncLogTime = now;
|
|
13644
13661
|
this.lastOutOfBoundsState = isOutOfBounds;
|
|
13645
13662
|
}
|
|
13646
|
-
|
|
13647
|
-
|
|
13663
|
+
if (!this.isFrameStarved) {
|
|
13664
|
+
this.isFrameStarved = true;
|
|
13665
|
+
const audioTime = ((_a = this.animationPlayer) == null ? void 0 : _a.getCurrentTime()) ?? 0;
|
|
13666
|
+
this.frameStarvationEvents.push({ audioTime });
|
|
13667
|
+
}
|
|
13668
|
+
} else {
|
|
13669
|
+
this.isFrameStarved = false;
|
|
13670
|
+
if (isOutOfBounds !== this.lastOutOfBoundsState) {
|
|
13671
|
+
this.lastOutOfBoundsState = isOutOfBounds;
|
|
13672
|
+
}
|
|
13648
13673
|
}
|
|
13649
13674
|
if (this.currentKeyframes.length > this.MAX_KEYFRAMES) {
|
|
13650
13675
|
const framesToKeep = this.KEYFRAMES_CLEANUP_THRESHOLD;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED