美文网首页
AVplayer开发音乐模块详解(三)

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

作者: 三年坎坷 | 来源:发表于2017-05-27 12:59 被阅读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,再加上后缀。

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

    相关文章

      网友评论

          本文标题:AVplayer开发音乐模块详解(三)

          本文链接:https://www.haomeiwen.com/subject/gqptfxtx.html