zjf
2023-03-13 881f0da670f20c401c1e1d08b36253abb28f72d2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
//
//  PBAVPlayerManager.m
//  IphoneBIMe
//
//  Created by zjf on 2019/1/3.
//  Copyright © 2019 ProBIM. All rights reserved.
//
 
#import "PBAVPlayerManager.h"
 
@interface PBAVPlayerManager()<AVPlayerItemOutputPullDelegate>
@property (nonatomic, strong) AVPlayer *player;
@property (nonatomic, strong) AVPlayerItem *item;
@end
 
@implementation PBAVPlayerManager
+ (instancetype)sharedManager{
    static PBAVPlayerManager *manager;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[PBAVPlayerManager alloc] init];
    });
    return manager;
}
- (instancetype)init {
    self = [super init];
    if (self) {
        _player = [[AVPlayer alloc] init];
    }
    return self;
}
#pragma mark - 播放本地录音
- (void)playItemWithName:(NSString *)recodingName {
    if (recodingName != nil) {
        //真机必须添加此代码
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];
        [session setActive:YES error:nil];
        NSURL *sourceMovieUrl = [NSURL fileURLWithPath:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:recodingName]];
        AVAsset *movieAsset = [AVURLAsset URLAssetWithURL:sourceMovieUrl options:nil];
        AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:movieAsset];
        if (self.item) {
            [self removeObserverFromPlayerItem:self.item];
            [_player  replaceCurrentItemWithPlayerItem:playerItem];
        }else {
            _player = [AVPlayer playerWithPlayerItem:playerItem];
        }
        self.item = playerItem;
//        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
        [self addObserverToPlayerItem:self.item];
        [_player play];
    }else {
        [YJProgressHUD showMessage:@"没有找到此音频文件" inView:nil];
    }
}
 
#pragma mark - 播放网络音频
- (void)playItemWithUrl:(NSString *)recordingUrl {
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];
    [session setActive:YES error:nil];
    //    NSURL *sourceMovieUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@",BaseUrl,recordingUrl]];
    NSURL *sourceMovieUrl = [NSURL URLWithString:recordingUrl];
    AVAsset *movieAsset = [AVURLAsset URLAssetWithURL:sourceMovieUrl options:nil];
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:movieAsset];
    if (self.item) {
        [self removeObserverFromPlayerItem:self.item];
        [_player  replaceCurrentItemWithPlayerItem:playerItem];
    } else {
        _player = [AVPlayer playerWithPlayerItem:playerItem];
    }
    self.item = playerItem;
    [_player replaceCurrentItemWithPlayerItem:playerItem];
//    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
    [self addObserverToPlayerItem:self.item];
    [_player play];
}
/**
 *  给AVPlayerItem添加监控
 *
 *  @param playerItem AVPlayerItem对象
 */
- (void)addObserverToPlayerItem:(AVPlayerItem *)playerItem
{
    if (playerItem) {
        [playerItem addObserver:self
                     forKeyPath:@"status"
                        options:NSKeyValueObservingOptionNew
                        context:nil];
        //监控网络加载情况属性
        [playerItem addObserver:self
                     forKeyPath:@"loadedTimeRanges"
                        options:NSKeyValueObservingOptionNew
                        context:nil];
        //给AVPlayerItem添加播放完成通知
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
    }
}
 
- (void)removeObserverFromPlayerItem:(AVPlayerItem *)playerItem
{
    if (playerItem) {
        [playerItem removeObserver:self forKeyPath:@"status"];
        [playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
        [[NSNotificationCenter defaultCenter]removeObserver:self
                                                       name:AVPlayerItemDidPlayToEndTimeNotification
                                                     object:playerItem];
    }
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    AVPlayerItem *playerItem = object;
    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
        switch (status) {
            case AVPlayerStatusUnknown:{
                self.status = ETPlayer_UnkonwError;
                if ([self respondsDelegate]) {
                    [self.delegate currentPlayerStatus:ETPlayer_UnkonwError];
                }
                break;
            }
            case AVPlayerStatusReadyToPlay:{
                self.status = ETPlayer_ReadyToPlay;
                if ([self respondsDelegate]) {
                    [self.delegate currentPlayerStatus:ETPlayer_ReadyToPlay];
                }
                CMTime time = _player.currentItem.duration;
                float value1 = time.value / time.timescale;
                float value2 = CMTimeGetSeconds(self.player.currentItem.asset.duration);
                NSLog(@"正在播放,_player.currentItem.duration 总长度:%.2f", value1);
                NSLog(@"正在播放,_player.currentItem.asset.duration总长度:%.2f", value2);
                break;
            }
            case AVPlayerStatusFailed: {
                self.status = ETPlayer_PlayFailed;
                if ([self respondsDelegate]) {
                    [self.delegate currentPlayerStatus:ETPlayer_PlayFailed];
                }
                [PBNoteCenter postNotificationName:PBNoteCenterPlayOver object:nil];
                [YJProgressHUD showMessage:@"加载音频失败" inView:nil];
                break;
            }
            default:
                break;
        }
    }else if([keyPath isEqualToString:@"loadedTimeRanges"]) {
        double timeInterval = [self availableDuration];
        CMTime duration = playerItem.duration;
        double totalDuration = CMTimeGetSeconds(duration);
        NSLog(@"timeInterval:%f",timeInterval);
        NSLog(@"totalDuration:%f",totalDuration);
        if (timeInterval < 1.5 * totalDuration) {
            self.status = ETPlayer_Loading;
            if ([self respondsDelegate]) { [self.delegate currentPlayerStatus:ETPlayer_Loading]; }
        }else if ([self isPlaying]) {
            self.status = ETPlayer_Playing;
            if ([self respondsDelegate]) { [self.delegate currentPlayerStatus:ETPlayer_Playing]; }
        } else {
            self.status = ETPlayer_Loading;
            if ([self respondsDelegate]) { [self.delegate currentPlayerStatus:ETPlayer_Loading]; }
        }
    }
}
- (BOOL)respondsDelegate {
    if (self.delegate && [self.delegate respondsToSelector:@selector(currentPlayerStatus:)]) {
        return YES;
    }
    return NO;
}
- (BOOL)isPlaying
{
    // 可以根据值去判断播放还是暂停
    if (_player.rate == 0.0) {
        return NO;
    }
    return YES;
}
- (double)availableDuration{
    NSArray *loadedTimeRanges = self.player.currentItem.loadedTimeRanges;
    NSValue *value = loadedTimeRanges.firstObject;
    CMTimeRange timeRange = value.CMTimeRangeValue;
    double startSeconds = CMTimeGetSeconds(timeRange.duration);
    double durationSeconds = CMTimeGetSeconds(timeRange.duration);
    return startSeconds + durationSeconds;
}
- (void)playbackFinished:(NSNotification *)noti {
    [PBNoteCenter postNotificationName:PBNoteCenterPlayOver object:nil];
}
 
- (void)stopPlay {
    [_player pause];
}
 
 
 
 
 
 
@end