Created
August 6, 2025 17:43
-
-
Save JayGoldberg/c0d209a7385551515bff1a259f51b755 to your computer and use it in GitHub Desktop.
A "push-to-talk" app. This example uses plain HTML and JavaScript, leveraging the MediaDevices API for microphone access and the MediaRecorder API to handle the recording. Handles all the logic: requesting microphone access, starting and stopping the recording based on button presses, and creating a downloadable link for the final audio file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Push-to-Talk Recorder</title> | |
<style> | |
body { | |
font-family: sans-serif; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
justify-content: center; | |
height: 100vh; | |
margin: 0; | |
background-color: #f0f0f0; | |
} | |
#recordButton { | |
padding: 20px 40px; | |
font-size: 1.5em; | |
cursor: pointer; | |
border: none; | |
border-radius: 10px; | |
background-color: #007bff; | |
color: white; | |
transition: background-color 0.2s ease; | |
} | |
#recordButton:active { | |
background-color: #0056b3; | |
} | |
#download-link { | |
margin-top: 20px; | |
display: none; /* Initially hidden */ | |
font-size: 1.2em; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Hold to Talk</h1> | |
<button id="recordButton">Push to Talk</button> | |
<a id="download-link" href="#" download="my-recording.webm">Download Recording</a> | |
<script src="app.js"></script> | |
</body> | |
<script> | |
let mediaRecorder; | |
let audioChunks = []; | |
let stream; | |
const recordButton = document.getElementById('recordButton'); | |
const downloadLink = document.getElementById('download-link'); | |
// Request microphone access when the page loads | |
navigator.mediaDevices.getUserMedia({ audio: true }) | |
.then(s => { | |
stream = s; | |
console.log('Microphone access granted!'); | |
}) | |
.catch(err => { | |
console.error('Microphone access denied:', err); | |
alert('Please allow microphone access to use this feature.'); | |
}); | |
// Start recording when the button is held down | |
recordButton.addEventListener('mousedown', () => { | |
if (!stream) { | |
alert('Microphone access not granted yet. Please refresh and allow.'); | |
return; | |
} | |
// Create a new MediaRecorder instance | |
mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' }); | |
// Store audio data chunks as they become available | |
mediaRecorder.ondataavailable = e => { | |
audioChunks.push(e.data); | |
}; | |
// Begin recording | |
mediaRecorder.start(); | |
recordButton.textContent = 'Recording...'; | |
downloadLink.style.display = 'none'; // Hide the download link while recording | |
console.log('Recording started.'); | |
}); | |
// Stop recording when the button is released | |
recordButton.addEventListener('mouseup', () => { | |
if (mediaRecorder && mediaRecorder.state === 'recording') { | |
// Stop the recorder | |
mediaRecorder.stop(); | |
recordButton.textContent = 'Push to Talk'; | |
console.log('Recording stopped.'); | |
// This event is fired when the recording is stopped | |
mediaRecorder.onstop = () => { | |
// Combine all recorded chunks into a single Blob | |
const audioBlob = new Blob(audioChunks, { type: 'audio/webm' }); | |
// Create a URL for the Blob | |
const audioUrl = URL.createObjectURL(audioBlob); | |
// Update the download link | |
downloadLink.href = audioUrl; | |
downloadLink.style.display = 'block'; // Show the download link | |
// Clear the chunks array for the next recording | |
audioChunks = []; | |
}; | |
} | |
}); | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment