Advertisement
Guest User

Untitled

a guest
Mar 20th, 2019
53
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.21 KB | None | 0 0
  1. import { Injectable, EventEmitter } from '@angular/core';
  2. import * as RecordRTC from 'recordrtc';
  3. import * as Lamejs from 'lamejs';
  4.  
  5. navigator.getUserMedia =
  6. navigator['mediaDevices'] && navigator['mediaDevices'].getUserMedia ?
  7. navigator['mediaDevices'].getUserMedia : ( navigator['getUserMedia'] || navigator['webkitGetUserMedia'] || navigator['mozGetUserMedia'] || navigator['msGetUserMedia'] );
  8.  
  9. enum Time {
  10. Segundo = 1000,
  11. Minuto = 60 * Time.Segundo,
  12. Hora = 60 * Time.Minuto
  13. }
  14.  
  15. @Injectable()
  16. export class Audio2RecordService {
  17.  
  18.  
  19. private currentAudioStream: MediaStream = null;;
  20. private recordRTC: any = null;
  21. private recStoppedEvent: EventEmitter<any> = new EventEmitter<string>();
  22. private microphone: any = null;
  23. private audioContext: any = null;
  24.  
  25. private mp3encoder;
  26. private mp3Data = [];
  27. private lameOptions = {
  28. channels: 1, //1 for mono or 2 for stereo
  29. sampleRate: 44100, //44.1khz (normal mp3 samplerate)
  30. kbps: 128 //encode 128kbps mp3
  31. };
  32.  
  33. // Processor buffer size
  34. private readonly BUFFER_SIZE = [256, 512, 1024, 2048, 4096, 8192, 16384];
  35. // MP3 bit ratenumberOfAudioChannels: 1
  36. private readonly BIT_RATE = [64, 80, 96, 112, 128, 160, 192, 224, 256, 320];
  37.  
  38. constructor() {
  39.  
  40. this.mp3encoder = new Lamejs.Mp3Encoder(this.lameOptions.channels, this.lameOptions.sampleRate, this.lameOptions.kbps);
  41.  
  42. }
  43.  
  44. /**
  45. * Inicia el proceso de grabación.
  46. *
  47. * @param maxRecDuration Tiempo maximo de grabación
  48. */
  49. startRecording( maxRecDuration?: number ): Promise<void> {
  50.  
  51. this.mp3Data = [];
  52.  
  53. return new Promise(
  54. ( resolve, reject ) => {
  55. this.initMicrophone()
  56. .then(
  57. audioStream => {
  58. this.currentAudioStream = audioStream;
  59. let options = {
  60. recorderType: RecordRTC.StereoAudioRecorder,
  61. type: 'audio',
  62. mimeType: 'audio/wav',
  63. numberOfAudioChannels: 1,
  64. bufferSize: this.BUFFER_SIZE[4],
  65. bitsPerSecond: this.BIT_RATE[4],
  66. sampleRate: 44100,
  67. timeSlice: 1 * Time.Segundo,
  68. ondataavailable: this.processAudioSlice.bind(this)
  69. };
  70.  
  71. this.recordRTC = RecordRTC(audioStream, options);
  72.  
  73. // Auto stop recording after maxRecDuration seconds
  74. if ( maxRecDuration )
  75. this.recordRTC.setRecordingDuration(maxRecDuration).onRecordingStopped(this.emitRecStoppedEvent.bind(this));
  76.  
  77. this.recordRTC.startRecording();
  78. resolve();
  79. }, error => {
  80. reject(error);
  81. }
  82. );
  83. }
  84. );
  85.  
  86. }
  87.  
  88. /**
  89. * Para la grabación.
  90. */
  91. stopRecording(): Promise<Blob> {
  92.  
  93.  
  94.  
  95. return new Promise(
  96. (resolve, reject) => {
  97.  
  98. this.recordRTC.stopRecording(
  99. recURL => {
  100. this.stopRecordingProcess(false);
  101. let mp3Blob = this.getMP3File()
  102. resolve(mp3Blob);
  103. }
  104. );
  105.  
  106. }
  107. );
  108.  
  109. }
  110.  
  111. /**
  112. * Emite una señal indicando que ha alcanzado el tiempo maximo de grabación.
  113. *
  114. * @param recURL
  115. */
  116. emitRecStoppedEvent(recURL: string){
  117.  
  118. this.recStoppedEvent.emit(recURL);
  119.  
  120. }
  121.  
  122. /**
  123. * Cancela la grabación.
  124. */
  125. cancelRecording() {
  126.  
  127. this.recordRTC.stopRecording(
  128. recURL => this.stopRecordingProcess(false)
  129. );
  130.  
  131. }
  132.  
  133. /**
  134. * Inicia el proceso de paro de la grabación.
  135. */
  136. stopRecordingProcess(finish) {
  137.  
  138. this.microphone.disconnect();
  139. this.recordRTC.clearRecordedData();
  140. this.recordRTC = null;
  141. if (!finish && this.microphone)
  142. this.endMicrophone();
  143.  
  144. }
  145.  
  146. /**
  147. * Finaliza el microfono.
  148. */
  149. endMicrophone() {
  150.  
  151. this.currentAudioStream.getAudioTracks().forEach( track => track.stop() );
  152. this.currentAudioStream = null;
  153. this.microphone = null;
  154.  
  155. this.audioContext.close();
  156. this.audioContext = null;
  157. }
  158.  
  159. /**
  160. * Codifica un archivo binario a mp3
  161. *
  162. * @param chunkBlob Pedazo de archivo binario a codificar
  163. */
  164. processAudioSlice(chunkBlob: Blob) {
  165.  
  166. this.convBlobToBufferArray(chunkBlob)
  167. .then(
  168. arrayBuffer => this.encodeBufferChunkToMP3(arrayBuffer)
  169. );
  170.  
  171. }
  172.  
  173. /**
  174. * Codifica un pedazo de grabación a MP3.
  175. *
  176. * @param audioData Información a codificar
  177. */
  178. encodeBufferChunkToMP3(audioData: ArrayBuffer) {
  179.  
  180. let samples = new Int16Array(audioData);
  181. let remaining = samples.length;
  182. let sampleBlockSize = 1152;
  183.  
  184. for (let i = 0; i < samples.length; i += sampleBlockSize) {
  185. let sampleChunk = samples.subarray(i, i + sampleBlockSize);
  186. var mp3buf = this.mp3encoder.encodeBuffer(sampleChunk);
  187. if (mp3buf.length > 0) {
  188. this.mp3Data.push(new Int8Array(mp3buf));
  189. }
  190. }
  191.  
  192. }
  193.  
  194. /**
  195. * Obtiene un archivo MP3
  196. */
  197. getMP3File(): Blob {
  198.  
  199. let mp3buf = this.mp3encoder.flush(); //finish writing mp3
  200.  
  201. if (mp3buf.length > 0)
  202. this.mp3Data.push(new Int8Array(mp3buf));
  203.  
  204. let mp3Blob = new Blob(this.mp3Data, {type: 'audio/mp3'});
  205. window.open(window.URL.createObjectURL(mp3Blob));
  206.  
  207.  
  208. return mp3Blob;
  209.  
  210. }
  211.  
  212. /**
  213. * Convierte un objeto Blob a ArrayBuffer
  214. *
  215. * @param blob Información binaria
  216. */
  217. convBlobToBufferArray(blob: Blob): Promise<ArrayBuffer> {
  218.  
  219. return new Promise(
  220. ( resolve, reject ) => {
  221. var fileReader = new FileReader();
  222. fileReader.onload = ( event: any ) => {
  223. let arrayBuffer = event.target.result;
  224. resolve(arrayBuffer);
  225. };
  226. fileReader.readAsArrayBuffer(blob);
  227. }
  228. )
  229.  
  230. }
  231.  
  232. /**
  233. * Inicializa el microfono.
  234. */
  235. initMicrophone(): Promise<any> {
  236.  
  237. return new Promise(
  238. (resolve, reject) => {
  239. if (this.microphone == null) {
  240. var AudioContext = window['AudioContext'] || window['webkitAudioContext'];
  241. this.audioContext = new AudioContext();
  242.  
  243. if (this.audioContext.createScriptProcessor == null)
  244. this.audioContext.createScriptProcessor = this.audioContext['createJavaScriptNode'];
  245.  
  246. if (navigator['mediaDevices'] && navigator['mediaDevices'].getUserMedia) {
  247. navigator.getUserMedia.call(navigator['mediaDevices'], { audio: true })
  248. .then(
  249. stream => {
  250. this.microphone = this.audioContext.createMediaStreamSource(stream);
  251. resolve(stream);
  252. }
  253. ).catch(
  254. error => {
  255. console.error("Error: No se puede iniciar el microfono");
  256. reject(error);
  257. }
  258. );
  259. } else {
  260. navigator.getUserMedia(
  261. { audio: true },
  262. stream => {
  263. this.microphone = this.audioContext.createMediaStreamSource(stream);
  264. resolve(stream);
  265. },
  266. error => {
  267. console.error("Error: No se puede iniciar el microfono");
  268. reject(error);
  269. }
  270. );
  271. }
  272. }
  273. }
  274. );
  275.  
  276. }
  277.  
  278. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement