synxed-sdk 0.2.3 → 0.2.5
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/index.d.mts +168 -7
- package/dist/index.d.ts +168 -7
- package/dist/index.js +31 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +31 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -10
package/dist/index.d.mts
CHANGED
|
@@ -12,7 +12,14 @@ declare enum ContentKind {
|
|
|
12
12
|
SONG = 1,
|
|
13
13
|
PLAYLIST = 2,
|
|
14
14
|
CATEGORY = 3,
|
|
15
|
-
RADIO = 4
|
|
15
|
+
RADIO = 4,
|
|
16
|
+
VOICE = 5
|
|
17
|
+
}
|
|
18
|
+
declare enum SdkVoiceAction {
|
|
19
|
+
VOICE_UNSPECIFIED = 0,
|
|
20
|
+
VOICE_START = 1,
|
|
21
|
+
VOICE_CHUNK = 2,
|
|
22
|
+
VOICE_END = 3
|
|
16
23
|
}
|
|
17
24
|
declare enum ErrorCode {
|
|
18
25
|
UNSPECIFIED = 0,
|
|
@@ -32,6 +39,8 @@ interface SynxedConfig {
|
|
|
32
39
|
/** Listening context sent on init for ad targeting (e.g. "menu", "gameplay"). */
|
|
33
40
|
gameContext?: string;
|
|
34
41
|
deviceType?: string;
|
|
42
|
+
/** Default voice silence detection settings (used by `beginVoiceHold`). */
|
|
43
|
+
voice?: Omit<VoiceHoldOptions, 'listenerId'>;
|
|
35
44
|
}
|
|
36
45
|
interface PlaySongOptions {
|
|
37
46
|
catalogTrackId?: string;
|
|
@@ -66,6 +75,26 @@ interface PlayerState {
|
|
|
66
75
|
duration: number;
|
|
67
76
|
volume: number;
|
|
68
77
|
}
|
|
78
|
+
type VoiceState = 'idle' | 'listening' | 'processing' | 'ready' | 'error';
|
|
79
|
+
interface VoiceResult {
|
|
80
|
+
status: string;
|
|
81
|
+
transcript?: string;
|
|
82
|
+
playlistCode?: string;
|
|
83
|
+
playlistName?: string;
|
|
84
|
+
}
|
|
85
|
+
interface VoiceHoldOptions {
|
|
86
|
+
listenerId?: string;
|
|
87
|
+
/** Auto-end capture when the user stops talking. Default `true`. */
|
|
88
|
+
autoEndOnSilence?: boolean;
|
|
89
|
+
/** RMS level below which audio counts as silence (0–1). Default `0.018`. */
|
|
90
|
+
silenceThreshold?: number;
|
|
91
|
+
/** Ms of silence after speech before auto-end. Default `1500`. */
|
|
92
|
+
silenceDurationMs?: number;
|
|
93
|
+
/** Minimum speech ms before silence can trigger end. Default `400`. */
|
|
94
|
+
minSpeechMs?: number;
|
|
95
|
+
/** Max capture length in ms. Default `30000`. */
|
|
96
|
+
maxDurationMs?: number;
|
|
97
|
+
}
|
|
69
98
|
interface SynxedEvents {
|
|
70
99
|
stateChange: (state: PlayerState) => void;
|
|
71
100
|
timeUpdate: (time: {
|
|
@@ -76,6 +105,13 @@ interface SynxedEvents {
|
|
|
76
105
|
queueUpdated: (tracks: TrackInfo[]) => void;
|
|
77
106
|
adStart: (ad: AdInfo) => void;
|
|
78
107
|
adEnd: (ad: AdInfo) => void;
|
|
108
|
+
adSkipUpdate: (state: AdSkipState) => void;
|
|
109
|
+
voiceStateChange: (state: VoiceState) => void;
|
|
110
|
+
voiceResult: (result: VoiceResult) => void;
|
|
111
|
+
/** Mic level crossed above silence threshold — user started speaking. */
|
|
112
|
+
voiceSpeechStart: () => void;
|
|
113
|
+
/** Silence detected after speech — user stopped talking. */
|
|
114
|
+
voiceSpeechEnd: () => void;
|
|
79
115
|
error: (error: Error) => void;
|
|
80
116
|
connected: () => void;
|
|
81
117
|
disconnected: (reason: string) => void;
|
|
@@ -93,29 +129,69 @@ interface AdInfo {
|
|
|
93
129
|
companionBannerUrl: string;
|
|
94
130
|
campaignName: string;
|
|
95
131
|
}
|
|
132
|
+
/** Emitted while a skippable ad plays — use for custom skip UI (YouTube-style countdown). */
|
|
133
|
+
interface AdSkipState {
|
|
134
|
+
ad: AdInfo;
|
|
135
|
+
/** Seconds remaining before skip is allowed (0 when `canSkip` is true). */
|
|
136
|
+
countdownSeconds: number;
|
|
137
|
+
/** True once the ad has played for `skipAfterSeconds` (e.g. 5s). */
|
|
138
|
+
canSkip: boolean;
|
|
139
|
+
}
|
|
96
140
|
|
|
97
141
|
declare class SynxedPlayer extends EventEmitter<SynxedEvents> {
|
|
98
142
|
private transport;
|
|
99
143
|
private audio;
|
|
100
144
|
private playlist;
|
|
145
|
+
private voiceCapture;
|
|
101
146
|
private config;
|
|
102
147
|
private status;
|
|
103
148
|
private volume;
|
|
104
149
|
private activeContentKind;
|
|
105
150
|
private heartbeatTimer;
|
|
106
151
|
private adPlaying;
|
|
107
|
-
private
|
|
152
|
+
private _currentAd;
|
|
153
|
+
private _voiceState;
|
|
154
|
+
private voiceMimeType;
|
|
155
|
+
private voiceListenerId;
|
|
156
|
+
private pendingPlaybackLoad;
|
|
157
|
+
private voiceAutoEndOnSilence;
|
|
158
|
+
private pausedForVoice;
|
|
108
159
|
constructor(config: SynxedConfig);
|
|
109
160
|
get currentTrack(): TrackInfo | null;
|
|
110
161
|
/** Active playback init kind from the last `play*` call (RADIO, PLAYLIST, SONG, …). */
|
|
111
162
|
get contentKind(): ContentKind;
|
|
163
|
+
get currentAd(): AdInfo | null;
|
|
164
|
+
get isAdPlaying(): boolean;
|
|
165
|
+
/** True when a skippable ad has played for at least `skipAfterSeconds` (default 5s). */
|
|
166
|
+
canSkipAd(): boolean;
|
|
167
|
+
/** Seconds until skip unlocks; `0` when skip is available; `null` when not in a skippable ad. */
|
|
168
|
+
getAdSkipCountdownSeconds(): number | null;
|
|
169
|
+
get voiceState(): VoiceState;
|
|
112
170
|
private controlPositionMs;
|
|
113
171
|
private setupListeners;
|
|
172
|
+
private resolveVoiceOptions;
|
|
114
173
|
private connect;
|
|
115
174
|
private buildInitExtras;
|
|
116
175
|
playSong(options: PlaySongOptions): Promise<void>;
|
|
117
176
|
playPlaylist(options: PlayPlaylistOptions): Promise<void>;
|
|
118
177
|
playRadio(options?: PlayRadioOptions): Promise<void>;
|
|
178
|
+
/**
|
|
179
|
+
* Press-and-hold the DJ avatar (or call manually): start mic capture and stream chunks.
|
|
180
|
+
* Ends automatically when the user stops talking (`voiceSpeechEnd`) or call `endVoiceHold()`.
|
|
181
|
+
*/
|
|
182
|
+
beginVoiceHold(options?: VoiceHoldOptions): Promise<void>;
|
|
183
|
+
/**
|
|
184
|
+
* Release press-and-hold: flush final audio chunk and request playlist generation.
|
|
185
|
+
*/
|
|
186
|
+
endVoiceHold(): Promise<void>;
|
|
187
|
+
/** Cancel an in-progress voice hold without sending audio to the server. */
|
|
188
|
+
cancelVoiceHold(): void;
|
|
189
|
+
/**
|
|
190
|
+
* Close the voice UI: cancel recording if active and resume playback if it was
|
|
191
|
+
* paused for voice.
|
|
192
|
+
*/
|
|
193
|
+
dismissVoiceAndResume(): void;
|
|
194
|
+
get isVoiceUiActive(): boolean;
|
|
119
195
|
pause(): void;
|
|
120
196
|
resume(): void;
|
|
121
197
|
stop(): void;
|
|
@@ -129,7 +205,11 @@ declare class SynxedPlayer extends EventEmitter<SynxedEvents> {
|
|
|
129
205
|
private clearHeartbeat;
|
|
130
206
|
private startHeartbeat;
|
|
131
207
|
private applyContentSummary;
|
|
208
|
+
private emitAdSkipUpdate;
|
|
209
|
+
private setVoiceState;
|
|
210
|
+
private handleVoiceAck;
|
|
132
211
|
private handleServerMessage;
|
|
212
|
+
private startContentPlayback;
|
|
133
213
|
private handleAdPlayback;
|
|
134
214
|
skipAd(): void;
|
|
135
215
|
clickAd(): void;
|
|
@@ -168,6 +248,15 @@ declare class TransportManager extends EventEmitter<TransportEvents> {
|
|
|
168
248
|
sendInit(params: any): void;
|
|
169
249
|
sendControl(params: any): void;
|
|
170
250
|
sendAnalytics(params: any): void;
|
|
251
|
+
sendVoice(params: {
|
|
252
|
+
action: number;
|
|
253
|
+
audioData?: Uint8Array;
|
|
254
|
+
mimeType?: string;
|
|
255
|
+
sequence?: number;
|
|
256
|
+
listenerId?: string;
|
|
257
|
+
deviceType?: string;
|
|
258
|
+
gameContext?: string;
|
|
259
|
+
}): void;
|
|
171
260
|
get isConnected(): boolean;
|
|
172
261
|
private sendBytes;
|
|
173
262
|
}
|
|
@@ -178,8 +267,51 @@ declare class TransportManager extends EventEmitter<TransportEvents> {
|
|
|
178
267
|
*/
|
|
179
268
|
declare function fetchRadioNowPlaying(serverUrl: string, init?: RequestInit): Promise<RadioNowPlaying | null>;
|
|
180
269
|
|
|
181
|
-
|
|
182
|
-
|
|
270
|
+
interface VoiceCaptureEvents {
|
|
271
|
+
chunk: (data: Uint8Array, sequence: number) => void;
|
|
272
|
+
error: (error: Error) => void;
|
|
273
|
+
/** User started speaking (level crossed above silence threshold). */
|
|
274
|
+
speechStart: () => void;
|
|
275
|
+
/** User stopped speaking (silence after speech, or max duration reached). */
|
|
276
|
+
speechEnd: () => void;
|
|
277
|
+
}
|
|
278
|
+
interface VoiceCaptureOptions {
|
|
279
|
+
/** RMS level below which audio counts as silence (0–1). Default `0.018`. */
|
|
280
|
+
silenceThreshold?: number;
|
|
281
|
+
/** Ms of silence after speech before `speechEnd`. Default `1500`. */
|
|
282
|
+
silenceDurationMs?: number;
|
|
283
|
+
/** Minimum speech ms before silence can end capture. Default `400`. */
|
|
284
|
+
minSpeechMs?: number;
|
|
285
|
+
/** Safety cap — auto `speechEnd` after this many ms. Default `30000`. */
|
|
286
|
+
maxDurationMs?: number;
|
|
287
|
+
/** Monitor mic levels for end-of-speech. Default `true`. */
|
|
288
|
+
detectSilence?: boolean;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Native MediaRecorder capture with optional Web Audio silence detection.
|
|
292
|
+
*/
|
|
293
|
+
declare class VoiceCaptureManager extends EventEmitter<VoiceCaptureEvents> {
|
|
294
|
+
private stream;
|
|
295
|
+
private recorder;
|
|
296
|
+
private sequence;
|
|
297
|
+
private capturing;
|
|
298
|
+
private mimeType;
|
|
299
|
+
private audioContext;
|
|
300
|
+
private silenceRaf;
|
|
301
|
+
private speechEndEmitted;
|
|
302
|
+
private captureOptions;
|
|
303
|
+
get isCapturing(): boolean;
|
|
304
|
+
get activeMimeType(): string;
|
|
305
|
+
start(options?: VoiceCaptureOptions): Promise<string>;
|
|
306
|
+
stop(): Promise<void>;
|
|
307
|
+
cancel(): void;
|
|
308
|
+
private startSilenceMonitor;
|
|
309
|
+
private stopSilenceMonitor;
|
|
310
|
+
private releaseStream;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
type SynxedWebPlayerMode = "mini" | "wide" | "large";
|
|
314
|
+
type SynxedWebPlayerPlacement = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "bottom-center";
|
|
183
315
|
interface SynxedWebPlayerTheme {
|
|
184
316
|
accent?: string;
|
|
185
317
|
accentMuted?: string;
|
|
@@ -198,10 +330,10 @@ interface SynxedWebPlayerPosition {
|
|
|
198
330
|
offsetY?: number;
|
|
199
331
|
}
|
|
200
332
|
type SynxedWebPlayerSource = {
|
|
201
|
-
type:
|
|
333
|
+
type: "playlist";
|
|
202
334
|
playlistCode: string;
|
|
203
335
|
} | {
|
|
204
|
-
type:
|
|
336
|
+
type: "radio";
|
|
205
337
|
};
|
|
206
338
|
interface SynxedWebPlayerOptions {
|
|
207
339
|
/** Mount target. If omitted, a fixed overlay root is appended to `document.body`. */
|
|
@@ -213,6 +345,7 @@ interface SynxedWebPlayerOptions {
|
|
|
213
345
|
theme?: SynxedWebPlayerTheme;
|
|
214
346
|
position?: SynxedWebPlayerPosition;
|
|
215
347
|
avatarUrl?: string;
|
|
348
|
+
voiceAvatarUrl?: string;
|
|
216
349
|
attribution?: string;
|
|
217
350
|
nowPlayingPollMs?: number;
|
|
218
351
|
powerByLabel?: string;
|
|
@@ -221,6 +354,11 @@ interface SynxedWebPlayerOptions {
|
|
|
221
354
|
style?: Partial<CSSStyleDeclaration>;
|
|
222
355
|
onMiniClick?: () => void;
|
|
223
356
|
draggable?: boolean;
|
|
357
|
+
/** Press-and-hold DJ avatar for voice. Set `false` to disable. Default `true`. */
|
|
358
|
+
enableVoice?: boolean;
|
|
359
|
+
/** Ms to hold before voice starts (prevents opening AI on quick tap). Default `450`. */
|
|
360
|
+
voiceHoldMs?: number;
|
|
361
|
+
listenerId?: string;
|
|
224
362
|
}
|
|
225
363
|
|
|
226
364
|
/**
|
|
@@ -248,6 +386,13 @@ declare class SynxedWebPlayer {
|
|
|
248
386
|
private artistBlockEl;
|
|
249
387
|
private footerEl;
|
|
250
388
|
private playBtn;
|
|
389
|
+
private avatarVoiceHolding;
|
|
390
|
+
private suppressMiniClick;
|
|
391
|
+
private voiceAvatarPreview;
|
|
392
|
+
private voiceHoldActivated;
|
|
393
|
+
private voiceUiDismissed;
|
|
394
|
+
private voiceHoldTimer;
|
|
395
|
+
private readonly defaultVoiceHoldMs;
|
|
251
396
|
constructor(options: SynxedWebPlayerOptions);
|
|
252
397
|
/** Convenience factory — same as `new SynxedWebPlayer(options)`. */
|
|
253
398
|
static mount(options: SynxedWebPlayerOptions): SynxedWebPlayer;
|
|
@@ -255,12 +400,14 @@ declare class SynxedWebPlayer {
|
|
|
255
400
|
get player(): SynxedPlayer | null;
|
|
256
401
|
get element(): HTMLElement;
|
|
257
402
|
destroy(): void;
|
|
403
|
+
private get voiceEnabled();
|
|
258
404
|
private get isRadio();
|
|
259
405
|
private get mode();
|
|
260
406
|
private mountShell;
|
|
261
407
|
private makeDraggable;
|
|
262
408
|
private buildAvatar;
|
|
263
409
|
private buildMini;
|
|
410
|
+
private handleMiniActivate;
|
|
264
411
|
private buildWide;
|
|
265
412
|
private buildLarge;
|
|
266
413
|
private roundControlStyle;
|
|
@@ -268,8 +415,22 @@ declare class SynxedWebPlayer {
|
|
|
268
415
|
private buildVisualizer;
|
|
269
416
|
private decoLines;
|
|
270
417
|
private initEngine;
|
|
418
|
+
/** Press-and-hold DJ avatar to stream voice; release or silence auto-ends capture. */
|
|
419
|
+
private wireAvatarVoiceHold;
|
|
420
|
+
private isVoiceUiOpen;
|
|
421
|
+
private dismissVoiceUi;
|
|
422
|
+
private resetVoiceHoldState;
|
|
423
|
+
private applyVoiceVisual;
|
|
424
|
+
private isVoiceAvatarActive;
|
|
425
|
+
private getAvatarImageUrl;
|
|
426
|
+
private refreshAvatarImage;
|
|
271
427
|
private startNowPlayingPoll;
|
|
272
428
|
private stopNowPlayingPoll;
|
|
429
|
+
private handleSkipClick;
|
|
430
|
+
/** Countdown in the skip control during ads — no extra chrome. */
|
|
431
|
+
private applyAdSkipUi;
|
|
432
|
+
private clearAdSkipStyleOverrides;
|
|
433
|
+
private restoreTrackSkipButton;
|
|
273
434
|
private displayLine;
|
|
274
435
|
private refreshLabels;
|
|
275
436
|
private updateAvatar;
|
|
@@ -277,4 +438,4 @@ declare class SynxedWebPlayer {
|
|
|
277
438
|
private togglePlay;
|
|
278
439
|
}
|
|
279
440
|
|
|
280
|
-
export { type AdInfo, ContentKind, ErrorCode, type PlayPlaylistOptions, type PlayRadioOptions, type PlaySongOptions, type PlayerState, type RadioNowPlaying, type SynxedConfig, SynxedConnectionError, SynxedError, type SynxedEvents, SynxedPlaybackError, SynxedPlayer, SynxedProtocolError, SynxedWebPlayer, type SynxedWebPlayerMode, type SynxedWebPlayerOptions, type SynxedWebPlayerPlacement, type SynxedWebPlayerPosition, type SynxedWebPlayerSource, type SynxedWebPlayerTheme, type TrackInfo, type TransportEvents, TransportManager, buildSdkWebSocketUrl, fetchRadioNowPlaying };
|
|
441
|
+
export { type AdInfo, type AdSkipState, ContentKind, ErrorCode, type PlayPlaylistOptions, type PlayRadioOptions, type PlaySongOptions, type PlayerState, type RadioNowPlaying, SdkVoiceAction, type SynxedConfig, SynxedConnectionError, SynxedError, type SynxedEvents, SynxedPlaybackError, SynxedPlayer, SynxedProtocolError, SynxedWebPlayer, type SynxedWebPlayerMode, type SynxedWebPlayerOptions, type SynxedWebPlayerPlacement, type SynxedWebPlayerPosition, type SynxedWebPlayerSource, type SynxedWebPlayerTheme, type TrackInfo, type TransportEvents, TransportManager, VoiceCaptureManager, type VoiceCaptureOptions, type VoiceHoldOptions, type VoiceResult, type VoiceState, buildSdkWebSocketUrl, fetchRadioNowPlaying };
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,14 @@ declare enum ContentKind {
|
|
|
12
12
|
SONG = 1,
|
|
13
13
|
PLAYLIST = 2,
|
|
14
14
|
CATEGORY = 3,
|
|
15
|
-
RADIO = 4
|
|
15
|
+
RADIO = 4,
|
|
16
|
+
VOICE = 5
|
|
17
|
+
}
|
|
18
|
+
declare enum SdkVoiceAction {
|
|
19
|
+
VOICE_UNSPECIFIED = 0,
|
|
20
|
+
VOICE_START = 1,
|
|
21
|
+
VOICE_CHUNK = 2,
|
|
22
|
+
VOICE_END = 3
|
|
16
23
|
}
|
|
17
24
|
declare enum ErrorCode {
|
|
18
25
|
UNSPECIFIED = 0,
|
|
@@ -32,6 +39,8 @@ interface SynxedConfig {
|
|
|
32
39
|
/** Listening context sent on init for ad targeting (e.g. "menu", "gameplay"). */
|
|
33
40
|
gameContext?: string;
|
|
34
41
|
deviceType?: string;
|
|
42
|
+
/** Default voice silence detection settings (used by `beginVoiceHold`). */
|
|
43
|
+
voice?: Omit<VoiceHoldOptions, 'listenerId'>;
|
|
35
44
|
}
|
|
36
45
|
interface PlaySongOptions {
|
|
37
46
|
catalogTrackId?: string;
|
|
@@ -66,6 +75,26 @@ interface PlayerState {
|
|
|
66
75
|
duration: number;
|
|
67
76
|
volume: number;
|
|
68
77
|
}
|
|
78
|
+
type VoiceState = 'idle' | 'listening' | 'processing' | 'ready' | 'error';
|
|
79
|
+
interface VoiceResult {
|
|
80
|
+
status: string;
|
|
81
|
+
transcript?: string;
|
|
82
|
+
playlistCode?: string;
|
|
83
|
+
playlistName?: string;
|
|
84
|
+
}
|
|
85
|
+
interface VoiceHoldOptions {
|
|
86
|
+
listenerId?: string;
|
|
87
|
+
/** Auto-end capture when the user stops talking. Default `true`. */
|
|
88
|
+
autoEndOnSilence?: boolean;
|
|
89
|
+
/** RMS level below which audio counts as silence (0–1). Default `0.018`. */
|
|
90
|
+
silenceThreshold?: number;
|
|
91
|
+
/** Ms of silence after speech before auto-end. Default `1500`. */
|
|
92
|
+
silenceDurationMs?: number;
|
|
93
|
+
/** Minimum speech ms before silence can trigger end. Default `400`. */
|
|
94
|
+
minSpeechMs?: number;
|
|
95
|
+
/** Max capture length in ms. Default `30000`. */
|
|
96
|
+
maxDurationMs?: number;
|
|
97
|
+
}
|
|
69
98
|
interface SynxedEvents {
|
|
70
99
|
stateChange: (state: PlayerState) => void;
|
|
71
100
|
timeUpdate: (time: {
|
|
@@ -76,6 +105,13 @@ interface SynxedEvents {
|
|
|
76
105
|
queueUpdated: (tracks: TrackInfo[]) => void;
|
|
77
106
|
adStart: (ad: AdInfo) => void;
|
|
78
107
|
adEnd: (ad: AdInfo) => void;
|
|
108
|
+
adSkipUpdate: (state: AdSkipState) => void;
|
|
109
|
+
voiceStateChange: (state: VoiceState) => void;
|
|
110
|
+
voiceResult: (result: VoiceResult) => void;
|
|
111
|
+
/** Mic level crossed above silence threshold — user started speaking. */
|
|
112
|
+
voiceSpeechStart: () => void;
|
|
113
|
+
/** Silence detected after speech — user stopped talking. */
|
|
114
|
+
voiceSpeechEnd: () => void;
|
|
79
115
|
error: (error: Error) => void;
|
|
80
116
|
connected: () => void;
|
|
81
117
|
disconnected: (reason: string) => void;
|
|
@@ -93,29 +129,69 @@ interface AdInfo {
|
|
|
93
129
|
companionBannerUrl: string;
|
|
94
130
|
campaignName: string;
|
|
95
131
|
}
|
|
132
|
+
/** Emitted while a skippable ad plays — use for custom skip UI (YouTube-style countdown). */
|
|
133
|
+
interface AdSkipState {
|
|
134
|
+
ad: AdInfo;
|
|
135
|
+
/** Seconds remaining before skip is allowed (0 when `canSkip` is true). */
|
|
136
|
+
countdownSeconds: number;
|
|
137
|
+
/** True once the ad has played for `skipAfterSeconds` (e.g. 5s). */
|
|
138
|
+
canSkip: boolean;
|
|
139
|
+
}
|
|
96
140
|
|
|
97
141
|
declare class SynxedPlayer extends EventEmitter<SynxedEvents> {
|
|
98
142
|
private transport;
|
|
99
143
|
private audio;
|
|
100
144
|
private playlist;
|
|
145
|
+
private voiceCapture;
|
|
101
146
|
private config;
|
|
102
147
|
private status;
|
|
103
148
|
private volume;
|
|
104
149
|
private activeContentKind;
|
|
105
150
|
private heartbeatTimer;
|
|
106
151
|
private adPlaying;
|
|
107
|
-
private
|
|
152
|
+
private _currentAd;
|
|
153
|
+
private _voiceState;
|
|
154
|
+
private voiceMimeType;
|
|
155
|
+
private voiceListenerId;
|
|
156
|
+
private pendingPlaybackLoad;
|
|
157
|
+
private voiceAutoEndOnSilence;
|
|
158
|
+
private pausedForVoice;
|
|
108
159
|
constructor(config: SynxedConfig);
|
|
109
160
|
get currentTrack(): TrackInfo | null;
|
|
110
161
|
/** Active playback init kind from the last `play*` call (RADIO, PLAYLIST, SONG, …). */
|
|
111
162
|
get contentKind(): ContentKind;
|
|
163
|
+
get currentAd(): AdInfo | null;
|
|
164
|
+
get isAdPlaying(): boolean;
|
|
165
|
+
/** True when a skippable ad has played for at least `skipAfterSeconds` (default 5s). */
|
|
166
|
+
canSkipAd(): boolean;
|
|
167
|
+
/** Seconds until skip unlocks; `0` when skip is available; `null` when not in a skippable ad. */
|
|
168
|
+
getAdSkipCountdownSeconds(): number | null;
|
|
169
|
+
get voiceState(): VoiceState;
|
|
112
170
|
private controlPositionMs;
|
|
113
171
|
private setupListeners;
|
|
172
|
+
private resolveVoiceOptions;
|
|
114
173
|
private connect;
|
|
115
174
|
private buildInitExtras;
|
|
116
175
|
playSong(options: PlaySongOptions): Promise<void>;
|
|
117
176
|
playPlaylist(options: PlayPlaylistOptions): Promise<void>;
|
|
118
177
|
playRadio(options?: PlayRadioOptions): Promise<void>;
|
|
178
|
+
/**
|
|
179
|
+
* Press-and-hold the DJ avatar (or call manually): start mic capture and stream chunks.
|
|
180
|
+
* Ends automatically when the user stops talking (`voiceSpeechEnd`) or call `endVoiceHold()`.
|
|
181
|
+
*/
|
|
182
|
+
beginVoiceHold(options?: VoiceHoldOptions): Promise<void>;
|
|
183
|
+
/**
|
|
184
|
+
* Release press-and-hold: flush final audio chunk and request playlist generation.
|
|
185
|
+
*/
|
|
186
|
+
endVoiceHold(): Promise<void>;
|
|
187
|
+
/** Cancel an in-progress voice hold without sending audio to the server. */
|
|
188
|
+
cancelVoiceHold(): void;
|
|
189
|
+
/**
|
|
190
|
+
* Close the voice UI: cancel recording if active and resume playback if it was
|
|
191
|
+
* paused for voice.
|
|
192
|
+
*/
|
|
193
|
+
dismissVoiceAndResume(): void;
|
|
194
|
+
get isVoiceUiActive(): boolean;
|
|
119
195
|
pause(): void;
|
|
120
196
|
resume(): void;
|
|
121
197
|
stop(): void;
|
|
@@ -129,7 +205,11 @@ declare class SynxedPlayer extends EventEmitter<SynxedEvents> {
|
|
|
129
205
|
private clearHeartbeat;
|
|
130
206
|
private startHeartbeat;
|
|
131
207
|
private applyContentSummary;
|
|
208
|
+
private emitAdSkipUpdate;
|
|
209
|
+
private setVoiceState;
|
|
210
|
+
private handleVoiceAck;
|
|
132
211
|
private handleServerMessage;
|
|
212
|
+
private startContentPlayback;
|
|
133
213
|
private handleAdPlayback;
|
|
134
214
|
skipAd(): void;
|
|
135
215
|
clickAd(): void;
|
|
@@ -168,6 +248,15 @@ declare class TransportManager extends EventEmitter<TransportEvents> {
|
|
|
168
248
|
sendInit(params: any): void;
|
|
169
249
|
sendControl(params: any): void;
|
|
170
250
|
sendAnalytics(params: any): void;
|
|
251
|
+
sendVoice(params: {
|
|
252
|
+
action: number;
|
|
253
|
+
audioData?: Uint8Array;
|
|
254
|
+
mimeType?: string;
|
|
255
|
+
sequence?: number;
|
|
256
|
+
listenerId?: string;
|
|
257
|
+
deviceType?: string;
|
|
258
|
+
gameContext?: string;
|
|
259
|
+
}): void;
|
|
171
260
|
get isConnected(): boolean;
|
|
172
261
|
private sendBytes;
|
|
173
262
|
}
|
|
@@ -178,8 +267,51 @@ declare class TransportManager extends EventEmitter<TransportEvents> {
|
|
|
178
267
|
*/
|
|
179
268
|
declare function fetchRadioNowPlaying(serverUrl: string, init?: RequestInit): Promise<RadioNowPlaying | null>;
|
|
180
269
|
|
|
181
|
-
|
|
182
|
-
|
|
270
|
+
interface VoiceCaptureEvents {
|
|
271
|
+
chunk: (data: Uint8Array, sequence: number) => void;
|
|
272
|
+
error: (error: Error) => void;
|
|
273
|
+
/** User started speaking (level crossed above silence threshold). */
|
|
274
|
+
speechStart: () => void;
|
|
275
|
+
/** User stopped speaking (silence after speech, or max duration reached). */
|
|
276
|
+
speechEnd: () => void;
|
|
277
|
+
}
|
|
278
|
+
interface VoiceCaptureOptions {
|
|
279
|
+
/** RMS level below which audio counts as silence (0–1). Default `0.018`. */
|
|
280
|
+
silenceThreshold?: number;
|
|
281
|
+
/** Ms of silence after speech before `speechEnd`. Default `1500`. */
|
|
282
|
+
silenceDurationMs?: number;
|
|
283
|
+
/** Minimum speech ms before silence can end capture. Default `400`. */
|
|
284
|
+
minSpeechMs?: number;
|
|
285
|
+
/** Safety cap — auto `speechEnd` after this many ms. Default `30000`. */
|
|
286
|
+
maxDurationMs?: number;
|
|
287
|
+
/** Monitor mic levels for end-of-speech. Default `true`. */
|
|
288
|
+
detectSilence?: boolean;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Native MediaRecorder capture with optional Web Audio silence detection.
|
|
292
|
+
*/
|
|
293
|
+
declare class VoiceCaptureManager extends EventEmitter<VoiceCaptureEvents> {
|
|
294
|
+
private stream;
|
|
295
|
+
private recorder;
|
|
296
|
+
private sequence;
|
|
297
|
+
private capturing;
|
|
298
|
+
private mimeType;
|
|
299
|
+
private audioContext;
|
|
300
|
+
private silenceRaf;
|
|
301
|
+
private speechEndEmitted;
|
|
302
|
+
private captureOptions;
|
|
303
|
+
get isCapturing(): boolean;
|
|
304
|
+
get activeMimeType(): string;
|
|
305
|
+
start(options?: VoiceCaptureOptions): Promise<string>;
|
|
306
|
+
stop(): Promise<void>;
|
|
307
|
+
cancel(): void;
|
|
308
|
+
private startSilenceMonitor;
|
|
309
|
+
private stopSilenceMonitor;
|
|
310
|
+
private releaseStream;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
type SynxedWebPlayerMode = "mini" | "wide" | "large";
|
|
314
|
+
type SynxedWebPlayerPlacement = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "bottom-center";
|
|
183
315
|
interface SynxedWebPlayerTheme {
|
|
184
316
|
accent?: string;
|
|
185
317
|
accentMuted?: string;
|
|
@@ -198,10 +330,10 @@ interface SynxedWebPlayerPosition {
|
|
|
198
330
|
offsetY?: number;
|
|
199
331
|
}
|
|
200
332
|
type SynxedWebPlayerSource = {
|
|
201
|
-
type:
|
|
333
|
+
type: "playlist";
|
|
202
334
|
playlistCode: string;
|
|
203
335
|
} | {
|
|
204
|
-
type:
|
|
336
|
+
type: "radio";
|
|
205
337
|
};
|
|
206
338
|
interface SynxedWebPlayerOptions {
|
|
207
339
|
/** Mount target. If omitted, a fixed overlay root is appended to `document.body`. */
|
|
@@ -213,6 +345,7 @@ interface SynxedWebPlayerOptions {
|
|
|
213
345
|
theme?: SynxedWebPlayerTheme;
|
|
214
346
|
position?: SynxedWebPlayerPosition;
|
|
215
347
|
avatarUrl?: string;
|
|
348
|
+
voiceAvatarUrl?: string;
|
|
216
349
|
attribution?: string;
|
|
217
350
|
nowPlayingPollMs?: number;
|
|
218
351
|
powerByLabel?: string;
|
|
@@ -221,6 +354,11 @@ interface SynxedWebPlayerOptions {
|
|
|
221
354
|
style?: Partial<CSSStyleDeclaration>;
|
|
222
355
|
onMiniClick?: () => void;
|
|
223
356
|
draggable?: boolean;
|
|
357
|
+
/** Press-and-hold DJ avatar for voice. Set `false` to disable. Default `true`. */
|
|
358
|
+
enableVoice?: boolean;
|
|
359
|
+
/** Ms to hold before voice starts (prevents opening AI on quick tap). Default `450`. */
|
|
360
|
+
voiceHoldMs?: number;
|
|
361
|
+
listenerId?: string;
|
|
224
362
|
}
|
|
225
363
|
|
|
226
364
|
/**
|
|
@@ -248,6 +386,13 @@ declare class SynxedWebPlayer {
|
|
|
248
386
|
private artistBlockEl;
|
|
249
387
|
private footerEl;
|
|
250
388
|
private playBtn;
|
|
389
|
+
private avatarVoiceHolding;
|
|
390
|
+
private suppressMiniClick;
|
|
391
|
+
private voiceAvatarPreview;
|
|
392
|
+
private voiceHoldActivated;
|
|
393
|
+
private voiceUiDismissed;
|
|
394
|
+
private voiceHoldTimer;
|
|
395
|
+
private readonly defaultVoiceHoldMs;
|
|
251
396
|
constructor(options: SynxedWebPlayerOptions);
|
|
252
397
|
/** Convenience factory — same as `new SynxedWebPlayer(options)`. */
|
|
253
398
|
static mount(options: SynxedWebPlayerOptions): SynxedWebPlayer;
|
|
@@ -255,12 +400,14 @@ declare class SynxedWebPlayer {
|
|
|
255
400
|
get player(): SynxedPlayer | null;
|
|
256
401
|
get element(): HTMLElement;
|
|
257
402
|
destroy(): void;
|
|
403
|
+
private get voiceEnabled();
|
|
258
404
|
private get isRadio();
|
|
259
405
|
private get mode();
|
|
260
406
|
private mountShell;
|
|
261
407
|
private makeDraggable;
|
|
262
408
|
private buildAvatar;
|
|
263
409
|
private buildMini;
|
|
410
|
+
private handleMiniActivate;
|
|
264
411
|
private buildWide;
|
|
265
412
|
private buildLarge;
|
|
266
413
|
private roundControlStyle;
|
|
@@ -268,8 +415,22 @@ declare class SynxedWebPlayer {
|
|
|
268
415
|
private buildVisualizer;
|
|
269
416
|
private decoLines;
|
|
270
417
|
private initEngine;
|
|
418
|
+
/** Press-and-hold DJ avatar to stream voice; release or silence auto-ends capture. */
|
|
419
|
+
private wireAvatarVoiceHold;
|
|
420
|
+
private isVoiceUiOpen;
|
|
421
|
+
private dismissVoiceUi;
|
|
422
|
+
private resetVoiceHoldState;
|
|
423
|
+
private applyVoiceVisual;
|
|
424
|
+
private isVoiceAvatarActive;
|
|
425
|
+
private getAvatarImageUrl;
|
|
426
|
+
private refreshAvatarImage;
|
|
271
427
|
private startNowPlayingPoll;
|
|
272
428
|
private stopNowPlayingPoll;
|
|
429
|
+
private handleSkipClick;
|
|
430
|
+
/** Countdown in the skip control during ads — no extra chrome. */
|
|
431
|
+
private applyAdSkipUi;
|
|
432
|
+
private clearAdSkipStyleOverrides;
|
|
433
|
+
private restoreTrackSkipButton;
|
|
273
434
|
private displayLine;
|
|
274
435
|
private refreshLabels;
|
|
275
436
|
private updateAvatar;
|
|
@@ -277,4 +438,4 @@ declare class SynxedWebPlayer {
|
|
|
277
438
|
private togglePlay;
|
|
278
439
|
}
|
|
279
440
|
|
|
280
|
-
export { type AdInfo, ContentKind, ErrorCode, type PlayPlaylistOptions, type PlayRadioOptions, type PlaySongOptions, type PlayerState, type RadioNowPlaying, type SynxedConfig, SynxedConnectionError, SynxedError, type SynxedEvents, SynxedPlaybackError, SynxedPlayer, SynxedProtocolError, SynxedWebPlayer, type SynxedWebPlayerMode, type SynxedWebPlayerOptions, type SynxedWebPlayerPlacement, type SynxedWebPlayerPosition, type SynxedWebPlayerSource, type SynxedWebPlayerTheme, type TrackInfo, type TransportEvents, TransportManager, buildSdkWebSocketUrl, fetchRadioNowPlaying };
|
|
441
|
+
export { type AdInfo, type AdSkipState, ContentKind, ErrorCode, type PlayPlaylistOptions, type PlayRadioOptions, type PlaySongOptions, type PlayerState, type RadioNowPlaying, SdkVoiceAction, type SynxedConfig, SynxedConnectionError, SynxedError, type SynxedEvents, SynxedPlaybackError, SynxedPlayer, SynxedProtocolError, SynxedWebPlayer, type SynxedWebPlayerMode, type SynxedWebPlayerOptions, type SynxedWebPlayerPlacement, type SynxedWebPlayerPosition, type SynxedWebPlayerSource, type SynxedWebPlayerTheme, type TrackInfo, type TransportEvents, TransportManager, VoiceCaptureManager, type VoiceCaptureOptions, type VoiceHoldOptions, type VoiceResult, type VoiceState, buildSdkWebSocketUrl, fetchRadioNowPlaying };
|