本篇主要讲音频的后台播放和在线播放。

后台播放

上一篇写的工程运行之后程序退至后台,发现运行不了,歌停止了,这显然不行,音乐后台播放是标配啊。今天就来讲一下后台播放。

1.在plist文件里,告诉系统这是一款音乐软件。

<key>Required background modes</key>
<array>
<string>App plays audio or streams audio/video using AirPlay
</string>
</array>

2.代码里设置。这个方法最好在

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions ;

方法里调用,在别地调用也可以。

// 设置后台播放
- (void)setBackGroudPlay {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil]; }

3.其实完成前两步就可以实现后台播放了,不过后台播放最好加上一个过期时候的处理。

// 程序进入后台,执行这个方法
- (void)applicationDidEnterBackground:(UIApplication *)application { UIBackgroundTaskIdentifier taskID = [application beginBackgroundTaskWithExpirationHandler:^{
// 如果过期了,就停止任务
[application endBackgroundTask:taskID];
}];
}

在线播放(AVPlayer)

&emps;&emps;如果一个播放器仅仅支持本地音频播放显然是不够的,在线播放也是标配啊。用AVAudioPlayer框架只能实现本地播放,想要实现在线播放得用AVPlayer框架。AVPlayer框架是用来播放视频的,但是音频也没问题。

1.初识化UI



声明的变量

@interface FHAVPlayerViewController (){

    UIProgressView *_progressView; // 缓冲进度条
UISlider *_pregressSlider; // 播放控制条
UILabel *_pregressLabel; // 进度
UISlider *_volumeSlider; // 声音控制
} @property (nonatomic, strong)AVPlayer *avPlayer;
@property (nonatomic, strong)AVPlayerItem * songItem;
@property (nonatomic, strong)id timePlayProgerssObserver;// 播放器进度观察者 @end

&emps;&emps;黄色是UIProgressView,代表缓冲进度条,蓝色的是UISlider,代表播放控制条。

    // (1)初始化二个Button;
NSArray *titleArr = @[@"播放",@"暂停"];
for (int i = 0; i < titleArr.count; i++ ) { UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[self.view addSubview:button];
[button setFrame:CGRectMake(20 + i * 50, 130 , 60, 40)];
[button setTitle:titleArr[i] forState:UIControlStateNormal];
button.tag = i+100;
[button addTarget:self action:@selector(controlAVPlayerAction:) forControlEvents:UIControlEventTouchUpInside];
} // (2)初始化缓冲进度条
_progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(20, 59, ScreenWidth - 130 - 20, 5)];
// 设置缓冲进度条的颜色
_progressView.progressTintColor = [UIColor yellowColor];
[self.view addSubview:_progressView]; // (3)初始化播放进度
_pregressSlider = [[UISlider alloc] initWithFrame:CGRectMake(20, 50, ScreenWidth - 130 - 20, 20)];
_pregressSlider.minimumValue = 0.0f;
_pregressSlider.maximumValue = 1.0f;
// 把_pregressSlider小于滑块的部分设置成蓝色以显示播放进度
_pregressSlider.minimumTrackTintColor = [UIColor blueColor];
// 把_pregressSlider大于滑块的部分设置成透明以显示缓冲进度
_pregressSlider.maximumTrackTintColor = [UIColor clearColor];
[_pregressSlider addTarget:self action:@selector(pregressChange) forControlEvents:UIControlEventValueChanged];
[self.view addSubview: _pregressSlider];
// (4)时间
_pregressLabel = [[UILabel alloc] initWithFrame:CGRectMake(ScreenWidth - 120, 50, 100, 20)];
_pregressLabel.text = @"00:00/00:00";
[self.view addSubview:_pregressLabel]; // (5)初始化音量
_volumeSlider = [[UISlider alloc] initWithFrame:CGRectMake(20, 90, ScreenWidth - 130 - 20, 20)];
[_volumeSlider addTarget:self action:@selector(volumeChange) forControlEvents:UIControlEventValueChanged];
_volumeSlider.minimumValue = 0.0f;
_volumeSlider.maximumValue = 10.0f;
_volumeSlider.value = 1.0f;
[self.view addSubview:_volumeSlider];
UILabel *volumeLabel = [[UILabel alloc] initWithFrame:CGRectMake(ScreenWidth - 120, 90, 40, 20)];
volumeLabel.text = @"音量";
[self.view addSubview:volumeLabel];

注意:(1)播放进度条要放在缓冲进度条上面,否则缓冲进度遮挡播放进度。

(2)其他的和上一个工程一样,就不介绍了。具体的可以去本人的GitUp上下载。

2.实现在线播放

