使用AVPlayer流式传输mp3音频

25

我听到关于这个的一些矛盾报告。我想要做的是从URL流式传输mp3文件。我已经进行了数小时的研究,但我找不到任何好的指南,说明应该使用什么样的音频播放器,也不知道如何实现。

有些朋友告诉我AVPlayer可以流式传输mp3,但苹果的文档说它不能。我仔细阅读了Matt Gallagher的音频流播放器(http://www.cocoawithlove.com/2008/09/streaming-and-playing-live-mp3-stream.html),但那段代码是一段时间以前编写的,而且由于我对此还不够熟悉,所以很难通过自动释放和保留等方法解决问题。

我想要流式传输的音频是来自libsyn服务器的一个相当大的mp3文件,其URL格式为...

http://traffic.libsyn.com/podcastname/episode.mp3

我所需做的就是拿起它并开始播放,具有暂停和快进功能。所以首先要确定,AVPlayer可以流式传输mp3吗?如果可以,是否有任何指南或代码可以提供?如果不行,是否有任何一种音频播放器类可以流式传输音频?

我尝试创建一个带有URL初始化的AVPlayerItem,然后将其添加到AVPlayer中,但是我遇到了大量的“加载错误”和“符号未找到”的错误。感谢您提供任何关于此问题的信息,谢谢!


Matt Gallagher的音频流应用程序已更新。 - Paresh Navadiya
不过,这并不是从2010年开始的,对吧? - derekahc
5个回答

66

试试这个

 -(void)playselectedsong{

        AVPlayer *player = [[AVPlayer alloc]initWithURL:[NSURL URLWithString:urlString]];
        self.songPlayer = player;
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(playerItemDidReachEnd:)
                                                     name:AVPlayerItemDidPlayToEndTimeNotification
                                                   object:[songPlayer currentItem]];
        [self.songPlayer addObserver:self forKeyPath:@"status" options:0 context:nil];
        [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateProgress:) userInfo:nil repeats:YES];



    }
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

        if (object == songPlayer && [keyPath isEqualToString:@"status"]) {
            if (songPlayer.status == AVPlayerStatusFailed) {
                NSLog(@"AVPlayer Failed");

            } else if (songPlayer.status == AVPlayerStatusReadyToPlay) {
                NSLog(@"AVPlayerStatusReadyToPlay");
                [self.songPlayer play];


            } else if (songPlayer.status == AVPlayerItemStatusUnknown) {
                NSLog(@"AVPlayer Unknown");

            }
        }
    }

    - (void)playerItemDidReachEnd:(NSNotification *)notification {

     //  code here to play next sound file

    }

用一个URL来初始化它就像这样简单吗?这实际上可以流式传输音频吗? - derekahc
好的,我会尝试一下。我原本以为你需要干预服务器才能设置流媒体,或者至少设置某种流媒体协议。 - derekahc
4
这里的区别是AVPlayer能够进行流媒体播放,而AVAudioPlayer则不能。很容易混淆! - jocull
1
我认为这里有一个错误:在状态准备好之前,你不应该播放。换句话说,[self.songPlayer play]; 应该在 observeValueForKeyPath 中执行,当且仅当 songPlayer.status == AVPlayerStatusReadyToPlay 时才能播放。 - Bjorn Roche
它能在iOS 10和xcode 8上正常运行。如果你无法播放且使用的是http的URL,则需在info.plist中添加应用程序传输安全。 - Surjeet Rajput
显示剩余2条评论

15
你也可以尝试使用我的开源Audjustable库,它支持HTTP流媒体。它基于Matt的AudioStreamer,但已经进行了整理、优化和更新,以支持多个数据源(非HTTP)和无间断播放。 https://github.com/tumtumtum/audjustable

1
Audjustable现在被称为StreamingKit(上面的链接将重定向),似乎是HTTP流媒体和其他播放方式的不错基础。 - Hugh
到目前为止,我找到的唯一一个可用的库,做得非常好。 - Ahmed Elashker

2
除了Sumit Mundra的回答对我很有帮助之外,我发现这种技术实际上并没有从远程服务器“流式传输”MP3文件。当我实施时,文件会同步下载并阻塞我的UI,然后再播放。我发现正确流式传输MP3的方法是指向一个M3U文件。这只是一个带有.m3u扩展名的文本文件,其中包含指向原始MP3的链接。将Sumit的代码指向该文件,您就可以立即开始播放流。

我在这里找到了这些信息:http://www.soundabout.net/streammp3.htm


m3u文件必须在服务器上吗?也就是说,这个文件可以存在于iPhone本地(或者需要时我可以在本地创建它)吗? - FuzzyBunnySlippers
没有理由它不会工作,但实际上,本地文件会立即播放;你可能不会注意到任何区别。 - Aaron Vegh
不,我的意思是MP3文件存在远程服务器上,我知道它的地址。但我并不一定能在那里创建.m3u文件。因此,我想在本地创建一个引用该URL的.m3u文件。这样说清楚了吗? - FuzzyBunnySlippers
是的,这意义上说是正确的,但它并不起作用。请参阅https://dev59.com/7Z3ha4cB1Zd3GeqPSEzj。 - Igor Camilo

0

0
Aaron关于使用m3u文件而不是mp3的帖子对我很有用。我还发现AVPlayer对m3u语法很挑剔。例如,当我尝试以下操作时,我无法获得有效的持续时间(它总是无限期),并且相对路径也无法工作:
#EXTM3U
#EXTINF:71
https://test-domain.com/90c9a240-51b3-11e9-bb69-c1300ce2348f.mp3

然而,将m3u文件更新为以下内容后,这两个问题都得到了解决:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:70
#EXT-X-MEDIA-SEQUENCE:1
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:70.000,
8577d650-51b3-11e9-8e69-4f2b085e94aa.mp3
#EXT-X-ENDLIST

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接