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.
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.
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é.