Hello Everyone, I'm Hiro
Now I'm trying to load mp3 on Library Folder and play it. (Originally, the mp3 file was on bundle.main.path and was stored on Library Folder. And that seems being success)
let storedURL = directoryUrl.appendingPathComponent(fileName) // same url when a mp3 file was stored on Library Folder
do { let audioPlayer = try AVAudioPlayer(contentsOf: storedURL, fileTypeHint: AVFileType.mp3.rawValue) audioPlayer.play() } catch let error { print(error.localizedDescription) }
When I did above code, below error would happen. 2021-07-06 15:41:24.968272+0900 FileSaveSample[1438:69214] [aqsrv] AQServer.cpp:68:APIResult: Exception caught in AudioQueueInternalNotifyRunning - error -66671
And, the sound won't play on simulator and actual device.
Am I wrong on something basic?
I use XCode 12.5.1 and iOS 14.
Best regards,
Thanks for showing your code.
The critical thing in your code is this part:
do {
let audioPlayer = try AVAudioPlayer(contentsOf: storedURL, fileTypeHint: AVFileType.mp3.rawValue)
audioPlayer.play()
print("sound is playing")
} catch let error {
print("Sound Play Error.lDescription -> \(error.localizedDescription)")
print("Sound Play Error -> \(error)")
}
(As was shown in your first post, nice guess!)
The problem is that the variable audioPlayer
is local to the do-catch block. So, it will be lost immediately after print("sound is playing")
. With audioPlayer.play()
, playing the audio is just started but not finished.
The instance of AVAudioPlayer
needs to be held while playing.
Please try something like this:
struct ContentView: View {
let playerManager = AudioPlayerManager.shared //<-
@State var message: String = "Test Message2"
@State var storedURL: URL?
var body: some View {
Text(message)
.onTapGesture {
guard let path = Bundle.main.path(forResource: "selectSE", ofType: "mp3") else {
print("Sound file not found")
return
}
let url = URL(fileURLWithPath: path)
do {
let fileData = try Data(contentsOf: url)
storedURL = saveDataFile(data: fileData, fileName: "test.mp3", folderName: "testFolder")
print("File Writing on View -> Success \(storedURL?.absoluteString ?? "nil") ")
} catch {
print("Data.init(contentsOf:) failed: \(error)")
}
playerManager.play(url: storedURL!) //<-
print("end of code")
}
}
//...
}
class AudioPlayerManager {
static let shared = AudioPlayerManager()
var audioPlayer: AVAudioPlayer?
func play(url: URL) {
do {
audioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue) //<- No `let`
audioPlayer?.play()
print("sound is playing")
} catch let error {
print("Sound Play Error -> \(error)")
}
}
}
You have no need to copy the sound file each time onTapGesture, but it is not critical and you may improve it later.