Ionic 4 : Recording Audio and Send to Server (File has been corrupted)

3.1k views Asked by At

I would like to record the audio file in mobile application(iOS & Android) and tranfer to server as a formData in ionic 4. I have used the "cordova-plugin-media" to capture the audio using below logics

  if (this.platform.is('ios')) {
      this.filePaths = this.file.documentsDirectory;
      this.fileExtension = '.m4a';
    } else if (this.platform.is('android')) {
      this.filePaths = this.file.externalDataDirectory;
      this.fileExtension = '.3gp';
    }

  this.fileName = 'recording'+new Date().getHours()+new Date().getMinutes()+new Date().getSeconds()+this.fileExtension;

    if(this.filePaths) {
this.file.createFile(this.filePaths,this.fileName,true).then((entry:FileEntry)=> {
        this.audio = this.media.create(entry.toInternalURL());
        this.audio.startRecord();
      });
   }

Even I have tried to create the media directly without "File Creation"

I can record and play the audio, but If I am trying to send this file to server using below logics It won't send properly(corrupted data) and also web application unable to play .m4a extensions

.

Please correct me If I am doing anything wrong in my code

Upload logic:

let formData:FormData = new FormData();
 formData.append('recordID' , feedbackID);
  that.file.readAsDataURL(filePath,file.name).then((data)=>{
       const audioBlob = new Blob([data], { type: file.type });
       formData.append('files', audioBlob, file.name);
       that.uploadFormData(formData,feedbackID); //POST Logics - 
     })

;

I have used the soultion as suggested by Ankush and it works fine. Used readAsArrayBuffer instead of readAsDataURL. The .m4a format has supported both ios and android. Also I can download the the same file from web application.

1

There are 1 answers

1
Ankush Jain On BEST ANSWER

I am using below code to upload the image to the server. I assume that only a few modifications will be required in this code to transfer media instead of the image file.

private uploadPicture(imagePath: string, apiUrl: string): Observable<ApiResponse<ImageUploadResponseModel>> {

    return this.convertFileFromFilePathToBlob(imagePath).pipe(
      switchMap(item => this.convertBlobToFormData(item)),
      switchMap(formData => this.postImageToServer(formData, apiUrl))
    );
}

Rest functions used in above code:

private postImageToServer(formData: FormData, apiUrl: string): Observable<ApiResponse<ImageUploadResponseModel>> {
    const requestHeaders = new HttpHeaders({ enctype: 'multipart/form-data' });
    return this.http.post<ApiResponse<ImageUploadResponseModel>>(apiUrl, formData, { headers: requestHeaders });
}

private convertBlobToFormData(blob: Blob): Observable<FormData> {
    return new Observable<FormData>(subscriber => {
      // A Blob() is almost a File() - it's just missing the two properties below which we will add
      // tslint:disable-next-line: no-string-literal
      blob['lastModifiedDate'] = new Date();
      // tslint:disable-next-line: no-string-literal
      blob['name'] = 'sample.jpeg';
      const formData = new FormData();
      formData.append('file', blob as Blob, 'sample.jpeg');
      subscriber.next(formData);
      subscriber.complete();
    });
}

private convertFileFromFilePathToBlob(imagePath: string): Observable<Blob> {
    return new Observable<Blob>(subscriber => {
      const directoryPath = imagePath.substr(0, imagePath.lastIndexOf('/'));
      let fileName = imagePath.split('/').pop();
      fileName = fileName.split('?')[0];
      this.file.readAsArrayBuffer(directoryPath, fileName).then(fileEntry => {
          const imgBlob: any = new Blob([fileEntry], { type: 'image/jpeg' });
          imgBlob.name = 'sample.jpeg';
          subscriber.next(imgBlob);
          subscriber.complete();
      }, () => {
        subscriber.error('Some error occured while reading image from the filepath.');
      });
    });
}