5

Hello there is a bunch of related questions but I would say none of them gives clear answer how to capture photos with volume buttons.

Currently I add observer to AVAudioSession instance but it doesn't work on max and min volume values and seems showing volume status shadow popup over camera.

private func setupButtonsListener(){
    do {
        let audioSession = AVAudioSession.sharedInstance()
        try audioSession.setActive(true)

        audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil)
    } catch {
        print("Error")
    }

}

Then I handle event in function:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "outputVolume" {
        capturePhoto() // Same function which I use for capturing photo for screen button.
    } else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    }
}

Could you recommend me any solution which will: 1. Work even when max/min volume values reached. 2. Won't show volume value popup over screen.

EDIT:

based on @jayesh-kanzariya answer I add how to use JPSVolumeButtonHandler in Swift:

  1. Add pod 'JPSVolumeButtonHandler' to your pod file.
  2. In project's root execute pod install
  3. Configure bridging file for you project and add there: #import <JPSVolumeButtonHandler/JPSVolumeButtonHandler.h>
  4. In you ViewController add following code:

    import JPSVolumeButtonHandler
    
    class YourViewController {
        var volumeHandler: JPSVolumeButtonHandler?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.volumeHandler = JPSVolumeButtonHandler(up: {self.capturePhoto()}, downBlock: {self.capturePhoto()})
    
            ...
        }    
    }
    

Done!

Petr Shypila
  • 1,449
  • 9
  • 27
  • 47

3 Answers3

2

1) For the volume changes You need to implement your own "MPVolumeView", make sure this view is somewhere outside of visible bounds (setting its alpha to zero, or hiding it, will disable your view and will present the well-known apple volume control) E.g. x-offset -20, y-offsrt -20 and width/height equals 0

import MediaPlayer

let volumeView = MPVolumeView()
volumeView.frame = CGRect(x: -20, y: -20, width: 0, height: 0);

2) For getting continuous updates for volume changes, even if it has reached max/min As you are already registered as observer for the AVAudioSession. I would reset the volume of the AVAudioSession just after you received the event to a value between 0.1 and 0.9 (whatever you need for increasing/decreasing volume).

case let volumeSlider as UISlider in volumeView.subviews {
    volumeSlider.value = 0.2
}
Lepidopteron
  • 6,056
  • 5
  • 41
  • 53
2

Slightly modified version from @jayesh-kanzariya that works for me.

  1. Add pod 'JPSVolumeButtonHandler' to your pod file.

  2. In project's root execute pod install

  3. In you ViewController add following code:

    import JPSVolumeButtonHandler
    
    class YourViewController {
        var volumeHandler: JPSVolumeButtonHandler?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.volumeHandler = JPSVolumeButtonHandler(up: {self.capturePhoto()}, downBlock: {self.capturePhoto()})
    
            self.volumeHandler.start(true)
            ...
        }    
    }
    
1

A modified version from @user2377805 for use in SwiftUI

import JPSVolumeButtonHandler

struct ContentView: View {
    @State private var volumeHandler: JPSVolumeButtonHandler?

    var body: some View {
        YourView()
        .onAppear {
            volumeHandler = JPSVolumeButtonHandler(up: {self.capturePhoto()}, downBlock: {self.capturePhoto()})
        
            volumeHandler?.start(true)
        }
    }
}
Michael C
  • 96
  • 1
  • 8