Я играю звуки игр, используя OpenAL, и музыку bg, используя стандартный AV. Недавно я обнаружил, что после входящего звонка не работают все открытые звуки, пока играет фоновая музыка. Если я принудительно остановлю приложение и запущу снова, звуки появятся снова. Знает ли кто-нибудь, что происходит с openal во время/после входящего звонка?
открытые звуки не воспроизводятся после входящего звонка, до перезапуска приложения
Ответы (2)
Хорошо, кажется, я нашел решение. Я использую диспетчер звука obj-c, поэтому я просто добавил методы делегата beginInterruption и endInterruption AVAudioSession (и AVAudioPlayer) в свой класс.
beginInterruption выглядит так:
alcMakeContextCurrent(NULL);
и endInterruption выглядит примерно так:
NSError * audioSessionError = NULL;
[audioSession setCategory:soundCategory error:&audioSessionError];
if (audioSessionError)
{
Log(@"ERROR - SoundManager: Unable to set the audio session category");
return;
}
// Set the audio session state to true and report any errors
audioSessionError = NULL;
[audioSession setActive:YES error:&audioSessionError];
if (audioSessionError)
{
Log(@"ERROR - SoundManager: Unable to set the audio session state to YES with error %d.", (int) result);
return;
}
//music players handling
bool plays = false;
if (musicPlayer[currentPlayer] != nil)
plays = [musicPlayer[currentPlayer] isPlaying];
if (musicPlayer[currentPlayer] != nil && !plays)
[musicPlayer[currentPlayer] play];
alcMakeContextCurrent(context);
Да, это работает, если вы используете только звуки openAL. А вот для воспроизведения длинных треков лучше использовать AVAudioPlayer. Но вот снова магия Apple! Если вы воспроизводите музыку вместе со звуками OpenAL, происходит что-то странное. Отмените входящий вызов, и AVAudioSessionDelegate::endInterruption с AVAudioPlayerDelegate::audioPlayerEndInterruption никогда не будет вызываться. Только началоПрерывание, а не конец. Даже AppDelegate::applicationWillEnterForeground не будет вызываться, и приложение просто не узнает, что мы вернулись.
Но хорошая новость заключается в том, что вы можете вызвать endInterruption в методе AppDelegate::applicationDidBecomeActive, и контекст openAL будет восстановлен. И это работает!
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if (MySoundMngr != nil)
{
[MySoundMngr endInterruption];
}
// Restart any tasks that were paused and so on....
}
interruption
был разработан для AVAudio
. Вы имеете в виду, что OpenAL
также нужно прервать?
- person jayatubi; 27.10.2016
Alc.MakeContextCurrent(ContextHandle.Zero);
по прерыванию является ключевым здесь.
- person Meekohi; 26.02.2021
Мне было трудно понять это, поэтому я хотел добавить свой ответ здесь. Это все конкретно в Xamarin, но я подозреваю, что это применимо в целом и похоже на ответ @Tertium.
Вы можете запретить iOS прерывать звук в некоторых ситуациях (например, если вы получаете телефонный звонок, но отклоняете его), используя
AVAudioSession.SharedInstance().SetPrefersNoInterruptionsFromSystemAlerts(true, out NSError err);
Вас по-прежнему будут прерывать в некоторых ситуациях (например, вы принимаете телефонный звонок). Чтобы поймать их, вы должны
AVAudioSession.Notifications.ObserveInteruption(myAudioInterruptionHandler);
при запуске приложения.
Внутри этого обработчика вы можете определить, завершаете ли вы работу или возвращаетесь следующим образом:
void myAudioInterruptionHandler(object sender, AVAudioSessionInterruptionEventArgs args) {
args.Notification.UserInfo.TryGetValue(
new NSString("AVAudioSessionInterruptionTypeKey"),
out NSObject typeKey
);
bool isBeginningInterruption = (typeKey.ToString() == "1");
// ...
}
Прерывание начинается
Когда начинается прерывание, остановите воспроизведение любого звука (вам нужно будет справиться с этим самостоятельно на основе вашего приложения, но, возможно, вызывая AL.SourceStop
для всего). Затем, критически,
ContextHandle audioContextHandle = Alc.GetCurrentContext();
Alc.MakeContextCurrent(ContextHandle.Zero);
Если вы не сделаете этого сразу, iOS поджарит ваш контекст ALC, и вы обречены. Обратите внимание: если у вас есть обработчик для AudioRouteChanged
, это слишком поздно, вы должен сделать это в обработчике AudioInterruption
.
Прерывание заканчивается
Когда вы вернетесь после перерыва, сначала перезагрузите аудиосеанс iOS: AVAudioSession.SharedInstance().SetActive(true);
Вам также может понадобиться сбросить предпочтительный ввод (я думаю, что этот шаг необязателен, если вы всегда используете ввод по умолчанию) AVAudioSession.SharedInstance().SetPreferredInput(Input, out NSError err)
Затем восстановите свой контекст Alc.MakeContextCurrent(audioContextHandle);