webentwicklung-frage-antwort-db.com.de

Wie erhalte ich Benachrichtigungen zur Lautstärke und Lautstärkeänderung unter iOS?

Ich schreibe eine sehr einfache Anwendung, die beim Drücken einer Taste einen Ton wiedergibt. Da diese Schaltfläche nicht sehr sinnvoll ist, wenn das Gerät stummgeschaltet ist, möchte ich sie deaktivieren, wenn die Lautstärke des Geräts Null ist. (Und aktivieren Sie es anschließend wieder, wenn die Lautstärke wieder erhöht wird.)

Ich suche eine funktionierende (und AppStore-sichere) Methode, um die aktuelle Lautstärkeeinstellung zu ermitteln und eine Benachrichtigung/einen Rückruf zu erhalten, wenn sich die Lautstärke ändert. Ich möchte die Lautstärke nicht verändern Einstellung.

All dies ist in meinem ViewController implementiert, in dem diese Schaltfläche verwendet wird. Ich habe dies mit einem iPhone 4 mit iOS 4.0.1 und 4.0.2 sowie einem iPhone 3G mit 4.0.1 getestet. Erstellt mit iOS SDK 4.0.2 mit llvm 1.5. (Die Verwendung von gcc oder llvm-gcc verbessert nichts.) Während der Implementierung des Builds treten weder Fehler noch Warnungen auf. Static Analyzer freut sich auch.

Folgendes habe ich bisher versucht, alles ohne Erfolg.

Nach der Dokumentation zu den Audiodiensten von Apple sollte ich ein AudioSessionAddPropertyListener für kAudioSessionProperty_CurrentHardwareOutputVolume Registrieren, das folgendermaßen funktionieren sollte:

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

kAudioSessionProperty_CurrentHardwareOutputVolume ,
      audioVolumeChangeListenerCallback,
      self
);

returnvalue ist 0, was bedeutet, dass die Registrierung des Rückrufs funktioniert hat.

Leider bekomme ich nie einen Rückruf zu meiner Funktion audioVolumeChangeListenerCallback, wenn ich die Lautstärketasten auf meinem Gerät, den Headset-Clicker oder den Klingeltonschalter drücke.

Bei Verwendung des exakt gleichen Codes für die Registrierung für kAudioSessionProperty_AudioRouteChange (Der als analoges Beispielprojekt in WWDC-Videos, Entwicklerdokumentation und auf zahlreichen Websites in den Interwebs verwendet wird) habe ich tatsächlich do Erhalten Sie einen Rückruf, wenn Sie die Audioroute ändern (indem Sie ein Headset anschließen/ausstecken oder das Gerät andocken).

Ein Benutzer mit dem Namen Doug hat einen Thread mit dem Titel Ereignis iPhone-Lautstärke geändert für Lautstärke bereits max. geöffnet, in dem er behauptet, dass er diese Methode erfolgreich verwendet (es sei denn, die Lautstärke würde sich dadurch tatsächlich nicht ändern) ist bereits auf Maximum gesetzt). Trotzdem funktioniert es bei mir nicht.

Eine andere Möglichkeit, die ich versucht habe, besteht darin, mich auf diese Weise bei NSNotificationCenter zu registrieren.

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

Dies sollte meine Methode volumeChanged über alle SystemVolume -Änderungen benachrichtigen, tut dies jedoch nicht.

Da mir die gängige Meinung sagt, dass man etwas grundlegend falsch macht, wenn man zu hart arbeitet, um etwas mit Kakao zu erreichen, erwarte ich, dass man hier etwas verpasst. Es ist schwer zu glauben, dass es keine einfache Möglichkeit gibt, zu erhalten den aktuellen Lautstärkepegel, aber ich konnte keinen anhand von Apples Dokumentation, Beispiel, finden Code, Google, Apple Entwicklerforen oder durch Ansehen von WWDC 2010-Videos.

56
MacLemon

Haben Sie möglicherweise Ihre Unterschrift für die volumeChanged: -Methode falsch gemacht? Das hat bei mir geklappt, in meinem appdelegate abgeladen:

- (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
}

Meine volumeChanged: -Methode wird jedes Mal aufgerufen, wenn die Taste gedrückt wird, auch wenn sich die Lautstärke dadurch nicht ändert (weil sie bereits bei max/min liegt).

67
Sandy

Die von einigen Antworten hier verwendete AudioSession -API ist seit iOS 7 veraltet. Sie wurde durch AVAudioSession ersetzt, wodurch eine outputVolume -Eigenschaft für das systemweite Ausgabevolumen verfügbar gemacht wird. Dies kann mithilfe von KVO beobachtet werden, um Benachrichtigungen zu erhalten, wenn sich die Lautstärke ändert, wie in der Dokumentation angegeben:

Ein Wert im Bereich von 0,0 bis 1,0, wobei 0,0 für die minimale Lautstärke und 1,0 für die maximale Lautstärke steht.

Die systemweite Lautstärke kann nur vom Benutzer direkt eingestellt werden. Verwenden Sie die MPVolumeView-Klasse, um die Lautstärke in Ihrer App zu steuern.

Sie können Änderungen am Wert dieser Eigenschaft beobachten, indem Sie die Schlüsselwertbeobachtung verwenden.

Sie müssen sicherstellen, dass die Audiositzung Ihrer App aktiv ist, damit dies funktioniert:

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

Wenn Sie also nur das aktuelle Systemvolumen abfragen möchten, gehen Sie wie folgt vor:

let volume = audioSession.outputVolume

Oder wir können über Änderungen wie folgt informiert werden:

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)
    }
}

Vergiss nicht um das Beobachten zu beenden, bevor die Zuordnung aufgehoben wird:

func stopObservingVolumeChanges() {
    audioSession.removeObserver(self, forKeyPath: Observation.VolumeKey, context: &Observation.Context)
}
49
Stuart
-(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;
}

Das sollte Ihnen den aktuellen Lautstärkepegel anzeigen. 1 ist die maximale Lautstärke, 0 ist keine Lautstärke. Hinweis: Es müssen keine UI-Elemente angezeigt werden, damit dies funktioniert. Beachten Sie auch, dass der aktuelle Lautstärkepegel in Relation zu Kopfhörern oder Lautsprechern steht (dh, die beiden Lautstärkepegel sind unterschiedlich und Sie erfahren, was das Gerät gerade verwendet. Dies beantwortet nicht Ihre Frage, ob Sie Benachrichtigungen erhalten, wenn sich die Lautstärke ändert.

6
Mike

haben Sie die Audiositzung mit AudioSessionSetActive gestartet?

4
Karsten

Schnelle 3-Version von Stuarts exzellenter Antwort:

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)
    }
}
2

Hinzufügen zu Stuarts Antwort unter Verwendung von AVAudioSession, um einige Änderungen in Swift= zu berücksichtigen. 3. Ich hoffe, der Code macht klar, wohin die einzelnen Komponenten gehen.

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
Abundance

Schnell 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)
}

und dann rufst du an

var avAudioSession = AVAudioSession.sharedInstance()
try? avAudioSession.setActive(true)
startObservingVolumeChanges()
1
Reimond Hill

Ich denke, es hängt von anderen Implementierungen ab. Wenn Sie zum Beispiel den Schieberegler zum Regeln der Lautstärke verwenden, können Sie mit UIControlEventValueChanged eine Überprüfungsaktion durchführen. Wenn Sie den Wert 0 erhalten, können Sie die Schaltfläche ausblenden oder deaktivieren.

Etwas wie:

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

dabei könnte void checkZeroVolume den Vergleich des tatsächlichen Volumens durchführen, da er nach jeder Volumenänderung ausgelöst wird.

1
Vanya

Gehen Sie zu Einstellungen-> Sounds und aktivieren Sie das Kontrollkästchen 'Mit Schaltflächen ändern'. Wenn es ausgeschaltet ist, ändert sich die Systemlautstärke nicht, wenn die Lautstärketasten gedrückt werden. Vielleicht haben Sie deshalb keine Benachrichtigung erhalten.

0
fantaxy