ios - 从远程 URL 加载 MP3 并播放,冻结 UI

Posted

技术标签:

【中文标题】ios - 从远程 URL 加载 MP3 并播放,冻结 UI【英文标题】:ios - Loading an MP3 from remote URL and playing, freezing UI 【发布时间】:2015-02-03 17:55:50 【问题描述】:

我正在构建一个非常简单的应用程序,它可以播放来自 Internet 的非常小的(少于 30 秒的音频)静态 MP3 文件。这些文件在 TableView 中列出,单击单元格会打开一个视图,该视图依次加载和播放远程 MP3。使用AVAudioPlayer 播放音频。请注意,我试图流式传输实时、连续的音频 - 只是一个简短的剪辑。这是我正在尝试播放的示例-https://s3.amazonaws.com/tevfd-recording/All_Fire_and_EMS_2015-02-0314_38_54_457551.mp3

最初,我使用[NSData dataWithContentsOfURL:] 下载了 MP3 文件的数据,除了点击一行和加载视图/播放音频之间存在延迟之外,它运行良好。我喜欢这种方法的一件事是,当用户离开视图(按下后退按钮)时,音频会停止播放。

NSURL *callAudioURL = [NSURL URLWithString:[self.call objectForKey:@"url"]];
NSData *callAudioData = [NSData dataWithContentsOfURL:callAudioURL];
AVAudioPlayer *audio = [[AVAudioPlayer alloc] initWithData: callAudioData error:nil];
self.player = audio;
// Set slider to change position in audio
self.slider.minimumValue = 0;
self.slider.maximumValue = self.player.duration;
[self.player prepareToPlay];
[[self player] play];
self.updateTimer =     [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateSeekBar) userInfo:nil repeats:YES];

为了消除视图之间的延迟,我将文件的加载封装在对 `dispatch_async' 的调用中 -

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
        NSURL *callAudioURL = [NSURL URLWithString:[self.call objectForKey:@"url"]];
        NSData *callAudioData = [NSData dataWithContentsOfURL:callAudioURL];
        dispatch_async(dispatch_get_main_queue(), ^
            AVAudioPlayer *audio = [[AVAudioPlayer alloc] initWithData: callAudioData error:nil];
            self.player = audio;

            self.slider.minimumValue = 0;
            self.slider.maximumValue = self.player.duration;
            [self.player prepareToPlay];
            [[self player] play];
            self.updateTimer =     [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateSeekBar) userInfo:nil repeats:YES];
        );
    );

这很好用——segue 很快完成,数据从主线程加载。但是,如果用户在播放音频时按下返回按钮,它会继续播放。

我的问题: 我是否在正确的轨道上使用 dispatch_async 呢?如果是这样,当用户按下返回按钮时,我应该如何杀死玩家?

谢谢!

【问题讨论】:

【参考方案1】:

您可能应该不再使用-[NSData dataWithContentsOfURL:],而是开始使用NSURLSession 自己管理网络操作。 -[NSData dataWithContentsOfURL:] 总是会在播放任何内容之前加载 100% 的数据,并且它是同步的,因此在主线程上调用它是让操作系统杀死你的应用程序以停止主线程的好方法。使用dispatch_async 进行加载可以防止主线程停顿,但不能解决在您可以对其进行任何操作之前加载 100% 数据的问题。

【讨论】:

我是 ios 开发新手,不到一周。如果您可以显示一些代码或者可能为我指明教程的方向,将不胜感激。 :) LOL 我刚刚找到它,也许应该在询问之前尝试谷歌;) 稍作休息,将尝试实施几个。谢谢! 请查看更新后的问题 - 将所有内容都包装在 NSURLSession 的完成块中,应用程序现在崩溃.. 当问题发生如此巨大的变化时,你真的应该接受上一个问题的答案,然后继续下一个问题。无论如何,您可能应该去阅读更多关于 NSURLSession 的详细信息。您在此处使用它的方式会仍然在开始播放之前下载 100% 的数据。流式传输音频数据是一项相对复杂的任务。不太可能有一个 10 行的解决方案也能提供良好的用户体验。 明确地说,我并不是想在网络上直播音频,我本质上是想下载它以便播放 - 考虑到这一点,不会我想 100% 下载吗?

以上是关于ios - 从远程 URL 加载 MP3 并播放,冻结 UI的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin IOS:无法从互联网播放 mp3

使用 AVPlayer 从远程 URL 播放视频

iOS- MPMoviePlayerController 无法从远程 URL 播放视频

从 URL 获取音频并播放

使用 localForage 存储和检索音频 (mp3)

AVPlayer 不在 iOS 文档目录中播放 MP3 音频文件