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

中修复

所以升级到最新版本的插件应该可以解决这个问题。在这种情况下,插件不会在第一次尝试时正确安装。希望它应该解决正确升级的问题。干杯