MPMusicPlayerController setQueue and noPlayingItem defaults to index 0 - mpmusicplayercontroller

When I try to change the queue of a MPMusicPlayerController and set the nowPlayingItem the player always goes to the first item in the queue. The documentation says if I want to set the current position in a queue I should set the nowPlayingItem to an MPMediaItem in the queue. Am I doing something wrong?
MPMusicPlayerController *player = [MPMusicPlayerController systemMusicPlayer];
[player setRepeatMode:MPMusicRepeatModeNone];
[player setShuffleMode:MPMusicShuffleModeOff];
[player pause];
MPMediaItemCollection *collection = [MPMediaItemCollection collectionWithItems:[[HMFAudioManager sharedManager] playlist]];
[player setQueueWithItemCollection:collection];
MPMediaItem *selectedItem = collection.items[indexPath.row];
NSLog(#"selected item - %#",selectedItem.title);
NSLog(#"manager's current now playing item - %#",[[HMFAudioManager sharedManager] nowPlayingItem].title);
[[HMFAudioManager sharedManager] setNowPlayingItem:collection.items[indexPath.row]];
NSLog(#"manager's new now playing item - %#",[[HMFAudioManager sharedManager] nowPlayingItem].title);
player.nowPlayingItem = collection.items[indexPath.row];
player.currentPlaybackTime = [collection.items[indexPath.row] bookmarkTime];
[player play];
NSLog(#"player's now playing - %#",player.nowPlayingItem.title);
NSLog(#"manager's new now playing item - %#",selectedItem.title);
[self dismissViewControllerAnimated:YES completion:nil];
Log -
2015-08-07 16:51:42.003 Undulib[1986:487940] selected item - Star Wars: The Empire Strikes Back
2015-08-07 16:51:42.004 Undulib[1986:487940] manager's current now playing item - Star Wars: A New Hope
2015-08-07 16:51:42.005 Undulib[1986:487940] manager's new now playing item - Star Wars: The Empire Strikes Back
2015-08-07 16:51:42.238 Undulib[1986:487940] player's now playing - Star Wars: A New Hope
2015-08-07 16:51:42.238 Undulib[1986:487940] manager's new now playing item - Star Wars: The Empire Strikes Back

Stopping the player instead of pausing solved the issue.

Related

MPMoviePlayerController not working properly

I am making an application in which i am trying to play a video. The video starts properly but the video screen changes in black color after 4 sec. I dont know what is the problem.
also when i am setting player.movieplayer.shouldautoplay = NO, there is no effect of this line, video starts automatically.
Here is Code:
NSString *urlString = [[NSBundle mainBundle] pathForResource:#"Movie" ofType:#"m4v"];
NSURL *urlObj = [NSURL fileURLWithPath:urlString];
UIGraphicsBeginImageContext(CGSizeMake(1,1));
MPMoviePlayerViewController *player = [[MPMoviePlayerViewController alloc] initWithContentURL:urlObj];
UIGraphicsEndImageContext();
[player.view setBounds:self.view.bounds];
// when playing from server source type shoud be MPMovieSourceTypeStreaming
[player.moviePlayer setMovieSourceType:MPMovieSourceTypeStreaming];
[player.moviePlayer setScalingMode:MPMovieScalingModeAspectFill];
player.moviePlayer.shouldAutoplay = NO;
[self.view addSubview:player.view];
[player.moviePlayer play];
Am i missing something here??
I tried to get the total duration of video (using duration property of mpmovieplayercontroller) but its showing 0.0. how to get the duration of video??
NSString *urlString = [[NSBundle mainBundle] pathForResource:#"Movie" ofType:#"m4v"];
NSURL *urlObj = [NSURL fileURLWithPath:urlString];
UIGraphicsBeginImageContext(CGSizeMake(1,1));
MPMoviePlayerViewController *player = [[MPMoviePlayerViewController alloc] initWithContentURL:urlObj];
UIGraphicsEndImageContext();
[player.view setBounds:self.view.bounds];
// when playing from server source type shoud be MPMovieSourceTypeStreaming
[player.moviePlayer setMovieSourceType:MPMovieSourceTypeStreaming]; // I was missing this line therefore video was not playing
[player.moviePlayer setScalingMode:MPMovieScalingModeAspectFill];
[self.view addSubview:player.view];
[player.moviePlayer play];
There are several issues here:
For this type of usage (integrating the player into your view), you should be using MPMoviePlayerController, not MPMoviePlayerViewController. Use MPMoviePlayerViewController when you want to have a self-contained view controller which can be presented using presentMoviePlayerViewControllerAnimated:.
Assuming you are using ARC, the main problem is that nothing is keeping a reference to your player object. As a consequence, the player is disappearing shortly after you create it. You should keep a reference to it by assigning it to a property or instance variable of your view controller.
For a full example of this, see Till's excellent answer to a similar question.
I'm not sure what your intended purpose of the UIGraphicsBeginImageContext and UIGraphicsEndImageContext calls are, but I can't see that they're needed here.
As for shouldAutoplay = NO, the video is still starting because you are calling play immediately afterwards.
The player's duration property only contains a useful value after a MPMovieDurationAvailableNotification has been received. You'll need to do something similar to the following to have access to the actual duration:
__weak MediaPlayerController *weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:MPMovieDurationAvailableNotification object:self.player queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
NSLog(#"Movie duration: %lf", weakSelf.player.duration);
}];
Use removeObserver:name:object: to remove the observer when you are done.

MPMoviePlayerController stop button not working

I'm trying to use the same button to play and stop my radio stream, my button plays fine, then when i press for it to stop, it only stops for a few seconds then starts playing again.
here is the code im using.
- (IBAction)playStream:(id)sender {
self.buttonPressed.selected = !self.buttonPressed.selected;
NSString *urlAddress = #"http://67.159.28.74:8730";
NSURL *url = [NSURL URLWithString:urlAddress];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc]initWithContentURL:url];
player.movieSourceType = MPMovieSourceTypeStreaming;
player.view.hidden = YES;
self.myPlayer = player;
[self.view addSubview:self.myPlayer.view];
if (player.playbackState == MPMoviePlaybackStateStopped){
[self.myPlayer play];}
else if (player.playbackState == MPMoviePlaybackStatePlaying){
[self.myPlayer stop];}
}
Every time you press the button, a new instance of the movie player is created. Thus the check if (player.playbackState == MPMoviePlaybackStateStopped) will always return YES, and thus start the movie.

how to display new songs along with old songs in UITableView

-(void) mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection {
[self dismissViewControllerAnimated:YES completion:nil];
NSURL* assetUrl = [mediaItemCollection.representativeItem valueForProperty:MPMediaItemPropertyAssetURL];
AVURLAsset* asset = [AVURLAsset URLAssetWithURL:assetUrl options:nil];
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithAsset:asset];
myPlayer = [AVPlayer playerWithPlayerItem:playerItem];
collectionMutableCopy = [mediaItemCollection.items mutableCopy];
[self.myPlaylistTable reloadData];
//[self updatePlayerQueueWithMediaCollection: mediaItemCollection];
[myPlayer play];
}
I have a Button that allows me to select select songs from Iphone Library. I have another UIButton where it shows the list of selected songs from ipod Library.
I am displaying the selected songs in UITableview which is myPlaylistTable
when i select say two songs from iPod Library those two songs get displayed myPlaylistTable but problem happens when I try to add few more songs the two songs which was displayed earlier got disappear.
For ex if i select two songs first time and If I add another two songs it should show four songs .
Please considering doing the following.... It should help and resolve your problem.
self.clearsSelectionOnViewWillAppear = NO;
That will keep the row selected, unless you manually deselect the row or the user selects another row on the table.

seekToTime messes up simultaneous playback of two AVPlayers

Following problem. I have two AVPlayers, each initialized with a different AVPlayerItem.
Once the AVPlayerItem is successfully loaded, I add the AVPlayerLayer to the view layer. As you can see in the code below.
- (void)viewDidLoad
{
[super viewDidLoad];
self.playerItem = [[AVPlayerItem alloc] initWithURL:[self.video getVideoPath]];
[self.playerItem addObserver:self forKeyPath:#"status" options:0 context:nil];
[self.playerItem addObserver:self forKeyPath:#"playbackBufferEmpty" options:0 context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoEnded)
name:AVPlayerItemDidPlayToEndTimeNotification
object:nil];
self.player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
self.overlayPlayerItem = [[AVPlayerItem alloc] initWithURL:[self.compareVideo getVideoPath]];
[self.overlayPlayerItem addObserver:self forKeyPath:#"status" options:0 context:nil];
[self.overlayPlayerItem addObserver:self forKeyPath:#"playbackBufferEmpty" options:0 context:nil];
if (self.overlayPlayer==nil) {
self.overlayPlayer = [[AVPlayer alloc] initWithPlayerItem:self.overlayPlayerItem];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([object isKindOfClass:[AVPlayerItem class]])
{
AVPlayerItem *item = (AVPlayerItem *)object;
//playerItem status value changed?
if ([keyPath isEqualToString:#"status"])
{ //yes->check it...
switch(item.status)
{
case AVPlayerItemStatusFailed:
NSLog(#"player item status failed");
break;
case AVPlayerItemStatusReadyToPlay:
{
NSLog(#"player item status is ready to play");
if (item == self.playerItem && !videoLayerAdded) {
videoLayerAdded = YES;
AVPlayerLayer* layer = [AVPlayerLayer playerLayerWithPlayer:player];
layer.frame = self.videoContainer.bounds;
[self.videoContainer.layer insertSublayer:layer atIndex:0];
} else if (item == self.overlayPlayerItem && !overlayLayerAdded){
overlayLayerAdded = YES;
AVPlayerLayer* layer = [AVPlayerLayer playerLayerWithPlayer:overlayPlayer];
layer.frame = self.videoOverlayContainer.bounds;
[self.videoOverlayContainer.layer insertSublayer:layer atIndex:0];
}
break;
}
case AVPlayerItemStatusUnknown:
NSLog(#"player item status is unknown");
break;
}
}
else if ([keyPath isEqualToString:#"playbackBufferEmpty"])
{
if (item.playbackBufferEmpty)
{
NSLog(#"player item playback buffer is empty");
}
}
}
}
When I hit the play button the videos get played. If I hit it again they stop, so far so good.
- (IBAction)playButtonClicked:(id)sender{
//is playing
if(self.player.rate>0.0 || self.overlayPlayer.rate>0.0){
[self.player pause];
[self.overlayPlayer pause];
} else {
[self.player play];
[self.overlayPlayer play];
}
}
I have two UISlider that allow me to go forth and back through each video. I use seekToTime to jump to a certain time in a video.
- (IBAction)sliderChanged:(id)sender{
UISlider *slider = (UISlider *)sender;
//stop any video when using the slider
if(self.player.rate>0.0){
[self.player pause];
}
if(self.overlayPlayer.rate>0.0){
[self.overlayPlayer pause];
}
if (slider.tag == 1) {
double time = (self.playerTimeSlider.value * CMTimeGetSeconds(self.player.currentItem.asset.duration));
[self.player seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
} else if (slider.tag == 2){
double time = (self.overlayTimeSlider.value * CMTimeGetSeconds(self.overlayPlayer.currentItem.asset.duration));
[self.overlayPlayer seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
}
}
Videos can have different length as well. However, if a video ends, I set it back to the start, also with seekToTime.
My problem is that I can initially play both videos. I can pause and resume them without problem. But once I pause and use seekToTime for any video and resume or if the videos are at the end I reset them with seekToTime and hit play again my status observer fires AVPlayerItemStatusFailed for both PlayerItems.
Then the duration of those items becomes 0. I checked though, the PlayerItems are not nil.
I don't get a crash but I just can't play the videos anymore. When I only use one player I can jump through it with seekToTime and also reset it at the end of the video without problem.
I read through the forum and people say you can apparently use up to 4 AVPlayers, so I guess I should be save with 2. I also read about that other apps can use up video render pipelines, but I made sure that I don't have any other apps in the background on my iPad.
Any help as to why this is not working for me or even better, a fix, is highly appreciated.
Update:
I actually logged the error from the AVPlayerItem object now:
error: Error Domain=AVFoundationErrorDomain Code=-11819 "Cannot Complete Action"
UserInfo=0x19e370 {NSLocalizedRecoverySuggestion=Try again later.,
NSLocalizedDescription=Cannot Complete Action}
The code -11819 stands for AVErrorMediaServicesWereReset. Does that help anyone to help me?
This might be a long shot but take a look at the following page of the documentation:
AV Foundation Programming Guide - Seeking—Repositioning the Playhead
My hint is that by giving a tolerance of zero (before and after) you are probably causing the decoders to work their way out of a key frame calculating the exact requested frame.
This, in conjunction with playing two items at the same time, can cause the exhaustion of resources allocated to the iOS internal Media Services. Thus causing a reset.
I guess it depends on numerous factors being the most important the quality and format of the videos being played.
If you do not require precise time control in the scrubbing (!) try to play with the tolerance. I suggest that you try with values slightly larger than the maximum keyframe interval.
That value (the maximum keyframe interval) is, most likely, movie dependent.
If you have control of the movies and can live with insane movie file sizes try to export them using a max keyframe interval of 1 (!) and give it a spin.

dismissViewControllerAnimated doesn't dismiss using ZbarSDK qr code reader

I'm using the zbarSDK QR code reader http://zbar.sourceforge.net/iphone/sdkdoc/
The SDK is very great but i encountered a little problem. I need the user to visualize a view before to start scanning (containing information about how to scan), than him press a button which made the scan start (showing the camera) and when the qr code has been scanned to Segue to another View showing something linked to the specific qr code.
I've done this, but it goes all well when i frame the qr code after starting the scan, but not if when i start the scan the qr code is already framed in the videocamera view.
When i start scan i do this
-(IBAction)StartScan:(id) sender
{
ZBarReaderViewController *reader = [ZBarReaderViewController new];
reader.readerDelegate = self;
reader.readerView.torchMode = 0;
ZBarImageScanner *scanner = reader.scanner;
// present and release the controller
[self presentModalViewController: reader
animated: YES];
[reader release];
}
using
[self presentModalViewController: reader
animated: YES];
to show the videocamera and scan the qr code.
and then when the qr code has been scanned i do this:
- (void) imagePickerController: (UIImagePickerController*) reader didFinishPickingMediaWithInfo: (NSDictionary*) info
{
id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults];
ZBarSymbol *symbol = nil;
for(symbol in results)
hiddenData=[NSString stringWithString:symbol.data];
[reader dismissViewControllerAnimated:YES completion:^{ NSLog(#"Test"); }];
[self performSegueWithIdentifier:#"aDettaglioOpera" sender:self];
}
dismissing the camera view with
[reader dismissViewControllerAnimated:YES completion:^{ NSLog(#"Test"); }];
and presenting the view linked to the following segue.
Now all goes well if a point the camera to a point where there is not the qrcode and then point it to the qrcocde, instead if when i start scan i have already a qr code in the frame of the camera the imagePickerController get executed (i checked) but the dismissViewControllerAnimated:YES doesn't dismiss anything and doesn't execute the block after "completion" (which is instead correctly executed and nslogging "test")
What's the problem? The presentModalViewController has not the time it needs to allow the dismissViewControllerAnimated to function? And if the problem is this how can i avoid it?
I had the same problem and found a work around for this.
Set scanCrop property in reader as below before presentViewController and set it back back to default (0, 0, 1, 1) after 1 second. It works!!!
reader.scanCrop = CGRectMake(0, 0, 0.5, 0.5);
[self performSelector:#selector(changeScanCrop) withObject:nil afterDelay:1.0];
-(void)changeScanCrop {
reader.scanCrop = CGRectMake(0, 0, 1, 1);
}