//
//? XMGDownLoader.h
//? XMGDownLoader
//
//? Created by 小碼哥 on 2017/1/8.
//? Copyright ? 2017年 xmg. All rights reserved.
//
#import
@protocol XMGDownLoaderDelegate <NSObject>
- (void)downloadData:(NSData*)datapath:(NSString*)path;
@end
@interface XMGDownLoader : NSObject
- (void)downLoader:(NSURL*)url;
@property (nonatomic, weak) id<XMGDownLoaderDelegate> delegate;
@end
//
//? XMGDownLoader.m
//? XMGDownLoader
//
//? Created by 小碼哥 on 2017/1/8.
//? Copyright ? 2017年 xmg. All rights reserved.
//
#import "XMGDownLoader.h"
#import "XMGFileTool.h"
#define kTmpPath NSTemporaryDirectory()
@interface XMGDownLoader () <NSURLSessionDataDelegate>
@property (nonatomic, strong) NSURLSession *session;
@property (nonatomic, copy) NSString *downLoadingPath;
@property (nonatomic, strong) NSOutputStream *outputStream;
//是否開始有拉取到第一段數(shù)據(jù)了
@property (nonatomic, assign) BOOL isStarDownloadData;
@end
@implementation XMGDownLoader
- (instancetype)init {
? ? if(self= [superinit]) {
? ? }
? ? return self;
}
- (NSURLSession *)session {
? ? if(!_session) {
? ? ? ? NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
? ? ? ? _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
? ? }
? ? return _session;
}
- (void)downLoader:(NSURL*)url {
? ? self.isStarDownloadData = NO;
? ? NSString*fileName = url.lastPathComponent;
? ? self.downLoadingPath = [kTmpPath stringByAppendingPathComponent:fileName];
? ? //這里為了方便測試,再次點(diǎn)擊下載,如果發(fā)現(xiàn)downLoadingPath存在,那就刪除掉
? ? if ([XMGFileTool fileExists:self.downLoadingPath]) {
? ? ? ? [XMGFileTool removeFile:self.downLoadingPath];
? ? }
? ? // 從0字節(jié)開始請求資源
? ? [self downLoadWithURL:url offset:0];
}
#pragma mark- 協(xié)議方法
// 第一次接受到相應(yīng)的時(shí)候調(diào)用(響應(yīng)頭, 并沒有具體的資源內(nèi)容)
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
? ? // 繼續(xù)接受數(shù)據(jù)
? ? // 確定開始下載數(shù)據(jù)
? ? self.outputStream = [NSOutputStream outputStreamToFileAtPath:self.downLoadingPath append:YES];
? ? [self.outputStream open];
? ? completionHandler(NSURLSessionResponseAllow);
}
static NSInteger i = 0;
//下載到資源了,多次調(diào)用,直到下載完畢
- (void)URLSession:(NSURLSession*)sessiondataTask:(NSURLSessionDataTask*)dataTaskdidReceiveData:(NSData*)data
{
? ? //下載數(shù)據(jù)寫進(jìn)downLoadingPath
? ? [self.outputStream write:data.bytes maxLength:data.length];
? ? if(self.delegate&& [self.delegaterespondsToSelector:@selector(downloadData:path:)]) {
? ? ? ? if(self.isStarDownloadData == NO) {
? ? ? ? ? ? self.isStarDownloadData = YES;
? ? ? ? ? ? //這里我也不知道為啥調(diào)用一次,就能把那么長一首歌全播下來,按理來說,這里會多次收到下載數(shù)據(jù),應(yīng)該是一小段一小段數(shù)據(jù)下載下來的.理論上應(yīng)該一開始只播放幾秒. 所以猜測可能和NSOutputStream這種流的方式寫入文件有關(guān)系.? 如果用[data WriteToFile]這種就不行
? ? ? ? ? ? [self.delegate downloadData:data path:self.downLoadingPath];
? ? ? ? }
? ? }
? ? NSLog(@"在接受后續(xù)數(shù)據(jù)%ld",data.length);
}
// 請求完成的時(shí)候調(diào)用( != 請求成功/失敗)
- (void)URLSession:(NSURLSession*)sessiontask:(NSURLSessionTask*)taskdidCompleteWithError:(NSError*)error {
? ? NSLog(@"請求完成");
? ? if(error ==nil) {
? ? ? ? // 不一定是成功
? ? ? ? // 數(shù)據(jù)是肯定可以請求完畢
? ? ? ? // 判斷, 本地緩存 == 文件總大小 {filename: filesize: md5:xxx}
? ? ? ? // 如果等于 => 驗(yàn)證, 是否文件完整(file md5 )
? ? }else{
? ? ? ? NSLog(@"有問題");
? ? }
? ? [self.outputStream close];
}
#pragma mark- 私有方法
/**
?根據(jù)開始字節(jié), 請求資源
?@param url url
?@param offset 開始字節(jié)
?*/
- (void)downLoadWithURL:(NSURL*)urloffset:(longlong)offset {
? ? NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:0];
? ? [requestsetValue:[NSString stringWithFormat:@"bytes=%lld-", offset] forHTTPHeaderField:@"Range"];
? ? // session 分配的task, 默認(rèn)情況, 掛起狀態(tài)
? ? NSURLSessionDataTask*dataTask = [self.sessiondataTaskWithRequest:request];
? ? [dataTaskresume];
}
@end
//
//? XMGFileTool.h
//? XMGDownLoader
//
//? Created by 小碼哥 on 2017/1/8.
//? Copyright ? 2017年 xmg. All rights reserved.
//
#import
@interface XMGFileTool : NSObject
? ? + (BOOL)fileExists:(NSString*)filePath;
? ? + (longlong)fileSize:(NSString*)filePath;
? ? + (void)moveFile:(NSString*)fromPathtoPath:(NSString*)toPath;
? ? + (void)removeFile:(NSString*)filePath;
@end
//
//? XMGFileTool.m
//? XMGDownLoader
//
//? Created by 小碼哥 on 2017/1/8.
//? Copyright ? 2017年 xmg. All rights reserved.
//
#import "XMGFileTool.h"
@implementation XMGFileTool
? ? + (BOOL)fileExists:(NSString*)filePath {
? ? ? ? if(filePath.length==0) {
? ? ? ? ? ? returnNO;
? ? ? ? }
? ? ? ? return [[NSFileManager defaultManager] fileExistsAtPath:filePath];
? ? }
? ? + (longlong)fileSize:(NSString*)filePath {
? ? ? ? if(![selffileExists:filePath]) {
? ? ? ? ? ? return0;
? ? ? ? }
?? ? ? NSDictionary *fileInfo = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
? ? ? ? return[fileInfo[NSFileSize]longLongValue];
? ? }
? ? + (void)moveFile:(NSString*)fromPathtoPath:(NSString*)toPath {
? ? ? ? if(![selffileSize:fromPath]) {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? [[NSFileManager defaultManager] moveItemAtPath:fromPath toPath:toPath error:nil];
? ? }
? ? + (void)removeFile:(NSString*)filePath {
? ? ? ? [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
? ? }
@end
//
//? ViewController.m
//? XMGDownLoader
//
//? Created by 小碼哥 on 2017/1/8.
//? Copyright ? 2017年 xmg. All rights reserved.
//
#import "ViewController.h"
#import "XMGDownLoader.h"
#import
@interface ViewController ()<XMGDownLoaderDelegate>
@property (nonatomic, strong) XMGDownLoader *downLoader;
@property (nonatomic, strong) AVAudioEngine *engine;
@property (nonatomic, strong) AVAudioPlayerNode *playerNode;
@end
@implementation ViewController
- (XMGDownLoader *)downLoader {
? ? if (!_downLoader) {
? ? ? ? _downLoader= [XMGDownLoadernew];
? ? ? ? _downLoader.delegate = self;
? ? }
? ? return _downLoader;
}
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? self.engine= [[AVAudioEnginealloc]init];
? ? self.playerNode = [[AVAudioPlayerNode alloc] init];
? ? [self.engine attachNode:self.playerNode];
? ? [self.engine connect:self.playerNode to:self.engine.mainMixerNode format:nil];
? ? // 安裝音頻緩沖區(qū)的處理
? ? AVAudioFormat *format = [self.engine.mainMixerNode inputFormatForBus:0];
? ? [self.playerNodeinstallTapOnBus:0bufferSize:4096format:formatblock:^(AVAudioPCMBuffer*buffer,AVAudioTime*when) {
? ? ? ? [selfprocessAudioBuffer:buffer];
? ? }];
? ? NSError*error =nil;
? ? if(![self.enginestartAndReturnError:&error]) {
? ? ? ? NSLog(@"Audio Engine error: %@", error.localizedDescription);
? ? }
? ? [self.playerNode play];
? ? // Do any additional setup after loading the view.
? ? UIButton*btn = [[UIButtonalloc]initWithFrame:CGRectMake(0,100,100,100)];
? ? btn.backgroundColor = [UIColor redColor];
? ? [btnsetTitle:@"下載播放" forState:UIControlStateNormal];
? ? [btnaddTarget:self action:@selector(downAndPlayAudio) forControlEvents:UIControlEventTouchUpInside];
? ? [self.view addSubview:btn];
}
- (void)downAndPlayAudio {
? ? NSURL *url1 = [NSURL URLWithString:@"http://cdnringhs.shoujiduoduo.com/ringres/userv1/m96/482/317324482.mp3"];//短mp3音頻
? ? NSURL *url2 = [NSURL URLWithString:@"http://cdnringhs.shoujiduoduo.com/ringres/userv1/m96/290/315379290.mp3"];//長mp3音頻
? ? [self.downLoader downLoader:url2];
}
- (void)playWithUrl:(NSURL*)url {
? ? NSError*error =nil;
? ? AVAudioFile*file = [[AVAudioFilealloc]initForReading:urlerror:&error];
? ? if(error) {
? ? ? ? NSLog(@"Audio file error: %@", error.localizedDescription);
? ? ? ? return;
? ? }
? ? [self.playerNode scheduleFile:file atTime:nil completionHandler:^{
? ? ? ? NSLog(@"播放完成");
? ? }];
}
- (void)processAudioBuffer:(AVAudioPCMBuffer *)buffer {
? ? AVAudioChannelCountchannelCount = buffer.format.channelCount;
? ? if(channelCount >0) {
? ? ? ? float*channelData = buffer.floatChannelData[0];
? ? ? ? NSUIntegerframeLength = buffer.frameLength;
? ? ? ? NSMutableArray *channelDataArray = [NSMutableArrayarrayWithCapacity:frameLength];
? ? ? ? for(NSUIntegeri =0; i < frameLength; i++) {
? ? ? ? ? ? [channelDataArrayaddObject:@(channelData[i])];
? ? ? ? }
? ? ? ? floatrms =0;
? ? ? ? for(NSNumber*valueinchannelDataArray) {
? ? ? ? ? ? rms += value.floatValue* value.floatValue;
? ? ? ? }
? ? ? ? rms =sqrt(rms / frameLength);
? ? ? ? floatavgPower =20*log10(rms);
? ? ? ? dispatch_async(dispatch_get_main_queue(), ^{
//? ? ? ? ? ? NSLog(@"Current audio power: %f dB", avgPower);
? ? ? ? ? ? // 你可以在這里更新UI,如進(jìn)度條或波動圖
? ? ? ? });
? ? }
}
#pragma mark - XMGDownLoaderDelegate
- (void)downloadData:(NSData*)datapath:(NSString*)path {
? ? NSURL*url = [NSURLfileURLWithPath:path];
? ? [selfplayWithUrl:url];
}
@end