@@ -6,14 +6,18 @@ @interface ASVideoNode ()
66{
77 ASDN::RecursiveMutex _lock;
88
9- __weak id <ASVideoNodeDataSource> _dataSource ;
10-
9+ __weak id <ASVideoNodeDelegate> _delegate ;
10+
1111 BOOL _shouldBePlaying;
1212 AVAsset *_asset;
13+
1314 AVPlayerItem *_currentItem;
15+ AVPlayer *_player;
16+
1417 ASButtonNode *_playButton;
1518 ASDisplayNode *_playerNode;
1619 ASDisplayNode *_spinner;
20+ ASVideoGravity _gravity;
1721}
1822
1923@end
@@ -28,13 +32,6 @@ - (instancetype)init
2832{
2933 if (!(self = [super init ])) { return nil ; }
3034
31- _playerNode = [[ASDisplayNode alloc ] initWithLayerBlock: ^CALayer *{
32- AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc ] init ];
33- playerLayer.player = [[AVPlayer alloc ] init ];
34- return playerLayer;
35- }];
36- [self addSubnode: _playerNode];
37-
3835 self.gravity = ASVideoGravityResizeAspect;
3936
4037 [self addTarget: self action: @selector (tapped ) forControlEvents: ASControlNodeEventTouchUpInside];
@@ -51,12 +48,17 @@ - (void)setInterfaceState:(ASInterfaceState)newState
5148
5249 if (!(newState & ASInterfaceStateVisible)) {
5350 [self pause ];
51+ [(UIActivityIndicatorView *)_spinner.view stopAnimating ];
5452 [_spinner removeFromSupernode ];
5553 } else {
5654 if (_shouldBePlaying) {
5755 [self play ];
5856 }
5957 }
58+
59+ if (newState & ASInterfaceStateVisible) {
60+ [self displayDidFinish ];
61+ }
6062}
6163
6264- (void )observeValueForKeyPath : (NSString *)keyPath ofObject : (id )object change : (NSDictionary *)change context : (void *)context
@@ -76,7 +78,8 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
7678- (void )didPlayToEnd : (NSNotification *)notification
7779{
7880 if (ASObjectIsEqual ([[notification object ] asset ], _asset)) {
79- [[((AVPlayerLayer *)_playerNode.layer) player ] seekToTime: CMTimeMakeWithSeconds (0 , 1 )];
81+ [_delegate videoDidReachEnd: self ];
82+ [_player seekToTime: CMTimeMakeWithSeconds (0 , 1 )];
8083
8184 if (_autorepeat) {
8285 [self play ];
@@ -90,6 +93,12 @@ - (void)layout
9093{
9194 [super layout ];
9295 _playerNode.frame = self.bounds ;
96+
97+ CGFloat horizontalDiff = (self.bounds .size .width - _playButton.bounds .size .width )/2 ;
98+ CGFloat verticalDiff = (self.bounds .size .height - _playButton.bounds .size .height )/2 ;
99+ _playButton.hitTestSlop = UIEdgeInsetsMake (-verticalDiff, -horizontalDiff, -verticalDiff, -horizontalDiff);
100+
101+ _spinner.frame = _playButton.frame ;
93102}
94103
95104- (void )tapped
@@ -123,29 +132,61 @@ - (void)fetchData
123132 _currentItem = [[AVPlayerItem alloc ] initWithAsset: _asset];
124133 [_currentItem addObserver: self forKeyPath: NSStringFromSelector (@selector (status )) options: NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context: NULL ];
125134
126- if (((AVPlayerLayer *)_playerNode. layer ). player ) {
127- [((AVPlayerLayer *)_playerNode.layer).player replaceCurrentItemWithPlayerItem: _currentItem];
135+ if (_player ) {
136+ [_player replaceCurrentItemWithPlayerItem: _currentItem];
128137 } else {
129- ((AVPlayerLayer *)_playerNode. layer ). player = [[AVPlayer alloc ] initWithPlayerItem: _currentItem];
138+ _player = [[AVPlayer alloc ] initWithPlayerItem: _currentItem];
130139 }
131-
132140 }
141+ }
142+
143+ // FIXME: Adopt interfaceStateDidChange API
144+ - (void )displayDidFinish
145+ {
146+ [super displayDidFinish ];
147+
148+ ASDN::MutexLocker l (_lock);
149+
150+ _playerNode = [[ASDisplayNode alloc ] initWithLayerBlock: ^CALayer *{
151+ AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc ] init ];
152+ playerLayer.player = _player;
153+ playerLayer.videoGravity = [self videoGravity ];
154+ return playerLayer;
155+ }];
156+
157+ [self insertSubnode: _playerNode atIndex: 0 ];
158+
133159 if (_shouldAutoplay) {
134160 [self play ];
135161 }
136162}
137163
164+ - (NSString *)videoGravity
165+ {
166+ if (_gravity == ASVideoGravityResize) {
167+ return AVLayerVideoGravityResize;
168+ }
169+ if (_gravity == ASVideoGravityResizeAspectFill) {
170+ return AVLayerVideoGravityResizeAspectFill;
171+ }
172+
173+ return AVLayerVideoGravityResizeAspect;
174+ }
175+
138176- (void )clearFetchedData
139177{
140178 [super clearFetchedData ];
141179
142180 {
143181 ASDN::MutexLocker l (_lock);
144182 ((AVPlayerLayer *)_playerNode.layer ).player = nil ;
183+ _player = nil ;
145184 _shouldBePlaying = NO ;
146185 }
147186}
148187
188+ #pragma mark - Video Properties
189+
149190- (void )setPlayButton : (ASButtonNode *)playButton
150191{
151192 ASDN::MutexLocker l (_lock);
@@ -174,6 +215,7 @@ - (void)setAsset:(AVAsset *)asset
174215
175216 _asset = asset;
176217
218+ // FIXME: Adopt -setNeedsFetchData when it is available
177219 if (self.interfaceState & ASInterfaceStateFetchData) {
178220 [self fetchData ];
179221 }
@@ -185,6 +227,12 @@ - (AVAsset *)asset
185227 return _asset;
186228}
187229
230+ - (AVPlayer *)player
231+ {
232+ ASDN::MutexLocker l (_lock);
233+ return _player;
234+ }
235+
188236- (void )setGravity : (ASVideoGravity)gravity
189237{
190238 ASDN::MutexLocker l (_lock);
@@ -203,77 +251,92 @@ - (void)setGravity:(ASVideoGravity)gravity
203251 ((AVPlayerLayer *)_playerNode.layer ).videoGravity = AVLayerVideoGravityResizeAspect;
204252 break ;
205253 }
254+
255+ _gravity = gravity;
206256}
207257
208258- (ASVideoGravity)gravity
209259{
210260 ASDN::MutexLocker l (_lock);
211261
212- if (ASObjectIsEqual (((AVPlayerLayer *)_playerNode.layer ).contentsGravity , AVLayerVideoGravityResize)) {
213- return ASVideoGravityResize;
214- }
215- if (ASObjectIsEqual (((AVPlayerLayer *)_playerNode.layer ).contentsGravity , AVLayerVideoGravityResizeAspectFill)) {
216- return ASVideoGravityResizeAspectFill;
217- }
218-
219- return ASVideoGravityResizeAspect;
262+ return _gravity;
220263}
221264
265+ #pragma mark - Video Playback
266+
222267- (void )play
223268{
224269 ASDN::MutexLocker l (_lock);
225270
226271 if (!_spinner) {
227272 _spinner = [[ASDisplayNode alloc ] initWithViewBlock: ^UIView *{
228- UIActivityIndicatorView *spinnnerView = [[UIActivityIndicatorView alloc ] initWithFrame: _playButton.frame ];
273+ UIActivityIndicatorView *spinnnerView = [[UIActivityIndicatorView alloc ] init ];
229274 spinnnerView.color = [UIColor whiteColor ];
230- [spinnnerView startAnimating ];
231275
232276 return spinnnerView;
233277 }];
234278 }
235279
236- if (![self ready ]) {
237- [self addSubnode: _spinner];
238- }
239-
240- [[((AVPlayerLayer *)_playerNode.layer) player ] play ];
280+ [_player play ];
241281 _shouldBePlaying = YES ;
242282 _playButton.alpha = 0.0 ;
243- // if ([self ready] && ![self.subnodes containsObject:_spinner]) {
244- // }
283+
284+ if (![self ready ] && _shouldBePlaying && (self.interfaceState & ASInterfaceStateVisible)) {
285+ [self addSubnode: _spinner];
286+ [(UIActivityIndicatorView *)_spinner.view startAnimating ];
287+ }
245288}
246289
247290- (BOOL )ready
248291{
249- return [((AVPlayerLayer *)_playerNode.layer) player ]. currentItem .status == AVPlayerItemStatusReadyToPlay;
292+ return _currentItem .status == AVPlayerItemStatusReadyToPlay;
250293}
251294
252295- (void )pause
253296{
254297 ASDN::MutexLocker l (_lock);
255298
256- [[((AVPlayerLayer *)_playerNode.layer) player ] pause ];
299+ [_player pause ];
257300 [((UIActivityIndicatorView *)_spinner.view) stopAnimating ];
258301 _shouldBePlaying = NO ;
259302 _playButton.alpha = 1.0 ;
260303}
261304
262- - (AVPlayerItem *) currentItem
305+ - (BOOL ) isPlaying
263306{
264- return _currentItem;
307+ ASDN::MutexLocker l (_lock);
308+
309+ return (_player.rate > 0 && !_player.error );
265310}
266311
312+ #pragma mark - Property Accessors for Tests
313+
267314- (ASDisplayNode *)spinner
268315{
316+ ASDN::MutexLocker l (_lock);
269317 return _spinner;
270318}
271319
272320- (AVPlayerItem *)curentItem
273321{
322+ ASDN::MutexLocker l (_lock);
274323 return _currentItem;
275324}
276325
326+ - (ASDisplayNode *)playerNode
327+ {
328+ ASDN::MutexLocker l (_lock);
329+ return _playerNode;
330+ }
331+
332+ - (BOOL )shouldBePlaying
333+ {
334+ ASDN::MutexLocker l (_lock);
335+ return _shouldBePlaying;
336+ }
337+
338+ #pragma mark - Lifecycle
339+
277340- (void )dealloc
278341{
279342 [[NSNotificationCenter defaultCenter ] removeObserver: self ];
0 commit comments