synxed-sdk 0.2.5 → 0.2.7
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/README.md +109 -126
- package/dist/index.d.mts +27 -27
- package/dist/index.d.ts +27 -27
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +11 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,198 +1,181 @@
|
|
|
1
1
|
# Synxed SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Add Music to your website, Game or App in a few minutes — Stream Songs, playlists, live radio, voice commands, and a ready-made player UI.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/synxed-sdk)
|
|
6
|
-
[](https://www.typescriptlang.org/)
|
|
7
6
|
|
|
8
|
-
##
|
|
7
|
+
## What you need
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- **Framework-agnostic core**: `SynxedPlayer` works in React, Vue, Angular, or vanilla JS.
|
|
14
|
-
- **Optional web UI**: Vanilla DOM overlay (`SynxedWebPlayer`) with **mini**, **wide**, and **large** layouts — works in any framework; **theme** and **placement** are fully configurable.
|
|
15
|
-
- **Type-safe**: Written in TypeScript with full definitions.
|
|
9
|
+
1. A **Synxed API key** (from your Synxed developer account `https://portal.synxed.com`).
|
|
10
|
+
2. Your **API URL** (Our api url: `https://api.synxed.com`).
|
|
11
|
+
3. A **playlist code**, **Single Song** or choose **live radio**.
|
|
16
12
|
|
|
17
|
-
##
|
|
13
|
+
## Install
|
|
18
14
|
|
|
19
15
|
```bash
|
|
20
16
|
npm install synxed-sdk
|
|
21
17
|
```
|
|
22
18
|
|
|
23
|
-
|
|
19
|
+
## Easiest setup — built-in player
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
npm install hls.js
|
|
27
|
-
```
|
|
21
|
+
This adds a floating music bar to your page. No React or special framework required.
|
|
28
22
|
|
|
29
|
-
|
|
23
|
+
### Play a playlist
|
|
30
24
|
|
|
31
|
-
|
|
25
|
+
```html
|
|
26
|
+
<script type="module">
|
|
27
|
+
import { SynxedWebPlayer } from "synxed-sdk";
|
|
32
28
|
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
SynxedWebPlayer.mount({
|
|
30
|
+
apiKey: "YOUR_SYNXED_API_KEY",
|
|
31
|
+
serverUrl: "https://api.synxed.com",
|
|
32
|
+
source: { type: "playlist", playlistCode: "sxpl_YOUR_CODE" },
|
|
33
|
+
});
|
|
34
|
+
</script>
|
|
35
|
+
```
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
### Play live radio
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
SynxedWebPlayer.mount({
|
|
37
41
|
apiKey: "YOUR_SYNXED_API_KEY",
|
|
38
42
|
serverUrl: "https://api.synxed.com",
|
|
39
|
-
|
|
43
|
+
source: { type: "radio" },
|
|
40
44
|
});
|
|
41
45
|
```
|
|
42
46
|
|
|
43
|
-
###
|
|
47
|
+
### Put the player inside your own box
|
|
44
48
|
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
```javascript
|
|
50
|
+
SynxedWebPlayer.mount({
|
|
51
|
+
container: document.getElementById("my-player"),
|
|
52
|
+
apiKey: "YOUR_SYNXED_API_KEY",
|
|
53
|
+
serverUrl: "https://api.synxed.com",
|
|
54
|
+
source: { type: "playlist", playlistCode: "sxpl_YOUR_CODE" },
|
|
48
55
|
});
|
|
49
56
|
```
|
|
50
57
|
|
|
51
|
-
|
|
58
|
+
## Player sizes
|
|
52
59
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
| Mode | What it looks like |
|
|
61
|
+
| ------- | ------------------------------- |
|
|
62
|
+
| `wide` | Bar across the bottom (default) |
|
|
63
|
+
| `mini` | Small round DJ button |
|
|
64
|
+
| `large` | Bigger card with visualizer |
|
|
57
65
|
|
|
58
|
-
|
|
59
|
-
|
|
66
|
+
```javascript
|
|
67
|
+
SynxedWebPlayer.mount({
|
|
68
|
+
apiKey: "...",
|
|
69
|
+
serverUrl: "...",
|
|
70
|
+
source: { type: "playlist", playlistCode: "sxpl_..." },
|
|
71
|
+
mode: "mini",
|
|
60
72
|
});
|
|
61
73
|
```
|
|
62
74
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
Continuous **non-HLS** stream (not seekable). The SDK sends `CONTENT_KIND_RADIO` (`4`) over the same native `/sdk` WebSocket; the server returns a direct `playbackUrl` (e.g. MPEG stream).
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
await player.playRadio({ listenerId: "optional-stable-id" });
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
- **`skip` / `previous` / `skipTo` / `seek`**: no-ops for radio (the live edge keeps moving on the server).
|
|
72
|
-
- **`pause` / `resume`**: local audio only; when the user resumes, they rejoin the live stream.
|
|
73
|
-
- **Metadata**: poll the REST endpoint (unauthenticated on most deployments):
|
|
75
|
+
## Move the player on screen
|
|
74
76
|
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// { title, station?, isLive? } — poll every 10–15s for “now playing” UI
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Optional web player UI (vanilla — no React required)
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
import { SynxedWebPlayer } from "synxed-sdk";
|
|
86
|
-
|
|
87
|
-
const ui = SynxedWebPlayer.mount({
|
|
88
|
-
apiKey: "YOUR_SYNXED_API_KEY",
|
|
89
|
-
serverUrl: "https://api.synxed.com",
|
|
77
|
+
```javascript
|
|
78
|
+
SynxedWebPlayer.mount({
|
|
79
|
+
apiKey: "...",
|
|
80
|
+
serverUrl: "...",
|
|
90
81
|
source: { type: "radio" },
|
|
91
|
-
mode: "wide",
|
|
92
|
-
attribution: "DJ Jesse · Synxed × Your Brand",
|
|
93
|
-
theme: {
|
|
94
|
-
accent: "#ef4444",
|
|
95
|
-
glow: "rgba(239, 68, 68, 0.35)",
|
|
96
|
-
background: "#0a0707",
|
|
97
|
-
},
|
|
98
82
|
position: { placement: "top-left", offsetX: 16, offsetY: 16 },
|
|
99
83
|
draggable: true,
|
|
100
84
|
});
|
|
101
|
-
|
|
102
|
-
// Later: ui.destroy();
|
|
103
85
|
```
|
|
104
86
|
|
|
105
|
-
|
|
87
|
+
## Match your brand colors
|
|
106
88
|
|
|
107
|
-
```
|
|
89
|
+
```javascript
|
|
108
90
|
SynxedWebPlayer.mount({
|
|
109
|
-
container: document.getElementById("player-slot")!,
|
|
110
91
|
apiKey: "...",
|
|
111
92
|
serverUrl: "...",
|
|
112
93
|
source: { type: "playlist", playlistCode: "sxpl_..." },
|
|
94
|
+
theme: {
|
|
95
|
+
accent: "#22c55e",
|
|
96
|
+
background: "#0a0a0a",
|
|
97
|
+
glow: "rgba(34, 197, 94, 0.35)",
|
|
98
|
+
},
|
|
113
99
|
});
|
|
114
100
|
```
|
|
115
101
|
|
|
116
|
-
|
|
117
|
-
|
|
102
|
+
## Talk to the DJ (voice playlists)
|
|
103
|
+
|
|
104
|
+
**Hold** the Synxed DJ avatar (the spinning circle) and say what you want to hear — for example _“play upbeat workout songs”_.
|
|
118
105
|
|
|
119
|
-
|
|
106
|
+
- **Tap** the DJ → play or pause the music.
|
|
107
|
+
- **Hold** the DJ → speak your request; release when done (or stop talking and it sends automatically).
|
|
108
|
+
- While you speak, the DJ icon switches to the AI listening view.
|
|
109
|
+
- Music pauses while you talk and can resume when you tap again.
|
|
120
110
|
|
|
121
|
-
|
|
111
|
+
To turn voice off:
|
|
122
112
|
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
player.setVolume(0.8);
|
|
129
|
-
player.skip();
|
|
130
|
-
player.previous();
|
|
131
|
-
player.skipTo(2);
|
|
113
|
+
```javascript
|
|
114
|
+
SynxedWebPlayer.mount({
|
|
115
|
+
enableVoice: false,
|
|
116
|
+
// ...other options
|
|
117
|
+
});
|
|
132
118
|
```
|
|
133
119
|
|
|
134
|
-
##
|
|
120
|
+
## Skip button and ads
|
|
135
121
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
});
|
|
122
|
+
- During normal playback, the **skip** button jumps to the next song.
|
|
123
|
+
- During an ad, the same button shows a **short countdown** (about 5 seconds), then you can skip the ad.
|
|
124
|
+
- After the ad, the skip button works again for the next song.
|
|
140
125
|
|
|
141
|
-
|
|
142
|
-
const progress = (currentTime / duration) * 100;
|
|
143
|
-
console.log(`Progress: ${progress.toFixed(2)}%`);
|
|
144
|
-
});
|
|
126
|
+
## Build your own UI (optional)
|
|
145
127
|
|
|
146
|
-
|
|
147
|
-
console.error("Playback Error:", err.message);
|
|
148
|
-
});
|
|
149
|
-
```
|
|
128
|
+
If you want full control over buttons and layout, use `SynxedPlayer` instead of `SynxedWebPlayer`:
|
|
150
129
|
|
|
151
|
-
|
|
130
|
+
```javascript
|
|
131
|
+
import { SynxedPlayer } from "synxed-sdk";
|
|
152
132
|
|
|
153
|
-
|
|
133
|
+
const player = new SynxedPlayer({
|
|
134
|
+
apiKey: "YOUR_SYNXED_API_KEY",
|
|
135
|
+
serverUrl: "https://api.synxed.com",
|
|
136
|
+
autoConnect: true,
|
|
137
|
+
});
|
|
154
138
|
|
|
155
|
-
|
|
156
|
-
- `serverUrl`: `string` (required)
|
|
157
|
-
- `autoConnect`: `boolean` (default `true`)
|
|
139
|
+
await player.playPlaylist({ playlistCode: "sxpl_YOUR_CODE" });
|
|
158
140
|
|
|
159
|
-
|
|
141
|
+
document.getElementById("play").onclick = () => player.resume();
|
|
142
|
+
document.getElementById("pause").onclick = () => player.pause();
|
|
143
|
+
document.getElementById("skip").onclick = () => player.skip();
|
|
144
|
+
```
|
|
160
145
|
|
|
161
|
-
|
|
162
|
-
- `playPlaylist(options)`: `Promise<void>`
|
|
163
|
-
- `playRadio(options?)`: `Promise<void>` — live radio (`listenerId` optional)
|
|
164
|
-
- `pause()` / `resume()` / `stop()`
|
|
165
|
-
- `skip()` / `previous()` / `skipTo(index)` — playlist / on-demand only
|
|
166
|
-
- `seek(ms)` — on-demand only (no-op for radio)
|
|
167
|
-
- `setVolume(0–1)`
|
|
168
|
-
- `destroy()`
|
|
146
|
+
### Voice with your own buttons
|
|
169
147
|
|
|
170
|
-
|
|
148
|
+
```javascript
|
|
149
|
+
const dj = document.getElementById("dj-avatar");
|
|
171
150
|
|
|
172
|
-
|
|
173
|
-
|
|
151
|
+
dj.addEventListener("pointerdown", () => player.beginVoiceHold());
|
|
152
|
+
dj.addEventListener("pointerup", () => player.endVoiceHold());
|
|
153
|
+
```
|
|
174
154
|
|
|
175
|
-
|
|
155
|
+
## Clean up when leaving the page
|
|
176
156
|
|
|
177
|
-
|
|
157
|
+
```javascript
|
|
158
|
+
const ui = SynxedWebPlayer.mount({
|
|
159
|
+
/* ... */
|
|
160
|
+
});
|
|
178
161
|
|
|
179
|
-
|
|
162
|
+
// When your app unmounts or navigates away:
|
|
163
|
+
ui.destroy();
|
|
164
|
+
```
|
|
180
165
|
|
|
181
|
-
|
|
166
|
+
## Radio “now playing” title
|
|
182
167
|
|
|
183
|
-
|
|
168
|
+
For radio, you can show the current song name on your own label:
|
|
184
169
|
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
artist?: string;
|
|
191
|
-
duration?: number;
|
|
192
|
-
albumArt?: string;
|
|
193
|
-
}
|
|
170
|
+
```javascript
|
|
171
|
+
import { fetchRadioNowPlaying } from "synxed-sdk";
|
|
172
|
+
|
|
173
|
+
const info = await fetchRadioNowPlaying("https://api.synxed.com");
|
|
174
|
+
if (info) console.log(info.title);
|
|
194
175
|
```
|
|
195
176
|
|
|
177
|
+
Poll every 10–15 seconds to keep the title fresh.
|
|
178
|
+
|
|
196
179
|
## License
|
|
197
180
|
|
|
198
181
|
Copyright © [Synxed.com](https://synxed.com)
|
package/dist/index.d.mts
CHANGED
|
@@ -86,12 +86,6 @@ interface VoiceHoldOptions {
|
|
|
86
86
|
listenerId?: string;
|
|
87
87
|
/** Auto-end capture when the user stops talking. Default `true`. */
|
|
88
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
89
|
/** Max capture length in ms. Default `30000`. */
|
|
96
90
|
maxDurationMs?: number;
|
|
97
91
|
}
|
|
@@ -270,43 +264,46 @@ declare function fetchRadioNowPlaying(serverUrl: string, init?: RequestInit): Pr
|
|
|
270
264
|
interface VoiceCaptureEvents {
|
|
271
265
|
chunk: (data: Uint8Array, sequence: number) => void;
|
|
272
266
|
error: (error: Error) => void;
|
|
273
|
-
/** User started speaking (level crossed above silence threshold). */
|
|
274
267
|
speechStart: () => void;
|
|
275
|
-
/** User stopped speaking (silence after speech, or max duration reached). */
|
|
276
268
|
speechEnd: () => void;
|
|
277
269
|
}
|
|
278
270
|
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
271
|
/** Safety cap — auto `speechEnd` after this many ms. Default `30000`. */
|
|
286
272
|
maxDurationMs?: number;
|
|
287
|
-
/**
|
|
288
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Base URL where `@ricky0123/vad-web` model / worklet assets are served.
|
|
275
|
+
* Defaults to the jsDelivr CDN.
|
|
276
|
+
*/
|
|
277
|
+
vadBaseAssetPath?: string;
|
|
278
|
+
/**
|
|
279
|
+
* Base URL where ONNX Runtime WASM binaries are served.
|
|
280
|
+
* Defaults to the jsDelivr CDN.
|
|
281
|
+
*/
|
|
282
|
+
onnxWasmBasePath?: string;
|
|
289
283
|
}
|
|
290
284
|
/**
|
|
291
|
-
*
|
|
285
|
+
* Captures microphone audio and buffers it locally. Once the user is finished
|
|
286
|
+
* talking (detected via Silero VAD), the complete audio file is emitted to the
|
|
287
|
+
* backend as a single chunk, followed by the stream termination.
|
|
292
288
|
*/
|
|
293
289
|
declare class VoiceCaptureManager extends EventEmitter<VoiceCaptureEvents> {
|
|
294
290
|
private stream;
|
|
295
|
-
private
|
|
291
|
+
private audioContext;
|
|
292
|
+
private mediaStreamSource;
|
|
293
|
+
private processor;
|
|
294
|
+
private muteNode;
|
|
296
295
|
private sequence;
|
|
297
296
|
private capturing;
|
|
298
297
|
private mimeType;
|
|
299
|
-
private
|
|
300
|
-
private silenceRaf;
|
|
298
|
+
private micVad;
|
|
301
299
|
private speechEndEmitted;
|
|
302
|
-
private captureOptions;
|
|
303
300
|
get isCapturing(): boolean;
|
|
304
301
|
get activeMimeType(): string;
|
|
305
302
|
start(options?: VoiceCaptureOptions): Promise<string>;
|
|
306
303
|
stop(): Promise<void>;
|
|
307
304
|
cancel(): void;
|
|
308
|
-
private
|
|
309
|
-
private
|
|
305
|
+
private startVadMonitor;
|
|
306
|
+
private teardownVad;
|
|
310
307
|
private releaseStream;
|
|
311
308
|
}
|
|
312
309
|
|
|
@@ -344,8 +341,6 @@ interface SynxedWebPlayerOptions {
|
|
|
344
341
|
mode?: SynxedWebPlayerMode;
|
|
345
342
|
theme?: SynxedWebPlayerTheme;
|
|
346
343
|
position?: SynxedWebPlayerPosition;
|
|
347
|
-
avatarUrl?: string;
|
|
348
|
-
voiceAvatarUrl?: string;
|
|
349
344
|
attribution?: string;
|
|
350
345
|
nowPlayingPollMs?: number;
|
|
351
346
|
powerByLabel?: string;
|
|
@@ -393,6 +388,8 @@ declare class SynxedWebPlayer {
|
|
|
393
388
|
private voiceUiDismissed;
|
|
394
389
|
private voiceHoldTimer;
|
|
395
390
|
private readonly defaultVoiceHoldMs;
|
|
391
|
+
/** Avatar to restore after an ad (DJ / album art — not ad or voice AI). */
|
|
392
|
+
private avatarImageBeforeAd;
|
|
396
393
|
constructor(options: SynxedWebPlayerOptions);
|
|
397
394
|
/** Convenience factory — same as `new SynxedWebPlayer(options)`. */
|
|
398
395
|
static mount(options: SynxedWebPlayerOptions): SynxedWebPlayer;
|
|
@@ -422,14 +419,17 @@ declare class SynxedWebPlayer {
|
|
|
422
419
|
private resetVoiceHoldState;
|
|
423
420
|
private applyVoiceVisual;
|
|
424
421
|
private isVoiceAvatarActive;
|
|
422
|
+
private getContentAvatarUrl;
|
|
425
423
|
private getAvatarImageUrl;
|
|
426
424
|
private refreshAvatarImage;
|
|
427
425
|
private startNowPlayingPoll;
|
|
428
426
|
private stopNowPlayingPoll;
|
|
429
427
|
private handleSkipClick;
|
|
430
|
-
/**
|
|
428
|
+
/**
|
|
429
|
+
* During ads: swap skip icon for countdown text in the same control (no style changes).
|
|
430
|
+
* After ads: restore skip icon for the next track.
|
|
431
|
+
*/
|
|
431
432
|
private applyAdSkipUi;
|
|
432
|
-
private clearAdSkipStyleOverrides;
|
|
433
433
|
private restoreTrackSkipButton;
|
|
434
434
|
private displayLine;
|
|
435
435
|
private refreshLabels;
|
package/dist/index.d.ts
CHANGED
|
@@ -86,12 +86,6 @@ interface VoiceHoldOptions {
|
|
|
86
86
|
listenerId?: string;
|
|
87
87
|
/** Auto-end capture when the user stops talking. Default `true`. */
|
|
88
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
89
|
/** Max capture length in ms. Default `30000`. */
|
|
96
90
|
maxDurationMs?: number;
|
|
97
91
|
}
|
|
@@ -270,43 +264,46 @@ declare function fetchRadioNowPlaying(serverUrl: string, init?: RequestInit): Pr
|
|
|
270
264
|
interface VoiceCaptureEvents {
|
|
271
265
|
chunk: (data: Uint8Array, sequence: number) => void;
|
|
272
266
|
error: (error: Error) => void;
|
|
273
|
-
/** User started speaking (level crossed above silence threshold). */
|
|
274
267
|
speechStart: () => void;
|
|
275
|
-
/** User stopped speaking (silence after speech, or max duration reached). */
|
|
276
268
|
speechEnd: () => void;
|
|
277
269
|
}
|
|
278
270
|
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
271
|
/** Safety cap — auto `speechEnd` after this many ms. Default `30000`. */
|
|
286
272
|
maxDurationMs?: number;
|
|
287
|
-
/**
|
|
288
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Base URL where `@ricky0123/vad-web` model / worklet assets are served.
|
|
275
|
+
* Defaults to the jsDelivr CDN.
|
|
276
|
+
*/
|
|
277
|
+
vadBaseAssetPath?: string;
|
|
278
|
+
/**
|
|
279
|
+
* Base URL where ONNX Runtime WASM binaries are served.
|
|
280
|
+
* Defaults to the jsDelivr CDN.
|
|
281
|
+
*/
|
|
282
|
+
onnxWasmBasePath?: string;
|
|
289
283
|
}
|
|
290
284
|
/**
|
|
291
|
-
*
|
|
285
|
+
* Captures microphone audio and buffers it locally. Once the user is finished
|
|
286
|
+
* talking (detected via Silero VAD), the complete audio file is emitted to the
|
|
287
|
+
* backend as a single chunk, followed by the stream termination.
|
|
292
288
|
*/
|
|
293
289
|
declare class VoiceCaptureManager extends EventEmitter<VoiceCaptureEvents> {
|
|
294
290
|
private stream;
|
|
295
|
-
private
|
|
291
|
+
private audioContext;
|
|
292
|
+
private mediaStreamSource;
|
|
293
|
+
private processor;
|
|
294
|
+
private muteNode;
|
|
296
295
|
private sequence;
|
|
297
296
|
private capturing;
|
|
298
297
|
private mimeType;
|
|
299
|
-
private
|
|
300
|
-
private silenceRaf;
|
|
298
|
+
private micVad;
|
|
301
299
|
private speechEndEmitted;
|
|
302
|
-
private captureOptions;
|
|
303
300
|
get isCapturing(): boolean;
|
|
304
301
|
get activeMimeType(): string;
|
|
305
302
|
start(options?: VoiceCaptureOptions): Promise<string>;
|
|
306
303
|
stop(): Promise<void>;
|
|
307
304
|
cancel(): void;
|
|
308
|
-
private
|
|
309
|
-
private
|
|
305
|
+
private startVadMonitor;
|
|
306
|
+
private teardownVad;
|
|
310
307
|
private releaseStream;
|
|
311
308
|
}
|
|
312
309
|
|
|
@@ -344,8 +341,6 @@ interface SynxedWebPlayerOptions {
|
|
|
344
341
|
mode?: SynxedWebPlayerMode;
|
|
345
342
|
theme?: SynxedWebPlayerTheme;
|
|
346
343
|
position?: SynxedWebPlayerPosition;
|
|
347
|
-
avatarUrl?: string;
|
|
348
|
-
voiceAvatarUrl?: string;
|
|
349
344
|
attribution?: string;
|
|
350
345
|
nowPlayingPollMs?: number;
|
|
351
346
|
powerByLabel?: string;
|
|
@@ -393,6 +388,8 @@ declare class SynxedWebPlayer {
|
|
|
393
388
|
private voiceUiDismissed;
|
|
394
389
|
private voiceHoldTimer;
|
|
395
390
|
private readonly defaultVoiceHoldMs;
|
|
391
|
+
/** Avatar to restore after an ad (DJ / album art — not ad or voice AI). */
|
|
392
|
+
private avatarImageBeforeAd;
|
|
396
393
|
constructor(options: SynxedWebPlayerOptions);
|
|
397
394
|
/** Convenience factory — same as `new SynxedWebPlayer(options)`. */
|
|
398
395
|
static mount(options: SynxedWebPlayerOptions): SynxedWebPlayer;
|
|
@@ -422,14 +419,17 @@ declare class SynxedWebPlayer {
|
|
|
422
419
|
private resetVoiceHoldState;
|
|
423
420
|
private applyVoiceVisual;
|
|
424
421
|
private isVoiceAvatarActive;
|
|
422
|
+
private getContentAvatarUrl;
|
|
425
423
|
private getAvatarImageUrl;
|
|
426
424
|
private refreshAvatarImage;
|
|
427
425
|
private startNowPlayingPoll;
|
|
428
426
|
private stopNowPlayingPoll;
|
|
429
427
|
private handleSkipClick;
|
|
430
|
-
/**
|
|
428
|
+
/**
|
|
429
|
+
* During ads: swap skip icon for countdown text in the same control (no style changes).
|
|
430
|
+
* After ads: restore skip icon for the next track.
|
|
431
|
+
*/
|
|
431
432
|
private applyAdSkipUi;
|
|
432
|
-
private clearAdSkipStyleOverrides;
|
|
433
433
|
private restoreTrackSkipButton;
|
|
434
434
|
private displayLine;
|
|
435
435
|
private refreshLabels;
|