How to know when AVPlayer uses the audio only bit-rate? - iphone

While streaming when encountering slow connectivity the AVPlayer may choose to play the lowest bit-rate in the HTTP Live Streaming playlist.
Is there a way to identify this transition?
I've tried observing the AVPlayerItem "tracks" property via KVO to see when it contains only audio but in most cases the tracks property isn't changed even though the player switched to the audio only stream.

I found out that the AVPlayerItem tracks property was not dependable on the simulator but somewhat more dependable on the actual device (with a ~5 seconds deviation).
Whenever the tracks property changes (you can find out when via KVO) you should traverse the tracks and see if there are any tracks with 'mediaType' set to AVMediaTypeVideo.
If there are none then you can conclude that you are in an audio only state.

Related

How much video content is pre buffered when using AV player with HTTP Live Streaming and can that value be changed

I am writing a video app that plays streaming videos from the web and I am using AV player to do so. My question is how do I find out how much video content is pre buffered, in MPMoviePlayerController you can see the amount of buffered content on the UISlider. I would like to show the same using AV Player and also be able to change the amount of pre buffered content.
My ideal situation is - User streaming a movie file using my app, if he pauses the play button, the movie keeps buffering just like when you watch youtube videos.
Please Help !!
Thank you.
You can see the amount of data that has been loaded and buffered ahead of the playhead by looking at the AVPlayerItem loadedTimeRanges property.
e.g.
AVPlayer *player;
NSArray *loadedTimeRanges = player.currentItem.loadedTimeRanges;
NSLog(#"LoadedTimeRanges: %#", loadedTimeRanges);
In the case of my app I can see:
LoadedTimeRanges: (
"CMTimeRange: {{338070700809/1000000000 = 338.071}, {54651145016/1000000000 = 54.651, rounded}}"
)
where the second value (54.651) appears to be the amount of buffering that exists in front of the playhead. In the case of a stall this value decreases as playback continues until reaching approximately 0.
Between 55 and 60 seconds of pre-buffered content is all I've seen – you can only examine this value and cannot force the player to buffer any more data. You could, however, use this value to visually indicate the amount of data buffered to the user.

Movie is played with some delay after calling play on MPMoviePlayerController

I am developing an iPhone application in which I play videos using MPMoviePlayerController.
Sometimes, some of the videos don't play immediately after I call play on MPMoviePlayerController.
I have called prepareToPlay and in the notified method of MPMediaPlaybackIsPreparedToPlayDidChangeNotification, I am calling play on MPMoviePlayerController.
Could someone help in identifying the problem here?
Thanks,
Laxmilal
From my answer in a similar thread (reducing-the-initial-delay-when-playing-remote-video-content) - Note this fragment of the solution is valid for both, remote and local video content.
Use theMPMoviePlayerController.movieSourceTypeproperty when initializing your
player to cut down the media
recognition delay.
From the MPMoviePlayerController Class Reference:
The default value of this property is
MPMovieSourceTypeUnknown. This
property provides a clue to the
playback system as to how it should
download and buffer the movie content.
If you know the source type of the
movie, setting the value of this
property before playback begins can
improve the load times for the movie
content. If you do not set the source
type explicitly before playback, the
movie player controller must gather
this information, which might delay
playback.

MPMoviePlayerController and AVAudioPlayer audio mixing glitch

I'm developing an interactive storybook type application for the iPhone and I've recently encountered a frustrating bug concerning audio mixing on the device.
Firstly, I setup an audio session. I set the category to AVAudioSessionCategoryAmbient and then init and play my AVAudioPlayer instance. Now, in the background whilst the audio is playing I'm pre-loading a video to play using an MPMoviePlayerController followed by a call to prepareToPlay. The reason I pre-load the video this way is because I need it to play instantly later on cue with fairly strict timing.
In this configuration, the audio/movie works fine and they mix and do not interrupt each other. However, this particular audio session category does not permit audio to continue playing while the device is locked, a feature I really need. As a result I'm forced to consider a different category: AVAudioSessionCategoryPlayback.
By default this category does not permit mixing with other audio, according to the Apple docs. To enable mixing with other audio I am overriding the relevant category:
OSStatus propertySetError = 0;
UInt32 setProperty = 1;
propertySetError = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(setProperty), &setProperty);
assert(propertySetError == 0);
Unfortunately, this solves my playing whilst locked issue but introduces another issue: the AVAudioPlayer audio is interrupted briefly as the video loads with a minor stutter. The stutter is small, perhaps less than a second but is enough to disrupt the user experience. I've read this related post which enabled me to pre-load the video with the AVAudioSessionCategoryAmbient, but unfortunately the same approach doesn't seem to work with the new category.
The audio session category is applied successfully, according to the return code. Does anyone know why enabling audio mixing with this category is not the same as the mixing facility provided by ambient category?
The best way I've found working a similar problem is to use the newer AVPlayer (+1 #adam) and set your app to enable background audio and receive remote control notifications. I was tipped off to this by #MarquelV following How can you play music from the iPod app while still receiving remote control events in your app?
If you can get backgrounding working properly, that should enable you to continue playing while the device is locked. Oh, and don't forget to add keys to info.plist, its easy to do and then have no idea why it isn't working.

