59 votes

Comment obtenir le niveau du volume audio et les notifications de changement de volume sur iOS ?

J'écris une application très simple qui joue un son lorsqu'on appuie sur un bouton. Comme ce bouton n'a pas beaucoup de sens lorsque l'appareil est réglé sur le silence, je veux le désactiver lorsque le volume audio de l'appareil est à zéro. (Et le réactiver ensuite lorsque le volume est remonté).

Je cherche un moyen fonctionnel (et sûr pour l'AppStore) de détecter le réglage actuel du volume et recevoir une notification/un rappel lorsque le niveau de volume change. I ne pas vouloir modifier le volume réglage.

Tout ceci est mis en œuvre dans mon ViewController où ledit bouton est utilisé. J'ai testé ceci avec un iPhone 4 sous iOS 4.0.1 et 4.0.2 ainsi qu'un iPhone 3G sous 4.0.1. Construit avec iOS SDK 4.0.2 avec llvm 1.5. (L'utilisation de gcc ou llvm-gcc n'améliore rien.) Il n'y a pas de problèmes pendant la mise en œuvre de la compilation, ni d'erreurs ni d'avertissements. L'analyseur statique est également satisfait.

Voici ce que j'ai essayé jusqu'à présent, sans succès.

En suivant la documentation des services audio d'Apple, je devrais enregistrer un AudioSessionAddPropertyListener para kAudioSessionProperty_CurrentHardwareOutputVolume qui devrait fonctionner comme suit :

// Registering for Volume Change notifications
AudioSessionInitialize(NULL, NULL, NULL, NULL);
returnvalue = AudioSessionAddPropertyListener (

kAudioSessionProperty_CurrentHardwareOutputVolume ,
      audioVolumeChangeListenerCallback,
      self
);

returnvalue est 0 ce qui signifie que l'enregistrement de la fonction de rappel a fonctionné.

Malheureusement, je ne reçois jamais de rappel à ma fonction. audioVolumeChangeListenerCallback lorsque j'appuie sur les boutons de volume de mon appareil, sur le cliqueur de l'oreillette ou que je bascule l'interrupteur sonnerie-silence.

Lorsque l'on utilise exactement le même code pour s'enregistrer pour kAudioSessionProperty_AudioRouteChange (qui est utilisé comme un exemple de projet analogue dans les vidéos de la WWDC, dans la documentation destinée aux développeurs et sur de nombreux sites Internet), j'ai en fait faire obtenir un rappel lors du changement de la route audio (en branchant/débranchant un casque ou en connectant l'appareil).

Un utilisateur nommé Doug a ouvert un fil de discussion intitulé Événement de changement de volume de l'iPhone pour un volume déjà maximal où il affirme utiliser cette méthode avec succès (à moins que le volume ne change pas réellement car il est déjà réglé au maximum). Pourtant, cela ne fonctionne pas pour moi.

Un autre moyen que j'ai essayé est de s'inscrire à NSNotificationCenter comme ça.

// sharedAVSystemController 
AudioSessionInitialize(NULL, NULL, NULL, NULL);
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
                                         selector:@selector(volumeChanged:) 
                                             name:@"AVSystemController_SystemVolumeDidChangeNotification" 
                                           object:nil];

Cela devrait notifier ma méthode volumeChanged de tout SystemVolume mais il ne le fait pas réellement.

Comme la croyance commune me dit que si l'on travaille trop dur pour réaliser quelque chose avec Cocoa, on fait quelque chose de fondamentalement mauvais, je m'attends à rater quelque chose ici. Il est difficile de croire qu'il y a pas de moyen simple à obtenir le niveau de volume actuel, mais je n'ai pas été en mesure d'en trouver une en utilisant la documentation d'Apple, les exemples de code, Google, les forums de développeurs d'Apple ou en regardant les vidéos de la WWDC 2010.

1 votes

Consultez la réponse de Stuart ci-dessous pour la solution iOS7.

69voto

Sandy Points 1115

Y a-t-il une chance que vous ayez mal fait votre signature pour la méthode volumeChanged : ? Cela a fonctionné pour moi, dans mon appdelegate :

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(volumeChanged:)
     name:@"AVSystemController_SystemVolumeDidChangeNotification"
     object:nil];
}

- (void)volumeChanged:(NSNotification *)notification
{
    float volume =
    [[[notification userInfo]
      objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"]
     floatValue];

    // Do stuff with volume
}

Ma méthode volumeChanged : est activée chaque fois que l'on appuie sur le bouton, même si le volume ne change pas en conséquence (parce qu'il est déjà au maximum/minimum).

