/
SoundEffectsViewController.swift
461 lines (375 loc) · 15.9 KB
/
SoundEffectsViewController.swift
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
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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
/**
* 功能名称: VolcEngineRTC 美声与音效
* 功能简单描述:该功能展示了混响、变声、降噪等功能
* 参考文档:https://www.volcengine.com/docs/6348/1178327
*
* 此功能涉及的API及回调:
* createRTCVideo 创建引擎
* destroyRTCVideo 销毁引擎
* startAudioCapture 开启音频采集
* startVideoCapture 开启视频采集
* createRTCRoom 创建RTC房间
* joinRoom 进入RTC房间
* leaveRoom 离开RTC房间
* destroy 销毁RTC房间
*
* setVoiceReverbType 设置混响特效类型
* setVoiceChangerType 设置变声特效类型
* setLocalVoicePitch 开启本地语音变调功能
* enableLocalVoiceReverb 开启本地音效混响效果
* setLocalVoiceReverbParam 设置本地采集音频的混响效果
* setAnsMode 设置通话中的音频降噪模式
*
* onRoomStateChanged 房间状态回调
* onLeaveRoom 离房回调
* onUserJoined 用户加入回调
* onUserLeave 用户离开回调
* onUserPublishStream 用户发流回调
* onUserUnpublishStream 用户停止发流回调
*
*
* Demo实现时的逻辑
* 本Demo演示功能:美声与音效,演示了各种声音处理特效,使用该功能前请咨询技术人员
* 为了展示简单,所有功能的token都由客户端TokenGenerator类生成,请在真正接入时视具体情况而定
*/
import UIKit
import SnapKit
import VolcEngineRTC
class SoundEffectsViewController: BaseViewController, ByteRTCVideoDelegate, ByteRTCRoomDelegate {
var rtcVideo: ByteRTCVideo?
var rtcRoom: ByteRTCRoom?
override func viewDidLoad() {
super.viewDidLoad()
self.createUI()
self.buildRTCEngine()
self.buildActions()
}
deinit {
self.rtcRoom?.leaveRoom()
self.rtcRoom?.destroy()
self.rtcRoom = nil
ByteRTCVideo.destroyRTCVideo()
self.rtcVideo = nil
}
// MARK: Private method
@objc func joinRoom() {
let roomId = self.roomSettingItem.text ?? ""
let userId = self.userSettingItem.text ?? ""
var vaild = checkValid(roomId)
if vaild == false {
ToastComponents.shared.show(withMessage: "输入不合法,只支持数字、大小写字母、@._-,长度小于128字符")
return
}
vaild = checkValid(userId)
if vaild == false {
ToastComponents.shared.show(withMessage: "输入不合法,只支持数字、大小写字母、@._-,长度小于128字符")
return
}
joinButton.isSelected = !joinButton.isSelected
if joinButton.isSelected {
joinButton.setTitle("离开房间", for: .normal)
// 加入房间
self.rtcRoom = self.rtcVideo?.createRTCRoom(roomId)
self.rtcRoom?.delegate = self
// 获取token,建议从服务端获取
let token = generatorToken(roomId: roomId, userId: userId)
let userInfo = ByteRTCUserInfo.init()
userInfo.userId = userId
let roomCfg = ByteRTCRoomConfig.init()
roomCfg.isAutoPublish = true
roomCfg.isAutoSubscribeAudio = true
roomCfg.isAutoSubscribeVideo = true
self.rtcRoom?.joinRoom(token, userInfo: userInfo, roomConfig: roomCfg)
}
else {
joinButton.setTitle("加入房间", for: .normal)
self.rtcRoom?.leaveRoom()
}
}
func buildRTCEngine() {
// 创建引擎
self.rtcVideo = ByteRTCVideo.createRTCVideo(kAppID, delegate: self, parameters: [:])
// 开启本地音视频采集
self.rtcVideo?.startVideoCapture()
self.rtcVideo?.startAudioCapture()
self.bindLocalRenderView()
}
func bindLocalRenderView() {
// 设置本地渲染视图
let canvas = ByteRTCVideoCanvas.init()
canvas.view = self.localView.videoView
canvas.renderMode = .hidden
self.localView.userId = userSettingItem.text ?? ""
self.rtcVideo?.setLocalVideoCanvas(.indexMain, withCanvas: canvas);
}
func buildActions() {
weak var weakSelf = self
// 变声
self.voiceTypeSheetView.didSelectOption = {(value) in
weakSelf?.rtcVideo?.setVoiceChangerType(ByteRTCVoiceChangerType(rawValue: Int(value))!)
}
// 混响
self.voiceReverbSheetView.didSelectOption = {(value) in
weakSelf?.rtcVideo?.setVoiceReverbType(ByteRTCVoiceReverbType(rawValue: Int(value))!)
}
//变调
self.pitchSetting.onValueChanged = {(value) in
weakSelf?.rtcVideo?.setLocalVoicePitch(Int(value))
}
// 降噪
self.voiceAnsSheetView.didSelectOption = {(value) in
weakSelf?.rtcVideo?.setAnsMode(ByteRTCAnsMode(rawValue: Int(value))!)
}
}
@objc func modifyReverbConfig() {
self.rtcVideo?.enableLocalVoiceReverb(true)
let config = ByteRTCVoiceReverbConfig.init()
config.roomSize = Float(self.roomSizeSetting.valueLabel.text!)!
config.decayTime = Float(self.decayTimeSetting.valueLabel.text!)!
config.damping = Float(self.dampingSetting.valueLabel.text!)!
config.wetGain = Float(self.wetGainSetting.valueLabel.text!)!
config.dryGain = Float(self.dryGainSetting.valueLabel.text!)!
config.preDelay = Float(self.preDelaySetting.valueLabel.text!)!
self.rtcVideo?.setLocalVoiceReverbParam(config)
}
func createUI() -> Void {
// 添加视图
// scrollView
self.view.addSubview(scrollView)
scrollView.snp.makeConstraints { make in
make.top.equalTo(topView.snp.bottom)
make.left.right.bottom.equalToSuperview()
}
// 内容视图
let view = UIView()
scrollView.addSubview(view)
view.snp.makeConstraints { make in
make.edges.equalToSuperview()
make.width.equalToSuperview()
}
// 添加UI
view.addSubview(containerView)
containerView.snp.makeConstraints { make in
make.top.left.right.equalToSuperview()
make.height.equalTo(scrollView).multipliedBy(0.4)
}
containerView.addSubview(localView)
localView.snp.makeConstraints { make in
make.left.top.equalTo(self.containerView)
make.width.height.equalTo(self.containerView)
}
view.addSubview(roomSettingItem)
view.addSubview(userSettingItem)
view.addSubview(joinButton)
roomSettingItem.snp.makeConstraints { make in
make.top.equalTo(containerView.snp.bottom).offset(10)
make.left.equalToSuperview().offset(10)
make.height.equalTo(30)
}
userSettingItem.snp.makeConstraints { make in
make.centerY.equalTo(roomSettingItem)
make.left.equalTo(roomSettingItem.snp.right).offset(20)
make.right.equalToSuperview().offset(-10)
make.width.height.equalTo(roomSettingItem)
}
joinButton.snp.makeConstraints { make in
make.top.equalTo(roomSettingItem.snp.bottom).offset(20)
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
make.height.equalTo(36)
}
view.addSubview(effectLabel)
effectLabel.snp.makeConstraints { make in
make.top.equalTo(joinButton.snp.bottom).offset(20)
make.left.equalToSuperview().offset(10)
}
view.addSubview(voiceTypeSheetView)
view.addSubview(voiceReverbSheetView)
view.addSubview(pitchSetting)
voiceTypeSheetView.snp.makeConstraints { make in
make.top.equalTo(effectLabel.snp.bottom).offset(10)
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
}
voiceReverbSheetView.snp.makeConstraints { make in
make.top.equalTo(voiceTypeSheetView.snp.bottom).offset(10)
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
}
pitchSetting.snp.makeConstraints { make in
make.top.equalTo(voiceReverbSheetView.snp.bottom).offset(10)
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
}
view.addSubview(reverbConfigLabel)
view.addSubview(roomSizeSetting)
view.addSubview(decayTimeSetting)
view.addSubview(dampingSetting)
view.addSubview(wetGainSetting)
view.addSubview(dryGainSetting)
view.addSubview(preDelaySetting)
view.addSubview(modifyReverbButton)
reverbConfigLabel.snp.makeConstraints { make in
make.top.equalTo(pitchSetting.snp.bottom).offset(30)
make.left.equalTo(pitchSetting)
make.right.equalToSuperview().offset(-10)
}
roomSizeSetting.snp.makeConstraints { make in
make.top.equalTo(reverbConfigLabel.snp.bottom).offset(20)
make.left.equalTo(reverbConfigLabel)
make.right.equalToSuperview().offset(-10)
}
decayTimeSetting.snp.makeConstraints { make in
make.top.equalTo(roomSizeSetting.snp.bottom).offset(20)
make.left.equalTo(reverbConfigLabel)
make.right.equalToSuperview().offset(-10)
}
dampingSetting.snp.makeConstraints { make in
make.top.equalTo(decayTimeSetting.snp.bottom).offset(20)
make.left.equalTo(roomSizeSetting)
make.right.equalToSuperview().offset(-10)
}
wetGainSetting.snp.makeConstraints { make in
make.top.equalTo(dampingSetting.snp.bottom).offset(20)
make.left.equalTo(dampingSetting)
make.right.equalToSuperview().offset(-10)
}
dryGainSetting.snp.makeConstraints { make in
make.top.equalTo(wetGainSetting.snp.bottom).offset(20)
make.left.equalTo(wetGainSetting)
make.right.equalToSuperview().offset(-10)
}
preDelaySetting.snp.makeConstraints { make in
make.top.equalTo(dryGainSetting.snp.bottom).offset(20)
make.left.equalTo(dryGainSetting)
make.right.equalToSuperview().offset(-10)
}
modifyReverbButton.snp.makeConstraints { make in
make.top.equalTo(preDelaySetting.snp.bottom).offset(20)
make.left.equalTo(preDelaySetting)
make.right.equalToSuperview().offset(-10)
}
view.addSubview(ansLabel)
view.addSubview(voiceAnsSheetView)
ansLabel.snp.makeConstraints { make in
make.top.equalTo(modifyReverbButton.snp.bottom).offset(20)
make.left.equalTo(modifyReverbButton)
}
voiceAnsSheetView.snp.makeConstraints { make in
make.top.equalTo(ansLabel.snp.bottom).offset(10)
make.left.equalTo(modifyReverbButton)
make.right.equalToSuperview().offset(-10)
make.bottom.equalToSuperview().offset(-10)
}
}
// MARK: Lazy laod
lazy var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.showsVerticalScrollIndicator = false
return scrollView
}()
lazy var roomSettingItem: TextFieldView = {
let settingView = TextFieldView()
settingView.title = "房间"
return settingView
}()
lazy var userSettingItem: TextFieldView = {
let settingView = TextFieldView()
settingView.title = "用户"
return settingView
}()
lazy var joinButton: UIButton = {
let button = BaseButton()
button.setTitle("加入房间", for: .normal)
button.addTarget(self, action: #selector(joinRoom), for: .touchUpInside)
return button
}()
lazy var effectLabel: UILabel = {
let label = UILabel()
label.text = "特效"
label.font = UIFont.boldSystemFont(ofSize: 18)
return label
}()
lazy var voiceTypeSheetView: ActionSheetView = {
let actionSheetView = ActionSheetView.init(title: "变声特效", optionArray: ["Original","Giant","Chipmunk","Minionst","Vibrato","Robot"], defaultIndex: 0)
actionSheetView.presentingViewController = self
return actionSheetView
}()
lazy var voiceReverbSheetView: ActionSheetView = {
let actionSheetView = ActionSheetView.init(title: "混响特效", optionArray: ["Original","Echo","Concert","Ethereal","KTV","Studio","VirtualStereo","Spacious","3D"], defaultIndex: 0)
actionSheetView.presentingViewController = self
return actionSheetView
}()
lazy var pitchSetting: SliderView = {
let settingView = SliderView(minValue: -12, maxValue: 12, defaultValue: 0)
settingView.title = "变调"
return settingView
}()
lazy var reverbConfigLabel: UILabel = {
let label = UILabel()
label.text = "混响配置"
label.font = effectLabel.font
return label
}()
lazy var roomSizeSetting: SliderView = {
let settingView = SliderView(minValue: 0, maxValue: 100, defaultValue: 50)
settingView.title = "房间大小"
return settingView
}()
lazy var decayTimeSetting: SliderView = {
let settingView = SliderView(minValue: 0, maxValue: 100, defaultValue: 50)
settingView.title = "拖尾长度"
return settingView
}()
lazy var dampingSetting: SliderView = {
let settingView = SliderView(minValue: 0, maxValue: 100, defaultValue: 50)
settingView.title = "衰减阻尼大小"
return settingView
}()
lazy var wetGainSetting: SliderView = {
let settingView = SliderView(minValue: -20, maxValue: 10, defaultValue: 0)
settingView.title = "早期反射信号强度"
return settingView
}()
lazy var dryGainSetting: SliderView = {
let settingView = SliderView(minValue: -20, maxValue: 10, defaultValue: 0)
settingView.title = "原始信号强度"
return settingView
}()
lazy var preDelaySetting: SliderView = {
let settingView = SliderView(minValue: 0, maxValue: 200, defaultValue: 0)
settingView.title = "早期反射信号延迟"
return settingView
}()
lazy var modifyReverbButton: UIButton = {
let button = BaseButton()
button.setTitle("确认修改", for: .normal)
button.addTarget(self, action: #selector(modifyReverbConfig), for: .touchUpInside)
return button
}()
lazy var ansLabel: UILabel = {
let label = UILabel()
label.text = "降噪模式"
label.font = effectLabel.font
return label
}()
lazy var voiceAnsSheetView: ActionSheetView = {
let actionSheetView = ActionSheetView.init(title: "音频降噪", optionArray: ["Disable","Low","Medium","High","Automatic"], defaultIndex: 0)
actionSheetView.presentingViewController = self
return actionSheetView
}()
lazy var containerView: UIView = {
let view = UIView.init()
view.backgroundColor = .groupTableViewBackground
return view
}()
lazy var localView: UserVideoView = {
let view = UserVideoView.init()
return view
}()
// MARK: ByteRTCVideoDelegate & ByteRTCRoomDelegate
//进房状态
func rtcRoom(_ rtcRoom: ByteRTCRoom, onRoomStateChanged roomId: String, withUid uid: String, state: Int, extraInfo: String) {
ToastComponents.shared.show(withMessage: "onRoomStateChanged uid: \(uid) state:\(state)")
}
}