-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathAVPlayer+Convenience.m
229 lines (163 loc) · 5.59 KB
/
AVPlayer+Convenience.m
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
//
// AVPlayer+Convenience.m
// Ringo
//
// Created by Alexander Ivanov on 15.07.15.
// Copyright © 2015 Alexander Ivanov. All rights reserved.
//
#import "AVPlayer+Convenience.h"
@implementation AVPlayer (Convenience)
- (NSURL *)url {
return [self.currentItem.asset isKindOfClass:[AVURLAsset class]] ? ((AVURLAsset *)self.currentItem.asset).URL : Nil;
}
- (BOOL)isPlaying {
return self.rate > 0.0;
}
- (BOOL)isPlaying:(CMTime)currentTime {
return self.isPlaying && CMTimeCompare(currentTime, self.currentItem.duration) < 0;
}
@end
@implementation AVAudioPlayer (Convenience)
+ (instancetype)playerWithContentsOfURL:(NSURL *)url fileTypeHint:(NSString *)uriString {
NSError *error = Nil;
AVAudioPlayer *instance = uriString.length ? [[self alloc] initWithContentsOfURL:url fileTypeHint:uriString error:&error] : [[self alloc] initWithContentsOfURL:url error:&error];
[error log:@"AVAudioSegmentPlayer initWithContentsOfURL:"];
return error ? Nil : instance;
}
+ (instancetype)playerWithContentsOfURL:(NSURL *)url {
return url.isWebAddress || url.isExistingFile || url.isMediaItem ? [self playerWithContentsOfURL:url fileTypeHint:[NSString string]] : Nil;
}
+ (instancetype)playerWithData:(NSData *)data fileTypeHint:(NSString *)uriString {
NSError *error = Nil;
AVAudioPlayer *instance = uriString.length ? [[self alloc] initWithData:data fileTypeHint:uriString error:&error] : [[self alloc] initWithData:data error:&error];
[error log:@"AVAudioSegmentPlayer initWithData:"];
return error ? Nil : instance;
}
+ (instancetype)playerWithData:(NSData *)data {
return data.length ? [self playerWithData:data fileTypeHint:[NSString string]] : Nil;
}
@end
#define EPSILON 0.04
#define TIME 0.02
@interface AVAudioSegmentPlayer ()
@property (assign, nonatomic) BOOL prepared;
@end
@implementation AVAudioSegmentPlayer {
NSNumber *_segmentStart;
NSNumber *_segmentEnd;
}
- (void)performStatusChange {
__weak AVAudioSegmentPlayer *__self = self;
if (self.statusChange)
self.statusChange(__self);
}
- (void)performTimeChange {
__weak AVAudioSegmentPlayer *__self = self;
if (self.timeChange)
self.timeChange(__self);
}
- (instancetype)initWithContentsOfURL:(NSURL *)url fileTypeHint:(NSString *)utiString error:(NSError *__autoreleasing *)outError {
self = [super initWithContentsOfURL:url fileTypeHint:utiString error:outError];
if (self)
self.delegate = self;
return self;
}
- (instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError * _Nullable __autoreleasing *)outError {
self = [super initWithContentsOfURL:url error:outError];
if (self)
self.delegate = self;
return self;
}
- (instancetype)initWithData:(NSData *)data fileTypeHint:(NSString *)utiString error:(NSError *__autoreleasing *)outError {
self = [super initWithData:data fileTypeHint:utiString error:outError];
if (self)
self.delegate = self;
return self;
}
- (instancetype)initWithData:(NSData *)data error:(NSError * _Nullable __autoreleasing *)outError {
self = [super initWithData:data error:outError];
if (self)
self.delegate = self;
return self;
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
[self performStatusChange];
}
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error {
[error log:@"audioPlayerDecodeErrorDidOccur:"];
[self performStatusChange];
}
- (NSComparisonResult)segmentContainsTime:(NSTimeInterval)time {
BOOL greaterThanStart = !_segmentStart || time - self.segmentStart >= -EPSILON;
BOOL lessThanEnd = !_segmentEnd || time - self.segmentEnd < -EPSILON;
return !greaterThanStart ? NSOrderedAscending : !lessThanEnd ? NSOrderedDescending : NSOrderedSame;
}
- (NSTimeInterval)segmentStart {
return _segmentStart.doubleValue;
}
- (NSTimeInterval)segmentEnd {
return _segmentEnd.doubleValue;
}
- (NSTimeInterval)segmentDuration {
return _segmentEnd.doubleValue - _segmentStart.doubleValue;
}
- (void)setSegmentStart:(NSTimeInterval)start andSegmentEnd:(NSTimeInterval)end {
NSTimeInterval s = fabs(start - self.segmentStart);
NSTimeInterval e = fabs(end - self.segmentEnd);
if (s <= EPSILON && e <= EPSILON)
return;
_segmentStart = @(start);
_segmentEnd = @(end);
NSComparisonResult contains = [self segmentContainsTime:self.currentTime];
if (contains == NSOrderedSame)
return;
[self stop];
if (contains == NSOrderedAscending)
[super setCurrentTime:0.0];
else if (contains == NSOrderedDescending)
[super setCurrentTime:self.duration];
}
- (void)timer {
if (!self.playing)
return;
if (self.numberOfLoops < 0 && [self segmentContainsTime:self.currentTime] == NSOrderedDescending) {
self.currentTime = self.segmentStart;
[self performSelector:@selector(timer) withObject:Nil afterDelay:TIME];
} else
if ([self segmentContainsTime:self.currentTime] != NSOrderedSame)
[self stop];
else
[self performSelector:@selector(timer) withObject:Nil afterDelay:TIME];
[self performTimeChange];
}
- (BOOL)prepareToPlay {
self.prepared = [super prepareToPlay];
[self performStatusChange];
return self.prepared;
}
- (BOOL)play {
if ([self segmentContainsTime:self.currentTime] != NSOrderedSame)
self.currentTime = self.segmentStart;
self.prepared = [super play];
[self performStatusChange];
[self timer];
return self.prepared;
}
- (BOOL)playAtTime:(NSTimeInterval)time {
return NO;
}
- (void)pause {
[super pause];
[self performStatusChange];
}
- (void)stop {
self.prepared = NO;
[super stop];
[self performStatusChange];
}
/*
- (void)setCurrentTime:(NSTimeInterval)currentTime {
[super setCurrentTime:[self segmentContainsTime:currentTime] == NSOrderedAscending ? self.segmentStart : currentTime];
}
*/
@end