web-dev-qa-db-fra.com

La détection du commutateur Sonnerie/Silence/Muet de l'iPhone avec AVAudioPlayer ne fonctionne pas

J'ai essayé d'utiliser ces méthodes pour tenter de détecter que le commutateur Sonnerie/Silence est activé ou non:

Comment détecter par programmation le commutateur de mise en sourdine de l'iPhone?

_ { La catégorie AVAudioSession ne fonctionne pas comme le stipule la documentation } _

Mais sur mon iPhone 4, la valeur "state" est toujours "Speaker" (et la valeur de la longueur renvoyée par CFStringGetLength (state) est toujours 7). Quelqu'un at-il utilisé cette méthode avec succès? Si oui, sur quel type d'appareil et de version de SDK?

Je l'appelle comme suit:


- (BOOL)deviceIsSilenced {
    CFStringRef state;
    UInt32 propertySize = sizeof(CFStringRef);
    OSStatus audioStatus = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
    if (audioStatus == kAudioSessionNoError) {
        NSLog(@"audio route: %@", state) // "Speaker" regardless of silent switch setting, but "Headphone" when my headphones are plugged in
        return (CFStringGetLength(state) <= 0);
    }
    return NO;
}

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

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    audioSession.delegate = self;
    [audioSession setCategory:AVAudioSessionCategoryAmbient error:nil];
    [audioSession setActive:YES error:nil];
    NSLog(@"muted? %i", [self deviceIsSilenced]);
    ...
}

Je pensais que peut-être un autre événement (plus précis) kAudioSessionProperty est déclenché lorsque le commutateur physique du téléphone est ... commuté. Quelqu'un a des idées?

En passant, j'utilise la catégorie AVAudioSessionCategoryAmbient avec mon [AVAudioSession sharedInstance].

Mise à jour: J'ai également essayé d'utiliser différentes catégories audio et une poignée d'autres propriétés de session audio. Aucune ne semble se déclencher lors de la mise en sourdine/réactivation du commutateur. :(

Mise à jour du 1er janvier 2014: C'est un peu un bidouillage et j'ai rencontré un blocage lors de la gestion multitâche sur mon iPhone 5S, mais la bibliothèque SoundSwitch liée dans la nouvelle réponse acceptée est la voie à suivre si vous voulez détecter le commutateur silencieux. Cela fonctionne même sous iOS 7.

31
taber

Je suis passé par cette bibliothèque VSSilentSwitch.
N'a pas fonctionné pour moi (ne fonctionne pas lorsque vous commencez à utiliser réellement l'audio).
Je réfléchissais à la façon dont il l'avait fait, puis je me suis rendu compte que l'appel d'achèvement du son est appelé presque dès que le son commence à jouer lorsque nous sommes silencieux.
Pour être un peu plus précis:
Les sons système lus à l'aide de AudioServicesPlaySystemSound termineront la lecture dès le début.
Bien sûr, cela ne fonctionnera que sur les catégories audio qui respectent le commutateur de silence (la valeur par défaut AVAudioSessionCategoryAmbient le respecte).
Ainsi, l’astuce consiste à créer un son système, de préférence un son silencieux, et à le lire encore et encore tout en vérifiant le temps qu’il a fallu de la lecture à la fin (installer une procédure d’achèvement utilisant AudioServicesAddSystemSoundCompletion).
Si le processus d'achèvement est appelé très bientôt (autoriser certains seuil) - cela signifie que le commutateur silencieux est activé.
Cette astuce présente de nombreuses mises en garde, la plus importante étant qu'elle ne fonctionnera pas avec toutes les catégories audio.
Si votre application lit l'audio en arrière-plan, assurez-vous d'arrêter ce test en arrière-plan, sinon votre application fonctionnera indéfiniment en arrière-plan (et sera également rejetée par Apple).

3
Moshe Gottlieb

Eh bien, j'ai trouvé la réponse grâce à quelqu'un du forum des développeurs et vous ne l'aimerez pas!

Apple a eu une réponse à ce sujet.

Ils ont dit qu'ils ne fournissaient pas et ne fournissaient jamais de méthode pour détecter le commutateur de mise en sourdine du matériel et qu'ils n'avaient pas l'intention de le faire.

