3

I use AVPlayer's -(id)addPeriodicTimeObserverForInterval: queue: usingBlock: method to update UI up to playback progress. However, my progress bar never reaches end.

CMTime duration = self.player.currentItem.asset.duration;
float totalSeconds = (Float64)(duration.value * 1000) / (Float64)(duration.timescale);
NSLog(@"duration: %.2f", totalSeconds);

__weak __typeof(self) welf = self;

_mTimeObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(10, 1000)
                                              queue:NULL // main queue
                                         usingBlock:^(CMTime time) {

  float totalSeconds = (Float64)(time.value * 1000) / (Float64)(time.timescale);
  NSLog(@"progress %f", totalSeconds);

                                                }];

logs:

App[2373:792179] duration: 3968.00

hit play button

App[2373:792179] progress 0011.176
App[2373:792179] progress 0021.175
...
App[2373:792179] progress 3701.319
App[2373:792179] progress 3704.000

Should not I expect last number to be 3968.0 ?

Audio is streamed from server.

EDIT

Last progress number is ALWAYS duration - 0.264 sec whatever actual duration length is.

This is so strange, I wish we could use emoticons on SO.

kerd
  • 307
  • 2
  • 13

2 Answers2

0

Good question. Try using CMTimeGetSeconds(time) instead of calculating the total seconds yourself.

Additionally, try to use CMTimeMakeWithSeconds(10.0, NSEC_PER_SEC) to create the time for the periodic time observer.

This post helped me a lot to wrap my head around the enigma that is CMTime: https://warrenmoore.net/understanding-cmtime

Johannes Fahrenkrug
  • 42,912
  • 19
  • 126
  • 165
  • Same stuff (other piece of sound): `duration:4.736 maxProgress:4.472`. What can be the reason? EDIT: Just saw you updated answer, I'll try other options – kerd Jun 22 '16 at 19:35
  • @kerd That's very interesting. Can you also use `CMTimeGetSeconds` to print the duration? And one more thing: Try a finer-grained callback value. Instead of 10 seconds, try `1.0/30.0`. – Johannes Fahrenkrug Jun 22 '16 at 19:50
  • In first comment i wrote result from `CMTimeGetSeconds`. Sorry if it was not clear. Also `CMTimeMakeWithSeconds(10.0, NSEC_PER_SEC)` that I've tried was the finest grain - it took 10 nanoseconds instead of 0.01 of a second which I use in my original post. – kerd Jun 22 '16 at 19:53
  • Try `CMTimeMakeWithSeconds(1.0/30.0, NSEC_PER_SEC)`. In your first comment the maxProgress was lower than the duration. In the question is was *higher* than the duration. So it could be that the callback just didn't fire because it wasn't fine-grained enough. – Johannes Fahrenkrug Jun 22 '16 at 19:58
  • @kerd Actually checking `CMTimeGetSeconds(self.player.currentTime)` is more accurate than using the passed-in `time`, since that is actually the time when the block was invoked. – Johannes Fahrenkrug Jun 22 '16 at 20:30
  • same result. sorry. – kerd Jun 22 '16 at 20:40
0

The docs clearly state:

You must retain the returned value as long as you want the time observer to be invoked by the player.

XVX
  • 1
  • Sorry, but could you assist with further clearance of how this information can help? Btw, isn't the observer already invoked? – kerd Jun 23 '16 at 00:00
  • He's saying you need to hold a strong reference to the observer object otherwise it will be released. For example your UIViewController could have a property called playerTimeObserver. – user3344977 Oct 25 '16 at 20:28