iOS - 尝试播放 mp3 文件失败

Posted

技术标签:

【中文标题】iOS - 尝试播放 mp3 文件失败【英文标题】:iOS - Attempting to play mp3 file fails 【发布时间】:2012-04-17 16:42:20 【问题描述】:

我正在尝试从我的应用程序中播放我从服务器检索的 mp3 文件,执行以下操作:

- (IBAction)play:(UIButton *)sender 
    dispatch_queue_t downloadQueue = dispatch_queue_create("audio data downloader", NULL);
    dispatch_async(downloadQueue, ^
        NSURL *audioURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@/%@.mp3", FONYK_FILES_URL, [self.voicenote valueForKeyPath:@"Fonyker.fonykid"], [self.voicenote valueForKeyPath:@"Voicenote.vnid"]]];
        NSData *audioData = [NSData dataWithContentsOfURL:audioURL];

        dispatch_async(dispatch_get_main_queue(), ^
            NSError *error = nil;
            AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithData:audioData error:&error];
            NSLog(@"%@", error);
            audioPlayer.delegate = self;
            [audioPlayer play]; 
        );
    );

播放失败,意味着没有声音发出,我在逐步调试我的应用程序时得到这个输出:

Catchpoint 2 (exception thrown).Single stepping until exit from function __cxa_throw, which has no line number information. 

当我在模拟器中 NSLog 错误时会出现这种情况:

Error Domain=NSOSStatusErrorDomain Code=-50 "The operation couldn’t be completed. (OSStatus error -50.)"

没有其他迹象表明它只是失败了,有什么想法吗?

更新:根据 J_D 的回答修改了我的代码并在模拟器中得到了这个:

Error loading /System/Library/Extensions/AudioIPCDriver.kext/Contents/Resources/AudioIPCPlugIn.bundle/Contents/MacOS/AudioIPCPlugIn:  dlopen(/System/Library/Extensions/AudioIPCDriver.kext/Contents/Resources/AudioIPCPlugIn.bundle/Contents/MacOS/AudioIPCPlugIn, 262): Symbol not found: ___CFObjCIsCollectable
  Referenced from: /System/Library/Frameworks/Security.framework/Versions/A/Security
  Expected in: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
 in /System/Library/Frameworks/Security.framework/Versions/A/Security
2012-04-17 15:03:43.054 Fonyk[8238:15307] Error loading /System/Library/Extensions/AudioIPCDriver.kext/Contents/Resources/AudioIPCPlugIn.bundle/Contents/MacOS/AudioIPCPlugIn:  dlopen(/System/Library/Extensions/AudioIPCDriver.kext/Contents/Resources/AudioIPCPlugIn.bundle/Contents/MacOS/AudioIPCPlugIn, 262): Symbol not found: ___CFObjCIsCollectable
  Referenced from: /System/Library/Frameworks/Security.framework/Versions/A/Security
  Expected in: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
 in /System/Library/Frameworks/Security.framework/Versions/A/Security

更新:我遇到的真正问题不是在我的代码中创建和 AVAudiosession 实例设置为播放,这样做以及我接受的更正答案使其工作。

【问题讨论】:

【参考方案1】:

我发现您的代码至少有一个问题,即

NSURL *fileURL = [NSURL URLWithString:filePath];

它尝试使用本地文件路径创建 URL。它可能会返回零。你应该改用:

NSURL *fileURL = [NSURL fileURLWithPath:filePath];

现在,即使这样,您的代码也无法运行(我尝试过并得到与您相同的错误)。我自己并没有经常使用 AVAudioPlayer,所以我不知道为什么会发生您的具体错误。

但是,我确实使用您的代码尝试了一个非常小的示例,并且能够正确播放 MP3。您可以使用 AVAudioPlayer 的 initWithData 构造函数,而不是将数据下载到文件并从文件加载 AVAudioPlayer:

AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithData:[NSData dataWithContentsOfURL:audioURL] error:&error];

