-
Notifications
You must be signed in to change notification settings - Fork 8
/
ViewController.swift
128 lines (96 loc) · 3.49 KB
/
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
//
// ViewController.swift
// MicRec
//
// Created by Valerii Lider on 9/20/16.
// Copyright © 2016 Valerii Lider. All rights reserved.
//
import UIKit
import AVFoundation
class ViewController: UIViewController {
// engine for getting audio pcm stream
var engine: AVAudioEngine?
// lame codec
var lame: lame_t?
// buffer for converting from pcm to mp3
var mp3buf = UnsafeMutablePointer<UInt8>.allocate(capacity: 4096)
// this is for testing purposes
var file = NSMutableData()
deinit {
mp3buf.deallocate(capacity: 4096)
// @TODO: possibly need to release resources taken by lame
}
override func viewDidLoad() {
super.viewDidLoad()
// initialize engine
engine = AVAudioEngine()
guard nil != engine?.inputNode else {
// @TODO: error out
return
}
// setup lame codec
prepareLame()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func startRecording(_: UIControl) {
installTap()
}
@IBAction func stopRecording(_: UIControl) {
removeTap()
}
func prepareLame() {
guard let engine = engine, let input = engine.inputNode else {
// @TODO: error out
return
}
let sampleRate = Int32(input.inputFormat(forBus: 0).sampleRate)
lame = lame_init()
lame_set_in_samplerate(lame, sampleRate / 2)
lame_set_VBR(lame, vbr_default/*vbr_off*/)
lame_set_out_samplerate(lame, 0) // which means LAME picks best value
lame_set_quality(lame, 4); // normal quality, quite fast encoding
lame_init_params(lame)
}
func installTap() {
engine = AVAudioEngine()
guard let engine = engine, let input = engine.inputNode else {
// @TODO: error out
return
}
let format = input.inputFormat(forBus: 0)
input.installTap(onBus: 0, bufferSize:4096, format:format, block: { [weak self] buffer, when in
guard let this = self else {
return
}
if let channel1Buffer = buffer.floatChannelData?[0] {
/// encode PCM to mp3
let frameLength = Int32(buffer.frameLength) / 2
let bytesWritten = lame_encode_buffer_interleaved_ieee_float(this.lame, channel1Buffer, frameLength, this.mp3buf, 4096)
// `bytesWritten` bytes stored in this.mp3buf now mp3-encoded
print("\(bytesWritten) encoded")
this.file.append(this.mp3buf, length: Int(bytesWritten))
// @TODO: send data, better to pass into separate queue for processing
}
})
engine.prepare()
do {
try engine.start()
} catch {
// @TODO: error out
}
}
func removeTap() {
engine?.inputNode?.removeTap(onBus: 0)
engine = nil
do {
var url = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
url.appendPathComponent("mic.mp3")
file.write(to: url, atomically: true)
print("path: \(url)")
} catch {
}
}
}