diff options
Diffstat (limited to 'public/js/components/voice-level.js')
| -rw-r--r-- | public/js/components/voice-level.js | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/public/js/components/voice-level.js b/public/js/components/voice-level.js new file mode 100644 index 0000000..44e9ccc --- /dev/null +++ b/public/js/components/voice-level.js @@ -0,0 +1,39 @@ +/* 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); + }, +}); |