最近折騰了Swift的語音錄制識別和轉碼,這塊還是比較坑的,由于語音識別的準確度實測大概也就80%左右,所以還是需要上傳錄音文件啊。首先是用訊飛語音SDK實現語音錄制和識別(語音聽寫),第一個坑是訊飛SDK只錄制了PCM格式的文件,這個文件是原始格式,默認比較大,另外播放器支持也不好,因此需要先把它轉成mp3,本來考慮使用系統的AudioConverter轉aac格式,不過aac好像不能在瀏覽器上播放。
轉成mp3需要lame庫支持,注意國內網搜到的lame.a庫不支持64位,所以現在不能用了,第二個坑啊。
還好已經有人做了這個事情,直接提供了最新編譯腳本和編譯好的framework庫,地址是https://github.com/wuqiong/mp3lame-for-iOS
我直接用了上面編譯的framework,沒有自己去編譯,直接把lame.framework拖到工程里。然后需要用oc寫個封裝類,我不確定這個封裝類能不能用swift寫,畢竟里面用了很多c的語法,還是用oc橋接一層比較保險。oc封裝類如下:
#import#import "AudioWrapper.h"
#import "lame/lame.h"
@implementation AudioWrapper
+ (void)audioPCMtoMP3 :(NSString *)audioFileSavePath :(NSString *)mp3FilePath
{
@try {
int read, write;
FILE *pcm = fopen([audioFileSavePath cStringUsingEncoding:1], "rb");? //source 被轉換的音頻文件位置
fseek(pcm, 4*1024, SEEK_CUR);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //skip file header
FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb");? //output 輸出生成的Mp3文件位置
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, 11025.0);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
read = 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]);
}
@finally {
NSLog(@"MP3 converted: %@",mp3FilePath);
}
}
@end
然后在橋接文件XXX-Bridging-Header.h中加入
#import "AudioWrapper.h"
最后 swift文件的調用如下:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
AudioWrapper.audioPCMtoMP3(path, pathMp3)
}
我覺得在主線程調用容易出問題,就新開了個線程調用,實測沒有問題。 如果需要轉碼的錄音文件時間長,必須放在新線程里面異步處理。