Comment obtenir le niveau de volume audio, et le volume modifié notifications sur iOS?

j'écris une application très simple qui joue un son en appuyant sur un bouton. Puisque ce bouton n'a pas beaucoup de sens quand l'appareil est réglé au silence, je veux le désactiver quand le volume audio de l'appareil est zéro. (Et ensuite le réenrêter lorsque le volume est augmenté de nouveau.)

je cherche un moyen efficace (et sûr AppStore) de détecter le réglage de volume actuel et obtenir un avis/rappel lorsque le volume les changements de niveau. I ne veulent pas modifier le réglage du volume .

tout ceci est implémenté dans mon ViewController où ce bouton est utilisé. J'ai testé cela avec un iPhone 4 tournant sous iOS 4.0.1 et 4.0.2 ainsi qu'un iPhone 3G tournant sous 4.0.1. Construit avec IOS SDK 4.0.2 avec llvm 1.5. (Utiliser gcc ou llvm-gcc n'améliore rien.) Il n'y a pas de problèmes lors de la mise en œuvre de la construction dans un sens ou dans l'autre, ni d'erreurs ni d'Avertissements. Analyseur statique est heureux ainsi.

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

suite à la documentation des services audio D'Apple je devrais enregistrer un AudioSessionAddPropertyListener pour kAudioSessionProperty_CurrentHardwareOutputVolume qui devrait fonctionner comme ceci:

// 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 du rappel a fonctionné.

malheureusement, je n'obtiens jamais un rappel à ma fonction audioVolumeChangeListenerCallback quand j'appuie sur les boutons de volume sur mon dispositif, le casque cliquent ou appuyer sur le commutateur ringer-silent.

lors de l'utilisation du même code pour s'enregistrer pour kAudioSessionProperty_AudioRouteChange (qui est utilisé comme un projet d'échantillon analogue dans les vidéos WWDC, la documentation du développeur et sur de nombreux sites sur les interwebs) Je effectivement do obtenir un rappel lors du changement de la route audio (en branchant/Hors un casque ou en amarrant l'appareil).

un utilisateur nommé Doug ouvert un fil intitulé iPhone volume changé événement pour le volume déjà max où il a déclaré qu'il utilise avec succès cette façon (à moins que le volume ne serait pas réellement changer parce qu'il est déjà fixé au maximum). Pourtant, il ne fonctionne pas pour moi.

une autre façon que j'ai essayé est de m'inscrire à NSNotificationCenter comme ceci.

// 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 toute modification SystemVolume mais il n'est pas réellement le faire.

depuis la croyance commune me dit que si on travaille trop dur pour accomplir quelque chose avec le cacao on fait quelque chose fondamentalement mal je m'attends à manquer quelque chose ici. Il est difficile de croire qu'Il ya no simple way à obtenir le niveau de volume actuel, mais je n'ai pas été en mesure d'en trouver un en utilisant la documentation D'Apple, code échantillon, Google, Apple Developer Forums ou en regardant WWDC 2010 vidéo.

49
demandé sur Community 2010-09-06 15:58:50

9 réponses

y a-t-il une chance que vous ayez mal signé pour la méthode volumeChanged:? Cela a fonctionné pour moi, jeté 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
}

Mon volumeChanged: méthode reçoit le coup à chaque fois que le bouton est pressé, même si le volume ne change pas (car il est déjà au max/min).

65
répondu Sandy 2011-06-24 18:25:05

L'API AudioSession utilisée par certaines réponses a été dépréciée depuis iOS 7. Il a été remplacé par AVAudioSession , qui expose une propriété outputVolume pour le volume de production à l'échelle du système. Cela peut être observé en utilisant KVO pour recevoir des notifications lorsque le volume change, comme indiqué dans la documentation:

valeur comprise entre 0,0 et 1,0, 0,0 représentant le minimum volume et 1.0 représentant le volume maximum.

le volume de sortie à l'échelle du système ne peut être réglé directement que par l'utilisateur; à fournir le contrôle de volume dans votre application, Utilisez la classe MPVolumeView.

vous pouvez observer les changements de la valeur de cette propriété en utilisant observation de la valeur clé.

vous devez vous assurer que la session audio de votre application est active pour que cela fonctionne:

