Introduction
The full form of WAV is "Waveform Audio File Format." It is standard for storing an audio bitstream on computers. Developed by IBM and Microsoft, the WAV format is based on the Resource Interchange File Format (RIFF), and it is commonly used for storing uncompressed audio data on Windows systems. The files saved in the WAV format keep high quality and can be large, as they have detailed audio information.
To record audio from a microphone in an Angular application, you can make use of the native “MediaRecorder”.
The “MediaRecorder” interface of the Web API supplies functionality to easily record media. It is designed to record audio or video directly from the browser, simplifying the process of capturing media streams.
Key features and capabilities of MediaRecorder:
Media Capture: It allows you to record audio and video streams directly from the user's camera and microphone.
Stream Recording: It records the media streams in chunks, which can be processed or saved individually.
Different Media Formats: It supports various audio and video formats, depending on the browser and system.
Event Handling: It supplies several event handlers such as ondataavailable, onstart, onstop, onerror, and more to handle various aspects of recording.
Configurable: You can configure the MediaRecorder by setting options like the MIME type of the recording, the bits per second, and so on.
“MediaRecorder” is widely supported in modern browsers, but the specific codecs and formats supported can vary between browsers. It is always good practice to check the compatibility and capabilities of the browser at runtime.
The “MediaRecorder” interface simplifies the process of recording audio and video in web applications, providing developers with a powerful tool to capture and work with media streams directly in the browser.
By default, MediaRecorder captures audio as webm format. If you want a genuine WAV file and not just a webm file with a .wav extension, you'll have to convert the recorded audio buffer to WAV format.
Create an Angular 16 application using Angular CLI (Command Line Interface)
Use the command below to create a new Angular application.
ng new AudioRecorder
We can choose the default Routing and Styling options and continue further.
Create a helper class to convert audio buffer to WAV format.
audio-helper.ts
export function bufferToWave(abuffer:any, len:number) {
let numOfChan = abuffer.numberOfChannels,
length = len * numOfChan * 2 + 44,
buffer = new ArrayBuffer(length),
view = new DataView(buffer),
channels = [],
i, sample,
offset = 0,
pos = 0;
// write WAVE header
setUint32(0x46464952); // "RIFF"
setUint32(length - 8); // file length - 8
setUint32(0x45564157); // "WAVE"
setUint32(0x20746d66); // "fmt " chunk
setUint32(16); // length = 16
setUint16(1); // PCM (uncompressed)
setUint16(numOfChan);
setUint32(abuffer.sampleRate);
setUint32(abuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
setUint16(numOfChan * 2); // block-align
setUint16(16); // 16-bit (hardcoded in this demo)
setUint32(0x61746164); // "data" - chunk
setUint32(length - pos - 8); // chunk length
// write interleaved data
for (i = 0; i < abuffer.numberOfChannels; i++)
channels.push(abuffer.getChannelData(i));
while (pos < length) {
for (i = 0; i < numOfChan; i++) { // interleave channels
sample = Math.max(-1, Math.min(1, channels[i][offset])); // clamp
sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767)|0; // scale to 16-bit signed int
view.setInt16(pos, sample, true); // write 16-bit sample
pos += 2;
}
offset++ // next source sample
}
// create Blob
return new Blob([buffer], { type: "audio/wav" });
function setUint16(data:any) {
view.setUint16(pos, data, true);
pos += 2;
}
function setUint32(data:any) {
view.setUint32(pos, data, true);
pos += 4;
}
}
We can create an Audio Recording service and integrate the helper function in the service.
ng g s AudioRecording
audio-recording-service.ts
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { bufferToWave } from './audio-helper';
@Injectable({
providedIn: 'root'
})
export class AudioRecordingService {
private chunks: any[] = [];
private mediaRecorder: any;
private audioContext: AudioContext = new AudioContext();
private audioBlobSubject = new Subject<Blob>();
audioBlob$ = this.audioBlobSubject.asObservable();
async startRecording() {
if (this.audioContext.state === 'suspended') {
await this.audioContext.resume();
}
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
this.mediaRecorder = new MediaRecorder(stream);
this.mediaRecorder.ondataavailable = (event: any) => this.chunks.push(event.data);
this.mediaRecorder.start();
}
async stopRecording() {
if (this.mediaRecorder) {
this.mediaRecorder.onstop = async () => {
const audioData = await new Blob(this.chunks).arrayBuffer();
const audioBuffer = await this.audioContext.decodeAudioData(audioData);
const wavBlob = bufferToWave(audioBuffer, audioBuffer.length);
this.audioBlobSubject.next(wavBlob);
this.chunks = [];
};
this.mediaRecorder.stop();
}
}
}
Update the component html file with code below.
app.component.html
<div class="content" role="main">
<div class="row justify-content-center pt-2 pb-2">
<button title="Click here to start recording action" class="btn-mic w-auto" (click)="startRecording()"
*ngIf="!isRecording" style="margin-right: 3px;">
<img src="../../assets/mic.png" />
</button>
<button title="Click here to stop recording" class="btn-stop w-auto" (click)="stopRecording()" *ngIf="isRecording"
style="margin-right: 3px;">
<img src="../../assets/stop.png" />
</button>
</div>
<audio #audioPlayer controls style="margin: 10px;"></audio>
<a *ngIf="audioURL" [href]="audioURL" download="recorded_audio.wav">Download last reecorded Audio</a>
</div>


danishPosted May 15, 2024, 6:21 AM
The code you provide is not work anymore.
marcosPosted Apr 17, 2024, 7:16 PM
Hola, como podria cambiarlo en vez de que sea WAV que sea MP3, GRACIAS y SALUDOS
Jamil MoughalPosted Oct 22, 2023, 4:31 PM
Thanks for sharing