1
|
#
import
"STKAudioPlayer.h"
|
1
2
3
4
5
|
<key>
NSAppTransportSecurity
</key>
<dict>
<key>
NSAllowsArbitraryLoads
</key>
<
true
/>
</dict>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import
UIKit
import
AVFoundation
@UIApplicationMain
class
AppDelegate
:
UIResponder
,
UIApplicationDelegate
{
var
window:
UIWindow
?
func
application(_ application:
UIApplication
, didFinishLaunchingWithOptions
launchOptions: [
UIApplicationLaunchOptionsKey
:
Any
]?) ->
Bool
{
// 註冊後臺播放
let
session =
AVAudioSession
.sharedInstance()
do {
try session.setActive(
true
)
try session.setCategory(
AVAudioSessionCategoryPlayback
)
} catch {
print
(error)
}
return
true
}
func
applicationWillResignActive(_ application:
UIApplication
) {
}
func
applicationDidEnterBackground(_ application:
UIApplication
) {
}
func
applicationWillEnterForeground(_ application:
UIApplication
) {
}
func
applicationDidBecomeActive(_ application:
UIApplication
) {
}
func
applicationWillTerminate(_ application:
UIApplication
) {
}
}
|
import
UIKit
class
ViewController
:
UIViewController
{
//顯示歌曲標題
@IBOutlet
weak
var
titleLabel:
UILabel
!
//暫停按鈕
@IBOutlet
weak
var
pauseBtn:
UIButton
!
//可拖動的進度條
@IBOutlet
weak
var
playbackSlider:
UISlider
!
//當前播放時間標籤
@IBOutlet
weak
var
playTime:
UILabel
!
//更新進度條定時器
var
timer:
Timer
!
//音頻播放器
var
audioPlayer:
STKAudioPlayer
!
//播放列表
var
queue = [
Music
(name:
"歌曲1"
,
Music
(name:
"歌曲2"
,
Music
(name:
"歌曲3"
,
//當前播放音樂索引
var
currentIndex:
Int
= -1
//是否循環播放
var
loop:
Bool
=
false
//當前播放狀態
var
state:
STKAudioPlayerState
= []
override
func
viewDidLoad() {
super
.viewDidLoad()
//設置進度條相關屬性
playbackSlider!.minimumValue = 0
playbackSlider!.isContinuous =
false
//重置播放器
resetAudioPlayer()
//開始播放歌曲列表
playWithQueue(queue: queue)
//設置一個定時器,每三秒鐘滾動一次
timer =
Timer
.scheduledTimer(timeInterval: 0.1, target:
self
,
selector: #selector(tick), userInfo:
nil
, repeats:
true
)
}
//重置播放器
func
resetAudioPlayer() {
var
options =
STKAudioPlayerOptions
()
options.flushQueueOnSeek =
true
options.enableVolumeMixer =
true
audioPlayer =
STKAudioPlayer
(options: options)
audioPlayer.meteringEnabled =
true
audioPlayer.volume = 1
audioPlayer.delegate =
self
}
//開始播放歌曲列表(默認從第一首歌曲開始播放)
func
playWithQueue(queue: [
Music
], index:
Int
= 0) {
guard index >= 0 && index < queue.count
else
{
return
}
self
.queue = queue
audioPlayer.clearQueue()
let
url = queue[index].url
audioPlayer.play(url)
for
i
in
1 ..< queue.count {
audioPlayer.queue(queue[
Int
((index + i) % queue.count)].url)
}
currentIndex = index
loop =
false
}
//中止播放
func
stop() {
audioPlayer.stop()
queue = []
currentIndex = -1
}
//單獨播放某個歌曲
func
play(file:
Music
) {
audioPlayer.play(file.url)
}
//下一曲
func
next() {
guard queue.count > 0
else
{
return
}
currentIndex = (currentIndex + 1) % queue.count
playWithQueue(queue: queue, index: currentIndex)
}
//上一曲
func
prev() {
currentIndex =
max
(0, currentIndex - 1)
playWithQueue(queue: queue, index: currentIndex)
}
//下一曲按鈕點擊
@IBAction
func
nextBtnTapped(_ sender:
Any
) {
next()
}
//上一曲按鈕點擊
@IBAction
func
prevBtnTapped(_ sender:
Any
) {
prev()
}
//暫停繼續按鈕點擊
@IBAction
func
pauseBtnTapped(_ sender:
Any
) {
//在暫停和繼續兩個狀態間切換
if
self
.state == .paused {
audioPlayer.resume()
}
else
{
audioPlayer.pause()
}
}
//結束按鈕點擊
@IBAction
func
stopBtnTapped(_ sender:
Any
) {
stop()
}
//定時器響應,更新進度條和時間
func
tick() {
if
state == .playing {
//更新進度條進度值
self
.playbackSlider!.value =
Float
(audioPlayer.progress)
//一個小算法,來實現00:00這種格式的播放時間
let
all:
Int
=
Int
(audioPlayer.progress)
let
m:
Int
=all % 60
let
f:
Int
=
Int
(all/60)
var
time:
String
=
""
if
f<10{
time=
"0\(f):"
}
else
{
time=
"\(f)"
}
if
m<10{
time+=
"0\(m)"
}
else
{
time+=
"\(m)"
}
//更新播放時間
self
.playTime!.text=time
}
}
//拖動進度條改變值時觸發
@IBAction
func
playbackSliderValueChanged(_ sender:
Any
) {
//播放器定位到對應的位置
audioPlayer.seek(toTime:
Double
(playbackSlider.value))
//若是當前時暫停狀態,則繼續播放
if
state == .paused
{
audioPlayer.resume()
}
}
override
func
didReceiveMemoryWarning() {
super
.didReceiveMemoryWarning()
}
}
//Audio Player相關代理方法
extension
ViewController
:
STKAudioPlayerDelegate
{
//開始播放歌曲
func
audioPlayer(_ audioPlayer:
STKAudioPlayer
,
didStartPlayingQueueItemId queueItemId:
NSObject
) {
if
let
index = (queue.index { $0.url == queueItemId
as
!
URL
}) {
currentIndex = index
}
}
//緩衝完畢
func
audioPlayer(_ audioPlayer:
STKAudioPlayer
,
didFinishBufferingSourceWithQueueItemId queueItemId:
NSObject
) {
updateNowPlayingInfoCenter()
}
//播放狀態變化
func
audioPlayer(_ audioPlayer:
STKAudioPlayer
,
stateChanged state:
STKAudioPlayerState
,
previousState:
STKAudioPlayerState
) {
self
.state = state
if
state != .stopped && state != .error && state != .disposed {
}
updateNowPlayingInfoCenter()
}
//播放結束
func
audioPlayer(_ audioPlayer:
STKAudioPlayer
,
didFinishPlayingQueueItemId queueItemId:
NSObject
,
with stopReason:
STKAudioPlayerStopReason
,
andProgress progress:
Double
, andDuration duration:
Double
) {
if
let
index = (queue.index {
$0.url == audioPlayer.currentlyPlayingQueueItemId()
as
!
URL
}) {
currentIndex = index
}
//自動播放下一曲
if
stopReason == .eof {
next()
}
else
if
stopReason == .error {
stop()
resetAudioPlayer()
}
}
//發生錯誤
func
audioPlayer(_ audioPlayer:
STKAudioPlayer
,
unexpectedError errorCode:
STKAudioPlayerErrorCode
) {
print
(
"Error when playing music \(errorCode)"
)
resetAudioPlayer()
playWithQueue(queue: queue, index: currentIndex)
}
//更新當前播放信息
func
updateNowPlayingInfoCenter() {
if
currentIndex >= 0 {
let
music = queue[currentIndex]
//更新標題
titleLabel.text =
"當前播放:\(music.name)"
//更新暫停按鈕名字
let
pauseBtnTitle =
self
.state == .playing ?
"暫停"
:
"繼續"
pauseBtn.setTitle(pauseBtnTitle,
for
: .normal)
//設置進度條相關屬性
playbackSlider!.maximumValue =
Float
(audioPlayer.duration)
}
else
{
//中止播放
titleLabel.text =
"播放中止!"
//更新進度條和時間標籤
playbackSlider.value = 0
playTime.text =
"--:--"
}
}
}
//歌曲類
class
Music
{
var
name:
String
var
url:
URL
//類構造函數
init
(name:
String
, url:
URL
){
self
.name = name
self
.url = url
}
}
|