AVPlayer(或 AVAudioSession?)在我离开 ViewController 后播放,当我返回两个时播放

Posted

技术标签:

【中文标题】AVPlayer(或 AVAudioSession?)在我离开 ViewController 后播放,当我返回两个时播放【英文标题】:AVPlayer (or AVAudioSession?) plays after I leave the ViewController, and when I return two are then playing 【发布时间】:2015-05-25 02:39:29 【问题描述】:

我有一个 viewController 可以从网络传输音频。当我离开我的应用程序的那个页面时,音频会继续播放(这很好)。但是,当我返回时,viewdidload 方法会创建第二个音频播放器。我可以一遍又一遍地这样做,直到我拥有这么多 AVplayer。这听起来令人难以置信的回声。这是我所有的相关代码。

#import "ListenViewController.h"
#import <AVFoundation/AVAudioPlayer.h>
#import <AVFoundation/AVPlayerItem.h>
#import <AVFoundation/AVPlayer.h>
#import <AVFoundation/AVFoundation.h>
#import "RSPlayPauseButton.h"

@interface ListenViewController () <AVAudioPlayerDelegate, AVAudiosessionDelegate>

@property (nonatomic, strong) AVPlayer *player;
@property (nonatomic, strong) AVPlayerItem *playerItem;
@property (nonatomic, strong) RSPlayPauseButton *playPauseButton;
@property (nonatomic, copy) NSDate *now;



@end

@implementation ListenViewController

static int min = -2;

-(void) viewDidDisappear:(BOOL)animated

    [super viewDidDisappear:animated];

    //[self.player pause];
    min = -2;


-(void) viewDidLoad

    [super viewDidLoad];

    /*
    if ([AVAudioSession sharedInstance].isInputAvailable) 
        NSLog(@"XXXXXXXXX");
    
     */

    NSURL *streamingURL = [NSURL URLWithString:@"http://URL.m3u"];

    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:streamingURL];
    self.playerItem = playerItem;

    AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
    [player setAllowsExternalPlayback:NO];

    CMTime tm = CMTimeMake(1, 1);

    [player addPeriodicTimeObserverForInterval:tm
                                         queue:dispatch_get_main_queue() usingBlock:^(CMTime time) 
                                             /*
                                              NSDateFormatter *DateFormatter=[[NSDateFormatter alloc] init];
                                              [DateFormatter setDateFormat:@"yyyy-MM-dd hh:mm:ss:mmm"];
                                              NSLog(@"%@",[DateFormatter stringFromDate:[NSDate date]]);
                                              */
                                             if (!self.now) 
                                                 self.now = [NSDate date];
                                             

                                                 /*
                                                 NSDate *now = [NSDate date];
                                                 NSTimeInterval interval = [now timeIntervalSinceDate:self.now];
                                                 self.interval += 0.01;
                                                 interval -= (10 * self.rw2);
                                                 interval -= (60 * self.rw3);
                                                 interval += (10 * self.ff2);

                                                 self.timeLabel.text = [NSString stringWithFormat:@"%f", interval];
                                                 NSLog(@"INTERVAL: %@", [NSString stringWithFormat:@"%f", self.interval]);
                                                  */

                                             if (CMTimeGetSeconds(self.player.currentTime) >= 0) 
                                             self.timeLabel.text = [NSString stringWithFormat:@"%.0f", CMTimeGetSeconds(self.player.currentTime)];

                                                 NSTimeInterval time = CMTimeGetSeconds(self.player.currentTime);

                                                 //int min = time/60;

                                                 int sec = lroundf(time) % 60;




                                                 if (sec == 0) 
                                                     ++min;
                                                 
                                                 NSLog(@"sec: %d", sec);
                                                 // update your UI with timeLeft
                                                 self. timeLabel.text = [NSString stringWithFormat:@"%.2d:%.2d", min,sec];
                                             
                                         ];


    [self setPlayer:player];

    [player play];


    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    [[AVAudioSession sharedInstance] setActive: YES error: nil];

    if (!self.playPauseButton) 
        self.playPauseButton = [[RSPlayPauseButton alloc] initWithFrame:self.view.frame];
        self.playPauseButton.tintColor = [UIColor colorWithRed:1.0 green:155.0/255.0 blue:0.0 alpha:1.0];
        self.playPauseButton.animationStyle = RSPlayPauseButtonAnimationStyleSplitAndRotate;
        self.playPauseButton.paused = NO;
        [self.playPauseButton addTarget:self action:@selector(playPauseButtonDidPress:) forControlEvents:UIControlEventTouchUpInside];
    
    [self.view addSubview:self.playPauseButton];


