iOS - AVAudioPlayer не продолжает следующую песню в фоновом режиме - PullRequest
10 голосов
/ 12 марта 2012

Итак, у меня есть приложение, которое воспроизводит кучу песен, в то время как пользователь может пролистывать комиксы.Я использую AVAudioPlayer, и он настроен на воспроизведение песен в установленном порядке.Поэтому, когда одна песня заканчивается, следующая будет играть.Это работает безупречно, когда приложение открыто.Проблема возникает, когда приложение находится в фоновом режиме.Я настроил приложение для воспроизведения в фоновом режиме, и это прекрасно работает.Поэтому, когда пользователь нажимает на домашний экран, музыка продолжает играть.Проблема возникает, когда песня заканчивается, предполагается, что следующая песня будет воспроизводиться так же, как и при открытом приложении.Вместо этого ничего не происходит.Согласно моим заявлениям NSLog, правильные методы вызываются, но ничего не происходит.Вот мой код:

- (void)audioPlayerDidFinishPlaying: (AVAudioPlayer *)player successfully: (BOOL) flag {

NSLog(@"Song finished");

if ([songSelect isEqualToString: @"01icecapades"]) {
    isPlay = @"yes";
    songSelect = @"02sugarcube";
    imageSelect = @"playbanner02";
    [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0];
    [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: @"02sugarcube"]) {
    isPlay = @"yes";
    songSelect = @"03bullets";
    imageSelect = @"playbanner03";
    [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0];
    [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: @"03bullets"]) {
    isPlay = @"yes";
    songSelect = @"04satanama";
    imageSelect = @"playbanner04";
    [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0];
    [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: @"04satanama"]) {
    isPlay = @"yes";
    songSelect = @"05uglyjoke";
    imageSelect = @"playbanner05";
    [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0];
    [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: @"05uglyjoke"]) {
    isPlay = @"yes"; 
    songSelect = @"01icecapades";
    imageSelect = @"playbanner01";
    [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0];
    [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0];
}}

Выше приведен код, который распознает, какая песня воспроизводится, и устанавливает правильную песню следующей.Затем он запускает другой метод, который настраивает проигрыватель.

- (void)triggerSong {
NSLog(@"triggerSong called");
NSString       *path;
NSError        *error;
// Path the audio file
path = [[NSBundle mainBundle] pathForResource:songSelect ofType:@"mp3"];
// If we can access the file...
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) 
{    
    // Setup the player
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
    //player = [initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
    [player setDelegate: self];
    // Set the volume (range is 0 to 1)
    player.volume = 1.0f;     
    [player prepareToPlay];
    [player setNumberOfLoops:0];
    [player play];
    NSLog(@"player play");
    [error release];
    player.delegate = self;
    // schedules an action every second for countdown
    [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateTimeLeft) userInfo:nil repeats:YES];
}}

Теперь я предполагаю, что это не лучший способ сделать это, но он прекрасно работает, когда приложение находится в состоянии переднего плана.Я просматривал документацию и не могу найти причину этой проблемы.Я надеялся, что кто-нибудь сможет увидеть ошибку в моем подходе.Как я уже говорил ранее, вызывается два NSLog в методе triggerSong, поэтому я не могу понять, почему не вызывается AVAudioPlayer (player).

Также у меня есть правильная настройка в моем info.plist, и у меня есть это в моем viewDidLoad:

//Make sure the system follows our playback status
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];

Спасибо за любую информацию.Очень признателен.

Ответы [ 3 ]

27 голосов
/ 15 марта 2012

Актуальное обсуждение

КОРОТКИЙ ОТВЕТ:

Вам нужен этот код либо в методе init вашего первого view, либо в методе viewDidLoad:

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

ДЛИННЫЙ ОТВЕТ С ОБРАЗЦОМ:

Вот мой пример. Как и вы, я начал с приложения, которое будет воспроизводить музыку в фоновом режиме, но не сможет продолжить воспроизведение после окончания первого клипа. Я сделал копию оригинального Music.mp3 и назвал его Music2.mp3. Мое намерение состояло в том, чтобы играть Music2.mp3, как только Music.mp3 закончится (audioPlayerDidFinishPlaying :). Я некоторое время бездельничал с фоновыми задачами, пока не заработал, БЕЗ фоновой задачи:

-(id)init{
    self = [super initWithNibName:@"MediaPlayerViewController" bundle:nil];
    if(self){

        //Need this to play background playlist
        [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

        //MUSIC CLIP
        //Sets up the first song...
        NSString *musicPath = [[NSBundle mainBundle] pathForResource:@"Music" ofType:@"mp3"];
        if(musicPath){
            NSURL *musicURL = [NSURL fileURLWithPath:musicPath];
            audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil]; 
            [audioPlayer setDelegate:self];
        }
    }
    return self;
}


-(IBAction)playAudioFile:(id)sender{

    if([audioPlayer isPlaying]){
        //Stop playing audio and change test of button
        [audioPlayer stop];
        [sender setTitle:@"Play Audio File" forState:UIControlStateNormal];
    }
    else{
        //Start playing audio and change text of button so
        //user can tap to stop playback
        [audioPlayer play];
        [sender setTitle:@"Stop Audio File" forState:UIControlStateNormal];
    }
}


-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
    [audioButton setTitle:@"Play Audio File" forState:UIControlStateNormal];
    [playRecordingButton setTitle:@"Play Rec File" forState:UIControlStateNormal];

    //PLAY THE SECOND SONG
    NSString *musicPath2 = [[NSBundle mainBundle] pathForResource:@"Music2" ofType:@"mp3"];
    if(musicPath2){

        NSURL *musicURL2 = [NSURL fileURLWithPath:musicPath2];
        audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL2 error:nil];
        [audioPlayer setDelegate:self];
        NSLog(@"Play it again: \n%@", musicPath2);
        [audioPlayer play];
    } 
}

Конечным результатом является то, что мое приложение теперь воспроизводит Music2.mp3 в непрерывном цикле, даже если приложение находится в фоновом режиме.

5 голосов
/ 04 января 2015

Просто чтобы подтвердить сказанное Squatch, это также решение Swift:

UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
0 голосов
/ 19 ноября 2015

OS X демонстрирует ту же проблему при использовании AVAudioPlayer, однако UIApplication - конструкция, предназначенная только для iOS. OS X требует использования NSApplication вместо этого, но NSApplication не возвращается, пока приложение не завершает работу, поэтому нам нужно использовать потоки. В качестве бонуса, в недрах NSApplication есть assert (), который требует основной поток.

Эта гибридная функция C ++ / Objective C является одним из обходных путей для этой проблемы OS X:

void do_the_dumb (void real_application(void)) {
    std::thread thread ([real_application]() {
        real_application();
        [[NSApplication sharedApplication] terminate: [NSApplication sharedApplication]];
    });
    [[NSApplication sharedApplication] run];
    thread.join();
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...