AVPlayer vs. AVAudioPlayer

The documentation for AVPlayer states the following:
[The] player works equally well with local and remote media files
However, the documentation for AVAudioPlayer states the following:
Apple recommends that you use this class for audio playback unless you are playing audio captured from a network stream
For the work I am doing I need some of the capabilities of AVAudioPlayer, but all my audio is being streamed. The main thing I need from AVAudioPlayer that AVPlayer does not have is the "playing" property. It is difficult to build a player UI without that property, among others.
So what is the difference between AVPlayer and AVAudioPlayer that makes the latter unsuitable for network streaming? Is there a way to get some of the info from AVPlayer that AVAudioPlayer provides such as the "playing" property?
AVPlayer can play from AVPlayerItem using AVURLAsset with an iPod library url. The AVAudioPlayer cannot play from an iPod library url.
AVPlayer has no volume property and requires the use of the system volume setting which can be controlled only by the hardware switch or an MPVolumeView. But you can set the mix volume of AVAudioPlayer.
AVPlayer seems to report an incorrect currentTime after seeking. But AVAudioPlayer reports accurately.
7 years after...
From a point of view with dependence on Swift and CocoaPods, so my answer is comparing for iOS 8+ only.
1. iPod library support
identical support since iOS6
2. volume control
identical support:
You can set the mix volume of AVAudioPlayer directly.
You can set the mix volume of AVPlayer with an AVAudioMix on the AVPlayerItem
3. seeking control
both AVPlayer and AVAudioPlayer seem to report an incorrect currentTime after seeking:
for AVAudioPlayer, it is suggested to stop() the AVAudioPlayer before seeking
for AVPlayer, it is suggested to pass the option AVURLAssetPreferPreciseDurationAndTimingKey when initializing AVURLAssets. And rely on values given by observer block.
4. changing source
you need only one AVPlayer to play multiple files
you need multiple AVAudioPlayer to play multiple files
The AVPlayer actually has a similar property as the playing property of AVAudioPlayer.
Take a look at the rate property.

Find if an audio is currently playing

I need to find out if my program is currently playing any audio and in case it does, I want to stop the previous audio and start a new playback.
The property kAudioSessionProperty_OtherAudioIsPlaying always returns a 0 (probably only checks whether iPod music is playing)
There's another property kAudioQueueProperty_IsRunning but this always returns a 0 whether the audio is running or not. Can someone please tell me how I can find out if an audio is playing in my app or not.
Thanks.
Note: The class from which I invoke my streamer gets deallocated when I move back in the view hierarchy. So I do not have any way of accessing the AudioFileStreamID to know whether audio is playing. I need to use one of the properties provided by the SDK.
Found a workaround. Instead of creating the streamer object in a viewcontroller, I am using a reference in the appDelegate. This way I'll always have a live reference of the streamer class which I can access in any of the viewcontrollers to know whether audio is currently playing or not.