:(

OMI, il est vraiment utile de détecter le commutateur silencieux et d'informer l'utilisateur au cas où il l'aurait oublié ... Des gens se sont plaints de ne pas avoir de son et le commutateur silencieux en était la raison! Tant pis.

PS: Si vous souhaitez que Apple ajoute cette fonctionnalité (et vous le faites bien sûr!), Veuillez créer un nouveau rapport de bogue "Amélioration" pour "iPhone SDK" à l'adresse http://bugreport.Apple.com/

Update: Bien qu'il n'existe toujours aucun moyen officiel de vérifier l'état du commutateur de sourdine, il existe une solution de contournement/une bibliothèque appelée "SoundSwitch" qui semble faire l'affaire. Découvrez la nouvelle réponse acceptée pour le lien.

29
taber

"Cependant, si quelqu'un pouvait nous montrer comment utiliser cette AudioSessionProperty_AudioRouteDescription, la prime lui revient de droit."

Eh bien, juste NSLog () le résultat et vous obtenez

routes: {
    "RouteDetailedDescription_Inputs" =     (
    );
    "RouteDetailedDescription_Outputs" =     (
                {
            "RouteDetailedDescription_PortType" = Speaker;
        }
    );
}

Malheureusement, j'obtiens le même résultat sur un iPad2/OS 5.0 à la fois en sourdine et en sourdine. Donc, il semble être fonctionnellement équivalent à kAudioSessionProperty_AudioRoute, pas de joie là-bas.

En consultant les conseils des développeurs, on s’aperçoit que c’est un problème fréquemment rencontré, qui se résume le mieux avec

"J'ai signalé ce problème avec rdar: // 9781189 en juillet et le problème est toujours présent dans le MM."

Donc, oui ... on dirait que vous êtes SOL avec cela dans la version 5.0.

ADDENDA:

"Mais qu'en est-il de ce CFDictionary que vous vous connectez. Comment puis-je accéder à la clé" RouteDetailedDescription_PortType "?"

Le pontage sans frais est votre ami.

  CFDictionaryRef asCFType = nil;
  UInt32 dataSize = sizeof(asCFType);
  AudioSessionGetProperty(kAudioSessionProperty_AudioRouteDescription, &dataSize, &asCFType);
  NSDictionary *easyPeasy = (NSDictionary *)asCFType;
  NSDictionary *firstOutput = (NSDictionary *)[[easyPeasy valueForKey:@"RouteDetailedDescription_Outputs"] objectAtIndex:0];
  NSString *portType = (NSString *)[firstOutput valueForKey:@"RouteDetailedDescription_PortType"];
  NSLog(@"first output port type is: %@!", portType);

produit

le premier type de port de sortie est: Speaker!

De nombreux types CFTypes courants sont reliés à des types plus pratiques.

http://developer.Apple.com/library/ios/#documentation/CoreFoundation/Conceptual/CFDesignConcepts/Articles/tollFreeBridgedTypes.html

Maintenant, il faut un peu de pratique pour deviner correctement quels moulages d'incantation magique obtiendront quelque chose d'utile d'un dictionnaire comme ci-dessus. Un assistant de vidage de classe de ce type vous aidera à vous familiariser avec cela:

  - (void)whatsInThis:(CFDictionaryRef)thingy
  {
     NSDictionary *dict = (NSDictionary *)thingy;
     for (NSString *key in dict.allKeys)
     {
        id value = [dict valueForKey:key];
        NSLog(@"key: %@ value type %@", key, [value class]);
        if ([value isKindOfClass:[NSArray class]])
        {
           NSArray *array = (NSArray *)value;
           for (id item in array)
           {
              NSLog(@" -- object type %@", [item class]);
              if ([item isKindOfClass:[NSDictionary class]])
                 [self whatsInThis:item];
           }
        }
     }
  }

ce qui pour notre dictionnaire produit (ajout d’indentation pour plus de clarté)

key: RouteDetailedDescription_Inputs value type __NSCFArray
key: RouteDetailedDescription_Outputs value type __NSCFArray
  -- object type __NSCFDictionary
    key: RouteDetailedDescription_PortType value type __NSCFString

ce qui vous permet de savoir avec certitude ce que vous auriez pu déduire du journal d'origine, sachant que NSLog affiche des tableaux au sein de () et des dictionnaires au sein de {} afin que les conversions correctes soient parfaitement prévisibles. Mais certaines structures de type CFType sont plutôt difficiles à analyser.

11
Alex Curylo

Je pense que tu as la mauvaise impression. Un itinéraire est l'endroit où il va. Vous voulez connaître le niveau de volume. Utilisez kAudioSessionProperty_CurrentHardwareOutputVolume

0
slf

Trouvé cette bibliothèque http://www.verietassoftware.com/index.php?option=com_content&view=article&id=27&Itemid=115

Apple permettrait-il ce genre de choses? C’est une bibliothèque de 500Ko qui fait de la magie noire avec les paramètres audio et téléphoniques

0
Carl D'Halluin

Ok, après avoir suivi kAudioSessionProperty_AudioRoute en utilisant CMD + clic, j'ai trouvé ceci :(

/*!
 @enum           AudioSession audio categories states
 @abstract       Deprecated AudioSession properties
 @constant       kAudioSessionProperty_AudioRoute 
 Deprecated in iOS 5.0; Use kAudioSessionProperty_AudioRouteDescription 
 */
enum {
    kAudioSessionProperty_AudioRoute                            = 'rout',   // CFStringRef      (get only)        
};

s’avère que nous devons utiliser kAudioSessionProperty_AudioRouteDescription, mais ce gars-là retourne un CFDictionaryRef ou quelque chose du genre, et je ne sais absolument pas comment le gérer ....

J'ai fait cette réponse au cas où personne ne nous montrerait comment utiliser kAudioSessionProperty_AudioRouteDescription, où je vais essayer d'accepter ma réponse ...

Cependant, si quelqu'un pouvait nous montrer comment utiliser ce kAudioSessionProperty_AudioRouteDescription, la prime lui revient de plein droit. 

modifier:

Clairement, il s’agit d’un problème iOS 5. Je ne l'avais pas dit plus tôt parce que cela paraissait trop évident, mais j'ai alors pensé que cela pourrait ne pas être aussi évident pour les moteurs de recherche ... si vous comprenez ce que je veux dire.

Ainsi, iOS 5 ne fonctionne pas avec le commutateur silencieux/muet sur l'iPhone en raison de la valeur obsolète référée.

0
Mazyod

Essayez d'insérer cette ligne au-dessus de votre appel à AudioSessionGetProperty dans deviceIsSilenced

AudioSessionInitialize (NULL, NULL, NULL, NULL);

Devrait alors commencer à renvoyer une chaîne vide lorsque le commutateur est enfoncé (bien que affiche Headphone et certains autres états si un casque BT ou un accessoire est connecté, par exemple).

FWIW Je ne crois pas qu’il existe quoi que ce soit dans l’API publique qui se déclenche lorsque le commutateur est déplacé.

0
flake