假设 audioURL 有效,这对我来说效果很好。我指着我的服务器上的一个 mp4 进行测试。

所以用这个 initWithData 重写你的代码给出:

- (IBAction)play:(UIButton *)sender 
    dispatch_queue_t downloadQueue = dispatch_queue_create("audio data downloader", NULL);
    dispatch_async(downloadQueue, ^
        NSURL *audioURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@/%@.mp3", FONYK_FILES_URL, [self.voicenote valueForKeyPath:@"Fonyker.fonykid"], [self.voicenote valueForKeyPath:@"Voicenote.vnid"]]];
        NSData *audioData = [NSData dataWithContentsOfURL:audioURL];

        dispatch_async(dispatch_get_main_queue(), ^
            NSError *error = nil;
            AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithData:audioData error:&error];
            NSLog(@"%@", error);
            audioPlayer.delegate = self;
            [audioPlayer play]; 
        );
    );

最后一点:您在开始播放之前下载整个文件,这可能需要一段时间并消耗大量堆(或存储,如果您将其保存在文件中)

如果您想流式传输,您可以使用 MPMoviePlayerController,但不要将视图附加到视图层次结构中。这样,您将只有音频,不会更改应用程序的任何视觉效果。

一个例子是:

NSURL *audioURL = [NSURL URLWithString:@"MY_MP3_URL"];
MPMoviePlayerController* player = [[MPMoviePlayerController alloc] initWithContentURL:audioURL];
[player play];

再次,在我这边,在模拟器中,它工作正常。

不要忘记释放播放器。您还可以为重要通知注册代表。

详情请看:http://developer.apple.com/library/ios/#documentation/mediaplayer/reference/MPMoviePlayerController_Class/Reference/Reference.html

【讨论】:

谢谢,我试试看。关于您上次的观察,您知道我如何流式传输文件吗? 执行此操作,它在 AVAudioPlayer 实例化处停止并打印出:Catchpoint 10(抛出异常)。单步执行直到退出函数 __cxa_throw,该函数没有行号信息。如果我继续,它什么也不做。 我不知道为什么它在我这边运行良好,我使用了与我在答案中复制的完全相同的代码,只是我使用了自己的 URL。也许这与此 URL 的内容有关。我也在 Simulator 5.0 上进行测试。要回答有关流式传输的问题,请使用 MPMoviePlayerController。我将添加另一个答案以获得一些可读的代码。 只需编辑/扩展这个,最好让一切更有条理,谢谢。我会继续尝试看看问题是什么。 即使使用自动引用计数也必须释放吗?【参考方案2】:

您在某处收到 EXC_BAD_ACCESS。我建议删除所有异步代码并看看会发生什么。实际上,就异步调用而言,您的思考过程让我有些困惑。

请注意,AVAudioPlayer 仅适用于本地文件。看来您可能正在将其设置为播放来自服务器的音频文件,但这是行不通的。

另外,你为什么不尝试 NSLog 错误变量?

【讨论】:

得到这个错误域=NSOSStatusErrorDomain Code=-43“操作无法完成。(OSStatus错误-43。)”。不知道本地文件交易。我会用我找到的任何东西更新我的代码和我的问题。而且我在任何地方都没有获得 EXC_BAD_ACCESS,所以我不知道。得看。另外你为什么对我的思维过程感到困惑? 我猜 OP 应该使用 AVPlayer 而不是 AVAudioPlayer 从远程位置播放流。

以上是关于iOS - 尝试播放 mp3 文件失败的主要内容,如果未能解决你的问题,请参考以下文章

iOS - mp3 文件不播放,没有错误?

Ionic 媒体插件无法在 iOS 上播放本地存储的 mp3 文件

来自服务器的 MP3 文件在 iOS7 中无法使用 AVAudioPlayer 播放

iOS - 无法播放音频文件

我的网络应用程序用户如何单击按钮来播放本地存储的 mp3 文件?

在 iOS 上播放 MP3 或 AAC 文件都有哪些音频播放选项?