111 lines
3.4 KiB
JavaScript
111 lines
3.4 KiB
JavaScript
'use strict';
|
|
|
|
const bars = document.querySelectorAll('.volume-bar');
|
|
|
|
let audioContext = null;
|
|
let workletNode = null;
|
|
|
|
/**
|
|
* Check if audio context is supported
|
|
* @returns {boolean}
|
|
*/
|
|
function isAudioContextSupported() {
|
|
return !!(window.AudioContext || window.webkitAudioContext);
|
|
}
|
|
|
|
/**
|
|
* Start to handle microphone volume indicator
|
|
* @param {MediaStream} stream Media stream audio
|
|
*/
|
|
async function getMicrophoneVolumeIndicator(stream) {
|
|
if (isAudioContextSupported() && hasAudioTrack(stream)) {
|
|
try {
|
|
// Clean up any existing resources first
|
|
stopMicrophoneProcessing();
|
|
|
|
const audioTrack = getAudioTrack(stream);
|
|
if (audioTrack) {
|
|
console.log('Start microphone volume indicator for audio track', audioTrack);
|
|
}
|
|
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
const microphone = audioContext.createMediaStreamSource(stream);
|
|
|
|
// Create and configure AudioWorkletNode
|
|
await audioContext.audioWorklet.addModule('/js/volumeProcessor.js');
|
|
workletNode = new AudioWorkletNode(audioContext, 'volume-processor', {
|
|
processorOptions: {
|
|
peerId: myPeerId, // Your peer ID
|
|
threshold: 10, // Volume threshold
|
|
silenceThreshold: 0.01, // Silence threshold
|
|
},
|
|
});
|
|
|
|
// Listen for messages from the processor
|
|
workletNode.port.onmessage = (event) => {
|
|
if (!myAudioStatus) return;
|
|
|
|
const data = event.data;
|
|
|
|
if (data.type === 'micVolume') {
|
|
// Send data to DataChannel
|
|
sendToDataChannel(data);
|
|
handleMyVolume(data); // Custom handling function
|
|
} else if (data.type === 'volumeIndicator') {
|
|
updateVolumeIndicator(data.volume); // Update volume indicator
|
|
}
|
|
};
|
|
|
|
// Connect audio graph
|
|
microphone.connect(workletNode);
|
|
workletNode.connect(audioContext.destination);
|
|
} catch (error) {
|
|
console.error('Error initializing microphone volume indicator:', error);
|
|
// Clean up on error
|
|
stopMicrophoneProcessing();
|
|
}
|
|
} else {
|
|
console.warn('Microphone volume indicator not supported for this browser');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stop microphone processing
|
|
*/
|
|
function stopMicrophoneProcessing() {
|
|
console.log('Stop microphone volume indicator');
|
|
|
|
// Clean up workletNode
|
|
if (workletNode) {
|
|
try {
|
|
workletNode.disconnect();
|
|
} catch (error) {
|
|
console.warn('Error disconnecting workletNode:', error);
|
|
}
|
|
workletNode = null;
|
|
}
|
|
|
|
// Clean up audioContext
|
|
if (audioContext) {
|
|
try {
|
|
if (audioContext.state !== 'closed') {
|
|
audioContext.close();
|
|
}
|
|
} catch (error) {
|
|
console.warn('Error closing audioContext:', error);
|
|
}
|
|
audioContext = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update volume indicator
|
|
* @param {number} volume
|
|
*/
|
|
function updateVolumeIndicator(volume) {
|
|
const normalizedVolume = Math.max(0, Math.min(1, volume));
|
|
const activeBars = Math.round(normalizedVolume * bars.length);
|
|
bars.forEach((bar, index) => {
|
|
bar.classList.toggle('active', index < activeBars);
|
|
});
|
|
}
|