加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Swift - 制作一个在线流媒体音乐播放器(使用StreamingKit库)

发布时间:2020-12-14 06:15:17 所属栏目:百科 来源:网络整理
导读:在之前的文章中,我介绍了如何使用 AVPlayer 制作一个简单的音乐播放器( 点击查看1、 点击查看2)。虽然这个播放器也可以播放网络音频,但其实际上是将音频文件下载到本地后再播放的。 本文演示如何使用第三方的 StreamingKit 库,来实现网络流音频的播放。
在之前的文章中,我介绍了如何使用 AVPlayer制作一个简单的音乐播放器( 点击查看1、 点击查看2)。虽然这个播放器也可以播放网络音频,但其实际上是将音频文件下载到本地后再播放的。
本文演示如何使用第三方的 StreamingKit库,来实现网络流音频的播放。

一、StreamingKit介绍和配置

1,基本介绍

(1) StreamingKit是一个适用于 iOSMac OSX的音频播放流媒体库。 StreamingKit提供了一个简洁的面向对象 API,用于在 CoreAudio框架下进行音频的解压和播放(采用硬件或软件编解码器)处理。
(2) StreamingKit的主要机制是对从播放器输入的数据源进行解耦,从而使高级定制的数据源可以进行诸如基于流媒体的渐进式下载、编码解码、自动恢复、动态缓冲之类的处理。 StreamingKit是唯一支持不同格式音频文件无缝播放的音频播放流媒体库。
(3) Github主页: https://github.com/tumtumtum/StreamingKit

2,主要特点

  • 免费开源
  • 简洁的API
  • 可读性很强的源代码
  • 精心使用多线程提供了一个快速响应的API,既能防止线程阻塞,又能保证缓冲流畅
  • 缓冲并无缝播放所有不同格式的音频文件
  • 容易实现的音频数据源(支持本地、HTTPAutoRecovering HTTP作为数据源)
  • 容易kuo扩展数据源以支持自动缓冲、编码等
  • 低耗电和低CPU使用率(CPU使用率0%,流式处理时使用率为1%
  • 优化线性数据源,仅随机访问数据源需要搜索
  • StreamingKit0.2.0使用AudioUnit API而不是速度较慢的音频队列API,允许对原始PCM数据进行实时截取以获得并行测量、EQ等特征
  • 电能计量
  • 内置的均衡器(iOS5.0及以上版本、OSX10.9及以上版本)支持音频播放的同时动态改变、启用、禁用均衡器
  • 提供了iOSMac OSX应用实例

3,安装配置

(1)将源码包下载下来后,将其中的 StreamingKit/StreamingKit文件夹复制到项目中来。

(2)创建桥接头文件,内容如下:
1
# import "STKAudioPlayer.h"

二、制作一个网络音频播放器

1,效果图

(1)程序运行后自动开始播放音乐(整个队列一个有 3首歌曲,默认先播放第一首)
(2)点击“ 上一曲”“ 下一曲”按钮可以切换当前播放歌曲。
(3)歌曲播放过程中进度条会随之变化,进度条右侧会显示出当前歌曲播放时间。
(4)进度条可以拖动,拖动结束后自动播放该时间点的音乐。
(5)点击“ 暂停”按钮可以交替切换播放器暂停、继续状态。
(6)点击“ 结束”按钮,结束整个播放器的音乐播放。

2,实现步骤

(1)在 info.plist中添加如下配置以支持 http传输。
1
2
3
4
5
<key> NSAppTransportSecurity </key>
<dict>
NSAllowsArbitraryLoads </key>
< true />
</dict>

(2)为了让播放器能在后台持续播放,我们需要将 Targets-> Capabilities-> BackgroundModes设为 ON,同时勾选“ Audio,AirPlay,and Picture in Picture”。

同时还要在 AppDelegate.swift中注册后台播放。
1
2
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 launchOptions: [ UIApplicationLaunchOptionsKey Any ]?) -> Bool {
// 注册后台播放
let session = AVAudioSession .sharedInstance()
do {
try session.setActive( )
try session.setCategory( AVAudioSessionCategoryPlayback )
} catch {
print (error)
}
return true
}
applicationWillResignActive(_ application: ) {
}
applicationDidEnterBackground(_ application: UIApplication ) {
}
applicationWillEnterForeground(_ application: ) {
}
applicationDidBecomeActive(_ application: ) {
}
applicationWillTerminate(_ application: ) {
}
}

