feat: implement audio fade in/out
This commit is contained in:
@@ -7,27 +7,37 @@ enum PlaybackState {
|
|||||||
case loading
|
case loading
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
class PlaybackManager: ObservableObject {
|
class PlaybackManager: ObservableObject {
|
||||||
@Published var playbackState: PlaybackState = .paused
|
@Published var playbackState: PlaybackState = .paused
|
||||||
@Published var hasError = false
|
@Published var hasError = false
|
||||||
|
|
||||||
private var audioPlayer = AVPlayer()
|
private var audioPlayer = AVPlayer()
|
||||||
|
private var fadeInTimer: Timer?
|
||||||
|
private var fadeOutTimer: Timer?
|
||||||
|
private var scheduledFadeOutTimer: Timer?
|
||||||
|
|
||||||
func nextTrack() {
|
func nextTrack() {
|
||||||
playbackState = .loading
|
playbackState = .loading
|
||||||
Task {
|
Task {
|
||||||
try await loadCurrentTrack()
|
try await loadAndPlayNextTrack()
|
||||||
|
await MainActor.run {
|
||||||
playbackState = .playing
|
playbackState = .playing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func stop() {
|
func stop() {
|
||||||
playbackState = .paused
|
playbackState = .paused
|
||||||
|
fadeInTimer?.invalidate()
|
||||||
|
fadeInTimer = nil
|
||||||
|
fadeOutTimer?.invalidate()
|
||||||
|
fadeOutTimer = nil
|
||||||
|
scheduledFadeOutTimer?.invalidate()
|
||||||
|
scheduledFadeOutTimer = nil
|
||||||
audioPlayer.pause()
|
audioPlayer.pause()
|
||||||
}
|
}
|
||||||
|
|
||||||
private nonisolated func loadCurrentTrack() async throws {
|
private nonisolated func loadAndPlayNextTrack() async throws {
|
||||||
let now = Date().timeIntervalSince1970
|
let now = Date().timeIntervalSince1970
|
||||||
guard let url = URL(string: "https://infinifi.cafe/current.mp3?t=\(now)") else {
|
guard let url = URL(string: "https://infinifi.cafe/current.mp3?t=\(now)") else {
|
||||||
return
|
return
|
||||||
@@ -41,11 +51,19 @@ class PlaybackManager: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let playerItem = AVPlayerItem(asset: asset)
|
let playerItem = AVPlayerItem(asset: asset)
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(playbackFinished), name: AVPlayerItem.didPlayToEndTimeNotification, object: playerItem)
|
NotificationCenter.default.addObserver(self, selector: #selector(playbackFinished), name: AVPlayerItem.didPlayToEndTimeNotification, object: playerItem)
|
||||||
|
|
||||||
await audioPlayer.replaceCurrentItem(with: playerItem)
|
audioPlayer.volume = 0.0
|
||||||
|
|
||||||
|
audioPlayer.replaceCurrentItem(with: playerItem)
|
||||||
await audioPlayer.play()
|
await audioPlayer.play()
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.fadeInAudio()
|
||||||
|
self.scheduledFadeOutTimer = Timer.scheduledTimer(withTimeInterval: 55, repeats: false) { _ in
|
||||||
|
self.fadeOutAudio()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
@@ -55,4 +73,22 @@ class PlaybackManager: ObservableObject {
|
|||||||
nextTrack()
|
nextTrack()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func fadeInAudio() {
|
||||||
|
fadeInTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
||||||
|
self.audioPlayer.volume += 0.01
|
||||||
|
if self.audioPlayer.volume >= 1.0 {
|
||||||
|
timer.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func fadeOutAudio() {
|
||||||
|
fadeOutTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
||||||
|
self.audioPlayer.volume -= 0.02
|
||||||
|
if self.audioPlayer.volume <= 0 {
|
||||||
|
timer.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user