Stefan Kendall
Stefan Kendall

Reputation: 67872

iOS audio controls not working with singleton

I'm trying to use a class to manage a global AVAudioPlayer instance, but I can't get the lock screen controls to appear. The class subclasses UIResponder, but no matter what I try lock screen controls don't appear.

Client classes use - (void)setUrl:(NSURL *)url withTitle:(NSString *)title to load audio and playAudio to play. What am I doing wrong here?

I have background-execution permission set to audio & car play, and this is failing even after simulator > Reset Content and Settings.

- (void)playAudio {
    [self.audioPlayer play];
    [self updateNowPlayingInfo];
}

- (void)stopAudio {
    [self.audioPlayer stop];
    [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:nil];
}

- (void)pauseAudio {
    [self.audioPlayer pause];
    [self updateNowPlayingInfo];
}

- (void)setupAudioSession {
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    NSError *setCategoryError = nil;
    [audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
    NSError *activationError = nil;
    [audioSession setActive:YES error:&activationError];
}

- (void)setupAudioControls {
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];
    [self updateNowPlayingInfo];
}

- (BOOL)canBecomeFirstResponder {
    return YES;
}

- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
    if (receivedEvent.type == UIEventTypeRemoteControl) {
        switch (receivedEvent.subtype) {
            case UIEventSubtypeRemoteControlTogglePlayPause:
                NSLog(@"Play pause");
                if (self.audioPlayer.isPlaying) {
                    [self.audioPlayer pause];
                }
                else {
                    [self.audioPlayer play];
                }
                break;

            case UIEventSubtypeRemoteControlPreviousTrack:
                break;

            case UIEventSubtypeRemoteControlNextTrack:
                break;

            default:
                break;
        }

        [self updateNowPlayingInfo];
    }
}

- (void)updateNowPlayingInfo {
    NSMutableDictionary *albumInfo = [[NSMutableDictionary alloc] init];
    albumInfo[MPMediaItemPropertyTitle] = self.title;
    albumInfo[MPMediaItemPropertyArtist] = @"Fidelity";
    albumInfo[MPMediaItemPropertyAlbumTitle] = self.title;
    albumInfo[MPMediaItemPropertyPlaybackDuration] = @(self.audioPlayer.duration);
    albumInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = @(self.audioPlayer.currentTime);
    [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:albumInfo];
}

- (void)setUrl:(NSURL *)url withTitle:(NSString *)title {
    self.title = title;
    self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
    [self setupAudioSession];
    [self setupAudioControls];
}

Upvotes: 1

Views: 473

Answers (1)

orkenstein
orkenstein

Reputation: 2858

Your -(void)setupAudioControls should be called right after going to background. In my app:

...
  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(appDidEnterBackground:)
                                               name:UIApplicationDidEnterBackgroundNotification
                                             object:nil];
...

- (void)appDidEnterBackground:(NSNotification *)notification {
  [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
  [self becomeFirstResponder];

  [self updateMediaInfo];
}

Upvotes: 1

Related Questions