teste-microphone / index.html
Ravisil's picture
Add 1 files
7af88f5 verified
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Microphone Checker | Teste seu Microfone</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.waveform {
height: 80px;
background: linear-gradient(90deg, #3b82f6, #8b5cf6);
position: relative;
overflow: hidden;
}
.waveform::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 80' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 40 Q 25 10, 50 40 T 100 40 T 150 40 T 200 40' stroke='%23ffffff10' fill='none' stroke-width='2'/%3E%3C/svg%3E");
opacity: 0.3;
}
.audio-level {
height: 100%;
width: 0;
background-color: rgba(255, 255, 255, 0.2);
transition: width 0.05s ease-out;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.pulse {
animation: pulse 2s infinite;
}
.volume-slider {
-webkit-appearance: none;
width: 100%;
height: 8px;
border-radius: 4px;
background: #e2e8f0;
outline: none;
}
.volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #3b82f6;
cursor: pointer;
transition: all 0.2s;
}
.volume-slider::-webkit-slider-thumb:hover {
background: #2563eb;
transform: scale(1.1);
}
</style>
</head>
<body class="bg-gradient-to-br from-blue-50 to-purple-50 min-h-screen">
<div class="container mx-auto px-4 py-12">
<div class="max-w-3xl mx-auto">
<!-- Header -->
<div class="text-center mb-12">
<h1 class="text-4xl font-bold text-gray-800 mb-2">Microphone Checker</h1>
<p class="text-lg text-gray-600">Verifique e teste seus dispositivos de microfone</p>
</div>
<!-- Main Card -->
<div class="bg-white rounded-xl shadow-xl overflow-hidden transition-all duration-300 hover:shadow-2xl">
<!-- Status Section -->
<div class="p-8 border-b border-gray-100">
<div class="flex items-center justify-between">
<div>
<h2 class="text-2xl font-semibold text-gray-800">Status do Microfone</h2>
<p class="text-gray-500" id="status-text">Verificando dispositivos...</p>
</div>
<div id="status-icon" class="text-4xl text-gray-400">
<i class="fas fa-microphone-slash"></i>
</div>
</div>
</div>
<!-- Device Selection -->
<div class="p-8 border-b border-gray-100" id="device-section" style="display: none;">
<h3 class="text-lg font-medium text-gray-700 mb-4">Selecione seu microfone</h3>
<select id="device-select" class="w-full p-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">Carregando dispositivos...</option>
</select>
</div>
<!-- Visualizer -->
<div class="waveform" id="visualizer">
<div class="audio-level" id="audio-level"></div>
</div>
<!-- Controls -->
<div class="p-8">
<div class="flex flex-col sm:flex-row gap-4 mb-6">
<button id="test-btn" class="flex-1 bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-6 rounded-lg transition-all flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed" disabled>
<i class="fas fa-play"></i> Testar Microfone
</button>
<button id="stop-btn" class="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-3 px-6 rounded-lg transition-all flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed" disabled>
<i class="fas fa-stop"></i> Parar Teste
</button>
</div>
<!-- Monitor Section -->
<div class="bg-purple-50 border border-purple-100 rounded-lg p-4 mb-6" id="monitor-section" style="display: none;">
<div class="flex items-center justify-between mb-3">
<h3 class="font-medium text-purple-800 flex items-center gap-2">
<i class="fas fa-headphones"></i> Monitorar Áudio
</h3>
<div class="flex items-center gap-2">
<span id="volume-value" class="text-sm text-purple-700">50%</span>
<i class="fas fa-volume-up text-purple-600"></i>
</div>
</div>
<div class="flex items-center gap-4">
<button id="monitor-btn" class="bg-purple-600 hover:bg-purple-700 text-white font-medium py-2 px-4 rounded-lg transition-all flex items-center justify-center gap-2">
<i class="fas fa-play"></i> Ouvir
</button>
<input type="range" min="0" max="100" value="50" class="volume-slider flex-1" id="volume-slider">
</div>
<div class="mt-3 flex items-center gap-2 text-sm text-purple-700">
<div class="h-3 w-3 rounded-full bg-purple-400" id="monitor-indicator"></div>
<span id="monitor-status">Pronto para monitorar</span>
</div>
</div>
<div class="mt-8 bg-blue-50 border border-blue-100 rounded-lg p-4" id="instructions">
<h3 class="font-medium text-blue-800 mb-2 flex items-center gap-2">
<i class="fas fa-info-circle"></i> Instruções
</h3>
<ol class="list-decimal list-inside text-blue-700 space-y-1">
<li>Permita o acesso ao microfone quando solicitado</li>
<li>Selecione seu dispositivo de microfone</li>
<li>Clique em "Testar Microfone" e comece a falar</li>
<li>Use o botão "Ouvir" para monitorar seu microfone em tempo real</li>
<li>O visualizador mostrará o nível de entrada de áudio</li>
</ol>
</div>
</div>
</div>
<!-- Footer -->
<div class="mt-12 text-center text-gray-500 text-sm">
<p>© 2023 Microphone Checker | Desenvolvido com <i class="fas fa-heart text-red-500"></i> para testar seus dispositivos de áudio</p>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const statusText = document.getElementById('status-text');
const statusIcon = document.getElementById('status-icon');
const deviceSection = document.getElementById('device-section');
const deviceSelect = document.getElementById('device-select');
const testBtn = document.getElementById('test-btn');
const stopBtn = document.getElementById('stop-btn');
const audioLevel = document.getElementById('audio-level');
const visualizer = document.getElementById('visualizer');
const instructions = document.getElementById('instructions');
const monitorSection = document.getElementById('monitor-section');
const monitorBtn = document.getElementById('monitor-btn');
const volumeSlider = document.getElementById('volume-slider');
const volumeValue = document.getElementById('volume-value');
const monitorStatus = document.getElementById('monitor-status');
const monitorIndicator = document.getElementById('monitor-indicator');
let audioContext;
let microphone;
let analyser;
let isTesting = false;
let devices = [];
let monitorStream = null;
let monitorGain = null;
let isMonitoring = false;
let volume = 0.5;
// Check microphone availability
checkMicrophoneAvailability();
async function checkMicrophoneAvailability() {
try {
// Request permission to list devices
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
stream.getTracks().forEach(track => track.stop());
// List audio devices
devices = await navigator.mediaDevices.enumerateDevices();
const audioDevices = devices.filter(device => device.kind === 'audioinput');
if (audioDevices.length > 0) {
// Update status
statusText.textContent = `${audioDevices.length} microfone(s) disponível(is)`;
statusIcon.innerHTML = '<i class="fas fa-microphone text-green-500 pulse"></i>';
// Show device selection and monitor section
deviceSection.style.display = 'block';
monitorSection.style.display = 'block';
populateDeviceSelect(audioDevices);
// Enable test button
testBtn.disabled = false;
} else {
statusText.textContent = 'Nenhum microfone encontrado';
statusIcon.innerHTML = '<i class="fas fa-microphone-slash text-red-500"></i>';
}
} catch (error) {
console.error('Error accessing microphone:', error);
statusText.textContent = 'Acesso ao microfone negado ou erro ao acessar';
statusIcon.innerHTML = '<i class="fas fa-microphone-slash text-red-500"></i>';
// Update instructions
instructions.querySelector('ol').innerHTML = `
<li class="text-red-500">Permissão para acessar o microfone foi negada</li>
<li>Atualize a página e permita o acesso ao microfone</li>
<li>Verifique as configurações de privacidade do seu navegador</li>
`;
}
}
function populateDeviceSelect(audioDevices) {
deviceSelect.innerHTML = '';
if (audioDevices.length === 0) {
deviceSelect.innerHTML = '<option value="">Nenhum microfone encontrado</option>';
return;
}
// Add default option
const defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = 'Selecione um microfone...';
deviceSelect.appendChild(defaultOption);
// Add devices
audioDevices.forEach(device => {
const option = document.createElement('option');
option.value = device.deviceId;
option.textContent = device.label || `Microfone ${deviceSelect.options.length}`;
deviceSelect.appendChild(option);
});
}
testBtn.addEventListener('click', startTest);
stopBtn.addEventListener('click', stopTest);
monitorBtn.addEventListener('click', toggleMonitor);
volumeSlider.addEventListener('input', updateVolume);
async function startTest() {
if (isTesting) return;
const deviceId = deviceSelect.value;
if (!deviceId) {
alert('Por favor, selecione um microfone primeiro');
return;
}
try {
isTesting = true;
testBtn.disabled = true;
stopBtn.disabled = false;
visualizer.style.background = 'linear-gradient(90deg, #10b981, #3b82f6)';
// Initialize audio context
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
analyser.fftSize = 32;
// Get microphone stream
const constraints = {
audio: {
deviceId: deviceId ? { exact: deviceId } : undefined,
echoCancellation: false,
noiseSuppression: false,
autoGainControl: false
}
};
const stream = await navigator.mediaDevices.getUserMedia(constraints);
microphone = audioContext.createMediaStreamSource(stream);
microphone.connect(analyser);
// Update UI
statusText.textContent = 'Testando microfone... Fale agora';
statusIcon.innerHTML = '<i class="fas fa-microphone text-green-500 animate-pulse"></i>';
// Start visualization
visualize();
} catch (error) {
console.error('Error starting test:', error);
statusText.textContent = 'Erro ao iniciar o teste do microfone';
statusIcon.innerHTML = '<i class="fas fa-microphone-slash text-red-500"></i>';
stopTest();
}
}
function stopTest() {
if (!isTesting) return;
isTesting = false;
testBtn.disabled = false;
stopBtn.disabled = true;
visualizer.style.background = 'linear-gradient(90deg, #3b82f6, #8b5cf6)';
// Stop all tracks
if (microphone && microphone.mediaStream) {
microphone.mediaStream.getTracks().forEach(track => track.stop());
}
// Disconnect audio nodes
if (microphone && analyser) {
microphone.disconnect();
}
// Update UI
statusText.textContent = 'Teste concluído';
statusIcon.innerHTML = '<i class="fas fa-microphone text-green-500"></i>';
audioLevel.style.width = '0';
}
function visualize() {
if (!isTesting) return;
const dataArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(dataArray);
// Calculate average volume
let sum = 0;
for (let i = 0; i < dataArray.length; i++) {
sum += dataArray[i];
}
const average = sum / dataArray.length;
// Update visualizer
audioLevel.style.width = `${average}%`;
// Color intensity based on volume
const intensity = Math.min(average / 100, 1);
const r = Math.floor(16 + (255 - 16) * intensity);
const g = Math.floor(182 + (255 - 182) * intensity);
const b = Math.floor(255 * intensity);
audioLevel.style.backgroundColor = `rgba(${r}, ${g}, ${b}, 0.5)`;
// Continue animation
requestAnimationFrame(visualize);
}
async function toggleMonitor() {
if (isMonitoring) {
stopMonitor();
} else {
await startMonitor();
}
}
async function startMonitor() {
const deviceId = deviceSelect.value;
if (!deviceId) {
alert('Por favor, selecione um microfone primeiro');
return;
}
try {
// Initialize audio context if not already done
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
// Get microphone stream
const constraints = {
audio: {
deviceId: deviceId ? { exact: deviceId } : undefined,
echoCancellation: false,
noiseSuppression: false,
autoGainControl: false
}
};
monitorStream = await navigator.mediaDevices.getUserMedia(constraints);
const source = audioContext.createMediaStreamSource(monitorStream);
// Create gain node for volume control
monitorGain = audioContext.createGain();
monitorGain.gain.value = volume;
// Connect to destination
source.connect(monitorGain);
monitorGain.connect(audioContext.destination);
// Update UI
isMonitoring = true;
monitorBtn.innerHTML = '<i class="fas fa-stop"></i> Parar';
monitorBtn.classList.remove('bg-purple-600', 'hover:bg-purple-700');
monitorBtn.classList.add('bg-red-500', 'hover:bg-red-600');
monitorStatus.textContent = 'Monitorando ativamente';
monitorIndicator.classList.remove('bg-purple-400');
monitorIndicator.classList.add('bg-green-500', 'animate-pulse');
} catch (error) {
console.error('Error starting monitor:', error);
alert('Erro ao iniciar o monitoramento: ' + error.message);
}
}
function stopMonitor() {
if (!isMonitoring) return;
// Stop all tracks
if (monitorStream) {
monitorStream.getTracks().forEach(track => track.stop());
}
// Disconnect audio nodes
if (monitorGain) {
monitorGain.disconnect();
}
// Update UI
isMonitoring = false;
monitorBtn.innerHTML = '<i class="fas fa-play"></i> Ouvir';
monitorBtn.classList.remove('bg-red-500', 'hover:bg-red-600');
monitorBtn.classList.add('bg-purple-600', 'hover:bg-purple-700');
monitorStatus.textContent = 'Pronto para monitorar';
monitorIndicator.classList.remove('bg-green-500', 'animate-pulse');
monitorIndicator.classList.add('bg-purple-400');
}
function updateVolume() {
volume = volumeSlider.value / 100;
volumeValue.textContent = `${volumeSlider.value}%`;
if (monitorGain) {
monitorGain.gain.value = volume;
}
}
// Handle device changes
navigator.mediaDevices.addEventListener('devicechange', async () => {
devices = await navigator.mediaDevices.enumerateDevices();
const audioDevices = devices.filter(device => device.kind === 'audioinput');
populateDeviceSelect(audioDevices);
if (audioDevices.length > 0) {
statusText.textContent = `${audioDevices.length} microfone(s) disponível(is)`;
statusIcon.innerHTML = '<i class="fas fa-microphone text-green-500 pulse"></i>';
monitorSection.style.display = 'block';
} else {
statusText.textContent = 'Nenhum microfone encontrado';
statusIcon.innerHTML = '<i class="fas fa-microphone-slash text-red-500"></i>';
monitorSection.style.display = 'none';
}
// Stop monitoring if device list changes
if (isMonitoring) {
stopMonitor();
}
});
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=Ravisil/teste-microphone" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
</html>