• 【音频】远程链接音频播放(AVPlayer)


    感觉没啥说的,直接看代码。

    WebMusicTool是控制单个音频的类。

    WebMusicOperationTool是控制流程播放控制的类。

    #import <Foundation/Foundation.h>
    #import "DenglSingleton.h"
    #import "WebMusicTool.h"
    #import "NLessonM.h"
    
    #import "NMusicMessageModel.h"
    
    @interface WebMusicOperationTool : NSObject
    DenglSingletonH(WebMusicOperationTool)
    
    @property(nonatomic,copy) NSArray *musicMs;
    
    -(void)playMusic:(NLessonM *)musicM;
    
    -(void)playCurrentMusic;
    
    -(void)pauseCurrentMusic;
    
    -(void)seekToTime:(float)p;
    
    -(NMusicMessageModel*)getMusicMessageModel;
    
    @end
    #import "WebMusicOperationTool.h"
    
    @interface WebMusicOperationTool ()
    {
        
    }
    
    @property(nonatomic,strong) WebMusicTool *tool;
    
    @property(nonatomic,assign) NSInteger currentPlayIndex;
    
    @property(nonatomic,strong) NMusicMessageModel *musicModel;
    
    @end
    
    @implementation WebMusicOperationTool
    DenglSingletonM(WebMusicOperationTool)
    
    #pragma mark - GET SET
    -(WebMusicTool *)tool{
        if (!_tool) {
            _tool = [[WebMusicTool alloc]init];
        }
        return _tool;
    }
    
    -(NMusicMessageModel *)musicModel{
        if (!_musicModel) {
            _musicModel = [[NMusicMessageModel alloc]init];
        }
        return _musicModel;
    }
    
    -(NMusicMessageModel*)getMusicMessageModel{
        // 在这里, 保持, 数据的最新状态, 就可以
        // 当前正在播放的歌曲信息
        self.musicModel.lessonmodel = self.musicMs[_currentPlayIndex];
        
        NSTimeInterval costTime = CMTimeGetSeconds(self.tool.player.currentItem.currentTime);
        if (isnan(costTime)) {
            costTime = 0;
        }
        self.musicModel.costTime = costTime;
        
        NSTimeInterval totalTime = CMTimeGetSeconds(self.tool.player.currentItem.duration);
        if (isnan(totalTime)) {
            totalTime = 0;
        }
        self.musicModel.totalTime = totalTime;
        
        self.musicModel.status = self.tool.status;
        
        self.musicModel.isPlaying = self.tool.isPlaying;
        
        return self.musicModel;
    }
    
    #pragma mark - play
    -(void)playMusic:(NLessonM *)musicM{
        
        // 播放数据模型对应的音乐
        [self.tool playMusic:musicM.main_audio[@"src"]];
        _currentPlayIndex = [self.musicMs indexOfObject:musicM];
        
    }
    
    -(void)playCurrentMusic{
        
        // 取出需要播放的音乐数据模型
        NLessonM * model = self.musicMs[_currentPlayIndex];
        
        // 播放音乐模型
        [self playMusic:model];
    }
    
    -(void)pauseCurrentMusic{
        [self.tool pauseMusic];
    }
    
    -(void)seekToTime:(float)p{
        [self.tool seekToTime:p];
    }
    @end
    #import <Foundation/Foundation.h>
    #import <AVFoundation/AVFoundation.h>
    
    //播放状态枚举值
    typedef NS_ENUM(NSInteger,NPlayerStatus){
        NPlayerStatusFailed,
        NPlayerStatusReadyToPlay,
        NPlayerStatusUnknown,
        NPlayerStatusBuffering,
        NPlayerStatusPlaying,
        NPlayerStatusStopped,
    };
    @interface WebMusicTool : NSObject
    
    @property(nonatomic,strong) AVPlayer *player;
    
    @property(nonatomic,assign) BOOL isPlaying;
    //播放状态
    @property (nonatomic,assign,readonly) NPlayerStatus status;
    
    -(void)playMusic:(NSString *)musicUrl;
    
    -(void)seekToTime:(float)p;
    
    -(void)pauseMusic;
    
    @end
    #import "WebMusicTool.h"
    
    @interface WebMusicTool (){
        id playbackTimerObserver;
    }
    
    //记录当前正在播放的曲目url
    @property(nonatomic,strong) NSString *currentUrl;
    
    //当前歌曲进度监听者
    @property(nonatomic,strong) id timeObserver;
    
    @end
    
    @implementation WebMusicTool
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            //后台播放三步走:1.background mode 2.setCategory 3.setActive
            AVAudioSession *session = [AVAudioSession sharedInstance];
            [session setCategory:AVAudioSessionCategoryPlayback error:nil];
            [session setActive:YES error:nil];
    
            //
    //        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVPlayerItemNotification:) name:AVPlayerItemTimeJumpedNotification object:nil];
    //        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVPlayerItemNotification:) name:AVPlayerItemFailedToPlayToEndTimeNotification object:nil];
    //        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVPlayerItemNotification:) name:AVPlayerItemPlaybackStalledNotification object:nil];
    //        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVPlayerItemNotification:) name:AVPlayerItemFailedToPlayToEndTimeErrorKey object:nil];
    //        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVPlayerItemNotification:) name:AVPlayerItemNewErrorLogEntryNotification object:nil];
    //        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVPlayerItemNotification:) name:AVPlayerItemNewAccessLogEntryNotification object:nil];
        }
        return self;
    }
    
    -(void)playMusic:(NSString *)musicUrl{
        // 1. 创建播放器
        if (!musicUrl) {
            return;
        }
        //2.
        if ([musicUrl isEqualToString:_currentUrl]) {
            [self.player play];
            return;
        }
        
        //3.
        [self stop];
        
        AVPlayerItem *item = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:musicUrl]];
        self.player = nil;
        self.player = [AVPlayer playerWithPlayerItem:item];
        _currentUrl = musicUrl;
        [self.player play];
        
        [self addKVO];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVPlayerItemNotification:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
        
        
        
    }
    
    -(void)seekToTime:(float)p{
        NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentItem.duration) * p;
        [self.player seekToTime:CMTimeMakeWithSeconds(currentTime, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
        [self.player play];
    }
    
    -(void)pauseMusic{
        [self.player pause];
    }
    
    #pragma mark - Notification
    -(void)AVPlayerItemNotification:(NSNotification* )noti{
        //
        if (noti.object == self.player.currentItem) {
            if ([noti.name isEqualToString:@"AVPlayerItemDidPlayToEndTimeNotification"]) {
                [self stop];
                [[NSNotificationCenter defaultCenter] postNotificationName:@"NPlayerFinishNotification" object:nil];
            }
        }
    }
    #pragma mark - 监听音乐各种状态 KVO
    //添加KVO
    -(void)addKVO{
        //监听状态属性
        [self.player.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
        //监听网络加载情况属性
        [self.player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
        //监听播放的区域缓存是否为空
        [self.player.currentItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
        //缓存可以播放的时候调用
        [self.player.currentItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
        //监听暂停或者播放中
        [self.player addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:nil];
    }
    -(void)stop{
        [self.player.currentItem removeObserver:self forKeyPath:@"status"];
        //    [self.player removeTimeObserver:playbackTimerObserver];
        [self.player.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
        [self.player.currentItem removeObserver:self forKeyPath:@"playbackBufferEmpty"];
        [self.player.currentItem removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];
        [self.player removeObserver:self forKeyPath:@"rate"];
        [[NSNotificationCenter defaultCenter]removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:[self.player currentItem]];
        if (self.player) {
            
            _currentUrl = nil;
            self.player = nil;
        }
    }
    //KVO
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        if ([keyPath isEqualToString:@"status"]) {
            AVPlayerItemStatus itemStatus = [[change objectForKey:NSKeyValueChangeNewKey]integerValue];
            
            switch (itemStatus) {
                case AVPlayerItemStatusUnknown:
                {
                    _status = NPlayerStatusUnknown;
                    NSLog(@"AVPlayerItemStatusUnknown");
                }
                    break;
                case AVPlayerItemStatusReadyToPlay:
                {
                    _status = NPlayerStatusReadyToPlay;
                    [self.player play];
                    NSLog(@"AVPlayerItemStatusReadyToPlay");
                    
                }
                    break;
                case AVPlayerItemStatusFailed:
                {
                    _status = NPlayerStatusFailed;
                    NSLog(@"AVPlayerItemStatusFailed");
                    [self stop];
                    
                }
                    break;
                default:
                    break;
            }
        }else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {  //监听播放器的下载进度
            NSArray *loadedTimeRanges = [self.player.currentItem loadedTimeRanges];
            CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 获取缓冲区域
            float startSeconds = CMTimeGetSeconds(timeRange.start);
            float durationSeconds = CMTimeGetSeconds(timeRange.duration);
            NSTimeInterval timeInterval = startSeconds + durationSeconds;// 计算缓冲总进度
            CMTime duration = self.player.currentItem.duration;
            CGFloat totalDuration = CMTimeGetSeconds(duration);
            //缓存值
            CGFloat p = timeInterval / totalDuration;
            NSLog(@"%f",p);
        } else if ([keyPath isEqualToString:@"playbackBufferEmpty"]) { //监听播放器在缓冲数据的状态
            _status = NPlayerStatusBuffering;
            NSLog(@"缓冲中");
    //        if (!self.activityIndeView.isAnimating) {
    //            [self.activityIndeView startAnimating];
    //        }
        } else if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {
            NSLog(@"缓冲达到可播放");
    //        [self.activityIndeView stopAnimating];
        } else if ([keyPath isEqualToString:@"rate"]){//当rate==0时为暂停,rate==1时为播放,当rate等于负数时为回放
            if ([[change objectForKey:NSKeyValueChangeNewKey]integerValue]==1) {
                _isPlaying=YES;
                _status = NPlayerStatusPlaying;
            }else{
                _isPlaying=NO;
                _status = NPlayerStatusStopped;
            }
        }
        
    }
  • 相关阅读:
    为什么要有handler机制
    安卓五种数据存储的方式
    Activity生命周期详解
    JS的一些简单实例用法
    JSP 中的EL表达式详细介绍
    JSP九大内置对象和四个作用域
    JS实现---图片轮播效果
    实现 鼠标移动到表格的某行 该行换背景 ---myEclipse编写
    JS 菜单收拉样式
    spring中aware接口的
  • 原文地址:https://www.cnblogs.com/iOSDeng/p/6724046.html
Copyright © 2020-2023  润新知