MusicSequenceFileLoad Returns -1 在 iOS10 (AudioToolbox/MusicPlayer)

MusicSequenceFileLoad Returns -1 on iOS10 (AudioToolbox/MusicPlayer)

2016 年 9 月 10 日更新: 我在 2016 年 9 月 22 日与 Apple 一起打开了 Radar #28425770 以解决以下缺陷,他们刚刚将其标记为重复(来自 Radar #28327056),因此这似乎是 iOS10.

中的一个已知错误

我在调用 AudioToolbox / MusicPlayer API 方法 "MusicSequenceFileLoad()" 将 MIDI 文件的内容(来自给定 URL)加载到音乐序列时遇到错误iOS10 iPad Pro(wifi 型号),非常感谢社区在调试方面提供的一些帮助。

到目前为止我能够进行的研究/观察:

如果有人对我调试此问题的其他方法有任何建议,将不胜感激。我最初认为它可能与内存管理有关,但是从我所看到的情况来看,我正在适当地处理内存(对应用程序使用 ARC 并根据需要释放 C-API 对象)并且分析没有发现任何我可以解决的问题看。

代码示例:

@property (readwrite, nonatomic) MusicPlayer midiMusicPlayer;
@property (readwrite, atomic) MusicSequence masterMidiMusicSequence;

- (void)initializeMusicPlayerAndMasterSequenceWithFile:(NSString *)midiFilename
{
    CheckError(NewMusicPlayer(&_midiMusicPlayer), "NewMusicPlayer: _midiMusicPlayer");
    CheckError(NewMusicSequence(&_masterMidiMusicSequence), "NewMusicSequence: _masterMidiMusicSequence");

    NSString *midiFilePath = [NSBundle pathForResource:midiFilename
                                                ofType:@"mid"
                               checkDocumentsDirectory:YES];
    NSURL *midiFileURL = [NSURL fileURLWithPath:midiFilePath];

    // Crash is encountered on the following line:
    CheckError(MusicSequenceFileLoad(self.masterMidiMusicSequence, (__bridge CFURLRef)midiFileURL, 0, 0), "MusicSequenceFileLoad");
}

您是否尝试将 NSAppleMusicUsageDescription 添加到您的 Info.plist

Starting in iOS 10, your Info.plist file must include a purpose string, for display in the permission alert, for each such item. If your app attempts to access a protected item without you having provided a corresponding purpose string, your app exits.

有关详细信息,请参阅 App Programming Guide for iOS

我通过 Core Audio Mailing List 收到了 Apple 工程师的一些指导,并在 iOS10 中成功实施了针对此问题建议的解决方法。

通过在调用失败后将 "errno" 值更新为 0,后续对 'MusicSequenceFileLoad' 的调用将生成成功的响应。因此,我修改了我的代码如下:

OSStatus statusOfInitialAttempt = CheckError(MusicSequenceFileLoad(self.masterMidiMusicSequence, (__bridge CFURLRef)midiFileURL, 0, 0), "MusicSequenceFileLoad");
if (statusOfInitialAttempt == -1) {
    errno = 0;

    OSStatus statusOfSecondAttempt = CheckErrorAndReturnOnFailure(MusicSequenceFileLoad(self.masterMidiMusicSequence, (__bridge CFURLRef)midiFileURL, 0, 0), "MusicSequenceFileLoad");

    if (statusOfSecondAttempt == -1) {
        // Handle error case
    }
}

... 其中 CheckError() 函数只是根据已知的 OSStatus 代码检查 OSStatus return 值,类似于 this one on GitHub (originally created by Chris Adamson from his blog post / presentation "Core Audio Cranks It Up").

我了解到,根据核心音频邮件列表上发布的内容,此问题有望在未来的 iOS 更新中得到解决。