I'm submitting a ... (check one with "x")
[x] bug report
[ ] feature request
Current behavior:
Deployed to an android v5.1.1 tablet and the code hits all console.log message successfully.
Expected behavior:
the audio file should have the content and appears in correct path.
Steps to reproduce:
Related code:
import { Component } from '@angular/core';
import { Platform, IonicPage, NavController } from 'ionic-angular';
import { MediaPlugin, MediaObject } from '@ionic-native/media';
import { File } from '@ionic-native/file';
constructor(public navCtrl: NavController, private media: MediaPlugin, private file: File, private platform: Platform) {
this.platform.ready().then(() => {
if (!this.platform.is('cordova')) {
return false;
}
if (this.platform.is('ios')) {
this.storageDirectory = file.documentsDirectory.replace(/^file:\/\//, '');
}
else if (this.platform.is('android')) {
this.storageDirectory = file.dataDirectory;
}
else {
// future usage for more platform support
return false;
}
});
}
record() {
const fileName = 'record.m4a';
this.file.createFile(this.storageDirectory, fileName, true).then(() => {
let audioObject: MediaObject = this.media.create(this.storageDirectory + fileName);
audioObject.startRecord();
console.log('cache dir: ' + this.file.cacheDirectory);
console.log(`start recording ${fileName}`);
window.setTimeout(() => {
audioObject.stopRecord();
console.log('duration: ' + audioObject.getDuration());
audioObject.release();
console.log(`done recording ${fileName}`);
/** Do something with the record file and then delete */
// this.file.removeFile(this.file.tempDirectory, 'record.m4a');
}, 5000);
});
}
Other information:
this thread has similar issue, but with older version ionic-native.
https://forum.ionicframework.com/t/audio-recording-with-the-native-media-plugin-on-android/86042
package.json info:
{
"name": "firebase-email-auth",
"version": "0.0.1",
"author": "Ionic Framework",
"homepage": "http://ionicframework.com/",
"private": true,
"scripts": {
"clean": "ionic-app-scripts clean",
"build": "ionic-app-scripts build",
"lint": "ionic-app-scripts lint",
"ionic:build": "ionic-app-scripts build",
"ionic:serve": "ionic-app-scripts serve"
},
"dependencies": {
"@angular/common": "4.1.0",
"@angular/compiler": "4.1.0",
"@angular/compiler-cli": "4.1.0",
"@angular/core": "4.1.0",
"@angular/forms": "4.1.0",
"@angular/http": "4.1.0",
"@angular/platform-browser": "4.1.0",
"@angular/platform-browser-dynamic": "4.1.0",
"@ionic-native/core": "3.7.0",
"@ionic-native/facebook": "^3.10.3",
"@ionic-native/file": "^3.10.3",
"@ionic-native/keyboard": "^3.10.3",
"@ionic-native/media": "^3.10.3",
"@ionic-native/splash-screen": "^3.7.0",
"@ionic-native/status-bar": "3.7.0",
"@ionic-native/transfer": "^3.10.3",
"@ionic/storage": "2.0.1",
"angularfire2": "^4.0.0-rc.0",
"cordova-android": "^6.2.3",
"cordova-plugin-compat": "^1.1.0",
"cordova-plugin-console": "^1.0.5",
"cordova-plugin-crosswalk-webview": "^2.3.0",
"cordova-plugin-device": "^1.1.4",
"cordova-plugin-facebook4": "^1.9.0",
"cordova-plugin-file": "^4.3.3",
"cordova-plugin-file-transfer": "^1.6.3",
"cordova-plugin-media": "^3.0.1",
"cordova-plugin-splashscreen": "^4.0.3",
"cordova-plugin-statusbar": "^2.2.2",
"cordova-plugin-whitelist": "^1.3.1",
"cordova-plugin-wkwebview-engine": "git+https://github.com/driftyco/cordova-plugin-wkwebview-engine.git",
"firebase": "3.9.0",
"ionic-angular": "3.2.1",
"ionic-plugin-keyboard": "^2.2.1",
"ionicons": "3.0.0",
"plyr": "^2.0.13",
"rxjs": "5.1.1",
"sw-toolbox": "3.6.0",
"zone.js": "0.8.10"
},
"devDependencies": {
"@ionic/app-scripts": "1.3.7",
"@ionic/cli-plugin-cordova": "1.2.1",
"@ionic/cli-plugin-ionic-angular": "1.2.0",
"typescript": "2.2.1"
},
"description": "An Ionic project",
"cordova": {
"plugins": {
"cordova-plugin-facebook4": {
"APP_ID": "229997797493525",
"APP_NAME": "test-mobile"
},
"cordova-plugin-console": {},
"cordova-plugin-device": {},
"cordova-plugin-splashscreen": {},
"cordova-plugin-statusbar": {},
"cordova-plugin-whitelist": {},
"ionic-plugin-keyboard": {},
"cordova-plugin-media": {},
"cordova-plugin-file-transfer": {},
"cordova-plugin-crosswalk-webview": {
"XWALK_VERSION": "23+",
"XWALK_LITEVERSION": "xwalk_core_library_canary:17+",
"XWALK_COMMANDLINE": "--disable-pull-to-refresh-effect",
"XWALK_MODE": "embedded",
"XWALK_MULTIPLEAPK": "true"
},
"cordova-plugin-wkwebview-engine": {}
},
"platforms": [
"android"
]
}
}
This is not an issue with Ionic Native.. Just how the plugin works.
I'm not so sure how it to works to be honest. I noticed that if I just provide a file name it works well. But if I try to provide a full path like what you're trying to do, it doesn't work that well.
When I provide only the file name, it saves it to the root storage directory of my Android device.
I'll try to have a look at this when I get a chance. Let me know if you figure it out. We should probably update the docs so the usage is more clear.
I have spent the whole day figuring it, no success.
I also tried using cordova-plugin-media directly (both latest version and older versions) without ionic-native wrapper. Same problem.
I am now really uncertain whether it is my device or what caused this..
@ihadeed I assume an app has no write permission to root?
when you say 'it doesn't work that well', do you mean you have exact same symptom?
Ok I just figured out how to get this working on Android...
I tried using full file URLs and it didn't work, even with cdvfile:/// protocol. Here's what did work though:
file.mp3/sdcard/file.mp3... meaning you can retrieve it by calling this.file.resolveLocalFilesystemUrl(this.file.externalRootDirectory + 'file.mp3')So my guess is that on Android, the path is relative to /sdcard/ (or externalRootDirectory).
I haven't tested this on iOS yet but by reading their docs here, it looks like you can do something like this:
let file = this.media.create(this.file.tempDirectory + 'file.mp3');
Here's my code:
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { HomePage } from '../pages/home/home';
import { MediaPlugin } from '@ionic-native/media';
import { File } from '@ionic-native/file';
@Component({
templateUrl: 'app.html',
providers: [ MediaPlugin, File ]
})
export class MyApp {
rootPage:any = HomePage;
constructor(platform: Platform, media: MediaPlugin, file: File) {
platform.ready()
.then(() => {
let stopCount = 0;
const fileName: string = 'myfile2.mp3';
let m = media.create(fileName, (status) => {
console.log('Status updated. ', status, (status === 4 && ++stopCount === 2 && m.getDuration()) || '');
}, x => console.log('Success: ', x), e => console.log('Error: ', e));
m.startRecord();
console.log('RECORDING');
setTimeout(() => {
m.stopRecord();
console.log('DONE RECORDING');
m.play();
console.log('PLAYING');
file.resolveLocalFilesystemUrl(file.externalRootDirectory + fileName)
.then(r => console.log(r))
.catch(e => console.log('Error #2: ', e));
}, 3000);
});
}
}
@ihadeed Thanks for your time! The problem has been located in the thread below.
It seems the media.create resolves file-path in an odd way both for iOS and Android.
MediaPlugin has since updated and it seems like using the "file:///" replace is no longer the solution; it just causes a different error to pop up.
I've been able to save the file under the internal root directory on android and then I can move it elsewhere. It does solve the problem in a way, but there's no reason I can't outright save the file in the correct place.
Hi everyone, I found this solution for Android
// Create root file -> my_file.mp3
this.file.createFile(this.file.externalApplicationStorageDirectory, 'my_file.mp3', true).then(() => {
// Get file created -> my_file.mp3
let audioObject: MediaObject = this.media.create(this.file.externalApplicationStorageDirectory.replace(/file:\/\//g, '') + 'my_file.mp3');
audioObject.release();
// Start Record
audioObject.startRecord();
// This method is very important to know your execution process
// In my case the recording interface is not shown as in IOS
audioObject.onStatusUpdate.forEach(n => {
switch (n) {
case MEDIA_STATUS.RUNNING: // return code 2 = recording audio
// recording
break;
case MEDIA_STATUS.STOPPED: // return code 4 = stopped audio
this.file.readAsDataURL(this.file.externalApplicationStorageDirectory, 'my_file.mp3').then(audioo => {
// base64 audio
});
this.loading.hide();
break;
}
});
window.setTimeout(() => audioObject.stopRecord(), 9000);
});
DOCS https://www.npmjs.com/package/cordova-plugin-media
Media.MEDIA_NONE = 0;
Media.MEDIA_STARTING = 1;
Media.MEDIA_RUNNING = 2;
Media.MEDIA_PAUSED = 3;
Media.MEDIA_STOPPED = 4;
I hope it helps many. 馃憤
I'm not familiar with using externalApplicationStorageDirectory, but doesn't that also involve external storage, same as externalRootDirectory?
Most helpful comment
Ok I just figured out how to get this working on Android...
I tried using full file URLs and it didn't work, even with
cdvfile:///protocol. Here's what did work though:file.mp3/sdcard/file.mp3... meaning you can retrieve it by callingthis.file.resolveLocalFilesystemUrl(this.file.externalRootDirectory + 'file.mp3')So my guess is that on Android, the path is relative to
/sdcard/(or externalRootDirectory).I haven't tested this on iOS yet but by reading their docs here, it looks like you can do something like this:
Here's my code: