Cordova iOS - 即使文件已创建也无法录制媒体
Cordova iOS - can't record a media even though the file is created
我正在尝试使用 cordova-plugin-media 录制声音文件,但我总是收到此错误:
{message: "Failed to initialize AVAudioRecorder: (null)↵", code: 1}
我首先创建文件,像这样
iOSCreateFile(fileName, callback) {
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, (fs) => {
fs.root.getFile(fileName, {
create: true,
exclusive: false
}, (fileEntry) => {
console.log("fileEntry is file?" + fileEntry.isFile.toString());
// here I am getting true, so the file is obviously created
callback(fileEntry.nativeURL);
}, (error) => {
console.log('error create file: ' + error);
});
}, (error) => {
console.log('error loading file system: ' + error);
});
},
我发回的fileEntry.nativeURL
看起来像这样
file:///var/mobile/Containers/Data/Application/0EE019AA-EFBA-4FB9-97EC-1F16FFDDA36B/tmp/1496663387924.wav
然后,当这个回调时,我正在做以下事情
// that long file path string is passed here
let soundRecord = new Media(filePath, () => {
// success
// more code
}, (error) => {
console.log(error);
});
并且一旦它尝试执行新语句,它就会给我 Failed to initialize AVAudioRecorder 错误...
请问我做错了什么?
编辑:我也试过不创建文件,而只是将文件名字符串传递给新的媒体对象,例如“1240215251.wav”,它应该为我创建它,但我仍然得到同样的错误。
更新:我尝试在本地代码中捕获错误,但我不是很了解,调试时只能看到错误产生的位置,但没有别的,请检查下面的代码,我在需要的地方评论了
- (void)startRecordingAudio:(CDVInvokedUrlCommand*)command {
NSString* callbackId = command.callbackId;
#pragma unused(callbackId)
NSString* mediaId = [command argumentAtIndex:0];
CDVAudioFile* audioFile = [self audioFileForResource:[command argumentAtIndex:1] withId:mediaId doValidation:YES forRecording:YES];
__block NSString* jsString = nil;
__block NSString* errorMsg = @"";
if ((audioFile != nil) && (audioFile.resourceURL != nil)) {
__weak CDVSound* weakSelf = self;
void (^startRecording)(void) = ^{
NSError* __autoreleasing error = nil;
if (audioFile.recorder != nil) {
[audioFile.recorder stop];
audioFile.recorder = nil;
}
if ([weakSelf hasAudioSession]) {
if (![weakSelf.avSession.category isEqualToString:AVAudioSessionCategoryPlayAndRecord]) {
[weakSelf.avSession setCategory:AVAudioSessionCategoryRecord error:nil];
}
if (![weakSelf.avSession setActive:YES error:&error]) {
// other audio with higher priority that does not allow mixing could cause this to fail
errorMsg = [NSString stringWithFormat:@"Unable to record audio: %@", [error localizedFailureReason]];
// jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova-plugin-media.Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_ABORTED];
jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova-plugin-media.Media').onStatus", mediaId, MEDIA_ERROR, [weakSelf createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]];
[weakSelf.commandDelegate evalJs:jsString];
return;
}
}
NSDictionary *audioSettings = @{AVFormatIDKey: @(kAudioFormatMPEG4AAC),
AVSampleRateKey: @(44100),
AVNumberOfChannelsKey: @(1),
AVEncoderAudioQualityKey: @(AVAudioQualityMedium)
};
audioFile.recorder = [[CDVAudioRecorder alloc] initWithURL:audioFile.resourceURL settings:audioSettings error:&error];
// HERE ^
// Just after this audioFile.recorder declaration, the error variable below gets a value - NSError * domain:
// @"NSOSStatusErrorDomain" - code: 1718449215 0x0000000170247e90
bool recordingSuccess = NO;
if (error == nil) {
audioFile.recorder.delegate = weakSelf;
audioFile.recorder.mediaId = mediaId;
audioFile.recorder.meteringEnabled = YES;
recordingSuccess = [audioFile.recorder record];
if (recordingSuccess) {
NSLog(@"Started recording audio sample '%@'", audioFile.resourcePath);
jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova-plugin-media.Media').onStatus", mediaId, MEDIA_STATE, MEDIA_RUNNING];
[weakSelf.commandDelegate evalJs:jsString];
}
}
if ((error != nil) || (recordingSuccess == NO)) {
// It then enters in one of below cases
if (error != nil) {
errorMsg = [NSString stringWithFormat:@"Failed to initialize AVAudioRecorder: %@\n", [error localizedFailureReason]];
} else {
errorMsg = @"Failed to start recording using AVAudioRecorder";
}
audioFile.recorder = nil;
if (weakSelf.avSession) {
[weakSelf.avSession setActive:NO error:nil];
}
jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova-plugin-media.Media').onStatus", mediaId, MEDIA_ERROR, [weakSelf createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]];
[weakSelf.commandDelegate evalJs:jsString];
}
};
...
// More irrelevant code of the method
...
}
我认为该插件无法创建 AVAudioRecorder,因为您传递的是 nativeURL,我不知道是否支持。您尝试过 quick-examples 之一吗?无需事先通过 iOSCreateFile 手动创建文件。
这个问题可能是因为使用了 3.0.0 版的 cordova 媒体插件。此版本在 iOS 中录制 "wav" 文件时存在问题。 issue 已在媒体插件的官方问题跟踪器中提出,并已在 VERSION 3.0.1
中修复
所以升级到最新版本的插件应该可以解决这个问题。在这种情况下,插件不会在第一次尝试时正确安装。希望它应该解决正确升级的问题。干杯
我正在尝试使用 cordova-plugin-media 录制声音文件,但我总是收到此错误:
{message: "Failed to initialize AVAudioRecorder: (null)↵", code: 1}
我首先创建文件,像这样
iOSCreateFile(fileName, callback) {
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, (fs) => {
fs.root.getFile(fileName, {
create: true,
exclusive: false
}, (fileEntry) => {
console.log("fileEntry is file?" + fileEntry.isFile.toString());
// here I am getting true, so the file is obviously created
callback(fileEntry.nativeURL);
}, (error) => {
console.log('error create file: ' + error);
});
}, (error) => {
console.log('error loading file system: ' + error);
});
},
我发回的fileEntry.nativeURL
看起来像这样
file:///var/mobile/Containers/Data/Application/0EE019AA-EFBA-4FB9-97EC-1F16FFDDA36B/tmp/1496663387924.wav
然后,当这个回调时,我正在做以下事情
// that long file path string is passed here
let soundRecord = new Media(filePath, () => {
// success
// more code
}, (error) => {
console.log(error);
});
并且一旦它尝试执行新语句,它就会给我 Failed to initialize AVAudioRecorder 错误...
请问我做错了什么?
编辑:我也试过不创建文件,而只是将文件名字符串传递给新的媒体对象,例如“1240215251.wav”,它应该为我创建它,但我仍然得到同样的错误。
更新:我尝试在本地代码中捕获错误,但我不是很了解,调试时只能看到错误产生的位置,但没有别的,请检查下面的代码,我在需要的地方评论了
- (void)startRecordingAudio:(CDVInvokedUrlCommand*)command {
NSString* callbackId = command.callbackId;
#pragma unused(callbackId)
NSString* mediaId = [command argumentAtIndex:0];
CDVAudioFile* audioFile = [self audioFileForResource:[command argumentAtIndex:1] withId:mediaId doValidation:YES forRecording:YES];
__block NSString* jsString = nil;
__block NSString* errorMsg = @"";
if ((audioFile != nil) && (audioFile.resourceURL != nil)) {
__weak CDVSound* weakSelf = self;
void (^startRecording)(void) = ^{
NSError* __autoreleasing error = nil;
if (audioFile.recorder != nil) {
[audioFile.recorder stop];
audioFile.recorder = nil;
}
if ([weakSelf hasAudioSession]) {
if (![weakSelf.avSession.category isEqualToString:AVAudioSessionCategoryPlayAndRecord]) {
[weakSelf.avSession setCategory:AVAudioSessionCategoryRecord error:nil];
}
if (![weakSelf.avSession setActive:YES error:&error]) {
// other audio with higher priority that does not allow mixing could cause this to fail
errorMsg = [NSString stringWithFormat:@"Unable to record audio: %@", [error localizedFailureReason]];
// jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova-plugin-media.Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_ABORTED];
jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova-plugin-media.Media').onStatus", mediaId, MEDIA_ERROR, [weakSelf createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]];
[weakSelf.commandDelegate evalJs:jsString];
return;
}
}
NSDictionary *audioSettings = @{AVFormatIDKey: @(kAudioFormatMPEG4AAC),
AVSampleRateKey: @(44100),
AVNumberOfChannelsKey: @(1),
AVEncoderAudioQualityKey: @(AVAudioQualityMedium)
};
audioFile.recorder = [[CDVAudioRecorder alloc] initWithURL:audioFile.resourceURL settings:audioSettings error:&error];
// HERE ^
// Just after this audioFile.recorder declaration, the error variable below gets a value - NSError * domain:
// @"NSOSStatusErrorDomain" - code: 1718449215 0x0000000170247e90
bool recordingSuccess = NO;
if (error == nil) {
audioFile.recorder.delegate = weakSelf;
audioFile.recorder.mediaId = mediaId;
audioFile.recorder.meteringEnabled = YES;
recordingSuccess = [audioFile.recorder record];
if (recordingSuccess) {
NSLog(@"Started recording audio sample '%@'", audioFile.resourcePath);
jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova-plugin-media.Media').onStatus", mediaId, MEDIA_STATE, MEDIA_RUNNING];
[weakSelf.commandDelegate evalJs:jsString];
}
}
if ((error != nil) || (recordingSuccess == NO)) {
// It then enters in one of below cases
if (error != nil) {
errorMsg = [NSString stringWithFormat:@"Failed to initialize AVAudioRecorder: %@\n", [error localizedFailureReason]];
} else {
errorMsg = @"Failed to start recording using AVAudioRecorder";
}
audioFile.recorder = nil;
if (weakSelf.avSession) {
[weakSelf.avSession setActive:NO error:nil];
}
jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova-plugin-media.Media').onStatus", mediaId, MEDIA_ERROR, [weakSelf createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]];
[weakSelf.commandDelegate evalJs:jsString];
}
};
...
// More irrelevant code of the method
...
}
我认为该插件无法创建 AVAudioRecorder,因为您传递的是 nativeURL,我不知道是否支持。您尝试过 quick-examples 之一吗?无需事先通过 iOSCreateFile 手动创建文件。
这个问题可能是因为使用了 3.0.0 版的 cordova 媒体插件。此版本在 iOS 中录制 "wav" 文件时存在问题。 issue 已在媒体插件的官方问题跟踪器中提出,并已在 VERSION 3.0.1
中修复所以升级到最新版本的插件应该可以解决这个问题。在这种情况下,插件不会在第一次尝试时正确安装。希望它应该解决正确升级的问题。干杯