准备:在plist文件里让工程支持http。

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
// (1)取得音频播放路径
NSString *strURL = @"http://yinyueshiting.baidu.com/data2/music/42783748/42783748.mp3?xcode=b31ae4e046eac3470c486914f0acd7b6";
// (2)把音频文件转化成url格式
NSURL *url = [NSURL URLWithString:strURL];
// (3)使用playerItem获取视频的信息,当前播放时间,总时间等
_songItem = [[AVPlayerItem alloc]initWithURL:url];
// (3)初始化音频类 并且添加播放文件
self.avPlayer = [[AVPlayer alloc]initWithPlayerItem:_songItem];
// (4) 设置初始音量大小 默认1,取值范围 0~1
self.avPlayer.volume = 1.0;

注意:必须等缓冲完了才能播放。

// 音频控制
- (void)controlAVPlayerAction : (UIButton *)button { NSInteger tag = button.tag;
// 播放
if (tag == 100) {
[self.avPlayer play];
}
// 暂停
if (tag == 101) { [self.avPlayer pause];
}
}

3.监听在线播放状态

(1) 监听播放器状态和缓冲状态

// (5)监听播放器状态 NSKeyValueObservingOptionNew 把更改之前的值提供给处理方法
[self.avPlayer.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
// (6)监听缓存状态
[self.avPlayer.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];

备注:监听self.avPlayer.currentItem的status和loadedTimeRanges属性,一有变化就把更改之前的值提供给下面的方法

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context {
if ([keyPath isEqualToString:@"status"]) {
switch (_avPlayer.status) {
case AVPlayerStatusUnknown:
NSLog(@"KVO:未知状态,此时不能播放");
break;
case AVPlayerStatusReadyToPlay:
NSLog(@"KVO:准备完毕,可以播放");
break;
case AVPlayerStatusFailed:
NSLog(@"KVO:加载失败,网络或者服务器出现问题");
break;
default:
break;
}
}
if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
NSArray * timeRanges = self.avPlayer.currentItem.loadedTimeRanges;
//本次缓冲的时间范围
CMTimeRange timeRange = [timeRanges.firstObject CMTimeRangeValue];
//缓冲总长度
NSTimeInterval totalLoadTime = CMTimeGetSeconds(timeRange.start) + CMTimeGetSeconds(timeRange.duration);
//音乐的总时间
NSTimeInterval duration = CMTimeGetSeconds(self.avPlayer.currentItem.duration);
//计算缓冲百分比例
NSTimeInterval scale = totalLoadTime/duration;
//更新缓冲进度条
_progressView.progress = scale;
}
}

注意:status是检测的硬件属性,也就是用户的手机。只要手机没坏都能准备完成.但是准备完成还不能播放,得能缓冲完。

(2)监听音乐播放的进度

    // 防止循环引用
__weak typeof(self) weakSelf = self;
__block UISlider *weakPregressSlider = _pregressSlider;
__block UILabel *weakPregressLabel = _pregressLabel;
self.timePlayProgerssObserver = [self.avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
// 当前播放的时间
float current = CMTimeGetSeconds(time);
// 总时间
float total = CMTimeGetSeconds(weakSelf.avPlayer.currentItem.duration);
// 更改当前播放时间
NSString *currentMStr = [weakSelf FormatTime: current / 60];
NSString *currentSStr = [weakSelf FormatTime: (int)current % 60];
NSString *durationMStr = [weakSelf FormatTime:total / 60];
NSString *durationSStr = [weakSelf FormatTime: (int)total % 60];
weakPregressLabel.text = [NSString stringWithFormat:@"%@:%@/%@:%@",currentMStr,currentSStr,durationMStr,durationSStr];
// 更新播放进度条
weakPregressSlider.value = current / total;
}];
- (NSString *)FormatTime: (int)time {

    if (time < 10) {
return [NSString stringWithFormat:@"0%d",time];
}else {
return [NSString stringWithFormat:@"%d",time];
}
}

注意:block里面一定要防止循环引用。

(3)监听音乐播放完成

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
- (void)playFinished:(NSNotification *)notification {
// 时间跳转到零 重新播放
[self.avPlayer seekToTime:kCMTimeZero];
[self.avPlayer play];
}

注意:播放完成如果你什么都不设置,就会变成停止播放。AVPlayer没有播放次数的属性,得我们自己实现。

3.最后

- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self.avPlayer removeTimeObserver:self.timePlayProgerssObserver];
self.timePlayProgerssObserver = nil;
}

注意:如果不移除观察者,将造成内存泄漏。

  要想获得完整工程可以去本人的GitUp上下载。

