0Day Forums
Check play state of AVPlayer - Printable Version

+- 0Day Forums (https://0day.red)
+-- Forum: Coding (https://0day.red/Forum-Coding)
+--- Forum: Objective-C (https://0day.red/Forum-Objective-C)
+--- Thread: Check play state of AVPlayer (/Thread-Check-play-state-of-AVPlayer)

Pages: 1 2


Check play state of AVPlayer - goodden979 - 07-21-2023

Is there a way to know whether an `AVPlayer` playback has stalled or reached the end?


RE: Check play state of AVPlayer - hired91301 - 07-21-2023

To get notification for reaching the end of an item (via [Apple][1]):

[[NSNotificationCenter defaultCenter]
addObserver:<self>
selector:@selector(<#The selector name#>)
name:AVPlayerItemDidPlayToEndTimeNotification
object:<#A player item#>];




And to track playing you can:

"track changes in the position of the playhead in an AVPlayer object" by using **addPeriodicTimeObserverForInterval:queue:usingBlock:** or **addBoundaryTimeObserverForTimes:queue:usingBlock:**.

Example is from Apple:

// Assume a property: @property (retain) id playerObserver;

Float64 durationSeconds = CMTimeGetSeconds([<#An asset#> duration]);
CMTime firstThird = CMTimeMakeWithSeconds(durationSeconds/3.0, 1);
CMTime secondThird = CMTimeMakeWithSeconds(durationSeconds*2.0/3.0, 1);
NSArray *times = [NSArray arrayWithObjects:[NSValue valueWithCMTime:firstThird], [NSValue valueWithCMTime:secondThird], nil];

self.playerObserver = [<#A player#> addBoundaryTimeObserverForTimes:times queue:NULL usingBlock:^{
// Passing NULL for the queue specifies the main queue.

NSString *timeDescription = (NSString *)CMTimeCopyDescription(NULL, [self.player currentTime]);
NSLog(@"Passed a boundary at %@", timeDescription);
[timeDescription release];
}];


[1]:

[To see links please register here]




RE: Check play state of AVPlayer - hectorean916468 - 07-21-2023

For **Swift**:


*AVPlayer*:

let player = AVPlayer(URL: NSURL(string: "http://www.sample.com/movie.mov"))
if (player.rate != 0 && player.error == nil) {
println("playing")
}
**Update**:<br>
`player.rate > 0` condition changed to `player.rate != 0` because if video is playing in reverse it can be negative thanks to *Julian* for pointing out. <br>
**Note**: This might look same as above(Maz's) answer but in Swift '!player.error' was giving me a compiler error so you have to check for error using 'player.error == nil' in Swift.(because error property is not of 'Bool' type)

*AVAudioPlayer:*

if let theAudioPlayer = appDelegate.audioPlayer {
if (theAudioPlayer.playing) {
// playing
}
}
*AVQueuePlayer:*

if let theAudioQueuePlayer = appDelegate.audioPlayerQueue {
if (theAudioQueuePlayer.rate != 0 && theAudioQueuePlayer.error == nil) {
// playing
}
}


RE: Check play state of AVPlayer - elinaczurpulnnp - 07-21-2023

A more reliable alternative to `NSNotification` is to add yourself as observer to player's `rate` property.

[self.player addObserver:self
forKeyPath:@"rate"
options:NSKeyValueObservingOptionNew
context:NULL];

Then check if the new value for observed rate is zero, which means that playback has stopped for some reason, like reaching the end or stalling because of empty buffer.


- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSString *,id> *)change
context:(void *)context {
if ([keyPath isEqualToString:@"rate"]) {
float rate = [change[NSKeyValueChangeNewKey] floatValue];
if (rate == 0.0) {
// Playback stopped
} else if (rate == 1.0) {
// Normal playback
} else if (rate == -1.0) {
// Reverse playback
}
}
}

For `rate == 0.0` case, to know what exactly caused the playback to stop, you can do the following checks:

if (self.player.error != nil) {
// Playback failed
}
if (CMTimeGetSeconds(self.player.currentTime) >=
CMTimeGetSeconds(self.player.currentItem.duration)) {
// Playback reached end
} else if (!self.player.currentItem.playbackLikelyToKeepUp) {
// Not ready to play, wait until enough data is loaded
}

And don't forget to make your player stop when it reaches the end:

`self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;`


RE: Check play state of AVPlayer - normanish400920 - 07-21-2023

The Swift version of maxkonovalov's answer is this:

player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.New, context: nil)

and

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == "rate" {
if let rate = change?[NSKeyValueChangeNewKey] as? Float {
if rate == 0.0 {
print("playback stopped")
}
if rate == 1.0 {
print("normal playback")
}
if rate == -1.0 {
print("reverse playback")
}
}
}
}

Thank you maxkonovalov!


RE: Check play state of AVPlayer - sunday237579 - 07-21-2023

Swift extension based on the answer by maz

extension AVPlayer {

var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}


RE: Check play state of AVPlayer - anticipatorily85089 - 07-21-2023

You can tell it's playing using:

AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
// player is playing
}

Swift 3 extension:

extension AVPlayer {
var isPlaying: Bool {
return rate != 0 && error == nil
}
}


RE: Check play state of AVPlayer - curst994 - 07-21-2023

`rate` is **NOT** the way to check whether a video is *playing* (it could stalled). From documentation of `rate`:

> Indicates the desired rate of playback; 0.0 means "paused", 1.0 indicates a desire to play at the natural rate of the current item.

Key words "desire to play" - **a rate of `1.0` does not mean the video is playing.**

The solution since iOS 10.0 is to use `AVPlayerTimeControlStatus` which can be observed on `AVPlayer` `timeControlStatus` property.

The solution prior to iOS 10.0 (9.0, 8.0 etc.) is to roll your own solution. **A rate of `0.0` means that the video is paused. When `rate != 0.0` it means that the video is either playing *or* is stalled.**

You can find out the difference by observing player time via: `func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any`

The block returns the current player time in `CMTime`, so a comparison of `lastTime` (the time that was last received from the block) and `currentTime` (the time that the block just reported) will tell whether the player is playing or is stalled. For example, if `lastTime == currentTime` and `rate != 0.0`, then the player has stalled.

As noted by others, figuring out whether playback has finished is indicated by `AVPlayerItemDidPlayToEndTimeNotification`.


RE: Check play state of AVPlayer - released632596 - 07-21-2023

Currently with swift 5 the easiest way to check if the player is playing or paused is to check the *.timeControlStatus* variable.

player.timeControlStatus == .paused
player.timeControlStatus == .playing




RE: Check play state of AVPlayer - waterzooi422684 - 07-21-2023

player.timeControlStatus == AVPlayer.TimeControlStatus.playing