iOS 12 swift 开发(一)之录音

跟着佩奇一起唱–whistle

程序目标:实现录音以及播放功能

开发平台:Xcode 10

语言:swift

目标平台: iOS 12

实现步骤:

1. 首先建立一个single view 的iOS应用,在storyboard上添加三个按钮,”Start”, “Stop”, “Play”,分别对应app要实现的开始录音,结束录音和播放音频的操作UI

2. 获取语音授权

首先在Info.plist中找到Information Property List,点击添加在下拉菜单中选择
Privacy - Microphone Usage Description,然后在value中随意输入向用户询问许可时的文字。

下面的代码用于获取用户对麦克风的授权

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
func checkAuthoriztion(){
status = AVCaptureDevice.authorizationStatus(for: AVMediaType.audio)
if (status == .notDetermined){
print("Not determined")
}
if (status == .restricted)
{
print("restricted")
}
if (status == .denied){
print("denied")
}
if (status == .authorized){
print("Authorized")
return
}
// 获取麦克风权限
AVCaptureDevice.requestAccess(for: AVMediaType.audio, completionHandler: { (granted: Bool) -> Void in
if(granted){
//受限制
self.status = AVAuthorizationStatus.restricted
exit(0)
}
})

}

3. 在ViewController类中添加这三个按钮对应的响应代码:

3.1 开始录音

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
@IBAction func startRecord(_ sender: UIButton) {
checkAuthoriztion()
let session = AVAudioSession.sharedInstance()
//设置session类型
do {
try session.setCategory(AVAudioSession.Category.playAndRecord)
} catch let err{
print("设置类型失败:\(err.localizedDescription)")
}
//设置session动作
do {
try session.setActive(true)
} catch let err {
print("初始化动作失败:\(err.localizedDescription)")
}
//录音设置,注意,后面需要转换成NSNumber,如果不转换,你会发现,无法录制音频文件,我猜测是因为底层还是用OC写的原因
let recordSetting: [String: Any] = [AVSampleRateKey: NSNumber(value: 16000),//采样率
AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM),//音频格式
AVLinearPCMBitDepthKey: NSNumber(value: 16),//采样位数
AVNumberOfChannelsKey: NSNumber(value: 1),//通道数
AVEncoderAudioQualityKey: NSNumber(value: AVAudioQuality.min.rawValue)//录音质量
];
//开始录音
do {
let url = URL(fileURLWithPath: file_path!)
recorder = try AVAudioRecorder(url: url, settings: recordSetting)
recorder!.prepareToRecord()
recorder!.record()
print("开始录音")
} catch let err {
print("录音失败:\(err.localizedDescription)")
}
}

3.2 结束录音

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@IBAction func stopRecord(_ sender: UIButton) {
//结束录音
if let recorder = self.recorder {
if recorder.isRecording {
print("正在录音,马上结束它,文件保存到了:\(file_path!)")
}else {
print("没有录音,但是依然结束它")
}
recorder.stop()
self.recorder = nil
}else {
print("没有初始化")
}
}

3.3 播放录音文件

1
2
3
4
5
6
7
8
9
10
@IBAction func play(_ sender: UIButton) {
//播放
do {
player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: file_path!))
print("歌曲长度:\(player!.duration)")
player!.play()
} catch let err {
print("播放失败:\(err.localizedDescription)")
}
}

4. 实时显示录音分贝

在故事板添加Label控件,设置定时器,实时显示录音时的分贝值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 初始化一个Timer类型的定时器,并触发定时更新分贝值的函数
func startTimer()
{
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateMeter), userInfo: nil, repeats: true)
timer!.fire()
}

func stoptTimer()
{
if timer != nil {
timer!.invalidate() //销毁timer
timer = nil
}
}

//更新分贝值的函数
@objc func updateMeter()
{
recorder?.updateMeters()
audioLevel = (recorder?.averagePower(forChannel: 0))!
level.text = String(audioLevel)
}

完整代码(ViewController.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
//  Created by 姜帆 on 2019/4/23.
// Copyright © 2019 姜帆. All rights reserved.
//
import Foundation
import AVFoundation
import UIKit

class ViewController: UIViewController {
var status: AVAuthorizationStatus!
var recorder: AVAudioRecorder?
var player: AVAudioPlayer?
let file_path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first?.appending("/record.wav")
@IBOutlet weak var Start: UIButton!
@IBOutlet weak var Stop: UIButton!
@IBOutlet weak var Play: UIButton!
@IBOutlet weak var level: UILabel!
var audioLevel: Float = 0.0
var timer: Timer?

func checkAuthoriztion(){
status = AVCaptureDevice.authorizationStatus(for: AVMediaType.audio)
if (status == .notDetermined){
print("Not determined")
}
if (status == .restricted)
{
print("restricted")
}
if (status == .denied){
print("denied")
}
if (status == .authorized){
print("Authorized")
return
}
// 获取麦克风权限
AVCaptureDevice.requestAccess(for: AVMediaType.audio, completionHandler: { (granted: Bool) -> Void in
if(granted){
//受限制
self.status = AVAuthorizationStatus.restricted
exit(0)
}
})

}

func startTimer()
{
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateMeter), userInfo: nil, repeats: true)
timer!.fire()
}

func stoptTimer()
{
if timer != nil {
timer!.invalidate() //销毁timer
timer = nil
}
}

@objc func updateMeter()
{
recorder?.updateMeters()
audioLevel = (recorder?.averagePower(forChannel: 0))!
level.text = String(audioLevel)
}


@IBAction func startRecord(_ sender: UIButton) {
checkAuthoriztion()
let session = AVAudioSession.sharedInstance()
//设置session类型
do {
try session.setCategory(AVAudioSession.Category.playAndRecord)
} catch let err{
print("设置类型失败:\(err.localizedDescription)")
}
//设置session动作
do {
try session.setActive(true)
} catch let err {
print("初始化动作失败:\(err.localizedDescription)")
}
//录音设置,注意,后面需要转换成NSNumber,如果不转换,你会发现,无法录制音频文件,我猜测是因为底层还是用OC写的原因
let recordSetting: [String: Any] = [AVSampleRateKey: NSNumber(value: 16000),//采样率
AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM),//音频格式
AVLinearPCMBitDepthKey: NSNumber(value: 16),//采样位数
AVNumberOfChannelsKey: NSNumber(value: 1),//通道数
AVEncoderAudioQualityKey: NSNumber(value: AVAudioQuality.min.rawValue)//录音质量
];
//开始录音
do {
let url = URL(fileURLWithPath: file_path!)
recorder = try AVAudioRecorder(url: url, settings: recordSetting)
recorder!.isMeteringEnabled = true
recorder!.prepareToRecord()
recorder!.record()
startTimer()
print("开始录音")
}
catch let err {
print("录音失败:\(err.localizedDescription)")
}
}


@IBAction func stopRecord(_ sender: UIButton) {
//结束录音
if let recorder = self.recorder {
if recorder.isRecording {
print("正在录音,马上结束它,文件保存到了:\(file_path!)")
}else {
print("没有录音,但是依然结束它")
}
recorder.stop()
stoptTimer()
self.recorder = nil
}else {
print("没有初始化")
}
}

@IBAction func play(_ sender: UIButton) {
//播放
do {
player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: file_path!))
print("歌曲长度:\(player!.duration)")
player!.play()
}
catch let err {
print("播放失败:\(err.localizedDescription)")
}
}

}
Thank you for every coin~