iOS从零开始学习直播之音频2.后台播放和在线播放的更多相关文章

  1. iOS从零开始学习直播之音频1.播放本地音频文件

      现在直播越来越火,俨然已经成为了下一个红海.作为一个资深码农(我只喜欢这样称呼自己,不喜欢别人这样称呼我),我必须赶上时代的潮流,开始研究视频直播.发现视屏直播类的文章上来就讲拉流.推流.采集.美 ...

  2. iOS从零开始学习直播之音频4.歌词

      上一篇讲了歌曲的切换,这一篇主要讲歌词部分的实现.   先看效果图.当歌手唱到这句歌词时候,我们要标记出来,这里显示字体为黄色. 1.获取歌词   一般歌词都是一个链接.类似于"http ...

  3. iOS从零开始学习直播之音频3.歌曲切换

      上周迟到了,周末去参加OSC源创会了,还是有点启发的.但这不是重点,重点是 上一篇我只是实现了一首歌曲的在线播放,这肯定是不够的.这一篇博客主要是实现了多首歌曲的顺序播放以及上一首和下一首切换. ...

  4. iOS从零开始学习直播之2.采集

      直播的采集由采集的设备(摄像头.话筒)不同分为视频采集和音频采集,本篇文章会分别介绍. 1.采集步骤   1.创建捕捉会话(AVCaptureSession),iOS调用相机和话筒之前都需要创建捕 ...

  5. iOS从零开始学习直播之1.播放

      对于直播来说,客户端主要做两件事情,推流和播放.今天先讲播放. 播放流程 1.拉流:服务器已有直播内容,从指定地址进行拉取的过程.其实就是向服务器请求数据. 2.解码:对视屏数据进行解压缩. 3. ...

  6. iOS从零开始学习直播之3.美颜

      任何一款直播软件都必须进行美颜,不然哪来的那么多美女,所以技术改变世界,不只是说说而已.美颜在采集的时候就得就行,让主播实时看到直播的效果. 1.美颜原理   其实美颜的本质就是美白和磨皮,分别通 ...

  7. 流媒体技术学习笔记之(四)解决问题video.js 播放m3u8格式的文件,根据官方的文档添加videojs-contrib-hls也不行的原因解决了

    源码地址:https://github.com/Tinywan/PHP_Experience 总结: 说明: 测试环境:本测试全部来自阿里云直播和OSS存储点播以及本地服务器直播和点播 播放器:Vid ...

  8. iOS 直播-获取音频(视频)数据

    iOS 直播-获取音频(视频)数据 // // ViewController.m // capture-test // // Created by caoxu on 16/6/3. // Copyri ...

  9. iOS AvPlayer AvAudioPlayer音频的后台播放问题

    iOS 4开始引入的multitask,我们可以实现像ipod程序那样在后台播放音频了.如果音频操作是用苹果官方的AVFoundation.framework实现,像用AvAudioPlayer,Av ...

随机推荐

  1. 关于Java中进程和线程的详解

    一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而 ...

  2. 转: 解决Github访问超慢问题

    转自:http://zengrong.net/post/2092.htm 解决Github访问超慢问题 Github is so slowly. 这段时间访问 github 都非常慢,google了一 ...

  3. NodeJs 开发微信公众号(四)微信网页授权

    微信的网页授权指的是在微信公众号中访问第三方网页时获取用户地理.个人等信息的权限.对于开发了自己的网页app应用时,获取个人的信息非常重要.上篇博客讲到了注册时可以获取用户的信息,很多人会问为什么还需 ...

  4. opengl 笔记(2)

    /*- * Opengl Demo Test * * Fredric : 2016-7-10 */ #include <GLUT/GLUT.h> #include <stdlib.h ...

  5. 【UWP开源】图片编辑器,带贴图、滤镜、涂鸦等功能

    目录 说明 功能 实现原理 使用方法 效果截图 说明 最近空余时间研究了一下Win2D,它能为我们在UWP中提供一种类似GDI那样的绘图方法.就像传统Winform.MFC中那样重写OnPaint相关 ...

  6. Hbase学习笔记01

    最近做项目接触到了HDFS.mapreduce以及Hbase,有了实战机会,今天打算将这些知识好好总结下,以备不时之需.首先从Hbase开始吧. Hbase是建立在HDFS上的分布式数据库,下图是Hb ...

  7. LeetCode-1TwoSum(C#)

    # 题目 1. Two Sum Given an array of integers, return indices of the two numbers such that they add up ...

  8. Java基础之IO流

    很长时间都没有更新了,最近在补充JavaSE的一些细节部分 关于IO流的一些总结 首先要介绍的是File类,File类用于对文件和目录的一些操作 1.创建文件CreateNewFile() 2.对文件 ...

  9. Maven pom文件常用配置,转载

    什么是POM Project Object Model,项目对象模型.通过xml格式保存的pom.xml文件.作用类似ant的build.xml文件,功能更强大.该文件用于管理:源代码.配置文件.开发 ...

  10. Android-TextView跑马灯效果

    要实现跑马灯还是比较简单的. 同时有几个需要注意的点,先上代码: public class MTView extends TextView { public MTView(Context contex ...