ios 获取avplayer播放声音完成时的冲突探究

最近项目里有一个需求,是个直播项目,需要主播在开播端,点击聊天区某条语音信息的播放按钮来播放观众的语音(这里我用的是在语音播放单例添加播放完毕监听;在本vc控制器将出现时为语音播放处理单例添加语音播放完成监听,在vc控制器将要消失时为单例移出监听),并且播放完成,按钮切换为初始状态;而且在主播端开播前会播放一个“倒计时”视频,并且播放视频;但是在这里遇到一个问题:没有语音播放,但是却走了单里里边语音播放完成时监听的方法?

在这里猜测可能是开播前“倒计时”视频播放完毕也发出了播放完毕的通知,并且验证了下,的确是这样的,以后要注意。

代码如下:

单例.m文件,主要是add,remove播放完成通知方法被vc调用.

#import "JJHVoiceOpenQueue.h"
#import "JJHVoiceVentor.h"

@implementation JJHVoiceOpenQueue

+(JJHVoiceOpenQueue *)sharedQueue {
    static JJHVoiceOpenQueue  * instance = nil;
    static dispatch_once_t predict;
    dispatch_once(&predict, ^{
        instance = [[JJHVoiceOpenQueue alloc] init];
        //朱明俊:初始化的时候不用清除消息和暂停播放器
        //[instance otherOperationShouldStopNowPlayAndClearMp3Queue];
    });
    return instance;
}
//队列添加一个发言语音
-(void)addVoiceChatMp3FileUrlStr:(NSString*)Mp3UrlStr{
    
    if (self.voiceArray.count == 0) {
        //说明播放队列是播放完的,或者是刚启动程序初次播放,再加入就直接播放
        [self.voiceArray addObject:Mp3UrlStr];
        [self playVoiceArrFirst];
    }else{
        //说明播放队列没播放完,语音正在播放中,只添加
        [self.voiceArray addObject:Mp3UrlStr];
    }
}
//接着播放下一段
-(void)playWithNext{
    //流程:先删除播放完的录音->判断队列还有录音没有->有继续播放,没有不做操作
    if (self.voiceArray.count>0) {
        //删除刚刚播放过的语音
        [self.voiceArray removeObjectAtIndex:0];
        //如果大于0,继续下一首的播放
        [self playVoiceArrFirst];
    }
}
-(void)playVoiceArrFirst{
    //播放前毕发送通知,重置聊天区语音图标
    [[NSNotificationCenter defaultCenter] postNotificationName:VOICE_PLAYED_OVER_MSG object:nil userInfo:nil];
    
    //播放下一条
    if (self.voiceArray.count>0) {
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];
        [session setActive:YES error:nil];
        
        //http://jjhsound.jjhgame.com/181109105926-2690188-90602998.mp3
        NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:@"%@",self.voiceArray[0]]];
        AVPlayerItem * songItem = [[AVPlayerItem alloc]initWithURL:url];
        [self.voicePlayer replaceCurrentItemWithPlayerItem:songItem];
        [self.voicePlayer play];
        
        //播放发送通知,修改聊天区语音状态,就是修改图片为播放过的图片
        NSDictionary *voiceDic = @{@"urlStr":[NSString stringWithFormat:@"%@",self.voiceArray[0]]};
        [[NSNotificationCenter defaultCenter] postNotificationName:VOICE_PLAYED_MSG object:nil userInfo:voiceDic];
    }
    
    
}



//直播间直接点击播放
//播放语音
-(void)playVoiceWithVoiceUrlStr:(NSString*)voiceUrlStr{
    //清空播放队列
    [self otherOperationShouldStopNowPlayAndClearMp3Queue];
    
    //将获取的url添加到第一个
    [self addVoiceChatMp3FileUrlStr:voiceUrlStr];
    
}
//暂停播放,语音队列清空
//而且如果正在播放,需要暂停
//不必移除播放监听,播放监听只是顺序播放下一首,程序运行期间和本单例一直存在
-(void)otherOperationShouldStopNowPlayAndClearMp3Queue{
    [self.voicePlayer pause];
    [self.voiceArray removeAllObjects];
    
    //其他异常操作发送通知,重置聊天区语音图标,如,正在播放,点击录音等等情况
    [[NSNotificationCenter defaultCenter] postNotificationName:VOICE_PLAYED_OVER_MSG object:nil userInfo:nil];
}
#pragma - lazy
-(AVPlayer *)voicePlayer{
    if (!_voicePlayer) {
        _voicePlayer = [[AVPlayer alloc] initWithPlayerItem:nil];
    }
    return _voicePlayer;
}
//直播间成对调用
-(void)addNoti{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
}
-(void)removeNoti{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
}
-(void)playbackFinished{
    //播放完毕发送通知,重置聊天区语音图标
    [[NSNotificationCenter defaultCenter] postNotificationName:VOICE_PLAYED_OVER_MSG object:nil userInfo:nil];
    
NSLog(@"测试语音和视频播放完毕是否会发出走这个通知");
    //接着播放下一条录音,
    //[self playWithNext];
}
//声音url队列
-(NSMutableArray *)voiceArray{
    if (_voiceArray == nil) {
        _voiceArray = [[NSMutableArray alloc] init];
    }
    return _voiceArray;
}

@end

然后是vc的主要.m方法

- (void)playMovieBegin {
    
    NSString * path = [[NSBundle mainBundle] pathForResource:@"xxx" ofType:@"mp4"];
    
    //NSString *path =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSLog(@"path - %@",path);
    
    [self.moviePlayer setContentURL:[NSURL fileURLWithPath:path]];
    
    [self.moviePlayer prepareToPlay];
    
    [self.moviePlayer play];
    
}


- (MPMoviePlayerController *)moviePlayer {
    
    if(!_moviePlayer){
        _moviePlayer = [[MPMoviePlayerController alloc]init];
        [_moviePlayer.view setFrame:kYBScreenBounds];
        ///关闭自动播放
        [_moviePlayer setShouldAutoplay:NO];
        ///文件类型
        [_moviePlayer setMovieSourceType:MPMovieSourceTypeFile];
        ///取出控制进度条
        [_moviePlayer setControlStyle:MPMovieControlStyleNone];
        [[UIApplication sharedApplication].keyWindow addSubview:_moviePlayer.view];
        
    
    return _moviePlayer;
}

-(void)viewwillappear{
[super viewwillappear];
[[JJHVoiceOpenQueue sharedQueue] addNoti];
}

然后在没有聊天区语音信息播放的时候却在控制台打印出了

2018-12-19 11:41:54.514349+0800 Daka2[1404:397617] path - /var/containers/Bundle/Application/80173D9D-1D0A-4226-A62F-C2B6EA72392B/Daka2.app/Prepare.mp4
2018-12-19 11:41:58.397335+0800 Daka2[1404:397617] 测试语音和视频播放完毕是否会发出走这个通知

说明mp4视频播放完毕,也会发出AVPlayerItemDidPlayToEndTimeNotification通知,执行了我以为的语音播放完毕的方法,要注意(使用了MPMoviePlayerControllerAVPlayer来播放的文件,不管是声音还是视频,都会发出AVPlayerItemDidPlayToEndTimeNotification通知),要识别到底是声音播放完毕,还是视频播放完毕,还需要做更细致的区分.

另外使用MPMoviePlayerController播放视频,不需要设置成vc的strong属性,去持有它,不然p调用lay方法也无法正常播放

更多交流,请加群讨论:565191947

猜你喜欢

转载自blog.csdn.net/a787188834/article/details/85091836