import {ApplicationRef, ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, OnInit, Output, NgZone, OnChanges} from '@angular/core'; import {NzMessageService, NzNotificationService, UploadFile} from 'ng-zorro-antd'; import {HttpClient, HttpEvent, HttpEventType, HttpRequest} from '@angular/common/http'; import {environment} from '../../../environments/environment'; declare var Recorder; @Component({ selector: 'app-audio-recorder', templateUrl: './audio-recorder.component.html', styleUrls: ['./audio-recorder.component.scss'] }) export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { _audioUrl: string; audio = new Audio(); playIcon = 'play'; isPlaying = false; isRecording = false; isUploading = false; type = Type.UPLOAD; // record | upload Type = Type; @Input() withRmBtn = false; uploadUrl; uploadData; @Input() needRemove = false; @Input() audioItem: any = null; @Input() set audioUrl(url) { this._audioUrl = url; if (url) { this.audio.src = this._audioUrl; this.audio.load(); } this.init(); } get audioUrl() { return this._audioUrl; } @Output() audioUploaded = new EventEmitter(); @Output() audioUploadFailure = new EventEmitter(); @Output() audioRemoved = new EventEmitter(); percent = 0; progress = 0; recorder: any; audioBlob: any; constructor( private nzMessageService: NzMessageService, private zone: NgZone, private nzNotificationService: NzNotificationService, private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef, private httpClient: HttpClient) { this.uploadUrl = (<any> window).courseware.uploadUrl(); this.uploadData = (<any> window).courseware.uploadData(); window['air'].getUploadCallback = (url, data) => { this.uploadUrl = url; this.uploadData = data; }; this.recorder = new Recorder({ sampleRate: 44100, // 采样频率,默认为44100Hz(标准MP3采样率) bitRate: 128, // 比特率,默认为128kbps(标准MP3质量) success: () => { // 成功回调函数 }, error: (msg) => { // 失败回调函数 this.nzNotificationService.error('Init Audio Recorder Failed', msg, {nzDuration: 0}); }, fix: (msg) => { // 不支持H5录音回调函数 this.nzNotificationService.error('Init Audio Recorder Failed', msg, {nzDuration: 0}); } }); } init() { this.playIcon = 'play'; this.isPlaying = false; this.isRecording = false; this.isUploading = false; this.percent = 0; this.progress = 0; this.audioBlob = null; } ngOnChanges() { // if (!this.audioItem || !this.audioItem.type) { // return; // } // this.beforeUpload(this.audioItem); } ngOnInit() { this.audio.onplay = () => { this.onPlay(); }; this.audio.onpause = () => { this.onPause(); }; this.audio.ontimeupdate = (event) => { this.onTimeUpdate(event); }; this.audio.onended = (event) => { this.onEnded(); }; } ngOnDestroy() { this.audio.pause(); this.isPlaying = false; this.audio.remove(); if (this.recorder.worker) { this.recorder.worker.terminate(); } } progressText(percent) { return ``; } onPlay() { console.log('play'); this.playIcon = 'pause'; this.isPlaying = true; this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); } onPause() { console.log('pause'); this.playIcon = 'play'; this.isPlaying = false; this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); } onEnded() { console.log('on end'); this.playIcon = 'play'; this.percent = 0; this.isPlaying = false; this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); } onTimeUpdate(event) { this.percent = Math.floor((this.audio.currentTime / this.audio.duration) * 100); } onBtnPlay() { if (this.isRecording) { this.nzMessageService.warning('In Recording'); return; } if (this.isPlaying) { this.audio.pause(); } else { this.audio.play(); } } // 开始录音 onBtnRecord = () => { if (!this.isRecording) { this.isRecording = true; this.recorder.start(); } else { this.isRecording = false; this.recorder.stop(); this.recorder.getBlob((blob) => { this.audio.src = URL.createObjectURL(blob); this.audioBlob = blob; this.isUploading = true; const formData = new FormData(); formData.append('file', blob, 'courseware-item-record.mp3'); const req = new HttpRequest('POST', this.uploadUrl, formData, { reportProgress: true }); this.httpClient.request(req) .subscribe((event: HttpEvent<any>) => { switch (event.type) { case HttpEventType.UploadProgress: this.zone.run(() => { this.progress = Math.floor(100 * event.loaded / event.total); this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); }); break; case HttpEventType.Response: this.zone.run(() => { console.log(event); this.audioUploaded.emit(event.body); this.isUploading = false; this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); }); break; } }, (error) => { console.error(error); this.isUploading = false; }); }); } } // 切换模式 onBtnSwitchType() { if (this.isUploading) { this.nzMessageService.warning('In Uploading'); return; } else if (this.isRecording) { this.nzMessageService.warning('In Recording'); return; } if (this.type === Type.RECORD) { this.type = Type.UPLOAD; } else { this.type = Type.RECORD; } this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); } refresh() { setTimeout(() => { this.appRef.tick(); }, 1); } onBtnClearAudio() { this.audioUrl = null; this.audioRemoved.emit(); this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); } onBtnDeleteAudio() { this.audioUrl = null; this.audioRemoved.emit(); this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); } handleChange(info: { type: string, file: UploadFile, event: any }): void { switch (info.type) { case 'start': this.isUploading = true; this.progress = 0; break; case 'success': this.isUploading = false; this.uploadSuccess(info.file.response); this.audioUploaded.emit(info.file.response); break; case 'progress': this.progress = parseInt(info.event.percent, 10); break; } this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); } checkSelectFile(file: any) { if (!file) { return; } const isAudio = ['audio/mp3', 'audio/wav', 'audio/ogg'].includes(file.type); if (!isAudio) { this.nzMessageService.error('You can only upload Audio file ( mp3 | wav |ogg)'); return; } const delta = 25; const isOverSize = (file.size / 1024 / 1024) < delta; if (!isOverSize) { this.nzMessageService.error(`audio file must smaller than ${delta}MB!`); return false; } return true; } beforeUpload = (file: File) => { this.audioUrl = null; if (!this.checkSelectFile(file)) { return false; } this.isUploading = true; this.progress = 0; } uploadSuccess = (url) => { this.nzMessageService.info('Upload Success'); this.isUploading = false; this.audioUrl = url; this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); } uploadFailure = (err, file) => { this.isUploading = false; if (err.name && err.name === 'cancel') { return; } console.log(err); this.nzMessageService.error('Upload Error ' + err.message); this.audioUploadFailure.emit(file); this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); } doProgress = (p) => { if (p > 1) { p = 1; } if (p < 0) { p = 0; } // console.log(Math.floor(p * 100)); this.progress = Math.floor(p * 100); this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); } } enum Type { RECORD = 1, UPLOAD }