7

nella mia app iOS, sto cercando di implementare "ducking": mentre la mia app riproduce un breve suono "simile a un comando", qualsiasi musica di sottofondo dovrebbe essere ridotta di volume. Al termine della riproduzione del suono, il volume della musica dovrebbe tornare al suo valore originale.iOS AudioSessionSetActive() blocco thread principale?

Come implementato, il ducking funziona come previsto. Tuttavia, quando chiamo AudioSessionSetActive (NO) in audioPlayerDidFinishPlaying: per terminare il ducking, c'è una piccola pausa in tutti gli aggiornamenti dell'interfaccia utente che si verificano in questo momento. Ciò comporta il disegno personalizzato, così come per l'ex. scorrimento automatico del testo e così via.

Ora, ecco la domanda:

È questo un problema noto in iOS6? Sto eseguendo lo stesso codice su un iPod/iOS5, in cui non vedo questo comportamento. O mi manca qualcosa dal codice? Forse uno di voi ha già riscontrato lo stesso problema e trovato una soluzione praticabile.

Grazie mille per il vostro gentile supporto,

Goetz

- (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

Hai mai trovato una soluzione a questo problema? Sto avendo lo stesso identico problema. –

+0

Se non chiamo AudioSessionSetActive (NO), l'interfaccia utente rimane reattiva e non rilascia frame. Quando eseguo la chiamata al metodo, sono necessari circa 0,5 secondi durante la riproduzione dell'audio. Ma, come hai detto tu, se non lo chiami, l'audio rimane nascosto. –

risposta

3

Dopo un po 'la testa di graffiare, e il debug, ho trovato la risposta a questa domanda. Come afferma la domanda originale, per ripristinare il livello dell'audio dopo il ducking, è necessario disattivare la sessione audio.

Il problema è che la disattivazione della sessione provoca 0,5 secondi di ritardo quando l'audio è in riproduzione, che blocca il thread dell'interfaccia utente e fa sì che l'applicazione non risponde di andare (nel mio caso, un timer perde .5 secondi e balbetta).

Per risolvere il problema, effettuo la chiamata per disattivare il timer su un thread separato. Questo risolve il problema di blocco dell'interfaccia utente e consente all'audio di rallentare come previsto. Il codice seguente mostra la soluzione. Nota, questo è il codice C# perché sto utilizzando Xamarin, ma potrebbe essere facilmente tradotto in Objective-C o Swift per lo stesso risultato:

 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(); 
     } 

chiamo ActivateAudioSession prima di cablare il mio AVAudioPlayer e una volta che il mio lettore è finito di suonare, chiamo DeactivateAudioSession (che è necessario per ripristinare il livello audio). L'avvio della disattivazione su un nuovo thread fa retrocedere il livello audio, ma non blocca l'interfaccia utente.

+0

Possiamo usare la coda di invio invece di questa con coda in background? –

Problemi correlati