ios 獲取avplayer播放聲音完成時的衝突探究
阿新 • • 發佈:2018-12-21
最近專案裡有一個需求,是個直播專案,需要主播在開播端,點選聊天區某條語音資訊的播放按鈕來播放觀眾的語音(這裡我用的是在語音播放單例新增播放完畢監聽;在本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通知,執行了我以為的語音播放完畢的方法,要注意(使用了MPMoviePlayerController和AVPlayer來播放的檔案,不管是聲音還是視訊,都會發出AVPlayerItemDidPlayToEndTimeNotification通知),要識別到底是聲音播放完畢,還是視訊播放完畢,還需要做更細緻的區分.
另外使用MPMoviePlayerController播放視訊,不需要設定成vc的strong屬性,去持有它,不然p呼叫lay方法也無法正常播放
更多交流,請加群討論:565191947