7

в моем приложении iOS, я пытаюсь реализовать «ducking»: в то время как мое приложение играет короткий «командный звук», любая фоновая музыка должна быть понижена по объему. Закончив воспроизведение звука, музыкальный объем должен вернуться к исходному значению.iOS AudioSessionSetActive() блокирующий основной поток?

Как реализовано, ducking в основном работает, как ожидалось. Тем не менее, когда я вызываю AudioSessionSetActive (NO) в audioPlayerDidFinishPlaying: для того, чтобы прекратить уклонение, есть небольшая пауза в любых обновлениях пользовательского интерфейса, которые происходят в этот момент времени. Это включает в себя пользовательский чертеж, а также, например, автоматическая прокрутка текста и т. д.

Теперь вот вопрос:

Это известная проблема в iOS6? Я использую тот же код на iPod/iOS5, где я не вижу такого поведения. Или я что-то пропустил из кода? Возможно, один из вас уже столкнулся с одной и той же проблемой и нашел приемлемое решение.

Большого спасибо за вашу поддержку,

Гетц

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 

    //... 

    NSError *err = nil; 
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&err]; 

    //... 

} 

- (void) playSound { 

    // Enable ducking of music playing in the background (code taken from the Breadcrumb iOS Sample) 
    UInt32 value = kAudioSessionCategory_MediaPlayback; 
    AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(value), &value); 

    // Required if using kAudioSessionCategory_MediaPlayback 
    value = YES; 
    AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(value), &value); 

    UInt32 isOtherAudioPlaying = 0; 
    UInt32 size = sizeof(isOtherAudioPlaying); 
    AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying, &size, &isOtherAudioPlaying); 

    if (isOtherAudioPlaying) {   
     AudioSessionSetProperty(kAudioSessionProperty_OtherMixableAudioShouldDuck, sizeof(value), &value); 
    } 

    AudioSessionSetActive(YES); 

    // Initialization of the AVAudioPlayer 
    NSString  *soundFileName = [[NSBundle mainBundle] pathForResource:@"Beep" ofType:@"caf"]; 
    NSURL     *soundFileURL  = [[NSURL alloc] initFileURLWithPath:soundFileURL]; 
    self.soundPlayer  = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil]; 
    [self.soundPlayer setDelegate:self]; 
    [self.soundPlayer setVolume:[80.0/100.0]; 
    [self.soundPlayer play]; 
} 


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

    // Callback coming from the AVAudioPlayer 

    // This will block the main thread; however, it is necessary to disable ducking again 
    AudioSessionSetActive(NO);     
} 
+0

Вы когда-нибудь находили решение этой проблемы? У меня такая же проблема. –

+0

Если я не вызываю AudioSessionSetActive (НЕТ), мой интерфейс остается отзывчивым и не отбрасывает кадры. Когда я нахожу вызов этого метода, он занимает около 0,5 секунд, когда воспроизводится звук. Но, как вы сказали, если вы не назовете это, звук останется приглушенным. –

ответ

3

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

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

Чтобы решить эту проблему, я делаю свой запрос на деактивацию таймера в отдельном потоке. Это устраняет проблему блокировки пользовательского интерфейса и позволяет звуку утихать, как ожидалось. В приведенном ниже коде показано решение. Заметим, что это C# код, потому что я использую Xamarin, но она может быть легко переведен на Objective-C или Swift для того же результата:

 private void ActivateAudioSession() 
     { 
      var session = AVAudioSession.SharedInstance(); 
      session.SetCategory(AVAudioSessionCategory.Playback, AVAudioSessionCategoryOptions.DuckOthers); 
      session.SetActive(true); 
     } 

     private void DeactivateAudioSession() 
     { 
      new System.Threading.Thread(new System.Threading.ThreadStart(() => 
       { 
        var session = AVAudioSession.SharedInstance(); 
        session.SetActive(false); 
       })).Start(); 
     } 

Я называю ActivateAudioSession, прежде чем я подключить мой AVAudioPlayer и когда плеер выполняется игра, я вызываю DeactivateAudioSession (что необходимо для восстановления уровня звука). Запуск деактивации в новом потоке завершает восстановление уровня звука, но не блокирует пользовательский интерфейс.

+0

Можем ли мы использовать диспетчерскую очередь вместо нее с фоновой очередью? –

Смежные вопросы