4

If the app is playing the audio and phone screen is locked then control screen is shown as below. I am not able to take any action on avplayer

enter image description here

In my appdelegate I implemented:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    MPRemoteCommandCenter *rcc = [MPRemoteCommandCenter sharedCommandCenter];
[[rcc skipForwardCommand] setEnabled:NO];
[[rcc skipBackwardCommand] setEnabled:NO];
[[rcc nextTrackCommand] setEnabled:NO];
[[rcc previousTrackCommand] setEnabled:NO];
[[rcc skipForwardCommand] setEnabled:NO];
[[rcc skipBackwardCommand] setEnabled:NO];
rcc.playCommand.enabled = YES;
rcc.pauseCommand.enabled = YES;
[[MPRemoteCommandCenter sharedCommandCenter].playCommand addTarget:self action:@selector(play)];
[[MPRemoteCommandCenter sharedCommandCenter].pauseCommand addTarget:self action:@selector(pause)];
}

- (void) play {
[[MyVideoController instance] play];
}

- (void) pause {
[[MyVideoController instance] pause];
}

class MyVideoController consists of:

- (void) pause {
    [self.avPlayer pause];
}

- (void) play {
    [self.avPlayer play];
}

Even though these methods are triggered (added breakpoints to check), no action on avplayer is taken. No matter what, avplayer doesn't pause.

Is there any way to pause the avplayer?

EDIT 1: Adding the complete code

In my AppDelegate:

- (void) remoteControlReceivedWithEvent: (UIEvent *) event {
[[ZVideoPlayerController instance] eventReceived:event];
if (event.type == UIEventTypeRemoteControl) {
    switch (event.subtype) {
        case UIEventSubtypeRemoteControlTogglePlayPause: {

            break;
        }
        case UIEventSubtypeRemoteControlPlay: {
            [[ZVideoPlayerController instance] play];
            break;
        }
        case UIEventSubtypeRemoteControlPause: {
            [[ZVideoPlayerController instance] pause];
            break;
        }
        default:
            break;
    }
}

}

- (void)applicationDidEnterBackground:(UIApplication *)application {
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
}

I AM RECEIVING EVENTS BUT THE AUDIO DOESN'T PAUSE UPON CALLING PAUSE METHOD ON AVPLAYER.

EDIT 2: instance declaration in PlayerController class

+ (instancetype)instance {
static id instance = nil;
if (instance == nil)
{
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^(void) {
        NSAssert(instance == nil, @"Singleton instance is already allocated.");
        instance = [[super allocWithZone:NULL] init];
    });
}
return instance;
}

initialising AVPlayer

    AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:avAsset];
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
NSError *activationError = nil;
BOOL success = [[AVAudioSession sharedInstance] setActive: YES error: &activationError];

NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];

MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage: [UIImage imageNamed:@"Audio_Thumbnail_Play"]];
[songInfo setObject:title forKey:MPMediaItemPropertyTitle];
[songInfo setObject:@"100" forKey:MPMediaItemPropertyPlaybackDuration];
[songInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];
self.avPlayer = [AVPlayer playerWithPlayerItem:playerItem];
self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
A_G
  • 2,260
  • 3
  • 23
  • 56

3 Answers3

3

I found a solution to the problem. As I was getting nil value of avPlayer, I used my PageViewController class to get the instance of PlayerController. Then I used the instance of this playerController to play and pause my avplayer because this instance holds the reference to avPlayer.

- (PlayerController *)getVideoController {
NSArray *controllers = [UtiliyClass getNavigationController].viewControllers;
PageViewController *pageController = nil;
for (UIViewController *cont in controllers) {
    if ([cont isKindOfClass:[PageViewController class]]) {
        pageController = (PageViewController *)cont;
        break;
    }
}
if (pageController == nil) {
    return nil;
}
NSArray *objectsController =pageController.pageController.viewControllers;
PlayerController *videoPlayerController = nil;
for (UIViewController *item in objectsController) {
    if ([item isKindOfClass:[PlayerController class]]) {
        videoPlayerController = (PlayerController *)item;
        break;
    }
}
return videoPlayerController;
}

- (void) pause {
PlayerController *controller = [self getVideoController];
[controller.avPlayer pause];
}

- (void) play {
PlayerController *controller = [self getVideoController];
[controller.avPlayer play];
}
A_G
  • 2,260
  • 3
  • 23
  • 56
2

You need to register for remote notification to update player state when application is locked.For that follow following:

Add this in your AppDelegate , Ideally in applicationDidEnterBackground:

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];

And this in applicationDidBecomeActive:

[[UIApplication sharedApplication] endReceivingRemoteControlEvents];

