Reputation: 239
I have a stupid issue but for some reason I can't resolve it. I try to play sound with AVAudioPlayer but can't hear anything. There are no errors, but still my app is silent. Its built with SwiftUI. This is a piece of code:
struct SoundsListView: View {
var body: some View {
List(Helpers.shared.sounds, id:\.self) { item in
Text(item)
Spacer()
Button(action: {
var soundPlayer: AVAudioPlayer?
guard let audioFile: URL = Bundle.main.url(forResource: "Analog watch", withExtension: "mp3") else { return }
do {
soundPlayer = try AVAudioPlayer(contentsOf: audioFile)
print(soundPlayer)
guard let player = soundPlayer else { return }
player.play()
} catch let error {
print("Cannot play sound")
}
}) {
Image(systemName: "play")
} //: BUTTON
}
}
}
There are no errors, also sound files have target membership set. (What is strange it's that the same piece of code works with my older project, but written in Swift + Storyboards)
There is no sound generated neither in simulator nor hardware device. Silent mode is off, volume set to max. I have no idea what's wrong here.
BTW: This app sends notifications to user and sound is OK. But not in this piece of code
Upvotes: 1
Views: 3194
Reputation: 1172
For me the audio would only work sometimes. I had to ensure that when I declared my audio player in the SwiftUI View, it was an @State object. After I added @State before my property it played every time! I am importing AVKit on a separate file where I have my audio play functions... something like I have pasted below. Lmk if you need more clarification.
//In my View I have something like this at the top
struct ContentView: View {
@State var vm = PlayViewModel()
//When I want some audio to play I call it like this... vm.play(fileNamed: "blip")
//And the rest of my SwiftUI code below
}
//And then this is what I have setup in a separate Swift file.
import AVKit
class PlayViewModel {
private var audioPlayer: AVAudioPlayer!
func play(fileNamed:String) {
let sound = Bundle.main.path(forResource: fileNamed, ofType: "wav")
audioPlayer?.prepareToPlay() //maybe not needed? idk
do {
audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: sound!))
audioPlayer?.play()
} catch {
print(error)
}
}
}
Upvotes: 1
Reputation: 5105
Your AVAudioPlayer
only exists in the scope of your button action, so it’s deallocated before the sound can play. You need to save it somewhere… I think you could declare it in SoundsListView
as a @State var
, but it may be better to refactor it out of the SwiftUI view entirely.
EDIT: You probably also need to set your AVAudioSession, which lets you change playback category and control how your audio interacts with other audio e.g. music playback.
Example:
do {
try AVAudioSession.sharedInstance().setCategory(.playback)
try AVAudioSession.sharedInstance().setCategory(.playback, options: [.mixWithOthers])
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print(error)
}
Upvotes: 6