I am trying to show a volume indicator in my app, but first I need to monitor the systems current volume.
I am using an observer, and while the print statement shows the correct value, the UI never does.
import SwiftUI
import MediaPlayer
struct ContentView: View {
@State var vol: Float = 1.0
// Audio session object
private let session = AVAudioSession.sharedInstance()
// Observer
private var progressObserver: NSKeyValueObservation!
init() {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
try session.setActive(true, options: .notifyOthersOnDeactivation)
self.vol = 1.0
} catch {
print("cannot activate session")
}
progressObserver = session.observe(\.outputVolume) { [self] (session, value) in
print(session.outputVolume)
self.vol = session.outputVolume
}
}
var body: some View {
Text(String(self.vol))
}
}
// fixed (set category to ambient)(updated above code) Also, every time the application is launched, it stops all currently playing music.
Solved. Created a class that conforms to ObservableObject
and use the ObservedObject
property in the view. Also, the volume observer doesn't work in the simulator, only on device.
VolumeObserver.swift
import Foundation
import MediaPlayer
final class VolumeObserver: ObservableObject {
@Published var volume: Float = AVAudioSession.sharedInstance().outputVolume
// Audio session object
private let session = AVAudioSession.sharedInstance()
// Observer
private var progressObserver: NSKeyValueObservation!
func subscribe() {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
try session.setActive(true, options: .notifyOthersOnDeactivation)
} catch {
print("cannot activate session")
}
progressObserver = session.observe(\.outputVolume) { [self] (session, value) in
DispatchQueue.main.async {
self.volume = session.outputVolume
}
}
}
func unsubscribe() {
self.progressObserver.invalidate()
}
init() {
subscribe()
}
}
ContentView.swift
import SwiftUI
import MediaPlayer
struct ContentView: View {
@StateObject private var volObserver = VolumeObserver()
init() {
print(volObserver.volume)
}
var body: some View {
Text(String(volObserver.volume))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}