iOS 真正的流音訊秒播 邊緩衝邊播放 DOUAudioStreamer框架
上一篇音訊流播放 使用的是freestreamer 框架 後來又研究了一下DOUAudioStreamer 整理如下 僅供參考
安裝
pod 'DOUAudioStreamer','~> 0.2.15'
1.建立一對 track 檔案繼承於 NSObject
track.h
#import <Foundation/Foundation.h>
#import <DOUAudioFile.h>
@interface Track :NSObject<DOUAudioFile>
@property (nonatomic,strong)
@end
track.m#import "Track.h"
@implementation Track
@end
2. 建立播放器控制器 新增播放暫停,,上一曲,下一曲,進度提示,,緩衝提示,,當前時間提示,,總時間提示控制元件,,
進度提示使用uislider 可滑動選擇播放位置,,快取提示使用UIprogressView,,(
相關設定 ,,uislider覆蓋在UIprogressView上面並設定為透明色
self.progress = [[UIProgressViewalloc]init];
[self
self.progress.tintColor = [UIColorcyanColor];
[self.progressmas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.nowTimeLabel.mas_right).offset(0);
make.centerY.mas_equalTo(self.nowTimeLabel.mas_centerY);
make.height
make.width.mas_equalTo([UIScreenmainScreen].bounds.size.width - 140);
}];
self.slider = [[UISlideralloc]init];
[self.viewaddSubview:self.slider];
self.slider.tintColor = [UIColorredColor];
self.slider.maximumTrackTintColor = [UIColorclearColor];
[self.slidersetThumbImage:[UIImageimageNamed:@"球足球沙灘球-4"]forState:UIControlStateNormal];
self.slider.continuous =YES;
[self.slideraddTarget:selfaction:@selector(_actionSliderProgress:)forControlEvents:UIControlEventValueChanged];
[self.slideraddTarget:selfaction:@selector(durationSliderTouchEnded:)forControlEvents:UIControlEventTouchUpInside];
[self.slidermas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.nowTimeLabel.mas_right).offset(0);
make.top.mas_equalTo(self.progress.mas_top).offset(-10);
make.height.mas_equalTo(20); // 這個數值不能設定太小 高度代表可滑動範圍 太小的話劃不動的
make.width.mas_equalTo([UIScreenmainScreen].bounds.size.width - 140);
}];
/// 其餘控制元件省略了)
- (void)viewDidLoad {
[superviewDidLoad];
self.view.backgroundColor = [UIColorwhiteColor];
[selfcreateView]; // 建立控制元件 省略
[selfloadData];
// 音訊進度計時器
self.timer = [NSTimerscheduledTimerWithTimeInterval:1target:selfselector:@selector(_timerAction:)userInfo:nilrepeats:YES];
}
- (void)loadData{
self.titleLabel.text = self.songDic[@"title"];
self.nameLabel.text = self.songDic[@"nicName"];
NSURL *imageurl = [NSURLURLWithString:[NSStringstringWithFormat:@"%@%@",URLADDRESS,self.songDic[@"cover"]]];
[self.bigImageViewsd_setImageWithURL:imageurlplaceholderImage:[UIImageimageNamed:@""]];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
NSString *InPutUrl = [NSStringstringWithFormat:@"%@/audio/getAudioByIdentifier2/%@/0",URLADDRESS,self.songDic[@"identifier"]];
// 耗時的操作
[FMAFNetWorkingToolgetUrl:InPutUrlbody:nilresult:FMJSONheaderFile:nilsuccess:^(id result) {
self.audioTrack = [[Trackalloc]init];
// 獲取音訊播放地址
self.audioTrack.audioFileURL = [NSURLURLWithString:result[@"body"][@"ios_url_b"]];
// 建立播放器
[selfcreatePlayer];
/// 向前載入一條 向後載入一條 實現上下一曲 按需求更改
[selfloadMoreVideo:result[@"body"][@"id"]];
dispatch_async(dispatch_get_main_queue(), ^{
// 更新介面
});
} failure:^(NSError *error) {
}];
});
}
- (void)createPlayer{
//// 如果要實現全域性播放的播放器,,可以把播放器的建立使用單利建立。。。
self.streamer = [DOUAudioStreamerstreamerWithAudioFile:self.audioTrack];
[self.streameraddObserver:selfforKeyPath:@"status"options:NSKeyValueObservingOptionNewcontext:kStatusKVOKey];
[self.streameraddObserver:selfforKeyPath:@"duration"options:NSKeyValueObservingOptionNewcontext:kDurationKVOKey];
[self.streameraddObserver:selfforKeyPath:@"bufferingRatio"options:NSKeyValueObservingOptionNewcontext:kBufferingRatioKVOKey];
[self.streamerplay];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if (context ==kStatusKVOKey) {
[selfperformSelector:@selector(_updateStatus)
onThread:[NSThreadmainThread]
withObject:nil
waitUntilDone:NO];
}elseif (context ==kDurationKVOKey) {
[selfperformSelector:@selector(_timerAction:)
onThread:[NSThreadmainThread]
withObject:nil
waitUntilDone:NO];
}elseif (context ==kBufferingRatioKVOKey) {
}else {
[superobserveValueForKeyPath:keyPathofObject:objectchange:changecontext:context];
}
}
- (void)_updateStatus{
switch ([_streamerstatus]) {
caseDOUAudioStreamerPlaying:
[self.playButtonsetImage:[UIImageimageNamed:@"暫停"]forState:UIControlStateNormal];
break;
caseDOUAudioStreamerPaused:
[self.playButtonsetImage:[UIImageimageNamed:@"播放-3"]forState:UIControlStateNormal];
break;
caseDOUAudioStreamerIdle:
break;
caseDOUAudioStreamerFinished:
/// 當前音訊播放完成,,播放下一個音訊
[selfnextButtonAction];
break;
caseDOUAudioStreamerBuffering:
break;
caseDOUAudioStreamerError:
break;
}
}
//// 計時器 顯示 播放進度 時間
- (void)_timerAction:(id)timer{
if ([_streamerduration] ==0.0) {
[self.slidersetValue:0.0fanimated:NO];
self.nowTimeLabel.text =@"00:00";
}else {
/// 播放進度條 self.sliding bool值 在滑動進度除錯設定為yes 暫時停止進度條賦值。。
if (self.sliding ==YES) {
}else{ // 滑動結束後正常賦值
[self.slidersetValue:[_streamercurrentTime] / [_streamerduration]animated:YES];
}
//// 當前播放時間
double minutesElapsed =floor(fmod([_streamercurrentTime]/60.0,60.0));
double secondsElapsed =floor(fmod([_streamercurrentTime],60.0));
self.nowTimeLabel.text = [NSStringstringWithFormat:@"%02.0f:%02.0f",minutesElapsed, secondsElapsed];
/// 音訊總時長
double minutesElapsedtotal =floor(fmod([_streamerduration]/60.0,60.0));
double secondsElapsedtotal =floor(fmod([_streamerduration],60.0));
self.totalTimeLabel.text = [NSStringstringWithFormat:@"%02.0f:%02.0f",minutesElapsedtotal, secondsElapsedtotal];
}
/// 緩衝進度
self.progress.progress = [_streamerbufferingRatio];
}
/// 播放器銷燬
- (void)_cancelStreamer{
if (_streamer !=nil) {
[_streamerpause];
[_streamerremoveObserver:selfforKeyPath:@"status"];
[_streamerremoveObserver:selfforKeyPath:@"duration"];
[_streamerremoveObserver:selfforKeyPath:@"bufferingRatio"];
_streamer =nil;
}
}
// 此為進度條開始滑動的方法 ,,具體在uislider 建立的時候新增
- (void)_actionSliderProgress:(id)sender{
self.sliding =YES;
}
// 此為進度條滑動結束的方法 ,,具體在uislider 建立的時候新增
- (void)durationSliderTouchEnded:(UISlider *)slider{
/// 延時0.5秒 再給進度條賦值,,防止滑動進度條結束時會產生回彈。。
[selfperformSelector:@selector(reloadprogressValue)withObject:selfafterDelay:0.5];
/// 跳到指定時間播放
[_streamersetCurrentTime:[_streamerduration] * [slider value]];
}
- (void)reloadprogressValue{
self.sliding = NO;
}
- (void)lastButtonAction{
[self_cancelStreamer];
// 實現上一曲方法 建立播放器 新增URL 播放
}
- (void)nextButtonAction{
[self_cancelStreamer];
// 實現下一曲方法 建立播放器 新增URL 播放
}
/// 播放 暫停按鈕點選方法
- (void)playButtonAction{
if ([_streamerstatus] == DOUAudioStreamerPaused ||
[_streamerstatus] ==DOUAudioStreamerIdle) {
[_streamerplay];
[self.playButtonsetImage:[UIImageimageNamed:@"暫停"]forState:UIControlStateNormal];
[self.timersetFireDate:[NSDatedistantPast]];
}else {
[_streamerpause];
[self.playButtonsetImage:[UIImageimageNamed:@"播放-3"]forState:UIControlStateNormal];
[self.timersetFireDate:[NSDatedistantFuture]];
}
}
/// 返回按鈕 銷燬計時器和播放器
- (void)backaction{
[_timerinvalidate];
_timer =nil;
[self_cancelStreamer];
[selfdismissViewControllerAnimated:YEScompletion:^{
}];
}
#pragma mark 解決slider小範圍滑動不能觸發的問題
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if([gestureRecognizerlocationInView:gestureRecognizer.view].y >=self.slider.frame.origin.y && !self.slider.hidden)
returnNO;
returnYES;
}
demo 地址 http://code.cocoachina.com/view/135275