AVplayer开发音乐模块详解(三)

2017-05-27  本文已影响0人  三年坎坷

前言:

在开发每一个模块之前,一定要确定好你们的大致需求,将需求大致罗列出来,然后分析每一个需求。具体的需求的分析,我是借助MindNode实现的,就是将该需求细化到每一个属性,每一个方法,然后罗列每一个方法,根据开放-封闭原则,这些方法尽量颗粒小写,然后在后面的维护的时候便于扩展。最后强调一点一定要把需求明确之后在写代码,不然你就会浪费很多时间,换句话说需要把产品经理问吐!!(小心他揍你哈)

正文:

2、缓存的处理。

首先我们问先认识一个类  AVURLAsset,它有一个方法:

AVURLAsset * asset = [AVURLAsset URLAssetWithURL:url options:nil];

顾名思义,他是管理网络音乐的请求,并且对网络数据打包的AVAssetResourceLoader、AVAssetCache都是和他有关系的。

我的主要的处理方法是参考网上的一位作者的:

1、建立一个AVAResourceLoaderManager类,该类需要遵循AVAssetResourceLoaderDelegate的代理方法,然后在代理方法内部,根据系统的加载数据大小和状态,在进行重新自定义加载和存储。

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest

- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest

loadingRequest是AVAssetResourceLoadingRequest类,类中的方法和属性我就不做详细的介绍了,这点需要你自己摸索,只有自己的探索才能更快的掌握和应用(我就是懒!)。这个类中有一个我们需要的属性:

@property (nonatomic, readonly, nullable) AVAssetResourceLoadingDataRequest *dataRequest;

在这个属性中有我们需要的三个主要属性:1、requestedOffset   2、currentOffset 3、requestedLength。

分别对应本次请求的偏移量、本地的偏移量,请求的长度,然后我们根据这三个属性进行再次的请求设置。

看代码:

- (void)addLoadingRequest:(AVAssetResourceLoadingRequest *)loadRequest{

[self.requestList addObject:loadRequest];

@synchronized (self) {

if (self.requestTask) {

if (loadRequest.dataRequest.requestedOffset >= self.requestTask.requestOffset && loadRequest.dataRequest.requestedOffset <= self.requestTask.requestOffset + self.requestTask.cacheLength) {

/* 数据已经缓存,则直接完成 */

NSLog(@"数据已经缓存,则直接完成");

[self processRequestList];

}else{

// 数据还没有缓存,则等待数据下载; 如果是Seek操作,则重新请求

if (self.seekRequired) {

NSLog(@"Seek操作,则完成请求");

[self newTaskWithLoadingRequest:loadRequest cache:NO];}}}}

- (void)processRequestList{

NSMutableArray *finishRequestList = [NSMutableArray array];

for (AVAssetResourceLoadingRequest *loadingRequest in self.requestList) {

if ([self finishLoadingWithLoadingRequest:loadingRequest]) {

[finishRequestList addObject:loadingRequest];}}

[self.requestList removeObjectsInArray:finishRequestList];}

- (BOOL)finishLoadingWithLoadingRequest:(AVAssetResourceLoadingRequest *)loadRequest{

// 填充信息

CFStringRef contentType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)(MimeType), NULL);

loadRequest.contentInformationRequest.contentType = CFBridgingRelease(contentType);

loadRequest.contentInformationRequest.byteRangeAccessSupported = YES;

loadRequest.contentInformationRequest.contentLength = self.requestTask.fileLength;

//读文件,填充数据

NSUInteger cacheLength = self.requestTask.cacheLength;

NSUInteger requestedOffset = loadRequest.dataRequest.requestedOffset;

if (loadRequest.dataRequest.currentOffset != 0) {

requestedOffset = loadRequest.dataRequest.currentOffset;}

NSUInteger canReadLength = cacheLength - (requestedOffset - self.requestTask.requestOffset);

NSUInteger respondLength = MIN(canReadLength, loadRequest.dataRequest.requestedLength);

[loadRequest.dataRequest respondWithData:[AVFileHandle readTempFileDataWithOffset:requestedOffset - self.requestTask.requestOffset length:respondLength]];

// 如果完全响应了所需要的数据,则完成

NSUInteger nowendOffset = requestedOffset + canReadLength;

NSUInteger reqEndOffset = loadRequest.dataRequest.requestedOffset + loadRequest.dataRequest.requestedLength;

if (nowendOffset >= reqEndOffset) {

[loadRequest finishLoading];

return YES;}

return NO;}

- (void)newTaskWithLoadingRequest:(AVAssetResourceLoadingRequest *)loadRequest cache:(BOOL)cache{

NSUInteger fileLength = 0;

if (self.requestTask) {

fileLength = self.requestTask.fileLength;

self.requestTask.cancle = YES;}

self.requestTask = [[AVRequestTask alloc] init];

self.requestTask.requestURL = loadRequest.request.URL;

self.requestTask.requestOffset = loadRequest.dataRequest.requestedOffset;

self.requestTask.cache = cache;

if (fileLength > 0) {

self.requestTask.fileLength = fileLength;}

self.requestTask.delegate = self;

[self.requestTask start];

self.seekRequired = NO;}

这些是处理问题的核心代码,如果有用户全面的了解,请参考这篇文章:

http://blog.csdn.net/minggeqingchun/article/details/52210898

其他的类我就一一介绍了,这里我主要想说的是他的处理缓存的思路

1、开始播放,同时开始下载完整的文件,当文件下载完成时,保存到缓存文件夹中;

2、当seek时,

(1)如果seek到已下载到部分,直接seek成功(已经下载60%,seek进度50%)

(2)如果seek到未下载到的部分,则开始重新下载(如下载进度60%,seek进度70%)

3、当开始新的下载之后,由于文件不完整,下载完成之后不会保存到缓存文件夹中;

4、下次再播放同一首歌曲时,如果在缓存文件夹中存在,则直接播放缓存文件

在处理的过程中,我发现缓存的文件没有后缀,会导致播放失败,因此处理的方式是你在下载的时候直接加上extensionType的后缀,如果下载的文件过程你控制不了那就直接暴力点,在源文件的基础上生成hand link,再加上后缀。

好了,其他的音乐模块的东西基本上是具体需求具体分析了。有任何疑问请在下面留言。

上一篇下一篇

猜你喜欢

热点阅读