Воспроизведение аудио в приложении iOS

У меня есть приложение, в основном основанное на Core Bluetooth. Когда что-то происходит, приложение пробуждается с использованием фоновых режимов Core Bluetooth, и он отключает будильник, однако я не могу получить сигнал тревоги, когда приложение не находится на переднем плане.

У меня есть класс Singleton, который инициализирует AVAudioPlayer следующим образом:

NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
                    pathForResource:soundName
                             ofType:@"caf"]];

self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[self.player prepareToPlay];
self.player.numberOfLoops = -1;
[self.player setVolume:1.0];

NSLog(@"%@", self.player);

Это метод, который вызывается при вызове кода тревоги:

-(void)startAlert
{
    NSLog(@"%s", __FUNCTION__);

    playing = YES;
    [self.player play];
    NSLog(@"%i", self.player.playing);

    if (vibrate) {
        [self vibratePattern];
    }
}

Теперь, когда приложение находится на переднем плане, self.player.playing возвращает 1, однако, когда приложение находится в фоновом режиме self.player.playing возвращает 0. Почему это должно быть? Вызывается весь код, поэтому приложение бодрствует и работает. Вибрирует отлично, используя AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

Любая идея, почему этот звук не воспроизводится?

Спасибо

Ответ 1

У меня есть приложение, которое также нуждается в фоновом звуке, но мое приложение работает с фоновым режимом приложения "Голос по IP", поскольку он должен записывать иногда. Я воспроизвожу фоновое аудио, рассказывающее о приложении Singleton Мне нужно воспроизвести аудио в фоновом режиме:

UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
if([thePlayer play]){
    newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];   
}

РЕДАКТИРОВАТЬ: вы должны позвонить [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];, прежде чем ваше приложение перейдет на задний план. В моем приложении, в то же время, вы начинаете играть в своем, если игрок может быть запущен в фоновом режиме, вы должны сделать:

- (void)applicationDidEnterBackground:(UIApplication *)application{
  // You should retain newTaskId to check for background tasks and finish them 
  newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];   
}

Ответ 2

Apple имеет приятную техническую Q & статью об этом в своей документации (см. также Воспроизведение и запись фонового звука).

Я думаю, что одна большая недостающая вещь заключается в том, что вы не активировали фоновый режим звука в настройках Xcode: enter image description here

Возможно, добавление [self.player prepareToPlay] в ваш метод оповещения полезно.

Ответ 3

Apple docs

Включите поддержку звука из раздела "Фоновые режимы" вкладки Возможности

Или включите эту поддержку, включив ключ UIBackgroundModes со значением аудио в ваших приложениях Info.plist.

Ответ 4

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

Ответ 5

Вам нужно включить ваше приложение для обработки прерываний аудиозаписей (и прекращенных прерываний) в фоновом режиме. Приложения обрабатывают прерывания звука через центр уведомлений:

  • Сначала зарегистрируйте свое приложение в центре уведомлений:

    - (void) registerForMediaPlayerNotifications {
    
        [notificationCenter addObserver : self
                                selector: @selector (handle_iPodLibraryChanged:)
                                    name: MPMediaLibraryDidChangeNotification
                                  object: musicPlayer];
    
        [[MPMediaLibrary defaultMediaLibrary] beginGeneratingLibraryChangeNotifications];
    
    }
    
  • Теперь сохраните состояние игрока при начале прерывания:

    - (void) audioPlayerBeginInterruption: player {
    
        NSLog (@"Interrupted. The system has paused audio playback.");
    
        if (playing) {
            playing = NO;
            interruptedOnPlayback = YES;
        }
    }
    
  • Активируйте сеанс аудио и возобновите воспроизведение, когда прерывание закончится:

    -(void) audioPlayerEndInterruption: player {
    
        NSLog (@"Interruption ended. Resuming audio playback.");
    
        [[AVAudioSession sharedInstance] setActive: YES error: nil];
    
        if (interruptedOnPlayback) {
            [appSoundPlayer prepareToPlay];
            [appSoundPlayer play];
            playing = YES;
            interruptedOnPlayback = NO;
        }
    }
    

Здесь пример кода Apple с полной реализацией того, что вы пытаетесь достичь:

https://developer.apple.com/library/ios/samplecode/AddMusic/Introduction/Intro.html#//apple_ref/doc/uid/DTS40008845