require('bootstrap')
require('bootstrap/scss/bootstrap.scss')
require('@fortawesome/fontawesome-free/js/all')
require('./webchat.css')
const Server = require('./comm.js')
const WebRTC = require('./webrtc.js')
$(document).ready(function () {
// do not close the dropdown when selecting a mic or camera
$(document).on('click', '.dropdown-menu', function (e) {
if ($(this).hasClass('keep-open-on-click')) { e.stopPropagation() }
})
// update the list of mics and cameras
$('#settings').on('show.bs.dropdown', function () {
$('#mics').empty()
$('#cams').empty()
navigator.mediaDevices.enumerateDevices()
.then(devices => {
devices.forEach(function (device, idx) {
if (device.kind === 'audioinput') {
var radio = $(`
`)
radio.find('input').attr('value', device.deviceId)
radio.find('label').text(device.label || 'Unknown')
radio.find('label').prepend(' ')
$('#mics').append(radio)
} else if (device.kind === 'videoinput') {
radio = $(`
`)
radio.find('input').attr('value', device.deviceId)
radio.find('label').text(device.label || 'Unknown')
radio.find('label').prepend(' ')
$('#cams').append(radio)
}
})
})
})
function volumeAudioProcess(event) {
var buf = event.inputBuffer.getChannelData(0)
var bufLength = buf.length
var sum = 0
var x
// Do a root-mean-square on the samples: sum up the squares...
for (var i = 0; i < bufLength; i++) {
x = buf[i]
if (Math.abs(x) >= this.clipLevel) {
this.clipping = true
this.lastClip = window.performance.now()
}
sum += x * x
}
// ... then take the square root of the sum.
var rms = Math.sqrt(sum / bufLength)
// Now smooth this out with the averaging factor applied
// to the previous sample - take the max here because we
// want "fast attack, slow release."
this.volume = Math.max(rms, this.volume * this.averaging)
}
function createAudioMeter(audioCtx, clipLevel, averaging, clipLag) {
var processor = audioCtx.createScriptProcessor(512)
processor.onaudioprocess = volumeAudioProcess
processor.clipping = false
processor.lastClip = 0
processor.volume = 0
processor.clipLevel = clipLevel || 0.98
processor.averaging = averaging || 0.95
processor.clipLag = clipLag || 750
// this will have no effect, since we don't copy the input to the output,
// but works around a current Chrome bug.
processor.connect(audioCtx.destination)
processor.checkClipping =
function () {
if (!this.clipping) { return false }
if ((this.lastClip + this.clipLag) < window.performance.now()) { this.clipping = false }
return this.clipping
}
processor.shutdown =
function () {
this.disconnect()
this.onaudioprocess = null
}
return processor
}
function showStream(video, stream) {
// play the video
console.log('showStream', stream)
video.volume = 0
if ('srcObject' in video) {
video.srcObject = stream
} else {
video.src = URL.createObjectURL(stream)
}
video.onloadedmetadata = function (e) {
video.play()
video.muted = true
}
// set up the volume meter
var audioCtx = new AudioContext()
var source = audioCtx.createMediaStreamSource(stream)
var meter = createAudioMeter(audioCtx)
source.connect(meter)
video.meter = meter
}
// update the volume bars
setInterval(function () {
$('video').each(function () {
var volume = $(this).siblings('.volume')
if (this.meter) {
// check if we're currently clipping
if (this.meter.checkClipping()) { volume.css('background', '#ffc107') } else { volume.css('background', '#28a745') }
volume.css('height', Math.round(this.meter.volume * 140 + 5) + '%')
} else {
volume.css('height', 0)
}
})
}, 500)
navigator.mediaDevices.getUserMedia({audio: true, video: true})
.then(stream => {
console.log('Got MediaStream:', stream)
showStream($('#me')[0], stream)
})
.catch(error => {
alert('Error accessing media devices: ' + error)
})
var server = new Server()
server.ready(function () {
var webrtc = new WebRTC(server)
server.onMessage(function (msg) {
if (msg.message) {
$('#messages').append($('
').text(msg.message))
// scroll to bottom
var messagesDiv = document.getElementById('messages')
messagesDiv.scrollTop = messagesDiv.scrollHeight
} else {
webrtc.handleMessage(msg)
}
})
$('#message-input').submit(function (event) {
var message = $(this).find('input').val()
if (message) {
var msg = {message: message, sender: webrtc.identity}
server.sendMessage(msg)
}
$(this).find('input').val('')
event.preventDefault()
})
})
})