- (IBAction)rewind:(id)sender

    //NSLog(@"currenttime: %f", CMTimeGetSeconds(self.player.currentTime));
    //NSLog(@"timescale: %d", self.player.currentTime.timescale);
    CMTime cmTime = CMTimeMake(CMTimeGetSeconds(self.player.currentTime) - 1.0, 1);
    CMTime zero = CMTimeMake(1, 2);
    if (CMTimeGetSeconds(cmTime) > CMTimeGetSeconds(zero)) 
    [self.player.currentItem seekToTime:cmTime];
        NSLog(@"!");
    
    NSLog(@"RW");



- (IBAction)rewind2:(id)sender

    /*
    CMTime cmTime = CMTimeMakeWithSeconds(CMTimeGetSeconds(self.player.currentTime) - 10.0, self.player.currentTime.timescale);
    CMTime zero = CMTimeMake(0, 10000);
    if (CMTimeGetSeconds(cmTime) > CMTimeGetSeconds(zero)) 
        [self.player.currentItem seekToTime:cmTime];
        self.rw2 += 1;
        NSLog(@"RW2!");
    
     */
    NSLog(@"RW2");
    CMTime cmTime = CMTimeMakeWithSeconds(CMTimeGetSeconds(self.player.currentTime) - 10.0, self.player.currentTime.timescale);
    CMTime zero = CMTimeMake(1, 2);
    NSLog(@"cmTime: %f", CMTimeGetSeconds(cmTime));
    NSLog(@"zero: %f", CMTimeGetSeconds(zero));
    if (CMTimeGetSeconds(cmTime) > CMTimeGetSeconds(zero)) 
        [self.player.currentItem seekToTime:cmTime];
        NSLog(@"!");
     else 
        [self rewindAll];
    



- (IBAction)rewind3:(id)sender

    CMTime cmTime = CMTimeMakeWithSeconds(CMTimeGetSeconds(self.player.currentTime) - 60.0, self.player.currentTime.timescale);
    CMTime zero = CMTimeMake(0, 10000);
    if (CMTimeGetSeconds(cmTime) > CMTimeGetSeconds(zero)) 
        [self.player.currentItem seekToTime:cmTime];
        NSLog(@"RW3!");
    
    NSLog(@"RW3");


- (void) rewindAll

    CMTime one = CMTimeMake(1, 1);
    [self.player.currentItem seekToTime:one];


- (IBAction)fastForward:(id)sender


    CMTime cmTime = CMTimeMakeWithSeconds(CMTimeGetSeconds(self.player.currentTime) + 5.0, self.player.currentTime.timescale);
    NSDate *now = [NSDate date];

    NSTimeInterval interval = [now timeIntervalSinceDate:self.now];

    CMTime seekingCM = CMTimeMake(interval, 1);

    if (CMTimeGetSeconds(cmTime) < CMTimeGetSeconds(seekingCM)) 
        [self.player.currentItem seekToTime:cmTime];
    



- (IBAction)fastForward2:(id)sender


    CMTime cmTime = CMTimeMakeWithSeconds(CMTimeGetSeconds(self.player.currentTime) + 10.0, self.player.currentTime.timescale);
    NSDate *now = [NSDate date];

    NSTimeInterval interval = [now timeIntervalSinceDate:self.now];

    CMTime seekingCM = CMTimeMake(interval, 1);

    if (CMTimeGetSeconds(cmTime) < CMTimeGetSeconds(seekingCM)) 
        [self.player.currentItem seekToTime:cmTime];
        NSLog(@"FF2!");
     else 
        [self fastForward3:nil];
    


