teste-micro / index.html
Ravisil's picture
Add 2 files
6e694cf verified
raw
history blame
15.8 kB
<!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;
}
</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">
<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>
<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>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');
let audioContext;
let microphone;
let analyser;
let isTesting = false;
let devices = [];
// 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
deviceSection.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);
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);
}
// 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>';
} else {
statusText.textContent = 'Nenhum microfone encontrado';
statusIcon.innerHTML = '<i class="fas fa-microphone-slash text-red-500"></i>';
}
});
});
</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>