In my mission it really works very properly to play all of the sounds I want for a Meditation Timer. Now I need to let the customers select music from their iPhone storage to then play the music when the timer is operating.
I constructed the timer simply utilizing a music file that I dragged into my mission and it really works effective as all the time.
Then I attempted placing the URL from the storage file, that the consumer selected. However nothing is enjoying. The timer runs with none downside and there aren’t any errors thrown. Is it even potential to make use of AVAudioPlayer to play media exterior to the mission? I noticed some examples the place folks used it to play media from a Net URL. So I guessed it ought to work.
Listed here are the mandatory code snippets and likewise a screenshot of the File URL that’s chosen after which saved by the consumer.
import SwiftUI
import SwiftData
import AVFoundation /// For taking part in any sound
import AVKit /// For the AirPlay Button
import MediaPlayer /// For getting the Quantity Slider connected to the units quantity.
import CoreHaptics /// For making vibrations as soon as the timer is run out
struct TimerTapasMusicView: View {
@Setting(.dismiss) var dismiss /// To have the ability to dismiss the view
@State var countdownTimer = 5 * 60 /// The precise seconds of the timer, being counted down/up
@State var timerRunning = true /// Var to set and see if timer is operating
@State var gongSound: AVAudioPlayer? /// The Sound of the timer
**@State var musicSound: AVAudioPlayer? /// The Sound of the music**
@State non-public var hours: Int = 0 /// Vars for the picker wheel
@State non-public var minutes: Int = 0
@State non-public var seconds: Int = 0
@State non-public var brightnessLow = false/// Var for saving if the brightness button was used
@State non-public var engine: CHHapticEngine? /// The item creating the vibrations in a while
@Setting(.scenePhase) var scenePhase /// Var to maintain observe of state of app, to restart HapticEngine
/// Setting Objects
@EnvironmentObject var userStat: StatisticsObject /// Var to maintain observe of seconds utilizing the Timer
@EnvironmentObject var envObject: EnvObject /// For getting FullDarkness, vibrateTimer
/// Getting the Asana
@State var asana: TapasAsana
**let path = Bundle.primary.path(forResource: "bell_basu.mp3", ofType:nil)!
let musicPath = Bundle.primary.path(forResource: "authen.mp3", ofType:nil)!
let volumeView = MPVolumeView()**
var physique: some View {
/// For calculating hours, minutes, seconds
let fashion = Period.TimeFormatStyle(sample: .minuteSecond)
//let formTimer = Period.seconds(countdownTimer).formatted()
let formTimerShort = Period.seconds(countdownTimer).formatted(fashion)
**let url = URL(fileURLWithPath: path)
let musicUrl = asana.musicFile //URL(fileURLWithPath: musicPath)**
VStack {
/// The slider for the system quantity
HStack{
VolumeSliderView()
.body(width: 250, peak: 25)
.offset(y: 5)
RouteButtonView()
.body(width: 50, peak: 50)
}
.padding(.high, 40)
/// The buttons when the timer is operating
TimerTopButtonsView()
Textual content("(asana.identify)")
.font(.system(measurement: 50))
.padding(.backside, -100)
/// The primary Timer If there aren't any hours we disguise the hour quantity and make the timer greater on this approach.
Textual content("(formTimerShort)")
.onAppear(carry out: prepareHaptics) /// Making ready the Vibration Object
.onChange(of: scenePhase) { /// When app will get closed and reopnened, begin Haptic once more
prepareHaptics()
}
.onReceive(Timer.publish(each: 1, on: .primary, in: .widespread).autoconnect()) { _ in
if countdownTimer > 0 && timerRunning {
countdownTimer -= 1
}
else if countdownTimer == 5 {
gongSound?.prepareToPlay()
} else {
timerRunning = false
}
/// Performs the gong sound when timer hits 0 after operating
if countdownTimer == 0 && timerRunning {
do {
gongSound = attempt AVAudioPlayer(contentsOf: url)
gongSound?.play()
envObject.fullDarkness = false
timerRunning = false
timerVibration()
/// Including the seconds of lastTime to the TimerUsed stat
userStat.timerDuration += asana.length
UserDefaults.customary.set(userStat.timerDuration, forKey: "TimerDuration")
/// When the Timer is completed we've got executed the Asana and the Timer is dismissed.
asana.doneToday = true
asana.recoupCount = 0
} catch {
//Could not Load File.
}
}
}
.body(width: 500, peak: 220)
/// Change the dimensions relying if it's only minutes after which solely when timer operating
.font(.system(measurement: 140))
.monospacedDigit() /// Makes the numbers fastened in measurement and place.
.onTapGesture { gongSound?.cease() } /// Tapping it stops the sound.
.padding(.high, 30)
.padding(.backside, 30)
/// Prevents machine from sleep on seem and permits sleep on disappear
.onAppear{
UIApplication.shared.isIdleTimerDisabled = true
if (asana.recoupCount == 0 ) { countdownTimer = asana.length }
else { countdownTimer = asana.length * (asana.recoupCount + 1) }
**do {
musicSound = attempt AVAudioPlayer(contentsOf: musicUrl)
musicSound?.play()
musicSound?.numberOfLoops = 10000**
} catch {
}
}
.onDisappear{UIApplication.shared.isIdleTimerDisabled = false}
.toolbar(.hidden, for: .tabBar)
.... And extra Code that I believe shouldn't be vital right here.
Right here I’m letting the consumer select a file from their Storage:
} else if asana.executionType == "music" {
Button("Select Music File") {
chooseMusic = true
}
.fileImporter(isPresented: $chooseMusic, allowedContentTypes: [.item]) {end in
swap end result {
case .success(let Fileurl):
print(Fileurl)
asana.musicFile = Fileurl
case .failure(let error):
print(error)
}
}
Textual content("File Title: (asana.musicFile)")
And this can be a Screenshot of the URL, possibly I’m saving it in a flawed approach.
I edited the code to incorporate the Safety Scope in accordance with the instance within the documentation, however nonetheless there isn’t a sound enjoying.
.fileImporter(isPresented: $chooseMusic, allowedContentTypes: [.item]) {end in
swap end result {
case .success(let Fileurl):
let gotAccess = Fileurl.startAccessingSecurityScopedResource()
print(Fileurl)
asana.musicFile = Fileurl
Fileurl.stopAccessingSecurityScopedResource()
case .failure(let error):
print(error)
}
}