Introduction:
PCM (Pulse Code Modulation) is an audio encoding format that converts analog audio signals into digital data, commonly used for audio recording and storage. While it offers high-quality, lossless audio reproduction, PCM files are typically large and require specialized hardware or software support. Players like MPlayer and Audacity can handle PCM files, and various converters can transform PCM into more common formats like MP3.
Web browsers cannot directly play PCM audio files because this format lacks the necessary metadata that players require to properly interpret the audio data. PCM represents sound as raw digital values without headers containing information about sample rate, channel count, bit depth, or data size.
To implement real-time PCM audio playback in web browsers, we can use the pcm-player JavaScript library combined with WebSockets for streaming audio data.
1. Installing the pcm-player Package
The pcm-player library enables PCM audio playback in browser environments. This JavaScript package handles the conversion of raw PCM data into audible sound, making it ideal for web applications requiring real-time audio processing.
npm install pcm-player
2. Importing the Library
import AudioStreamer from 'pcm-player'
3. Creating an Audio Streaming Module
The following implementation establishes a WebSocket connection to receive PCM audio data and streams it to the browser using the pcm-player library:
import AudioStreamer from 'pcm-player';
let audioConnection = null;
const audioStreamer = new AudioStreamer({
encoding: '16bitInt', // Bit depth
channels: 1, // Mono channel
sampleRate: 16000, // Sampling rate
flushingTime: 1000, // PCM buffer flush interval
onstatechange: (node, event, status) => {}, // State change handler
onended: (node, event) => {} // Playback completion handler
});
function establishAudioStream(serverUrl) {
// Check WebSocket support
if (typeof(WebSocket) !== "function") {
alert("Your browser doesn't support WebSocket protocol. Please use a compatible browser.");
return;
}
audioConnection = new WebSocket(serverUrl);
// Message handler
audioConnection.onmessage = function(event) {
const response = JSON.parse(event.data);
if (response.audioData && response.audioData !== "") {
const pcmBuffer = convertBase64ToAudioBuffer(response.audioData);
audioStreamer.feed(pcmBuffer); // Send PCM data to the audio streamer
}
};
// Connection close handler
audioConnection.onclose = function(event) {
console.log("Audio stream connection closed");
};
// Connection open handler
audioConnection.onopen = function() {
console.info("Audio stream connection established");
};
// Error handler
audioConnection.onerror = function(error) {
console.error("WebSocket connection error occurred");
};
}
function convertBase64ToAudioBuffer(base64String) {
const decodedData = window.atob(base64String);
const byteLength = decodedData.length;
const audioBuffer = new Uint8Array(byteLength);
for (let i = 0; i < byteLength; i++) {
audioBuffer[i] = decodedData.charCodeAt(i);
}
return audioBuffer;
}
function sendAudioCommand(command) {
if (audioConnection && audioConnection.readyState === WebSocket.OPEN) {
audioConnection.send(JSON.stringify(command));
console.log("Command sent:", command);
}
}
function terminateAudioStream() {
if (audioConnection) {
audioConnection.close();
console.info("Audio stream terminated");
}
}
// Export public methods for external use
export {
establishAudioStream,
terminateAudioStream,
sendAudioCommand
}
4. Starting Audio Playback
audioStreamer.continue()
5. Pausing Audio Playback
audioStreamer.pause()