Audio Devices
Manage microphones, speakers, and audio settings in your PTT application.
Built-in Audio Player
The SDK includes a built-in audio player that automatically handles playback of incoming broadcasts — no manual audio setup required. Broadcasts are queued and played in order. The controls below let you customize which devices are used and adjust volume.
Listing Available Devices
Get lists of available audio input (microphones) and output (speakers) devices:
TypeScript
// Get all microphones
const microphones = await talker.getAudioInputDevices();
console.log('Available microphones:', microphones);
// Get all speakers
const speakers = await talker.getAudioOutputDevices();
console.log('Available speakers:', speakers);
// Each device is a MediaDeviceInfo object:
// {
// deviceId: string,
// label: string,
// kind: 'audioinput' | 'audiooutput',
// groupId: string
// }
Permission Required
Device labels are only available after the user has granted microphone permission. Before permission is granted, label will be empty.
Selecting Devices
Select Microphone
TypeScript
const microphones = await talker.getAudioInputDevices();
// Select a specific microphone
await talker.setAudioInputDevice(microphones[1].deviceId);
// The change takes effect immediately for any active or future recordings
Select Speaker
TypeScript
const speakers = await talker.getAudioOutputDevices();
// Select a specific speaker
await talker.setAudioOutputDevice(speakers[0].deviceId);
// Audio playback will now use the selected speaker
Building a Device Picker UI
TypeScript
async function populateDeviceSelectors() {
const micSelect = document.getElementById('mic-select') as HTMLSelectElement;
const speakerSelect = document.getElementById('speaker-select') as HTMLSelectElement;
// Get devices
const microphones = await talker.getAudioInputDevices();
const speakers = await talker.getAudioOutputDevices();
// Populate microphone dropdown
micSelect.innerHTML = '';
microphones.forEach(device => {
const option = document.createElement('option');
option.value = device.deviceId;
option.textContent = device.label || `Microphone ${micSelect.options.length + 1}`;
micSelect.appendChild(option);
});
// Populate speaker dropdown
speakerSelect.innerHTML = '';
speakers.forEach(device => {
const option = document.createElement('option');
option.value = device.deviceId;
option.textContent = device.label || `Speaker ${speakerSelect.options.length + 1}`;
speakerSelect.appendChild(option);
});
// Handle selection changes
micSelect.addEventListener('change', async () => {
await talker.setAudioInputDevice(micSelect.value);
});
speakerSelect.addEventListener('change', async () => {
await talker.setAudioOutputDevice(speakerSelect.value);
});
}
Volume Control
TypeScript
// Set volume (0 to 1)
talker.setVolume(0.8);
// Volume slider example
const volumeSlider = document.getElementById('volume') as HTMLInputElement;
volumeSlider.addEventListener('input', () => {
const volume = parseFloat(volumeSlider.value);
talker.setVolume(volume);
});
Muting Audio
Mute Speaker
TypeScript
// Mute incoming audio
talker.setSpeakerEnabled(false);
// Unmute
talker.setSpeakerEnabled(true);
// Toggle mute button
let speakerMuted = false;
muteButton.addEventListener('click', () => {
speakerMuted = !speakerMuted;
talker.setSpeakerEnabled(!speakerMuted);
muteButton.textContent = speakerMuted ? 'Unmute' : 'Mute';
});
Mute Microphone
TypeScript
// Disable microphone
talker.setMicrophoneEnabled(false);
// Re-enable microphone
talker.setMicrophoneEnabled(true);
Monitoring Audio Levels
Display real-time microphone input levels:
TypeScript
function startAudioMeter() {
const meter = document.getElementById('audio-meter');
function update() {
// Returns 0-1
const level = talker.getAudioLevel();
// Update visual meter
meter.style.width = `${level * 100}%`;
// Color based on level
if (level > 0.8) {
meter.style.backgroundColor = '#ef4444'; // Red - too loud
} else if (level > 0.1) {
meter.style.backgroundColor = '#10b981'; // Green - good
} else {
meter.style.backgroundColor = '#64748b'; // Gray - quiet
}
requestAnimationFrame(update);
}
update();
}
Handling Device Changes
Detect when devices are connected or disconnected:
TypeScript
// Listen for device changes
navigator.mediaDevices.addEventListener('devicechange', async () => {
console.log('Audio devices changed');
// Refresh device lists
await populateDeviceSelectors();
// Optionally notify user
showNotification('Audio devices updated');
});
Requesting Permissions
Request microphone permission before PTT:
TypeScript
async function requestMicrophonePermission(): Promise {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
// Stop the stream immediately - we just needed permission
stream.getTracks().forEach(track => track.stop());
return true;
} catch (error) {
if (error.name === 'NotAllowedError') {
showError('Microphone permission denied. Please enable it in your browser settings.');
} else if (error.name === 'NotFoundError') {
showError('No microphone found. Please connect a microphone.');
} else {
showError('Failed to access microphone: ' + error.message);
}
return false;
}
}
// Request permission on page load or button click
async function init() {
const hasPermission = await requestMicrophonePermission();
if (hasPermission) {
// Now device labels will be available
await populateDeviceSelectors();
}
}
Complete Settings Panel
HTML
<div class="audio-settings">
<h3>Audio Settings</h3>
<div class="setting-group">
<label for="mic-select">Microphone</label>
<select id="mic-select"></select>
</div>
<div class="setting-group">
<label for="speaker-select">Speaker</label>
<select id="speaker-select"></select>
</div>
<div class="setting-group">
<label for="volume">Volume</label>
<input type="range" id="volume" min="0" max="1" step="0.1" value="1">
</div>
<div class="setting-group">
<label>Input Level</label>
<div class="meter-container">
<div id="audio-meter"></div>
</div>
</div>
<button id="test-mic">Test Microphone</button>
</div>
TypeScript
class AudioSettings {
constructor(private talker: TalkerClient) {
this.init();
}
private async init() {
await this.populateDevices();
this.setupEventListeners();
this.startMeter();
}
private async populateDevices() {
const micSelect = document.getElementById('mic-select') as HTMLSelectElement;
const speakerSelect = document.getElementById('speaker-select') as HTMLSelectElement;
const [microphones, speakers] = await Promise.all([
this.talker.getAudioInputDevices(),
this.talker.getAudioOutputDevices(),
]);
micSelect.innerHTML = microphones.map(d =>
`<option value="${d.deviceId}">${d.label || 'Microphone'}</option>`
).join('');
speakerSelect.innerHTML = speakers.map(d =>
`<option value="${d.deviceId}">${d.label || 'Speaker'}</option>`
).join('');
}
private setupEventListeners() {
document.getElementById('mic-select')!.addEventListener('change', (e) => {
this.talker.setAudioInputDevice((e.target as HTMLSelectElement).value);
});
document.getElementById('speaker-select')!.addEventListener('change', (e) => {
this.talker.setAudioOutputDevice((e.target as HTMLSelectElement).value);
});
document.getElementById('volume')!.addEventListener('input', (e) => {
this.talker.setVolume(parseFloat((e.target as HTMLInputElement).value));
});
navigator.mediaDevices.addEventListener('devicechange', () => {
this.populateDevices();
});
}
private startMeter() {
const meter = document.getElementById('audio-meter')!;
const update = () => {
const level = this.talker.getAudioLevel();
meter.style.width = `${level * 100}%`;
requestAnimationFrame(update);
};
update();
}
}