Skip to content

Instantly share code, notes, and snippets.

@mperezguendulain
Last active March 15, 2019 18:48
Show Gist options
  • Save mperezguendulain/3ef390647b274916618cfe0521a9f6bd to your computer and use it in GitHub Desktop.
Save mperezguendulain/3ef390647b274916618cfe0521a9f6bd to your computer and use it in GitHub Desktop.
import { Injectable, EventEmitter } from '@angular/core';
import * as RecordRTC from 'recordrtc';
import * as Lamejs from 'lamejs';
navigator.getUserMedia =
navigator['mediaDevices'] && navigator['mediaDevices'].getUserMedia ?
navigator['mediaDevices'].getUserMedia : ( navigator['getUserMedia'] || navigator['webkitGetUserMedia'] || navigator['mozGetUserMedia'] || navigator['msGetUserMedia'] );
enum Time {
Segundo = 1000,
Minuto = 60 * Time.Segundo,
Hora = 60 * Time.Minuto
}
@Injectable()
export class Audio2RecordService {
private currentAudioStream: MediaStream = null;;
private recordRTC: any = null;
private recStoppedEvent: EventEmitter<any> = new EventEmitter<string>();
private microphone: any = null;
private audioContext: any = null;
private mp3encoder;
private mp3Data = [];
private lameOptions = {
channels: 1, //1 for mono or 2 for stereo
sampleRate: 44100, //44.1khz (normal mp3 samplerate)
kbps: 128 //encode 128kbps mp3
};
// Processor buffer size
private readonly BUFFER_SIZE = [256, 512, 1024, 2048, 4096, 8192, 16384];
// MP3 bit ratenumberOfAudioChannels: 1
private readonly BIT_RATE = [64, 80, 96, 112, 128, 160, 192, 224, 256, 320];
constructor() {
this.mp3encoder = new Lamejs.Mp3Encoder(this.lameOptions.channels, this.lameOptions.sampleRate, this.lameOptions.kbps);
}
/**
* Inicia el proceso de grabación.
*
* @param maxRecDuration Tiempo maximo de grabación
*/
startRecording( maxRecDuration?: number ): Promise<void> {
this.mp3Data = [];
return new Promise(
( resolve, reject ) => {
this.initMicrophone()
.then(
audioStream => {
this.currentAudioStream = audioStream;
let options = {
recorderType: RecordRTC.StereoAudioRecorder,
type: 'audio',
mimeType: 'audio/wav',
numberOfAudioChannels: 1,
bufferSize: this.BUFFER_SIZE[4],
bitsPerSecond: this.BIT_RATE[4],
sampleRate: 44100,
timeSlice: 1 * Time.Segundo,
ondataavailable: this.processAudioSlice.bind(this)
};
this.recordRTC = RecordRTC(audioStream, options);
// Auto stop recording after maxRecDuration seconds
if ( maxRecDuration )
this.recordRTC.setRecordingDuration(maxRecDuration).onRecordingStopped(this.emitRecStoppedEvent.bind(this));
this.recordRTC.startRecording();
resolve();
}, error => {
reject(error);
}
);
}
);
}
/**
* Para la grabación.
*/
stopRecording(): Promise<Blob> {
return new Promise(
(resolve, reject) => {
this.recordRTC.stopRecording(
recURL => {
this.stopRecordingProcess(false);
let mp3Blob = this.getMP3File()
resolve(mp3Blob);
}
);
}
);
}
/**
* Emite una señal indicando que ha alcanzado el tiempo maximo de grabación.
*
* @param recURL
*/
emitRecStoppedEvent(recURL: string){
this.recStoppedEvent.emit(recURL);
}
/**
* Cancela la grabación.
*/
cancelRecording() {
this.recordRTC.stopRecording(
recURL => this.stopRecordingProcess(false)
);
}
/**
* Inicia el proceso de paro de la grabación.
*/
stopRecordingProcess(finish) {
this.microphone.disconnect();
this.recordRTC.clearRecordedData();
this.recordRTC = null;
if (!finish && this.microphone)
this.endMicrophone();
}
/**
* Finaliza el microfono.
*/
endMicrophone() {
this.currentAudioStream.getAudioTracks().forEach( track => track.stop() );
this.currentAudioStream = null;
this.microphone = null;
this.audioContext.close();
this.audioContext = null;
}
/**
* Codifica un archivo binario a mp3
*
* @param chunkBlob Pedazo de archivo binario a codificar
*/
processAudioSlice(chunkBlob: Blob) {
this.convBlobToBufferArray(chunkBlob)
.then(
arrayBuffer => this.encodeBufferChunkToMP3(arrayBuffer)
);
}
/**
* Codifica un pedazo de grabación a MP3.
*
* @param audioData Información a codificar
*/
encodeBufferChunkToMP3(audioData: ArrayBuffer) {
let samples = new Int16Array(audioData);
let remaining = samples.length;
let sampleBlockSize = 1152;
for (let i = 0; i < samples.length; i += sampleBlockSize) {
let sampleChunk = samples.subarray(i, i + sampleBlockSize);
var mp3buf = this.mp3encoder.encodeBuffer(sampleChunk);
if (mp3buf.length > 0) {
this.mp3Data.push(new Int8Array(mp3buf));
}
}
}
/**
* Obtiene un archivo MP3
*/
getMP3File(): Blob {
let mp3buf = this.mp3encoder.flush(); //finish writing mp3
if (mp3buf.length > 0)
this.mp3Data.push(new Int8Array(mp3buf));
let mp3Blob = new Blob(this.mp3Data, {type: 'audio/mp3'});
window.open(window.URL.createObjectURL(mp3Blob));
return mp3Blob;
}
/**
* Convierte un objeto Blob a ArrayBuffer
*
* @param blob Información binaria
*/
convBlobToBufferArray(blob: Blob): Promise<ArrayBuffer> {
return new Promise(
( resolve, reject ) => {
var fileReader = new FileReader();
fileReader.onload = ( event: any ) => {
let arrayBuffer = event.target.result;
resolve(arrayBuffer);
};
fileReader.readAsArrayBuffer(blob);
}
)
}
/**
* Inicializa el microfono.
*/
initMicrophone(): Promise<any> {
return new Promise(
(resolve, reject) => {
if (this.microphone == null) {
var AudioContext = window['AudioContext'] || window['webkitAudioContext'];
this.audioContext = new AudioContext();
if (this.audioContext.createScriptProcessor == null)
this.audioContext.createScriptProcessor = this.audioContext['createJavaScriptNode'];
if (navigator['mediaDevices'] && navigator['mediaDevices'].getUserMedia) {
navigator.getUserMedia.call(navigator['mediaDevices'], { audio: true })
.then(
stream => {
this.microphone = this.audioContext.createMediaStreamSource(stream);
resolve(stream);
}
).catch(
error => {
console.error("Error: No se puede iniciar el microfono");
reject(error);
}
);
} else {
navigator.getUserMedia(
{ audio: true },
stream => {
this.microphone = this.audioContext.createMediaStreamSource(stream);
resolve(stream);
},
error => {
console.error("Error: No se puede iniciar el microfono");
reject(error);
}
);
}
}
}
);
}
}
@mperezguendulain
Copy link
Author

mperezguendulain commented Mar 15, 2019

Angular service that records microphone audio with the help of: https://github.com/muaz-khan/RecordRTC and encodes to mp3 with the help of: https://github.com/zhuker/lamejs

I have the following problem: Every second you hear a click on the encoded audio..

Can you help me please? I have only one instance of Mp3Encoder

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment