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.
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).
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)
}
-(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.
haben Sie die Audiositzung mit AudioSessionSetActive gestartet?
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)
}
}
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")
}
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()
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.
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.