@aituber-onair/voice
Version:
Voice synthesis library for AITuber OnAir
96 lines (95 loc) • 3.38 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BrowserAudioPlayer = void 0;
/**
* Browser-based audio player implementation using HTMLAudioElement
*/
class BrowserAudioPlayer {
constructor() {
this.audioElement = null;
this.isPlayingAudio = false;
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
this.audioElement = document.createElement('audio');
this.audioElement.addEventListener('ended', () => {
this.handlePlaybackEnd();
});
}
}
async play(audioBuffer, audioElementId) {
return new Promise((resolve, reject) => {
try {
if (typeof window === 'undefined' || typeof document === 'undefined') {
resolve();
return;
}
const blob = new Blob([audioBuffer], { type: 'audio/wav' });
const url = URL.createObjectURL(blob);
let audioEl = this.audioElement;
if (audioElementId) {
const customAudioEl = document.getElementById(audioElementId);
if (customAudioEl) {
audioEl = customAudioEl;
}
}
if (!audioEl) {
reject(new Error('Audio element not available'));
return;
}
const onEnded = () => {
URL.revokeObjectURL(url);
audioEl?.removeEventListener('ended', onEnded);
audioEl?.removeEventListener('error', onError);
this.handlePlaybackEnd();
resolve();
};
const onError = (e) => {
URL.revokeObjectURL(url);
audioEl?.removeEventListener('ended', onEnded);
audioEl?.removeEventListener('error', onError);
this.isPlayingAudio = false;
reject(new Error(`Audio playback error: ${e.message}`));
};
audioEl.addEventListener('ended', onEnded);
audioEl.addEventListener('error', onError);
this.isPlayingAudio = true;
audioEl.src = url;
audioEl.play().catch((error) => {
URL.revokeObjectURL(url);
this.isPlayingAudio = false;
reject(error);
});
}
catch (error) {
this.isPlayingAudio = false;
reject(error);
}
});
}
stop() {
if (this.audioElement) {
this.audioElement.pause();
this.audioElement.currentTime = 0;
}
this.isPlayingAudio = false;
}
isPlaying() {
return this.isPlayingAudio;
}
setOnComplete(callback) {
this.onCompleteCallback = callback;
}
dispose() {
this.stop();
if (this.audioElement) {
this.audioElement.remove();
this.audioElement = null;
}
}
handlePlaybackEnd() {
this.isPlayingAudio = false;
if (this.onCompleteCallback) {
this.onCompleteCallback();
}
}
}
exports.BrowserAudioPlayer = BrowserAudioPlayer;