Recieve remote notifcations by adding this in AppDelagate. This will listen all actions when phone is locked.

- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
    if (event.type == UIEventTypeRemoteControl){
        // Call method of your player where you want to make change (Pause , Paly),
        // I am calling a shared view for example, Its up to your logic how you want to deal it
      [[AudioPlayerView sharedPlayerView] remoteControlReceivedWithEvent:event];


    }
 }

And in that get your desired event and update state accordingly

 - (void)remoteControlReceivedWithEvent:(UIEvent *)event {

       if (event.type == UIEventTypeRemoteControl){
           switch (event.subtype){
               case UIEventSubtypeRemoteControlPlay:
                    [[MyVideoController instance] play];
                     break;
               case UIEventSubtypeRemoteControlPause:
                    [[MyVideoController instance] pause];
                    break;

               case UIEventSubtypeRemoteControlTogglePlayPause:
                   // Check if state is playing , call pause else call play
                    break;
                }
        default:
            break;
        }
     }
 }
MOHAMMAD ISHAQ
  • 988
  • 7
  • 15
  • As I already mentioned in the question, I AM RECEIVING PLAY/PAUSE EVENTS. It's just that I am not able to pause the audio upon calling pause function. Let me edit the question – A_G May 16 '17 at 07:04
  • Are you handling events in AVPlayer class ? or in AppDelgate ? – MOHAMMAD ISHAQ May 16 '17 at 07:06
  • AppDelegate. I edited the question. Thanks for looking into this. – A_G May 16 '17 at 07:08
  • When you checked with breakpoints , is there valid reference of AVPlayer ? – MOHAMMAD ISHAQ May 16 '17 at 07:13
  • Currently you are trying to play/pause in app delegate .try to pause/play in this method [[ZVideoPlayerController instance] eventReceived:event]; inside ZVideoPlayerController.m – MOHAMMAD ISHAQ May 16 '17 at 07:17
  • My self.avplayer is nil! Should I initialize it again? Won;t it lose the reference to the audio it is currently playing? – A_G May 16 '17 at 07:21
  • If your AVPlayer is nil than how can you update anything on it ? When you unlock phone , self,avplayer is still nil ? – MOHAMMAD ISHAQ May 16 '17 at 07:25
  • I think you didn't enabled background modes for your app. Go to target>capabilities >background modes > Audio, airplay ,,,,,,,,,,, – MOHAMMAD ISHAQ May 16 '17 at 07:27
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/144317/discussion-between-astha-gupta-and-mohammad-ishaq). – A_G May 16 '17 at 07:28
  • My background mode is enabled. If it hadn't been enabled then i would not have been able to play the audio in the first place :) When I unlock the phone then AVPlayer is not nil. I updated the initialization in EDIT 2 – A_G May 16 '17 at 07:30
  • Your player is of AutoRelease type thats why it is nill when app is in background . try this self.avPlayer = [[AVPlayer alloc] initWithPlayerItem:playerItem]; in place of self.avPlayer = [AVPlayer playerWithPlayerItem:playerItem]; – MOHAMMAD ISHAQ May 16 '17 at 07:35
  • Still nil :( Even avPlayerLayer is nil. – A_G May 16 '17 at 07:58
  • Problem is with your AutoRelease object.Try to initializer with alloc as AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:avAsset]; and everything else too. – MOHAMMAD ISHAQ May 16 '17 at 08:05
0

In iOS 7.1 and later, use the shared MPRemoteCommandCenter object to register for remote control events. You do not need to call this method when using the shared command center object. This method starts the delivery of remote control events using the responder chain. Remote-control events originate as commands issued by headsets and external accessories that are intended to control multimedia presented by an app. To stop the reception of remote-control events, you must call endReceivingRemoteControlEvents().

Add this following code for in didfinishlunching for init audio season and get remote control event :

        // Initialize the AVAudioSession here.
        if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&myErr]) {
            // Handle the error here.
            NSLog(@"Audio Session error %@, %@", myErr, [myErr userInfo]);
        }
        else{
            // Since there were no errors initializing the session, we'll allow begin receiving remote control events
            [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
        }

for reciving commadn use this code :

- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {

    if (receivedEvent.type == UIEventTypeRemoteControl) {

        switch (receivedEvent.subtype) {

            case UIEventSubtypeRemoteControlPreviousTrack:

                break;

            case UIEventSubtypeRemoteControlNextTrack:

                break;

            case UIEventSubtypeRemoteControlPlay:
                [[MyVideoController instance] play];
                break;

            case UIEventSubtypeRemoteControlPause:
                [[MyVideoController instance] pause];
                break;

            default:
                break;
        }
    }
}
Return Zero
  • 424
  • 4
  • 15