how to detect volume up/down button in ios?

Hello


I just want to make a simple application in which I change the text of a lable to "Hello" when ever the user press the volume up button on the device and to "Good bye" when the use press the volume down button.


thank you for the time you put to answer my question.

Replies

I tested this: works on iPhone (tested with 5C, target IOS 10.1) but not on simulator:


func listenVolumeButton() {
   do {
    try audioSession.setActive(true)
   } catch {
    print("some 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" {
    print("Hello")
  }
}

Call listenVolumeButton() in viewWillAppear

Shoulmd of course replace print by the required output.


credit : https://stackoverflow.com/questions/28471481/detect-volume-button-press

Thank you for your answer. I am already familiar with the code u just wrote my problem is that i want to print diffrent values depending on which button(up or down) pressed. The code you wrote will print the value nomatter which button has been pressed

Just added a property in the class:


private var audioLevel : Float = 0.0


and completed as follows.


     func listenVolumeButton(){
         
          let audioSession = AVAudioSession.sharedInstance()
          do {
               try audioSession.setActive(true, options: [])
          audioSession.addObserver(self, forKeyPath: "outputVolume",
                                   options: NSKeyValueObservingOptions.new, context: nil)
               audioLevel = audioSession.outputVolume
          } catch {
               print("Error")
          }
     }
    
     override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
          if keyPath == "outputVolume"{
               let audioSession = AVAudioSession.sharedInstance()
               if audioSession.outputVolume > audioLevel {
                    print("Hello")
               }
               if audioSession.outputVolume < audioLevel {
                    print("GoodBye")
               }
               audioLevel = audioSession.outputVolume
               print(audioSession.outputVolume)
          }
     }

Tested, it works.

Hello

0.375

GoodBye

0.3125


You could improve a little : if the level is already at max, pressing the up button will not change the value (simlilarly at min)

You could set the system volume to 0.9375 or 0.0625 when at max or at min (that would be minimal disturbance for user, but not perfect)

(values are coded on 4 bits, 16 values between 0 and 1)


This gets it done:


     override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
          if keyPath == "outputVolume"{
               let audioSession = AVAudioSession.sharedInstance()
               if audioSession.outputVolume > audioLevel {
                    print("Hello")
                    audioLevel = audioSession.outputVolume
               }
               if audioSession.outputVolume < audioLevel {
                    print("GoodBye")
                    audioLevel = audioSession.outputVolume
               }
               if audioSession.outputVolume > 0.999 {
                    (MPVolumeView().subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}.first as? UISlider)?.setValue(0.9375, animated: false)
                    audioLevel = 0.9375
               }
             
               if audioSession.outputVolume < 0.001 {
                    (MPVolumeView().subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}.first as? UISlider)?.setValue(0.0625, animated: false)
                    audioLevel = 0.0625
               }
          }
     }

But take care, changing the system setting could cause problem for App store.

Solution completed from : https://stackoverflow.com/questions/36322856/swift-how-to-set-the-iphone-volume-programmatically

thank you for your answer.

after adding the code u mentioned im getting an error and i can't understand why.



Extra argument 'options' in call ( line 22)



can you help me out here?

thank you



here is my code

import UIKit
import MediaPlayer
import AVFoundation

class ViewController: UIViewController {

    private var audioLevel : Float = 0.0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    override func viewWillAppear(_ animated: Bool) {
        listenVolumeButton()
    }
    
    func listenVolumeButton(){
        
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setActive(true, options: [])
            audioSession.addObserver(self, forKeyPath: "outputVolume",
                                     options: NSKeyValueObservingOptions.new, context: nil)
            audioLevel = audioSession.outputVolume
        } catch {
            print("Error")
        }
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "outputVolume"{
            let audioSession = AVAudioSession.sharedInstance()
            if audioSession.outputVolume > audioLevel {
                print("Hello")
                audioLevel = audioSession.outputVolume
            }
            if audioSession.outputVolume < audioLevel {
                print("GoodBye")
                audioLevel = audioSession.outputVolume
            }
            if audioSession.outputVolume > 0.999 {
                (MPVolumeView().subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}.first as? UISlider)?.setValue(0.9375, animated: false)
                audioLevel = 0.9375
            }
            
            if audioSession.outputVolume < 0.001 {
                (MPVolumeView().subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}.first as? UISlider)?.setValue(0.0625, animated: false)
                audioLevel = 0.0625
            }
        }
    }


}

Which version of XCode ?


I tested in XCode 10.0, works OK


Here is the signature:

func setActive(_ active: Bool, options: AVAudioSession.SetActiveOptions = []) throws


Parameters

active

Specify

true
to activate your app’s audio session, or
false
to deactivate it.
options

An integer bit mask containing one or more constants from the

AVAudioSession.SetActiveOptions
enumeration.



However, as the default value is [], you could also omit the options argument.

Does it work then ?

Thx again. I’m running the latest version of xcode. Is it suppose to run on simulator? Because it doesn’t. I havent check it on my iphone. I will update this post after I check.

No, does not work on simulator (does not detect), but perfectly on device.


Thanks to close thread by marking the correct answer if it works. Good luck.

This "solution" is actually not a good thing to do. There's a good reason why there isn't any API to detect volume button presses: to prevent apps from doing it.


What is it going to be like for a user who wants to change the volume of background music that's playing, if pressing the up/down button does something different depending which app is in the foreground, and does something different in each app? Users should start being afraid of pressing the buttons??


This has to be a case where common sense says, "Don't do that!".

I do agree. That's why I put a warning in trhe reply.

I think it's OK to be a bit more "reluctant" to show actual code, when it's clearly not an ideal solution. 🙂

I'll try to take more care in the future. Thanks.