Files
SwiftAudioEx/Example/SwiftAudio/ViewController.swift
T

170 lines
5.5 KiB
Swift

//
// ViewController.swift
// SwiftAudio
//
// Created by Jørgen Henrichsen on 03/11/2018.
// Copyright (c) 2018 Jørgen Henrichsen. All rights reserved.
//
import UIKit
import SwiftAudioEx
import AVFoundation
import MediaPlayer
class ViewController: UIViewController {
@IBOutlet weak var playButton: UIButton!
@IBOutlet weak var slider: UISlider!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var remainingTimeLabel: UILabel!
@IBOutlet weak var elapsedTimeLabel: UILabel!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var artistLabel: UILabel!
@IBOutlet weak var loadIndicator: UIActivityIndicatorView!
@IBOutlet weak var errorLabel: UILabel!
private var isScrubbing: Bool = false
private let controller = AudioController.shared
override func viewDidLoad() {
super.viewDidLoad()
controller.player.event.playWhenReadyChange.addListener(self, handlePlayWhenReadyChange)
controller.player.event.stateChange.addListener(self, handleAudioPlayerStateChange)
controller.player.event.playbackEnd.addListener(self, handleAudioPlayerPlaybackEnd(data:))
controller.player.event.secondElapse.addListener(self, handleAudioPlayerSecondElapsed)
controller.player.event.seek.addListener(self, handleAudioPlayerDidSeek)
controller.player.event.updateDuration.addListener(self, handleAudioPlayerUpdateDuration)
controller.player.event.didRecreateAVPlayer.addListener(self, handleAVPlayerRecreated)
handleAudioPlayerStateChange(data: controller.player.playerState)
DispatchQueue.main.async {
self.render()
}
}
// MARK: - Actions
@IBAction func togglePlay(_ sender: Any) {
if !controller.audioSessionController.audioSessionIsActive {
try? controller.audioSessionController.activateSession()
}
controller.player.playWhenReady = playButton.currentTitle == "Play"
}
@IBAction func previous(_ sender: Any) {
controller.player.previous()
}
@IBAction func next(_ sender: Any) {
controller.player.next()
}
@IBAction func startScrubbing(_ sender: UISlider) {
isScrubbing = true
}
@IBAction func scrubbing(_ sender: UISlider) {
controller.player.seek(to: Double(slider.value))
}
@IBAction func scrubbingValueChanged(_ sender: UISlider) {
let value = Double(slider.value)
elapsedTimeLabel.text = value.secondsToString()
remainingTimeLabel.text = (controller.player.duration - value).secondsToString()
}
// MARK: - Render
func renderTimeValues() {
self.slider.maximumValue = Float(self.controller.player.duration)
self.slider.setValue(Float(self.controller.player.currentTime), animated: true)
self.elapsedTimeLabel.text = self.controller.player.currentTime.secondsToString()
self.remainingTimeLabel.text = (self.controller.player.duration - self.controller.player.currentTime).secondsToString()
}
func render() {
let player = self.controller.player
// Render play button
self.playButton.setTitle(
!player.playWhenReady || player.playerState == .failed
? "Play"
: "Pause",
for: .normal
)
// Render metadata
if let item = player.currentItem {
self.titleLabel.text = item.getTitle()
self.artistLabel.text = item.getArtist()
item.getArtwork({ (image) in
self.imageView.image = image
})
}
// Render time values
self.renderTimeValues()
// Render error label
if (player.playerState == .failed) {
self.errorLabel.isHidden = false
self.errorLabel.text = "Playback failed."
} else {
self.errorLabel.text = ""
self.errorLabel.isHidden = true
}
// Render load indicator:
if (
(player.playerState == .loading || player.playerState == .buffering)
&& self.controller.player.playWhenReady // Avoid showing indicator before user has pressed play
) {
self.loadIndicator.startAnimating()
} else {
self.loadIndicator.stopAnimating()
}
}
// MARK: - AudioPlayer Event Handlers
func handleAudioPlayerStateChange(data: AudioPlayer.StateChangeEventData) {
print("state=\(data)")
DispatchQueue.main.async {
self.render()
}
}
func handlePlayWhenReadyChange(data: AudioPlayer.PlayWhenReadyChangeData) {
print("playWhenReady=\(data)")
DispatchQueue.main.async {
self.render()
}
}
func handleAudioPlayerPlaybackEnd(data: AudioPlayer.PlaybackEndEventData) {
print("playEndReason=\(data)")
}
func handleAudioPlayerSecondElapsed(data: AudioPlayer.SecondElapseEventData) {
if !isScrubbing {
DispatchQueue.main.async {
self.renderTimeValues()
}
}
}
func handleAudioPlayerDidSeek(data: AudioPlayer.SeekEventData) {
isScrubbing = false
}
func handleAudioPlayerUpdateDuration(data: AudioPlayer.UpdateDurationEventData) {
DispatchQueue.main.async {
self.renderTimeValues()
}
}
func handleAVPlayerRecreated() {
try? controller.audioSessionController.set(category: .playback)
}
}