如果要音乐支持后台播放
在AppDelegate.m的didFinishLaunch方法里面写下面
//支持后台播放
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
//激活
[session setActive:YES error:nil];
在info.plist里面修改
一、System Sound Service
它是最底层也是最简单的声音播放服务,通过调用AudioServicesPlaySystemSound这个函数就可以播放一些简单的音频文件
适用场景:很小的提示或者警告音
局限性
1.声音长度小于30秒
2.格式 IMA4
3.不能控制播放的进度
4.调用方法后立即播放声音
5.没有循环播放和立体声音播放
//先从bundle中获取音频文件
NSString *musicPath = [[NSBundle mainBundle]pathForResource:@"news" ofType:@"wav"];
//播放音频时,需要的路径为url
NSURL *musicUrl = [NSURL fileURLWithPath:musicPath];
//创建soundID 播放系统提示音或者指定的音频文件,都是根据soundID来找音频文件,大小范围为1000~2000
SystemSoundID mySoundID;
//创建
AudioServicesCreateSystemSoundID((__bridge CFURLRef)musicUrl, &mySoundID);
//播放纯音乐
AudioServicesPlaySystemSound(mySoundID);
//提示音和震动
AudioServicesPlayAlertSound(mySoundID);
二、AVAudioPlayer
我们可以把AVAudioPlayer看作一个高级的播放器,它支持广泛的音频格式
优势
1.支持更多格式
2.可播放任意长度
3.支持循环
4.可以同步播放多个
5.控制播放进度以及从音频的任意一点开始
//AVAudioPlayer
- (IBAction)avAudioPlayer:(UIButton *)sender {
//得到音频资源
NSString *musicPath = [[NSBundle mainBundle]pathForResource:@"小猪歌" ofType:@"mp3"];
//转换为URL
NSURL *musicUrl = [NSURL fileURLWithPath:musicPath];
//创建player对象
_audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:musicUrl error:nil];
//设置声音0~1
_audioPlayer.volume = 0.5;
//准备播放
[_audioPlayer prepareToPlay];
//播放进度
// _audioPlayer.currentTime = 0;
//循环播放次数 负数无限循环
// _audioPlayer.numberOfLoops = -1;
//播放
[_audioPlayer play];
//暂停
//[_audioPlayer pause];
//停止
//[_audioPlayer stop];
}
三、视频AVPlayer
iOS里视频播放使用AVPlayer,比AVAudioPlayer更强大,可以直接播放网络音视频
AVPlayerItem,资源管理对象,作用:切换视频播放,
1.状态 status
AVPlayerItemStatusUnknown,未知
AVPlayerItemStatusReadyToPlay,准备好播放,可以paly
AVPlayerItemStatusFailed,失败
2.loadedTimeRange
代表缓存的进度,监听此属性可以在UI中更新缓存进度
播放完成的通知,可以注册通知,做出响应
AVPlayerItemDidPlayToEndTimeNotification
AVPlayerLayer
单纯使用AVPlayer无法显示视频,因为这个类并没有真正的视图,需要将视频层添加到AVPlayerLayer中
@property (nonatomic,retain)AVPlayer *player;//播放器
@property (nonatomic,retain)AVPlayerItem *playerItem;//播放对象
@property (nonatomic,retain)AVPlayerLayer *playerLayer;//显示视频的层
@property (weak, nonatomic) IBOutlet UISlider *videoSlider;//视频播放进度
@property (nonatomic,assign)BOOL isReayToPlay;//判断是否已经开始播放O
@property (weak, nonatomic) IBOutlet UILabel *timeLabel; //显示事件的label
@property (nonatomic,retain)NSTimer *timer;
- (void)viewDidLoad {
[super viewDidLoad];
//还没有准备好播放视频
_isReayToPlay = NO;
//启动视频准备
[self netVideoPlay];
//计时器
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(progressAction) userInfo:nil repeats:YES];
}
//得到视频
-(void)netVideoPlay
{
NSString *urlStr = @"http://static.tripbe.com/videofiles/20121214/9533522808.f4v.mp4";
NSString *urlStr2 = [[NSBundle mainBundle]pathForResource:@"test" ofType:@"mp4"];
//播放下一个视频
// [_player replaceCurrentItemWithPlayerItem: nextPlayerItem];
//得到视频资源的URL
NSURL *videoURL = [NSURL fileURLWithPath:urlStr2];
//初始化item
_playerItem = [[AVPlayerItem alloc]initWithURL:videoURL];
//初始化播放器
_player = [AVPlayer playerWithPlayerItem:_playerItem];
//显示图像的layer
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
//将视频层添加到当前解密的layer上
[self.view.layer addSublayer:_playerLayer];
_playerLayer.frame = CGRectMake(100, 100, 200, 200);
//让视频层适应当前界面
_playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
//为item添加观察者,当视频已经准备好播放的时候再播放
[_playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
}
#pragma mark -- KVO回调方法
//keyPath:变化的属性的名称 如果属性是声明在.m中就监测不到?
//object:被观察的对象
//change:存放属性变化前后的值
//context:添加观察者时候context的值
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
AVPlayerItem *item = (AVPlayerItem*)object;
NSLog(@"item -- %@",item);
//取出变化之后的属性值
NSLog(@"new -- %@ ",change[NSKeyValueChangeNewKey]);
//取出变化之前的
NSLog(@"old -- %@",change[NSKeyValueChangeOldKey]);
//得到改变后的status
AVPlayerItemStatus status = [change[NSKeyValueChangeNewKey]intValue];
//对比,看目前播放单元的状态
switch (status) {
case AVPlayerItemStatusUnknown:
NSLog(@"未知状态");
break;
case AVPlayerItemStatusFailed:
NSLog(@"失败");
break;
case AVPlayerItemStatusReadyToPlay:
{
NSLog(@"准备好播放");
[self.player play];
_isReayToPlay = YES;
}
break;
default:
break;
}
//视频的总长度
float second = _playerItem.duration.value/_playerItem.duration.timescale;
NSLog(@"视频长度 %f",second);
//设置滑竿的最大值
_videoSlider.maximumValue = second;
_videoSlider.minimumValue = 0;
//移除观察者
[item removeObserver:self forKeyPath:@"status"];
这里略去了很多东西,我们应该添加一个sliderView,通过NSTimer的方法,来实时显示视频的播放进度,同时移动sliderView时可以控制视频的播放进度。
//进度条的回调方法
-(void)changeProgress:(UISlider*)sender
{
//每次调整之前,暂停播放
[_player pause];
if (_isReayToPlay) {
//说明已经有时长了,可以进行操作
//设置播放的区间
//参数1.CMTime从哪个时刻开始播放
//参数2.回调,设置完成后要进行的动作
[self.player seekToTime:CMTimeMakeWithSeconds(sender.value, self.playerItem.currentTime.timescale) completionHandler:^(BOOL finished) {
if (finished) {
//调整已经结束,可以播放了
[_player play];
}
}];
}
}
//进度条根据播放进度变动
-(void)progressAction
{
//label显示当前时间
NSDate *currentTime =[NSDate dateWithTimeIntervalSinceReferenceDate:round(_playerItem.currentTime.value/_playerItem.currentTime.timescale)];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"mm:ss"];
_timeLabel.text=[formatter stringFromDate:currentTime];
//进度条变动
_videoSlider.value = _playerItem.currentTime.value/_playerItem.currentTime.timescale;
}