Воспроизведение звука в didReceiveRemoteNotification, в то время как в фоновом режиме, используя функцию преобразования текста в речь

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

Звук не воспроизводится вообще после выхода приложения из режима ожидания.

Когда приложение находится на переднем плане, звук воспроизводится сразу после didReceiveRemoteNotification: метод называется.

Что было бы подходящим способом, чтобы звуки воспроизводились немедленно, когда didReceiveRemoteNotification: метод вызывается, когда приложение просыпается из приостановленного режима?

Вот некоторый код (класс менеджера речи):

-(void)textToSpeechWithMessage:(NSString*)message andLanguageCode:(NSString*)languageCode{

AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
DLog(@"Activating audio session");
if (![audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionMixWithOthers error:&error]) {
    DLog(@"Unable to set audio session category: %@", error);
}
BOOL result = [audioSession setActive:YES error:&error];
if (!result) {
    DLog(@"Error activating audio session: %@", error);

}else{
    AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:message];

    [utterance setRate:0.5f];

    [utterance setVolume:0.8f];

    utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:languageCode];

    [self.synthesizer speakUtterance:utterance];
}

}

-(void)textToSpeechWithMessage:(NSString*)message{

[self textToSpeechWithMessage:message andLanguageCode:[[NSLocale preferredLanguages] objectAtIndex:0]];

}

И позже в AppDelegate:

[[MCSpeechManager sharedInstance] textToSpeechWithMessage:messageText];

Я включил аудио,AirPlay и изображение в картинке в разделе Возможности-> Фоновые режимы.

РЕДАКТИРОВАТЬ:

Может быть, я должен запустить фоновую задачу и запустить обработчик истечения срока действия, если это необходимо? Я думаю, это может сработать, но я также хотел бы услышать общий способ решения подобных ситуаций.

Также с этим кодом я получаю следующую ошибку, когда получаю уведомление в фоновом режиме:

Ошибка активации аудиосеанса: Ошибка Domain=NSOSStatusErrorDomain Code=561015905 "(null)"

Код 561015905 относится к:

AVAudioSessionErrorCodeCannotStartPlaying = '! Pla', /* 0x21706C61, 561015905

И это описано как:

Этот тип ошибки может возникать, если список свойств информации приложения не позволяет использовать аудио, или если приложение находится в фоновом режиме и использует категорию, которая не допускает фоновое аудио.

но я получаю ту же ошибку с другими категориями (AVAudioSessionCategoryAmbient а также AVAudioSessionCategorySoloAmbient)

2 ответа

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

  • Вы собираете / тестируете / работаете с последним SDK? Там были значительные изменения вокруг механизма уведомлений в iOS X
  • Я должен предположить, что обращение к didReceiveRemoteNotification должно произойти в ответ на действие пользователя из указанного уведомления, например, при нажатии на сообщение уведомления.
  • Нет необходимости устанавливать какие-либо фоновые режимы. Приложение загружает контент в ответ на push-уведомления.

Если все вышеприведенные утверждения верны, настоящий ответ будет сосредоточен на том, что происходит при получении уведомления.

  1. Устройство получает уведомление
    Дистанционный пульт
  2. Пользователь нажимает на сообщение
  3. Приложение запускается
  4. didReceiveRemoteNotification вызывается

На шаге 4 textToSpeechWithMessage работает как положено:

func application(_ application: UIApplication,
                 didReceiveRemoteNotification
                 userInfo: [AnyHashable : Any],
                 fetchCompletionHandler completionHandler:
                 @escaping (UIBackgroundFetchResult) -> Void) {
    textToSpeechWithMessage(message: "Speak up", "en-US")
}

Для простоты я использую OneSignal для подключения уведомлений:

import OneSignal
...
_ = OneSignal.init(launchOptions: launchOptions,
                   appId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
// or
_ = OneSignal.init(launchOptions: launchOptions,
                   appId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
                   {
                       (s:String?, t:[AnyHashable : Any]?, u:Bool) in
                       self.textToSpeechWithMessage(message: "OneDignal", "en-US")
                   }

textToSpeechWithMessage в основном нетронутый, вот он в Swift 3 для полноты:

import AVFoundation
...
let synthesizer = AVSpeechSynthesizer()
func textToSpeechWithMessage(message:String, _ languageCode:String)
{
    let audioSession = AVAudioSession.sharedInstance()

    print("Activating audio session")
    do {
        try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord,
                                     with: [AVAudioSessionCategoryOptions.defaultToSpeaker,
                                            AVAudioSessionCategoryOptions.mixWithOthers]
        )
        try audioSession.setActive(true)

        let utterance = AVSpeechUtterance(string:message)
        utterance.rate = 0.5
        utterance.volume = 0.8
        utterance.voice = AVSpeechSynthesisVoice(language: languageCode)
        self.synthesizer.speak(utterance)

    } catch {
        print("Unable to set audio session category: %@", error);
    }
}

Пожалуйста, реализуйте

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler; 

метод. Вы получите обратный вызов в фоновом режиме для воспроизведения аудио.

Другие вопросы по тегам