web-dev-qa-db-fra.com

Détection des AVAudioSessions actives sur un appareil iOS

J'essaie de comprendre si cela est possible - mon application active une session audio qui est initialisée comme:

[[[AVAudioSession alloc] init] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];

Je voudrais pouvoir comprendre quand une session audio supplémentaire provenant d'une autre application ou du système d'exploitation est en cours de lecture.

Je connais la possibilité d'implémenter les méthodes déléguées beginInterruption: et endInterruption mais ceux-ci ne seront pas invoqués en raison de l'option AVAudioSessionCategoryOptionMixWithOthers que j'utilise.

Existe-t-il un moyen d'y parvenir sans utiliser d'API privée?

Merci d'avance.

26
Stavash

La façon dont vous gérez la session audio de votre application a connu des changements importants depuis iOS 6., et mérite tout d'abord une brève mention. Avant iOS 6., vous utilisiez les classes AVAudioSession et AudioSessionServices, incorporant respectivement la délégation et l'écoute des propriétés. À partir de iOS 6., utilisez la classe AVAudioSession et incorporez les notifications.

Ce qui suit est pour iOS 6.0 à partir de.

Pour savoir si un autre audio en dehors de votre sandbox d'applications est en cours de lecture, utilisez -

// query if other audio is playing
BOOL isPlayingWithOthers = [[AVAudioSession sharedInstance] isOtherAudioPlaying];
// test it with...
(isPlayingWithOthers) ? NSLog(@"other audio is playing") : NSLog(@"no other audio is playing");

En ce qui concerne la gestion des interruptions, vous devrez observer AVAudioSessionInterruptionNotification et AVAudioSessionRouteChangeNotification. Donc, dans la classe qui gère votre session audio, vous pouvez mettre quelque chose comme ceci - cela devrait être appelé une fois au début du cycle de vie de l'application et n'oubliez pas de supprimer Observer dans la méthode dealloc de la même classe.

// ensure we already have a singleton object
    [AVAudioSession sharedInstance];
    // register for notifications
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(interruption:)
                                                 name:AVAudioSessionInterruptionNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(routeChange:)
                                                 name:AVAudioSessionRouteChangeNotification
                                               object:nil];

Et enfin ajoutez les sélecteurs suivants interruption: et routeChange: - ceux-ci recevront un objet NSNotification qui possède une propriété appelée userInfo de type NSDictionary que vous lirez pour aider les conditions de votre application.

- (void)interruption:(NSNotification*)notification {
// get the user info dictionary
NSDictionary *interuptionDict = notification.userInfo;
// get the AVAudioSessionInterruptionTypeKey enum from the dictionary
NSInteger interuptionType = [[interuptionDict valueForKey:AVAudioSessionInterruptionTypeKey] integerValue];
// decide what to do based on interruption type here...
switch (interuptionType) {
    case AVAudioSessionInterruptionTypeBegan:
        NSLog(@"Audio Session Interruption case started.");
        // fork to handling method here...
        // EG:[self handleInterruptionStarted];
        break;

    case AVAudioSessionInterruptionTypeEnded:
        NSLog(@"Audio Session Interruption case ended.");
        // fork to handling method here...
        // EG:[self handleInterruptionEnded];
        break;

    default:
        NSLog(@"Audio Session Interruption Notification case default.");
        break;
} }

Et de même ...

- (void)routeChange:(NSNotification*)notification {

NSDictionary *interuptionDict = notification.userInfo;

NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];

switch (routeChangeReason) {
    case AVAudioSessionRouteChangeReasonUnknown:
        NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonUnknown");
        break;

    case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
        // a headset was added or removed
        NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonNewDeviceAvailable");
        break;

    case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
        // a headset was added or removed
        NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonOldDeviceUnavailable");
        break;

    case AVAudioSessionRouteChangeReasonCategoryChange:
        // called at start - also when other audio wants to play
        NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonCategoryChange");//AVAudioSessionRouteChangeReasonCategoryChange
        break;

    case AVAudioSessionRouteChangeReasonOverride:
        NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonOverride");
        break;

    case AVAudioSessionRouteChangeReasonWakeFromSleep:
        NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonWakeFromSleep");
        break;

    case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
        NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory");
        break;

    default:
        break;
} }

Il n'est pas nécessaire d'interroger quoi que ce soit tant que vous vérifiez l'état de la session audio de vos applications, par exemple dans le viewDidLoad de votre contrôleur de vue racine, au début du cycle de vie de vos applications. Tout changement à partir de là à la session audio de vos applications sera connu via ces deux notifications principales. Remplacez les instructions NSLog par tout ce que votre code doit faire en fonction des cas contenus dans le commutateur.

Vous pouvez trouver plus d'informations sur AVAudioSessionInterruptionTypeKey et AVAudioSessionRouteChangeReasonKey dans la documentation de référence de la classe AVAudioSession.

Je m'excuse pour la longue réponse, mais je pense que la gestion de la session audio dans iOS est plutôt compliquée et le guide de programmation de la session audio d'Apple, au moment d'écrire ces lignes, n'inclut pas d'exemples de code utilisant des notifications pour la gestion des interruptions.

68
Bamsworld

Vous pouvez vérifier si un autre son est lu comme ceci:

UInt32 otherAudioIsPlaying;
UInt32 propertySize = sizeof (otherAudioIsPlaying);
AudioSessionGetProperty (kAudioSessionProperty_OtherAudioIsPlaying, &propertySize, &otherAudioIsPlaying );

[self handleIfAudioIsPlaying: otherAudioIsPlaying];

Ensuite, vous pouvez ajouter une boucle et vérifier toutes les X secondes si quelque chose a changé.

5
BlackMouse