I am working on playing live streaming video using MPmovieplayercontroller. I can also display time of video playing. I am able to play video but when it gets buffer and regain its playing state meanwhile not able to get buffering state and so timer is not getting updated properly rather it jumps with some time.Is there any way to get it proper? Please help me to resolve. Thanks in advance
My code is here:-
NSNotificationCenter.defaultCenter().addObserver(self, selector: "moviePlayBackStateChanged:", name: "MPMoviePlayerLoadStateDidChangeNotification",object: moviePlayer)
if(moviePlayer?.playableDuration > 0)
{
currentTime = moviePlayer!.currentPlaybackTime
}
else
{
currentTime = 0
}
func moviePlayBackStateChanged(notification:NSNotification)
{
if(moviePlayer?.loadState == MPMovieLoadState.Playable)
{
currentTime = moviePlayer!.currentPlaybackTime
println("currentTime\(currentTime)")
lblTime?.text = stringFromTimeInterval(currentTime!)
}else if(moviePlayer?.loadState == MPMovieLoadState.Stalled)
{
lblTime?.text = stringFromTimeInterval(currentTime!)
}
}
Related
I have a Xamarin iOS app that I want to stream videos from an API endpoint that supports HTTP range requests. I've reviewed many similar questions here on SO, but I cannot seem to get the AVPlayer to start playing the video file before it is downloaded fully no matter what I try.
I've tried:
KVO on playbackLikelyToKeepUp, playbackBufferEmpty and playbackBufferEmpty to play the video as soon as it is ReadyToPlay
set AutomaticallyWaitsToMinimizeStalling = false on the AVPlayer
set CanUseNetworkResourcesForLiveStreamingWhilePaused = true, and PreferredForwardBufferDuration = 1 on the AVPlayerItem
called PlayImmediatelyAtRate(1) on the AVPlayer
But still the file is downloaded fully before the video starts to play, which causes a delay for the user.
Is it possible to get AVPlayer to start playing a video file before it has completed downloading it, similar to how the HTML video tag does it?
Here is my current code:
private void SetUpPlayer()
{
if (ViewModel.VideoStreamUrl == null)
{
return;
}
// See https://stackoverflow.com/questions/38865797/how-to-play-video-with-avplayerviewcontroller-avkit-in-xamarin-ios
_aVPlayerItem = new AVPlayerItem(ViewModel.VideoStreamUrl)
{
CanUseNetworkResourcesForLiveStreamingWhilePaused = true,
PreferredForwardBufferDuration = 1,
};
// See https://stackoverflow.com/questions/38867190/how-can-i-check-if-my-avplayer-is-buffering/38867386#38867386
_playbackLikelyToKeepUpObserver?.Dispose();
_playbackLikelyToKeepUpObserver = (NSObject)_aVPlayerItem.AddObserver("playbackLikelyToKeepUp",
NSKeyValueObservingOptions.New,
AVPlayerItem_BufferUpdated);
_playbackBufferEmptyObserver?.Dispose();
_playbackBufferEmptyObserver = (NSObject)_aVPlayerItem.AddObserver("playbackBufferEmpty",
NSKeyValueObservingOptions.New,
AVPlayerItem_BufferUpdated);
_playbackBufferFullObserver?.Dispose();
_playbackBufferFullObserver = (NSObject)_aVPlayerItem.AddObserver("playbackBufferFull",
NSKeyValueObservingOptions.New,
AVPlayerItem_BufferUpdated);
_aVPlayer = new AVPlayer(_aVPlayerItem)
{
AutomaticallyWaitsToMinimizeStalling = false,
};
var playerViewController = new AVPlayerViewController
{
Player = _aVPlayer,
};
AddChildViewController(playerViewController);
View.AddSubview(playerViewController.View);
playerViewController.View.Frame = View.Frame;
playerViewController.ShowsPlaybackControls = true;
_aVPlayer.PlayImmediatelyAtRate(1);
}
private void AVPlayerItem_BufferUpdated(NSObservedChange obj)
{
ReportVideoBuffering();
}
private void ReportVideoBuffering()
{
bool isBufferEmpty = _aVPlayerItem != null && _aVPlayerItem.PlaybackBufferEmpty;
Console.WriteLine($"Buffer empty? {isBufferEmpty}");
Console.WriteLine($"Player status? {_aVPlayer.Status}");
if (_aVPlayer.Status == AVPlayerStatus.ReadyToPlay)
{
Console.WriteLine($"Playing video.");
_aVPlayer.Play();
}
}
The simple answer to the question is no, the AVPlayer doesn't support streaming using http range requests and partial content (206) responses. In our case, we have decided to use Azure Media Services to provide a streaming endpoint which we can then use in the iPad app as well as on the web.
I am coding a video player with Xamarin, AVPlayer and AvPlayerViewController. My code supports AirPlay and configures AVPlayer according docs but is not working quite well. The following scenario seems to fail:
Play a video, send it to Apple TV.
Exit playback as it goes on the Apple TV
Try to resume playback from the current position. This leads to playback directly starting on the Apple TV but the seek which I do to resume from the last playback position kind of fails. What happens is that AvPlayerViewController UI shows that playback starts from the beginning while the Apple TV is playing back from the resume point. The AvPlayerViewController play/pause button is also wrong most of the time and is not reflecting the right play state.
I do the seek so I resume the video like this: wait ( by KVO ) for the avplayer status to become ready to play, seek and then play the video.
Note ... all this works just fine when player is not in airplay mode. Video resumes properly and UI is looking correct.
Code looks like this:
avItem = new AVPlayerItem(avAsset);
avPlayer = new AVPlayer(avItem)
{
AllowsExternalPlayback = true,
UsesExternalPlaybackWhileExternalScreenIsActive = true
};
avPlayerViewController = new AVPlayerViewController()
{
View =
{
ContentMode = UIViewContentMode.ScaleAspectFill,
AutoresizingMask = UIViewAutoresizing.All,
},
UpdatesNowPlayingInfoCenter = false,
Player = avPlayer
};
initialPlaybackTime = TimeSpan.FromSeconds(bookmarkTime);
AddChildViewController(avPlayerViewController);
View.AddSubview(avPlayerViewController.View);
avPlayerViewController.DidMoveToParentViewController(this);
avItem.AddObserver(this, new NSString("status"), NSKeyValueObservingOptions.Initial, IntPtr.Zero);
public override async void ObserveValue(NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context)
{
if (Equals(ofObject, avItem) && keyPath.Equals((NSString)"status"))
{
if (!initialPlaybackTimeSet && (avPlayer.Status == AVPlayerStatus.ReadyToPlay))
{
await avPlayer.SeekAsync(CMTime.FromSeconds(initialPlaybackTime.TotalSeconds, avPlayer.CurrentItem.Asset.Duration.TimeScale));
avPlayer.Play();
initialPlaybackTimeSet = true;
}
}
}
I have a streaming video app, and I would like to know how I can detect whether the app is buffering or not.
In AVPlayer, there is the currentItem.isPlaybackLikelyToKeepUp boolean that tells you when the playback buffer is likely to keep up at the current download speed, and currentItem.isPlaybackBufferEmpty that tells you when the playback buffer is empty.
The problem occurs when the video is playing, the video pauses because the internet is too slow. If I then press the play button, the rate of the player is 1, but it is not playing.
How can I detect that the video is paused because it is buffering? currentItem.isPlaybackBufferEmpty is true even when the video is playing...
EDIT: I have combined these 2 and now the loader I show to display buffering is only shown if currentItem.isPlaybackBufferEmpty && !currentItem.isPlaybackLikelyToKeepUp, the loader now only shows a few seconds after the video starts playing.
This works fine for me, maybe it can help, call self?.bufferState() inside addPeriodicTimeObserver
private func bufferState() {
if let currentItem = self.avPlayer.currentItem {
if currentItem.status == AVPlayerItemStatus.readyToPlay {
if currentItem.isPlaybackLikelyToKeepUp {
print("Playing ")
} else if currentItem.isPlaybackBufferEmpty {
print("Buffer empty - show loader")
} else if currentItem.isPlaybackBufferFull {
print("Buffer full - hide loader")
} else {
print("Buffering ")
}
} else if currentItem.status == AVPlayerItemStatus.failed {
print("Failed ")
} else if currentItem.status == AVPlayerItemStatus.unknown {
print("Unknown ")
}
} else {
print("avPlayer.currentItem is nil")
}
}
I am making a noiseMaker application for iOS in xCode where there are different buttons that play different sounds. Each sound is given a tag of 0-3 along with each button in the storyboard. And the randomize button has a tag of 4, Here is the code so far:
func play (index: Int) {
if !player.isEmpty && index >= 0 && index < player.count {
player[index].play()
}
if index == 4{
let randomNumber = Int(arc4random_uniform (4) + 0)
player[randomNumber].play()
}
However, what I want is for the current song to stop playing when I press on another button or even on the same button again. I believe the stop AVAudioPlayer code would go right when the function "play" begins so that it stops the player before any other song starts playing.
All help is appreciated. Thanks in advance...
You can check that currently player is playing or not.
Check the playing property returns status of player is playing or not.
if (aPlayer.playing) {
aPlayer.stop()
//Then play again by aPlayer.play()
}
else {
aPlayer.play()
}
So I'm making a music player using system.musicplayer() since ipod.musicplayer() was deprecated with iOS 8. Anyway, I have pause and play buttons that work perfectly when the stock music app is open in the background but not when it is terminated (i.e. removed from multitasking). Before adding the ifcondition, the app would crash, and now nothing happens at all since I don't really know what to add. Any advice? I am truly lost.
#IBAction func playButtonAction(sender: AnyObject) {
if let mediaItem = musicPlayer.nowPlayingItem {
if (self.isPlay) {
musicPlayer.pause()
self.isPlay = false
} else {
musicPlayer.play()
self.isPlay = true
setupCurrentMediaItem()
handleShuffleAndReplayMode()
}
} else {
//music
}
}