AVAudioPlayer With Slider in SwiftUI

Viewed 33

I am using AVAudioPlayer to play an audio in SwiftUI which I am fetching from Firebase. It is playing successfully. I had made a slider to show how much sound is played and how much is remaining. This is also working fine but the problem I am facing is when I use the slider to move forward or backward it should start the audio from that part.

This is what I had done so far:

struct AudioMessageView: View {
    
    @ObservedObject var vm = ViewModel()

    var body: some View {

     HStack {

        Button {
           vm.startPlaying(url: URL(string: "https://firebasestorage.googleapis.com:443/v0/b/unified-45b5c.appspot.com/o/AudioMessage%2F8%2B5%2F5_Audio_15-09-202211:18:05.m4a?alt=media&token=acdda32e-ea2b-4ac0-acf5-7a8bd26918e2"))
         } label: {

            HStack(spacing: 20) {
                
                Image(systemName: "pause.fill")
                    .foregroundColor(sender .black)
                    .padding([.top, .bottom])
                
                Text("\(vm.convertToTimeInterval())")
                    .foregroundColor(.white)
            }
       }

           ZStack(alignment: Alignment(horizontal: .leading, vertical: .center)) {
                Capsule()
                    .fill(Color.black.opacity(0.6))
                    .frame(width: 250, height: 6)
                
            ZStack(alignment: Alignment(horizontal: .trailing, vertical: .center)) {
                Capsule()
                        .fill(.blue)
                        .frame(width: vm.value, height: 6)
                
                Circle()
                    .fill(.blue)
                    .frame(width: 20, height: 20)
                    .clipShape(Circle())
                
              }
        }.gesture(DragGesture().onChanged({ (value) in
            
            if value.location.x <= 250 && value.location.x >= 0 {
                
                self.vm.value = value.location.x
            }
        }))

     }
  }
}

And in my ViewModel :

class ViewModel: NSObject, ObservableObject , AVAudioPlayerDelegate {

    @Published var value : CGFloat = 0
    @Published var plusValue = 0
    @Published var remainingTime  = 0
    @Published var isStartPlay : Bool = false
    var audioPlayer : AVAudioPlayer!

 
   func startPlaying(url : URL) {
        
        do {
            
            let session = AVAudioSession.sharedInstance()
            try session.setCategory(AVAudioSession.Category.playback)
            let soundData = try Data(contentsOf: url)
            audioPlayer = try AVAudioPlayer(data: soundData)
            audioPlayer.prepareToPlay()
            audioPlayer.play()
            let totalDuration = Int(audioPlayer.duration)
            self.remainingTime = totalDuration
            
            let plus = 250 / totalDuration
            
            print("time remain: \(remainingTime)")
            var timer = Timer()
            timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
                
                if self.remainingTime > 0 {
                    self.remainingTime -= 1
                    self.value += CGFloat(plus)
                } else {
                    audioPlayer.stop()
                    self.isStartPlay = false
                    timer.invalidate()
                }
            }
        } catch {
            print("Playing Failed")
            print(error.localizedDescription)
        }
    } 
}

This results in: slider

I want this to work like the WhatsApp audio. Is this will be achieved using this code or I had to change it? I just want this to be like WhatsApp.

0 Answers
Related