- (IBAction)fastForward3:(id)sender


    NSDate *now = [NSDate date];
    NSLog(@"FIRSTDATE: %@", self.now);
    NSTimeInterval interval = [now timeIntervalSinceDate:self.now];
    interval -= 0.5f;
    NSLog(@"INT: %f", interval);

    CMTime seekingCM = CMTimeMake(interval, 1);


    /*
    NSTimeInterval interval = self.interval - 1.0;
    CMTime seekingCM = CMTimeMake(interval, 1);
    [self.player.currentItem seekToTime:seekingCM];
     */
    //CMTime seekingCM = CMTimeMake(self.interval, 1);
    [self.player.currentItem seekToTime:seekingCM];
    NSLog(@"FF3!");


- (NSTimeInterval)currentPlaybackTime

    return CMTimeGetSeconds(self.player.currentItem.currentTime);


- (void)setCurrentPlaybackTime:(NSTimeInterval)time

    CMTime cmTime = CMTimeMakeWithSeconds(time, NSEC_PER_SEC);
    [self.player.currentItem seekToTime:cmTime];


- (void)viewDidLayoutSubviews

    [self.playPauseButton sizeToFit];
    self.playPauseButton.center = CGPointMake(self.view.frame.size.width / 2.0, self.view.frame.size.height / 1.2);



- (void)playPauseButtonDidPress:(RSPlayPauseButton *)playPauseButton

    [playPauseButton setPaused:!playPauseButton.isPaused animated:YES];
    if (playPauseButton.isPaused) 
        [self.player pause];
    
    else 
        [self.player play];
    


- (void)didReceiveMemoryWarning 
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.



@end

顺便说一句,有一个 UIlabel 给出了播放器的当前时间,但是如果我离开页面并返回,标签会在 00:00 自动重新开始。这是因为它给出了新 AVPlayer 的当前时间。有没有办法让它给出原始 AVPlayer 的当前时间?

【问题讨论】:

【参考方案1】:

我会创建一个单例对象来控制AVPlayer,所以无论你有多少视图控制器,它们都会与这个玩家控制器进行通信。所以基本上我建议你将viewDidLoad 中的所有代码移动到一些MYPlayerController 单例类中。

【讨论】:

@Jameson 你能发布解决方案吗? 我最终做了一个单例音频播放器,而不是创建一个新的,我只是得到了单例。【参考方案2】:

这是我的 swift 视图控制器,如果它可以帮助你,那很好,我已经在那里实现了所有无线电的东西:

swift view controller

【讨论】:

我不确定在不创建新实例的情况下该怎么做。我如何检查它们是否已经创建,因为对于那个 viewController,当 VC 加载时,它的所有属性都是 nil。正在播放的 AVPlayer 属于最后一个 VC。对吗? 不,你需要创建正确的新实例,但创建它们时没有定义,所以它将是对私有成员的引用,而不是新变量 嗯。好吧,我取出了定义(例如,AVPlayerItem * playerItem = ...,所以它只是说playerItem = ...),我仍然面临同样的问题。删除这些定义会在我的代码中产生很多错误,因为从未定义过 playerItemplayer,所以我不得不将它们称为属性 self.playerItemself.player 好吧,对不起,我的错,我有相同的广播流应用程序,我只是重写了 viewDidLoad 方法,比如:“override func viewDidAppear(anumated: Bool)”,不知道是怎么回事在 obj-C 中,抱歉 没问题,非常感谢您的尝试。你能用 swift 或任何语言发布你所做的事情,我会尝试翻译它吗?

以上是关于AVPlayer(或 AVAudioSession?)在我离开 ViewController 后播放,当我返回两个时播放的主要内容,如果未能解决你的问题,请参考以下文章

AVAudioSession 类别变为 nil 并且 mediaServicesWereReset,avplayer 播放一直失败

AVPlayer自定制视频播放器——耳机线控中断以及AVAudioSession的使用

AVPlayer 类事件

iOS - 后台的 AVAudioSession 路由更改通知

iOS:如何停止直播 AVPlayer?

如何获取 AVPlayer 的中断开始/结束事件