文章結(jié)束后實(shí)現(xiàn):
- 用戶點(diǎn)擊 錄音按鈕 錄制聲音
- 松開 錄音按鈕 的時候,音頻文件轉(zhuǎn)換為 mp3 格式上傳到服務(wù)器
- 點(diǎn)擊 播發(fā)按鈕 播放之前錄制的聲音文件
需要的類
1: 導(dǎo)入 AVFoundation 框架,使用:
- AVAudioRecorder履怯, 聲音錄制
- AVAudioPlayer回还, 聲音播放
2: 需要 lame 進(jìn)行聲音轉(zhuǎn)化
plist 配置
允許使用麥克風(fēng)
屏幕快照 2017-07-19 下午5.10.08.png
代碼
示例代碼:
import UIKit
import AVFoundation
class ViewController: UIViewController {
private var session: AVAudioSession!
private var recorder: AVAudioRecorder!
private var player: AVAudioPlayer!
private var pcmPath: String!
private var mp3FilePath: String!
private var recorderSetting: [String: AnyObject]!
private var mp3FileURL: URL!
private let avSampleRateKey = 44100
override func viewDidLoad() {
super.viewDidLoad()
session = AVAudioSession.sharedInstance()
try! session.setActive(true)
let docDic = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
pcmPath = docDic + "/play.pcm"
mp3FilePath = docDic + "/play.mp3"
mp3FileURL = URL(fileURLWithPath: mp3FilePath)
recorderSetting =
[
AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM),
AVNumberOfChannelsKey: 2 as AnyObject, //錄音的聲道數(shù),立體聲為雙聲道
AVEncoderAudioQualityKey : AVAudioQuality.max.rawValue as AnyObject,
AVEncoderBitRateKey : 640000 as AnyObject,
AVSampleRateKey : avSampleRateKey as AnyObject //錄音器每秒采集的錄音樣本數(shù)
]
}
@IBAction func touchDown() {
do {
try session.setCategory(AVAudioSessionCategoryPlayAndRecord)
recorder = try AVAudioRecorder(url: URL(string: pcmPath)!, settings: recorderSetting)
recorder.isMeteringEnabled = true
recorder.record()
} catch let error {
print("create recorder error: \(error)")
}
}
@IBAction func touchUp() {
recorder.stop()
DispatchQueue.global().async {
let success = AudioTransform.transformToMp3(fromPath: self.pcmPath,
toMp3Path: self.mp3FilePath,
withAVSampleRateKey: Int32(self.avSampleRateKey))
DispatchQueue.main.async {
print("transform success")
if success {
do {
let data = try Data(contentsOf: self.mp3FileURL!)
print("data: \(data)")
DemoModel.uploadRecord(data: data) { (success, info) in
}
} catch let error {
print("upload audio error: \(error)")
}
}
}
}
}
@IBAction func play() {
do {
try session.setCategory(AVAudioSessionCategoryPlayback)
player = try AVAudioPlayer(contentsOf: recorder.url)
player.play()
} catch let error {
print("paly audio error: \(error)")
}
}
}
注意需要為 錄制按鈕 實(shí)現(xiàn):
- touchDown 事件(按住按鈕觸發(fā))
- touchUpInside 事件(松開按鈕觸發(fā))
轉(zhuǎn)化為 mp3 代碼:
#import "lame.h"
@implementation AudioTransform
+ (BOOL)transformToMp3FromPath:(NSString *)originalPath
toMp3Path:(NSString *)mp3Path
withAVSampleRateKey:(int)rateKey {
@try {
int read, write;
FILE *pcm = fopen([originalPath cStringUsingEncoding:1], "rb"); //source
fseek(pcm, 4*1024, SEEK_CUR); //skip file header
FILE *mp3 = fopen([mp3Path cStringUsingEncoding:1], "wb"); //output
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE*2];
unsigned char mp3_buffer[MP3_SIZE];
lame_t lame = lame_init();
lame_set_in_samplerate(lame, rateKey);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
read = (int)fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
if (read == 0)
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
else
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
lame_close(lame);
fclose(mp3);
fclose(pcm);
}
@catch (NSException *exception) {
NSLog(@"%@",[exception description]);
return false;
}
@finally {
return true;
}
}
@end
注意:需要使用 lame 這個小插件實(shí)現(xiàn)轉(zhuǎn)化叹洲,lame下載地址柠硕。你也可以直接使用Demo內(nèi)的 fat-lame 里面是已經(jīng)編譯好的文件 (轉(zhuǎn)化文件是用 Objective-C 寫的,在 Swift 項(xiàng)目中需要一個bridge 文件)
屏幕快照 2017-07-19 下午5.33.17.png
錄制完聲音后运提,如果播放的時候發(fā)現(xiàn) 聲音變小
在播放聲音的方法內(nèi)設(shè)置:
try! session.setCategory(AVAudioSessionCategoryPlayback)
錄制聲音的方法內(nèi)設(shè)置:
try! session.setCategory(AVAudioSessionCategoryPlayAndRecord)
參考鏈接:
音頻的文件格式和數(shù)據(jù)格式