Reputation: 21
I‘ve read a lot solution provided by stackOverFlow and gitHub, and all of them doesn's work for me.I've tried the following tow way:
override func viewWillAppear(_ animated: Bool) {
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setActive(true, options: [])
} catch {
print("error")
}
// this print shows, got the current volume.
//but what I need is the notification of the change of volume
print("view will appear ,this volume is \(audioSession.outputVolume)")
audioSession.addObserver(self,
forKeyPath: "outputVolume",
options: [.new],
context: nil)
}
override class func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
if keyPath == "outputVolume"{
let audioSession = AVAudioSession.sharedInstance()
let volume = audioSession.outputVolume
//this print doesn't shows up
print("observed volume is \(volume)")
}
}
override func viewWillAppear(_ animated: Bool) {
NotificationCenter.default.addObserver(self, selector: #selector(observed(_:)), name: Notification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"), object: nil)
}
@objc func observed(_ notification: Notification){
print("observed")
}
by the way, I'm using simulator(iPhone11, iOS13.1),Xcode version is 11.1
Upvotes: 2
Views: 1989
Reputation: 499
Try to use following:
import UIKit
import MediaPlayer
import AVFoundation
class ViewController: UIViewController {
private var audioLevel: Float = 0.0
deinit {
audioSession.removeObserver(self, forKeyPath: "outputVolume")
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
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
}
}
}
}
Hope this will help you!
Upvotes: 3
Reputation: 63
You need to ensure your app's audio session is active for this to work:
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setActive(true)
startObservingVolumeChanges()
} catch {
print(“Failed to activate audio session")
}
So if all you need is to query the current system volume:
let volume = audioSession.outputVolume
Or we can be notified of changes like so:
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)
}
}
Don't forget to stop observing before being deallocated:
func stopObservingVolumeChanges() {
audioSession.removeObserver(self, forKeyPath: Observation.VolumeKey,
context: &Observation.Context)
}
Upvotes: 1