最近一個做安卓的朋友在項目中遇到了類似微信發(fā)送語音消息的功能沸柔,就進行了一些討論最楷,錄音功能很簡單整份,但為了實現(xiàn)錄制的音頻文件在多個平臺都能正常播放(eg:iOS端錄制的文件能夠上傳服務(wù)器后支持在網(wǎng)站或者安卓端播放)待错,一般要將音頻文件轉(zhuǎn)換成MP3格式。而且轉(zhuǎn)換成MP3格式后文件體積將會變小很多烈评。
在網(wǎng)上搜索資料后火俄,發(fā)現(xiàn)關(guān)于音頻文件格式轉(zhuǎn)換的資料并不是很多,自己就相關(guān)資料整理一下寫一個小demo以便以后用到之時能夠返回查閱讲冠。
PCM轉(zhuǎn)MP3格式一般使用lame,首先要對lame庫進行編譯生成我們需要的庫文件和頭文件瓜客。
1. 編譯lame生成庫文件和頭文件
編譯步驟在這篇文章有詳細說明竿开,此處不在贅述谱仪。
2. 錄音準(zhǔn)備
要先實現(xiàn)錄音,需要AVAudioRecorder對象
- (AVAudioRecorder *)recoder
{
if (!_recoder) {
//存放錄音文件的地址
NSString * path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString * filePath = [path stringByAppendingPathComponent:@"123.caf"];
self.recordeFilePath = filePath;
NSURL * url = [NSURL URLWithString:filePath];
self.url = url;
//錄音設(shè)置
NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init];
//設(shè)置錄音格式
[recordSettings setValue :[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey: AVFormatIDKey];
//采樣率 采樣率必須要設(shè)為11025才能使轉(zhuǎn)化成mp3格式后不會失真
[recordSettings setValue :[NSNumber numberWithFloat:11025.0] forKey: AVSampleRateKey];//44100.0
//通道數(shù)要轉(zhuǎn)換成MP3格式必須為雙通道
[recordSettings setValue :[NSNumber numberWithInt:2] forKey: AVNumberOfChannelsKey];
//音頻質(zhì)量,采樣質(zhì)量
[recordSettings setValue:[NSNumber numberWithInt:AVAudioQualityMin] forKey:AVEncoderAudioQualityKey];
//創(chuàng)建錄音對象
_recoder = [[AVAudioRecorder alloc] initWithURL:url settings:recordSettings error:nil];
[_recoder prepareToRecord];
}
return _recoder;
}
3. 音頻文件轉(zhuǎn)碼成MP3格式
在demo中我實現(xiàn)的是錄完之后轉(zhuǎn)碼否彩,但實際上邊錄邊轉(zhuǎn)速度將會更快疯攒。對邊錄邊轉(zhuǎn)的實現(xiàn)可參考這篇文章
lame實現(xiàn)轉(zhuǎn)碼的重要代碼如下:
- (void)convertToMp3
{
NSString *fileName = [NSString stringWithFormat:@"/%@.mp3", @"test"];
NSString *filePath = [[NSHomeDirectory() stringByAppendingFormat:@"/Documents/"] stringByAppendingPathComponent:fileName];
NSLog(@"%@",filePath);
_mp3Url = [NSURL URLWithString:filePath];
@try {
int read,write;
//只讀方式打開被轉(zhuǎn)換音頻文件
FILE *pcm = fopen([self.recordeFilePath cStringUsingEncoding:1], "rb");
fseek(pcm, 4 * 1024, SEEK_CUR);//刪除頭,否則在前一秒鐘會有雜音
//只寫方式打開生成的MP3文件
FILE *mp3 = fopen([filePath cStringUsingEncoding:1], "wb");
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE * 2];
unsigned char mp3_buffer[MP3_SIZE];
//這里要注意列荔,lame的配置要跟AVAudioRecorder的配置一致敬尺,否則會造成轉(zhuǎn)換不成功
lame_t lame = lame_init();
lame_set_in_samplerate(lame, 11025.0);//采樣率
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
//以二進制形式讀取文件中的數(shù)據(jù)
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);
//二進制形式寫數(shù)據(jù)到文件中 mp3_buffer:數(shù)據(jù)輸出到文件的緩沖區(qū)首地址 write:一個數(shù)據(jù)塊的字節(jié)數(shù) 1:指定一次輸出數(shù)據(jù)塊的個數(shù) mp3:文件指針
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
lame_close(lame);
fclose(mp3);
fclose(pcm);
} @catch (NSException *exception) {
NSLog(@"%@",[exception description]);
} @finally {
NSLog(@"MP3生成成功!!!");
}
}
4. 實現(xiàn)過程中遇到的坑
在模擬器上調(diào)試的時候錄制的音頻文件可以正常播放,但在真機上錄制的音頻文件播放時卻沒有聲音肌毅。通過設(shè)置音頻會話分類解決:
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
demo地址筷转,也放入了我編譯的lame庫