@rimori/client 2.5.28-next.1 → 2.5.28-next.3
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.
|
@@ -40,6 +40,10 @@ export interface RimoriInfo {
|
|
|
40
40
|
* - 'plugins' for beta and stable release channels
|
|
41
41
|
*/
|
|
42
42
|
dbSchema: 'plugins' | 'plugins_alpha';
|
|
43
|
+
/**
|
|
44
|
+
* Whether text-to-speech is enabled globally (set in rimori-main navbar).
|
|
45
|
+
*/
|
|
46
|
+
ttsEnabled: boolean;
|
|
43
47
|
}
|
|
44
48
|
export declare class RimoriCommunicationHandler {
|
|
45
49
|
private port;
|
|
@@ -13,6 +13,8 @@ export declare class ChunkedAudioPlayer {
|
|
|
13
13
|
private startedPlaying;
|
|
14
14
|
private onEndOfSpeech;
|
|
15
15
|
private readonly backgroundNoiseLevel;
|
|
16
|
+
private currentSource;
|
|
17
|
+
private stopped;
|
|
16
18
|
constructor();
|
|
17
19
|
private init;
|
|
18
20
|
setOnLoudnessChange(callback: (value: number) => void): void;
|
|
@@ -20,6 +20,8 @@ export class ChunkedAudioPlayer {
|
|
|
20
20
|
this.startedPlaying = false;
|
|
21
21
|
this.onEndOfSpeech = () => { };
|
|
22
22
|
this.backgroundNoiseLevel = 30; // Background noise level that should be treated as baseline (0)
|
|
23
|
+
this.currentSource = null;
|
|
24
|
+
this.stopped = false;
|
|
23
25
|
this.init();
|
|
24
26
|
}
|
|
25
27
|
init() {
|
|
@@ -37,12 +39,10 @@ export class ChunkedAudioPlayer {
|
|
|
37
39
|
}
|
|
38
40
|
addChunk(chunk, position) {
|
|
39
41
|
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
if (this.stopped)
|
|
43
|
+
return;
|
|
40
44
|
console.log('Adding chunk', position, chunk);
|
|
41
45
|
this.chunkQueue[position] = chunk;
|
|
42
|
-
// console.log("received chunk", {
|
|
43
|
-
// chunkQueue: this.chunkQueue.length,
|
|
44
|
-
// isPlaying: this.isPlaying,
|
|
45
|
-
// })
|
|
46
46
|
if (position === 0 && !this.startedPlaying) {
|
|
47
47
|
this.startedPlaying = true;
|
|
48
48
|
this.playChunks();
|
|
@@ -50,25 +50,27 @@ export class ChunkedAudioPlayer {
|
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
playChunks() {
|
|
53
|
-
|
|
54
|
-
if (this.isPlaying)
|
|
53
|
+
if (this.isPlaying || this.stopped)
|
|
55
54
|
return;
|
|
56
55
|
if (!this.chunkQueue[this.currentIndex]) {
|
|
57
56
|
// wait until the correct chunk arrives
|
|
58
57
|
setTimeout(() => this.playChunks(), 10);
|
|
58
|
+
return;
|
|
59
59
|
}
|
|
60
60
|
this.isPlaying = true;
|
|
61
61
|
this.playChunk(this.chunkQueue[this.currentIndex]).then(() => {
|
|
62
62
|
this.isPlaying = false;
|
|
63
|
+
if (this.stopped)
|
|
64
|
+
return;
|
|
63
65
|
this.currentIndex++;
|
|
64
66
|
if (this.chunkQueue[this.currentIndex]) {
|
|
65
67
|
this.shouldMonitorLoudness = true;
|
|
66
68
|
this.playChunks();
|
|
67
69
|
}
|
|
68
70
|
else {
|
|
69
|
-
// console.log('Playback finished', { currentIndex: this.currentIndex, chunkQueue: this.chunkQueue });
|
|
70
71
|
setTimeout(() => {
|
|
71
|
-
|
|
72
|
+
if (this.stopped)
|
|
73
|
+
return;
|
|
72
74
|
if (this.chunkQueue.length > this.currentIndex) {
|
|
73
75
|
this.playChunks();
|
|
74
76
|
}
|
|
@@ -81,13 +83,23 @@ export class ChunkedAudioPlayer {
|
|
|
81
83
|
});
|
|
82
84
|
}
|
|
83
85
|
stopPlayback() {
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
+
this.stopped = true;
|
|
87
|
+
// Stop the currently playing audio source node
|
|
88
|
+
if (this.currentSource) {
|
|
89
|
+
try {
|
|
90
|
+
this.currentSource.stop();
|
|
91
|
+
}
|
|
92
|
+
catch (_a) {
|
|
93
|
+
// already stopped
|
|
94
|
+
}
|
|
95
|
+
this.currentSource = null;
|
|
96
|
+
}
|
|
86
97
|
this.isPlaying = false;
|
|
87
98
|
this.chunkQueue = [];
|
|
88
99
|
this.startedPlaying = false;
|
|
89
100
|
this.shouldMonitorLoudness = false;
|
|
90
101
|
cancelAnimationFrame(this.handle);
|
|
102
|
+
this.loudnessCallback(0);
|
|
91
103
|
}
|
|
92
104
|
cleanup() {
|
|
93
105
|
// Stop playback first
|
|
@@ -100,14 +112,17 @@ export class ChunkedAudioPlayer {
|
|
|
100
112
|
}
|
|
101
113
|
}
|
|
102
114
|
playChunk(chunk) {
|
|
103
|
-
|
|
104
|
-
if (!chunk) {
|
|
115
|
+
if (!chunk || this.stopped) {
|
|
105
116
|
return Promise.resolve();
|
|
106
117
|
}
|
|
107
|
-
// console.log('Playing chunk', chunk);
|
|
108
118
|
return new Promise((resolve) => {
|
|
109
119
|
const source = this.audioContext.createBufferSource();
|
|
120
|
+
this.currentSource = source;
|
|
110
121
|
this.audioContext.decodeAudioData(chunk.slice(0)).then((audioBuffer) => {
|
|
122
|
+
if (this.stopped) {
|
|
123
|
+
resolve();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
111
126
|
source.buffer = audioBuffer;
|
|
112
127
|
// Create a GainNode for volume control
|
|
113
128
|
const gainNode = this.audioContext.createGain();
|
|
@@ -117,10 +132,11 @@ export class ChunkedAudioPlayer {
|
|
|
117
132
|
gainNode.connect(this.analyser);
|
|
118
133
|
this.analyser.connect(this.audioContext.destination);
|
|
119
134
|
source.start(0);
|
|
120
|
-
// console.log('Playing chunk', this.currentIndex);
|
|
121
135
|
gainNode.gain.value = this.volume;
|
|
122
136
|
source.onended = () => {
|
|
123
|
-
|
|
137
|
+
if (this.currentSource === source) {
|
|
138
|
+
this.currentSource = null;
|
|
139
|
+
}
|
|
124
140
|
resolve();
|
|
125
141
|
};
|
|
126
142
|
// Start monitoring loudness only once
|
|
@@ -190,11 +206,10 @@ export class ChunkedAudioPlayer {
|
|
|
190
206
|
this.handle = requestAnimationFrame(() => this.monitorLoudness());
|
|
191
207
|
}
|
|
192
208
|
reset() {
|
|
193
|
-
// console.log('Resetting player');
|
|
194
209
|
this.stopPlayback();
|
|
210
|
+
this.stopped = false;
|
|
195
211
|
this.currentIndex = 0;
|
|
196
212
|
this.shouldMonitorLoudness = true;
|
|
197
|
-
//reset to the beginning when the class gets initialized
|
|
198
213
|
this.isMonitoring = false;
|
|
199
214
|
this.isPlaying = false;
|
|
200
215
|
this.init();
|