0 votes

Cela fonctionne pour moi : Je copie et colle l'exemple de code de Sandy. Je vous suggère de prendre d'abord l'exemple de code fourni par Apple (j'utilise 'aurioTouch') et d'y ajouter l'exemple de code de Sandy. Cela pourrait peut-être vous aider à comprendre ce qui s'est passé.

7 votes

Cela fonctionne bien si vous ajoutez MPVolumeView *slide = [MPVolumeView new]; et aussi #import <MediaPlayer/MediaPlayer.h>

0 votes

@Sandy : les commentaires de Flopes et Gal fonctionnent. Vous devriez ajouter ceci à votre réponse

6voto

Mike Points 354
-(float) getVolumeLevel
{
    MPVolumeView *slide = [MPVolumeView new];
    UISlider *volumeViewSlider;

    for (UIView *view in [slide subviews]){
        if ([[[view class] description] isEqualToString:@"MPVolumeSlider"]) {
            volumeViewSlider = (UISlider *) view;
        }
    }

    float val = [volumeViewSlider value];
    [slide release];

    return val;
}

Cela devrait vous permettre d'obtenir le niveau de volume actuel. 1 est le volume maximal, 0 est le volume nul. Remarque : aucun élément de l'interface utilisateur ne doit être affiché pour que cela fonctionne. Notez également que le niveau de volume actuel est relatif aux écouteurs ou aux haut-parleurs (ce qui signifie que les deux niveaux de volume sont différents et que vous obtenez celui que l'appareil utilise actuellement). Cela ne répond pas à votre question concernant la réception de notifications en cas de changement de volume.

1 votes

Magnifique, mais ce code n'est pas à l'épreuve du temps. Si Apple change les choses et que votre code ne trouve pas de UISlider, l'application plantera lorsqu'elle essaiera de récupérer la valeur puisque UISlider n'a pas été initialisé.

0 votes

Initialiser uislider comme UISlider *volumeViewSlider = nil.... alors avant de récupérer la valeur, vérifiez si volumeViewSlider est nil. Si c'est le cas, n'essayez pas d'obtenir la valeur ou de la libérer !

0 votes

De tels piratages sont fortement déconseillés !

4voto

Karsten Points 1605

Avez-vous démarré la session audio avec AudioSessionSetActive ?

0 votes

Ajout de AudioSessionSetActive (true); ne change rien. Apple ne le fait pas non plus dans ses exemples.

0 votes

Après avoir défini les propriétés d'écoute et activé la session audio, cela a commencé à fonctionner pour moi. Cela est logique car une autre session audio, l'iPod en général, prend en charge les changements de volume.

0 votes

J'ai défini AudioSessionSetActive(YES) ; avant d'appeler float volume = [[AVAudioSession sharedInstance] outputVolume] ; et cela a fonctionné. Sans appeler AudioSessionSetActive(YES), j'ai continué à obtenir le même volume (incorrect).

1voto

Vanya Points 2611

Je pense que cela dépend d'autres implémentations. Si vous utilisez par exemple le curseur pour contrôler le volume du son, vous pouvez effectuer une action de contrôle par UIControlEventValueChanged et si vous obtenez une valeur de 0 vous pouvez mettre le bouton caché ou désactivé.

Quelque chose comme :

[MusicsliderCtl addTarget:self action:@selector(checkZeroVolume:)forControlEvents:UIControlEventValueChanged];

où le vide checkZeroVolume pourrait faire la comparaison du volume réel puisqu'il est déclenché après tout changement de volume.

0 votes

Comme je n'ai pas besoin ou ne veux pas contrôler le volume, je n'implémente pas une MPVolumeView à laquelle je pourrais demander une valeur de curseur.

1 votes

Néanmoins, si la performance n'est pas un problème, le plus simple est de faire comme Vanya le suggère et d'avoir une MPVolumeView cachée et d'ajouter un KVO à sa value propriété

0 votes

Downvoting pour aider à faire remonter la réponse plus à jour de Stuart pour les futurs lecteurs.

0voto

Phoenix Kyaw Points 126

Consultez le lien suivant : http://inchoo.net/mobile-development/iphone-development/how-to-add-volume-level-control-in-iphone-app/ Le lien ci-dessus peut résoudre votre problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X