/* global AFRAME */ // Measures how loud a remote person is talking (0..1) from their incoming voice // stream, for lip-sync and the speaking indicator. AFRAME.registerComponent('voice-level', { init() { this.level = 0; this.analyser = null; this.samples = null; this.onSoundSource = (evt) => { const source = evt.detail.soundSource; if (this.analyser) this.analyser.disconnect(); this.analyser = source.context.createAnalyser(); this.analyser.fftSize = 512; this.samples = new Uint8Array(this.analyser.fftSize); source.connect(this.analyser); }; this.el.addEventListener('sound-source-set', this.onSoundSource); }, remove() { this.el.removeEventListener('sound-source-set', this.onSoundSource); if (this.analyser) this.analyser.disconnect(); }, tick() { if (!this.analyser) return; this.analyser.getByteTimeDomainData(this.samples); let sum = 0; for (let i = 0; i < this.samples.length; i++) { const v = (this.samples[i] - 128) / 128; sum += v * v; } const rms = Math.sqrt(sum / this.samples.length); const target = Math.min(1, Math.max(0, (rms - 0.012) * 9)); // Open quickly, close a little slower, so mouths don't chatter. this.level += (target - this.level) * (target > this.level ? 0.6 : 0.2); }, });