(3)主视图代码( ViewController.swift
13
14
15
16
17
18
19
20
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
UIKit
ViewController UIViewController {
//显示歌曲标题
@IBOutlet weak titleLabel: UILabel !
//暂停按钮
pauseBtn: UIButton !
//可拖动的进度条
playbackSlider: UISlider !
//当前播放时间标签
playTime: UILabel !
//更新进度条定时器
timer: Timer !
//音频播放器
audioPlayer: STKAudioPlayer !
//播放列表
queue = [ Music (name: "歌曲1" url: URL (string: "http://mxd.766.com/sdo/music/data/3/m10.mp3" )!),
"歌曲2" "http://mxd.766.com/sdo/music/data/3/m12.mp3" "歌曲3" "http://mxd.766.com/sdo/music/data/3/m13.mp3" )!)]
//当前播放音乐索引
currentIndex: Int = -1
//是否循环播放
loop: Bool = false
//当前播放状态
state: STKAudioPlayerState = []
override viewDidLoad() {
super .viewDidLoad()
//设置进度条相关属性
playbackSlider!.minimumValue = 0
playbackSlider!.isContinuous = false
//重置播放器
resetAudioPlayer()
//开始播放歌曲列表
playWithQueue(queue: queue)
//设置一个定时器,每三秒钟滚动一次
timer = .scheduledTimer(timeInterval: 0.1,target: self selector: #selector(tick),userInfo: nil )
}
//重置播放器
resetAudioPlayer() {
options = STKAudioPlayerOptions ()
options.flushQueueOnSeek = true
options.enableVolumeMixer = true
audioPlayer = (options: options)
audioPlayer.meteringEnabled = true
audioPlayer.volume = 1
audioPlayer.delegate = self
}
//开始播放歌曲列表(默认从第一首歌曲开始播放)
playWithQueue(queue: [ ],index: Int = 0) {
guard index >= 0 && index < queue.count else {
return
}
.queue = queue
audioPlayer.clearQueue()
url = queue[index].url
audioPlayer.play(url)
for i in 1 ..< queue.count {
audioPlayer.queue(queue[ ((index + i) % queue.count)].url)
}
currentIndex = index
loop = false
}
//停止播放
stop() {
audioPlayer.stop()
queue = []
currentIndex = -1
}
//单独播放某个歌曲
play(file: ) {
audioPlayer.play(file.url)
}
//下一曲
next() {
guard queue.count > 0 {
return
}
currentIndex = (currentIndex + 1) % queue.count
playWithQueue(queue: queue,index: currentIndex)
}
//上一曲
prev() {
currentIndex = max (0,currentIndex - 1)
}
//下一曲按钮点击
@IBAction nextBtnTapped(_ sender: ) {
next()
}
//上一曲按钮点击
prevBtnTapped(_ sender: ) {
prev()
}
//暂停继续按钮点击
pauseBtnTapped(_ sender: ) {
//在暂停和继续两个状态间切换
if .state == .paused {
audioPlayer.resume()
} {
audioPlayer.pause()
}
}
//结束按钮点击
stopBtnTapped(_ sender: ) {
stop()
}
//定时器响应,更新进度条和时间
tick() {
if state == .playing {
//更新进度条进度值
.playbackSlider!.value = Float (audioPlayer.progress)
//一个小算法,来实现00:00这种格式的播放时间
all: = (audioPlayer.progress)
m: =all % 60
f: (all/60)
time: String = ""
f<10{
time= "0(f):"
{
"(f)"
}
m<10{
time+= "0(m)"
{
"(m)"
}
//更新播放时间
.playTime!.text=time
}
}
//拖动进度条改变值时触发
playbackSliderValueChanged(_ sender: ) {
//播放器定位到对应的位置
audioPlayer.seek(toTime: Double (playbackSlider.value))
//如果当前时暂停状态,则继续播放
state == .paused
{
audioPlayer.resume()
}
}
didReceiveMemoryWarning() {
.didReceiveMemoryWarning()
}
}
//Audio Player相关代理方法
extension STKAudioPlayerDelegate {
//开始播放歌曲
audioPlayer(_ audioPlayer: didStartPlayingQueueItemId queueItemId: NSObject ) {
index = (queue.index { $0.url == queueItemId as ! }) {
currentIndex = index
}
}
//缓冲完毕
didFinishBufferingSourceWithQueueItemId queueItemId: ) {
updateNowPlayingInfoCenter()
}
//播放状态变化
stateChanged state: previousState: ) {
.state = state
state != .stopped && state != .error && state != .disposed {
}
updateNowPlayingInfoCenter()
}
//播放结束
didFinishPlayingQueueItemId queueItemId: with stopReason: STKAudioPlayerStopReason andProgress progress: Double ) {
index = (queue.index {
$0.url == audioPlayer.currentlyPlayingQueueItemId() URL
}) {
currentIndex = index
}
//自动播放下一曲
stopReason == .eof {
next()
else stopReason == .error {
stop()
resetAudioPlayer()
}
}
//发生错误
unexpectedError errorCode: STKAudioPlayerErrorCode ) {
( "Error when playing music (errorCode)" )
resetAudioPlayer()
}
//更新当前播放信息
updateNowPlayingInfoCenter() {
currentIndex >= 0 {
music = queue[currentIndex]
//更新标题
titleLabel.text = "当前播放:(music.name)"
//更新暂停按钮名字
pauseBtnTitle = .state == .playing ? "暂停" : "继续"
pauseBtn.setTitle(pauseBtnTitle, : .normal)
//设置进度条相关属性
playbackSlider!.maximumValue = Float (audioPlayer.duration)
{
//停止播放
"播放停止!"
//更新进度条和时间标签
playbackSlider.value = 0
playTime.text = "--:--"
}
}
}
//歌曲类
{
name: String
URL
//类构造函数
init (name: ){
.name = name
.url = url
}
}
源码下载: hangge_1667.zip

原文出自: www.hangge.com 转载请保留原文链接: http://www.hangge.com/blog/cache/detail_1667.html

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读