This example records from the selected audio input device (microphone) and plays to the selected audio output device (speaker). Be aware of a possible audio loop.
The web browser will block you from getting a proper media device list when just running on filesystem files. You’ll have to host them on a web server, which can be local.
For testing purposes under Windows just activate IIS under the system features. The localhost files are kept under ‘C:\inetpub\wwwroot’. Put the following files in a subfolder. Then open them with the web browser at ‘localhost/<subfolder>’.
index.html
<html> <head> <script src="script.js" defer></script> </head> <body> <table> <tr><td>Input</td><td><select id='input'></select></td></tr> <tr><td>Output</td><td><select id='output'></select></td></tr> </table> <audio id='player' autoplay></audio> </body> </html>
script.js
const input = document.getElementById('input'); const output = document.getElementById('output'); const player = document.getElementById('player'); function setStream(stream) { player.srcObject = stream; }; function getDevices() { return navigator.mediaDevices.enumerateDevices(); } function fillLists(devices) { devices.forEach(function(device) { const option = document.createElement('option'); option.value = device.deviceId; if (device.kind === 'audioinput') { option.text = (device.label || 'Audio Input Device ' + input.length); input.appendChild(option); } else if (device.kind === 'audiooutput') { option.text = (device.label || 'Audio Output Device ' + output.length); output.appendChild(option); } }); } function outputChanged() { player.setSinkId(output.value ? output.value : 'default'); } function inputChanged() { const constraint = { audio: { deviceId: input.value ? input.value : 'default' } }; navigator.mediaDevices.getUserMedia(constraint) .then(setStream); } function initalize() { navigator.mediaDevices.getUserMedia({ audio: true }) .then(setStream).then(getDevices).then(fillLists); } output.onchange = outputChanged; input.onchange = inputChanged; initalize();