iOS 真正的流音频秒播 边缓冲边播放 DOUAudioStreamer框架

时间:2022-11-19 16:33:11

上一篇音频流播放 使用的是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)NSURL *audioFileURL;


@end

 track.m

#import "Track.h"


@implementation Track


@end

2. 创建播放器控制器 添加播放暂停,,上一曲,下一曲,进度提示,,缓冲提示,,当前时间提示,,总时间提示控件,,

进度提示使用uislider 可滑动选择播放位置,,缓存提示使用UIprogressView,,(

相关设置 ,,uislider覆盖在UIprogressView上面并设置为透明色

    self.progress = [[UIProgressViewalloc]init];

    [self.viewaddSubview:self.progress];

    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.mas_equalTo(2);

        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);

    }];

/// 其余控件省略了

iOS 真正的流音频秒播 边缓冲边播放 DOUAudioStreamer框架

- (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 = [_streamer bufferingRatio];

}

 /// 播放器销毁

- (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