AutoCat/AutoCatCore/Services/RecordPlayerService/RecordPlayerService.swift

137 lines
3.4 KiB
Swift

//
// RecordPlayerService.swift
// AutoCatCore
//
// Created by Selim Mustafaev on 31.03.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import AVFoundation
public final class RecordPlayerService: NSObject {
var player: AVAudioPlayer?
var record: AudioRecordDto?
var onStop: ((AudioRecordDto, Error?) -> Void)?
var onProgress: ((Double) -> Void)?
var progressTimer: Timer?
func playNewRecord(
record: AudioRecordDto,
onStop: ((AudioRecordDto, Error?) -> Void)?,
onProgress: ((Double) -> Void)?
) throws {
let url = try FileManager.default.url(for: record.path, in: Constants.audioRecordsFolder)
player = try AVAudioPlayer(contentsOf: url)
player?.delegate = self
self.record = record
self.onStop = onStop
activateProgressTimer()
self.onProgress = onProgress
try activateSession()
player?.play()
}
func activateSession() throws {
try AVAudioSession.sharedInstance().setCategory(
.playback,
mode: .default,
options: [.duckOthers]
)
try AVAudioSession.sharedInstance().setActive(true)
}
func deactivateSession() throws {
try AVAudioSession.sharedInstance().setActive(
false,
options: .notifyOthersOnDeactivation
)
}
func activateProgressTimer() {
progressTimer?.invalidate()
progressTimer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { [weak self] _ in
if let player = self?.player {
let progress = player.currentTime/player.duration
self?.onProgress?(progress)
}
}
}
func deactivateProgressTimer() {
progressTimer?.invalidate()
progressTimer = nil
}
}
extension RecordPlayerService: RecordPlayerServiceProtocol {
public func play(
record: AudioRecordDto,
onStop: ((AudioRecordDto, Error?) -> Void)?,
onProgress: ((Double) -> Void)?
) throws {
guard let player, self.record?.id == record.id else {
try playNewRecord(record: record, onStop: onStop, onProgress: onProgress)
return
}
if player.isPlaying {
player.pause()
deactivateProgressTimer()
try deactivateSession()
} else {
try activateSession()
activateProgressTimer()
player.play()
}
}
public var currentPlayingId: String? {
guard player?.isPlaying == true else {
return nil
}
return record?.id
}
}
extension RecordPlayerService: AVAudioPlayerDelegate {
public func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
guard let record else {
return
}
onStop?(record, nil)
reset()
}
public func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: (any Error)?) {
guard let record else {
return
}
onStop?(record, error)
reset()
}
func reset() {
onStop = nil
player = nil
record = nil
deactivateProgressTimer()
try? deactivateSession()
}
}