最近项目里有一个需求,是个直播项目,需要主播在开播端,点击聊天区某条语音信息的播放按钮来播放观众的语音(这里我用的是在语音播放单例添加播放完毕监听;在本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];
});
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