let audioSession = AVAudioSession.sharedInstance()
do {
    try audioSession.setActive(true)
    startObservingVolumeChanges()
} catch {
    print(“Failed to activate audio session")
}

donc si tout ce que vous avez besoin est d'interroger le volume du système actuel:

let volume = audioSession.outputVolume

Ou nous pouvons être informé des changements de la sorte:

private struct Observation {
    static let VolumeKey = "outputVolume"
    static var Context = 0

}

func startObservingVolumeChanges() {
    audioSession.addObserver(self, forKeyPath: Observation.VolumeKey, options: [.Initial, .New], context: &Observation.Context)
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if context == &Observation.Context {
        if keyPath == Observation.VolumeKey, let volume = (change?[NSKeyValueChangeNewKey] as? NSNumber)?.floatValue {
            // `volume` contains the new system output volume...
            print("Volume: \(volume)")
        }
    } else {
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
}

N'oubliez pas arrêter d'observer avant d'être désalloué:

func stopObservingVolumeChanges() {
    audioSession.removeObserver(self, forKeyPath: Observation.VolumeKey, context: &Observation.Context)
}
43
répondu Stuart 2017-08-15 14:57:38
-(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;
}

qui devrait vous donner le niveau de volume actuel. 1 est le volume maximum, 0 n'est pas le volume. Remarque: Il n'est pas nécessaire d'Afficher des éléments D'assurance-chômage pour que cela fonctionne. Notez également que le niveau de volume actuel est relatif aux écouteurs ou haut-parleurs (c'est-à-dire que les deux niveaux de volume sont différents, ce qui vous permet de choisir celui que l'appareil utilise actuellement. Cela ne répond pas à votre question concernant la réception des notifications de changement de volume.

6
répondu Mike 2012-02-04 03:41:01

avez-vous commencé la session audio avec AudioSessionSetActive

3
répondu Karsten 2010-09-06 13:05:33

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 faire une action de vérification par UIControlEventValueChanged et si vous obtenez une valeur 0, Vous pouvez régler le bouton caché ou désactivé.

quelque chose comme:

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

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

1
répondu Vanya 2016-11-21 21:29:16

ajout à la réponse de Stuart en utilisant AVAudioSession pour rendre compte de certains changements dans Swift 3. J'espère que le code indiquera clairement où va chaque composante.

override func viewWillAppear(_ animated: Bool) {
    listenVolumeButton()
}

func listenVolumeButton(){
   let audioSession = AVAudioSession.sharedInstance()
   do{
       try audioSession.setActive(true)
       let vol = audioSession.outputVolume
       print(vol.description) //gets initial volume
     }
   catch{
       print("Error info: \(error)")
   }
   audioSession.addObserver(self, forKeyPath: "outputVolume", options: 
   NSKeyValueObservingOptions.new, context: nil)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "outputVolume"{
        let volume = (change?[NSKeyValueChangeKey.newKey] as 
        NSNumber)?.floatValue
        print("volume " + volume!.description)
    }
}

 override func viewWillDisappear(_ animated: Bool) {
     audioSession.removeObserver(self, forKeyPath: "outputVolume")
 }
1
répondu Abundance 2017-03-26 18:16:58

version Swift 3 de L'excellente réponse de Stuart:

let audioSession = AVAudioSession.sharedInstance()

do {
    try audioSession.setActive(true)
    startObservingVolumeChanges()
} 
catch {
    print("Failed to activate audio session")
}

let volume = audioSession.outputVolume

private struct Observation {
    static let VolumeKey = "outputVolume"
    static var Context = 0
}

func startObservingVolumeChanges() {
    audioSession.addObserver(self, forKeyPath: Observation.VolumeKey, options: [.Initial, .New], context: &Observation.Context)
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if context == &Observation.Context {
        if keyPath == Observation.VolumeKey, let volume = (change?[NSKeyValueChangeNewKey] as? NSNumber)?.floatValue {
            // `volume` contains the new system output volume...
            print("Volume: \(volume)")
        }
    } else {
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
}
1
répondu Joshua C. Lerner 2017-08-15 12:39:14

Swift 4

func startObservingVolumeChanges() {
    avAudioSession.addObserver(self, forKeyPath: Observation.VolumeKey, options: [.initial, .new], context: &Observation.Context)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if context == &Observation.Context {
        if keyPath == Observation.VolumeKey, let volume = (change?[NSKeyValueChangeKey.newKey] as? NSNumber)?.floatValue {
            print("\(logClassName): Volume: \(volume)")
        }
    } else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    }
}

func stopObservingVolumeChanges() {
    avAudioSession.removeObserver(self, forKeyPath: Observation.VolumeKey, context: &Observation.Context)
}

et puis vous appelez

var avAudioSession = AVAudioSession.sharedInstance()
try? avAudioSession.setActive(true)
startObservingVolumeChanges()
1
répondu Reimond Hill 2018-01-19 14:11:02

Allez dans paramètres->sons et cocher "Modifier avec les Boutons'. S'il est éteint le volume du système ne changera pas en appuyant sur les boutons de volume. C'est peut-être la raison pour laquelle vous n'avez pas averti.

0
répondu fantaxy 2014-04-17 06:43:03