Skip to content

Instantly share code, notes, and snippets.

@jdnichollsc
Last active July 17, 2021 05:18
Show Gist options
  • Save jdnichollsc/9d450ee36d9d75b201c01549f8f36fd7 to your computer and use it in GitHub Desktop.
Save jdnichollsc/9d450ee36d9d75b201c01549f8f36fd7 to your computer and use it in GitHub Desktop.
Record audio (Cordova/Ionic) using cordova-plugin-media and cordova-plugin-file
import { Media, MediaObject } from '@ionic-native/media';
import { File as NativeFile, FileEntry } from '@ionic-native/file';
import { delay, getBlobFromFileEntry } from './utils'
// Detect platform device and select extension (Cordova platform, etc)
// Android
const AUDIO_EXTENSION = '.mp3'
// iOS
const AUDIO_EXTENSION = '.m4a'
export class PageDemo {
private audioFile: FileEntry
private audioMedia: MediaObject
// private audioMediaSrc: string
async onStartRecording() {
const path = NativeFile.dataDirectory;
const name = `record_${(new Date()).getTime() + AUDIO_EXTENSION}`;
this.audioFile = await NativeFile.createFile(path, name, true);
// Deprecated versions
// this.audioMediaSrc = this.audioFile.nativeURL.replace(/^file:[\/]+/, '');
// this.audioMedia = Media.create(this.audioMediaSrc);
this.audioMedia = Media.create(this.audioFile.nativeURL);
this.audioMedia.startRecord();
}
async onStopRecording() {
if (this.audioFile) {
try {
this.audioMedia.stopRecord();
// It requires a little delay to get media file data
await delay(200);
const blob = await getBlobFromFileEntry(this.audioFile);
// SAVE AUDIO HERE!
// uploadFile(this.audioFile.name, blob)
} finally {
this.audioFile = null;
}
}
}
}
import { FileEntry } from '@ionic-native/file';
export const getBlobFromFileEntry = (fileEntry: FileEntry): Promise<Blob> => {
return new Promise((resolve, reject) => {
fileEntry.file((file) => {
const reader = new FileReader();
reader.onloadend = function(e) {
try {
const { result: buffer } = e.target
const blob = new Blob(
[new Uint8Array(buffer as any)],
{ type: file.type }
);
resolve(blob);
} catch (error) {
reject(error);
}
};
reader.onabort = (ev) => reject(ev);
reader.onerror = (ev) => reject(ev);
reader.readAsArrayBuffer(file);
}, reject)
})
}
export const delay = (time: number) =>
new Promise(resolve => setTimeout(() => resolve(), time))
@gregor-srdic
Copy link

gregor-srdic commented Jul 17, 2021

Hi guys, great example, thanks, but I am running into a strange problem (although I am setting the file path manualy as above):
W/System.err: java.io.FileNotFoundException: /storage/emulated/0/tmprecording-1626497965957.3gp: open failed: EPERM (Operation not permitted)
Adding android:requestLegacyExternalStorage="true" solved the problem, but I would need to avoid that.
Any idea? Thanks!

@jdnichollsc
Copy link
Author

Why are you using that format? 3gp. Do you know if that codec is supported by that platform? Did you request the permissions for recording audio?

@gregor-srdic
Copy link

I am not using any specific format, it seems like it is the default. This is my entire code, I didn't manually request permissions, but the dialog for recording and file access does popup.

@Injectable()
export class MediaService {
  private readonly logger = new Logger(this.constructor.name);

  constructor(private readonly media: Media, private readonly file: File) {}

  async recordAudio(): Promise<void> {
    const path = this.file.dataDirectory;
    const name = 'recording.mp3';
    const file = await this.file.createFile(path, name, true);
    console.log('file native url', file.nativeURL);

    const mediaFile: MediaObject = this.media.create(file.nativeURL);
    mediaFile.startRecord();
    await wait(10000);
    this.logger.debug('recording stopped');
    mediaFile.stopRecord();
    await wait(1000);
    this.logger.debug('playing started');
    mediaFile.play();
  }
}

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