TeaWeb/js/voice/AudioController.ts

115 lines
3.6 KiB
TypeScript
Raw Normal View History

2018-03-07 20:14:36 +01:00
enum PlayerState {
PREBUFFERING,
PLAYING,
BUFFERING,
STOPPED
}
2018-03-07 19:06:52 +01:00
class AudioController {
private static _globalContext;
static get globalContext() : AudioContext {
if(this._globalContext) return this._globalContext;
this._globalContext = new AudioContext();
return this._globalContext;
}
speakerContext: AudioContext;
2018-03-07 20:14:36 +01:00
private timeIndex: number = 0;
private playerState: PlayerState = PlayerState.STOPPED;
private audioCache: AudioBuffer[];
private _playingSources: AudioBufferSourceNode[] = [];
2018-03-24 23:38:01 +01:00
allowBuffering: boolean = true;
2018-03-07 20:14:36 +01:00
2018-03-07 19:06:52 +01:00
//Events
onSpeaking: () => void;
onSilence: () => void;
constructor() {
this.speakerContext = AudioController.globalContext;
this.audioCache = [];
this.onSpeaking = function () { };
this.onSilence = function () { };
}
2018-03-07 20:14:36 +01:00
playBuffer(buffer: AudioBuffer) {
2018-03-07 19:06:52 +01:00
if (buffer.sampleRate != this.speakerContext.sampleRate)
console.warn("[AudioController] Source sample rate isn't equal to playback sample rate!");
this.audioCache.push(buffer);
2018-03-07 20:14:36 +01:00
if(this.playerState == PlayerState.STOPPED) {
console.log("[Audio] Starting new playback");
this.playerState = PlayerState.PREBUFFERING;
//New audio
2018-03-07 19:06:52 +01:00
}
2018-03-07 20:14:36 +01:00
switch (this.playerState) {
case PlayerState.PREBUFFERING:
case PlayerState.BUFFERING:
if(this.audioCache.length < 5) {
if(this.playerState == PlayerState.BUFFERING) {
if(this.allowBuffering) break;
} else break;
}
if(this.playerState == PlayerState.PREBUFFERING) {
console.log("[Audio] Prebuffering succeeded (Replaying now)");
this.onSpeaking();
} else {
if(this.allowBuffering)
console.log("[Audio] Buffering succeeded (Replaying now)");
}
this.timeIndex = 0; //Instant replay
this.playerState = PlayerState.PLAYING;
case PlayerState.PLAYING:
this.playCache(this.audioCache);
break;
default:
break;
2018-03-07 19:06:52 +01:00
}
}
2018-03-07 20:14:36 +01:00
private playCache(cache) {
2018-03-07 19:06:52 +01:00
while (cache.length) {
let buffer = cache.shift();
let source = this.speakerContext.createBufferSource();
source.buffer = buffer;
source.connect(this.speakerContext.destination);
source.onended = () => {
this._playingSources.remove(source);
2018-03-07 20:14:36 +01:00
this.testBufferQueue();
2018-03-07 19:06:52 +01:00
};
2018-03-07 20:14:36 +01:00
if (this.timeIndex == 0) {
this.timeIndex = this.speakerContext.currentTime;
2018-03-07 19:06:52 +01:00
console.log("New next time!");
}
2018-03-07 20:14:36 +01:00
source.start(this.timeIndex);
this.timeIndex += source.buffer.duration;
2018-03-07 19:06:52 +01:00
this._playingSources.push(source);
}
};
stopAudio(now: boolean = false) {
2018-03-07 20:14:36 +01:00
this.playerState = PlayerState.STOPPED;
2018-03-07 19:06:52 +01:00
if(now) {
for(let e of this._playingSources)
e.stop();
this._playingSources = [];
}
}
2018-03-07 20:14:36 +01:00
private testBufferQueue() {
2018-03-07 19:06:52 +01:00
if(this._playingSources.length == 0) {
2018-03-07 20:14:36 +01:00
if(this.playerState != PlayerState.STOPPED) {
this.playerState = PlayerState.BUFFERING;
if(!this.allowBuffering)
2018-03-24 23:38:01 +01:00
console.warn("[Audio] Detected a buffer underflow!");
} else this.onSilence();
2018-03-07 19:06:52 +01:00
}
}
close(){
}
}