iOS開發(fā)之錄音功能開發(fā)2019-06-06

項(xiàng)目開發(fā)需求

  • 應(yīng)用場(chǎng)景:項(xiàng)目中用到了答疑提問的功能亲桥,這個(gè)功能的應(yīng)用就是學(xué)員端提交答案和教師端回答問題,兩端配合使用固耘,那么考慮到學(xué)員提問的時(shí)候?qū)栴}描述不清晰以及在教師回答問題的時(shí)候更加方便快速题篷,所以就加上了錄音答疑的功能。

音頻相關(guān)知識(shí)介紹:

  1. 文件格式(不同的文件格式厅目,可保存不同的編碼格式的文件)
    1.1 WAV:
    特點(diǎn):音質(zhì)最好的格式番枚,對(duì)應(yīng)PCM編碼
    適用:多媒體開發(fā),保存音樂和音效素材损敷。
    1.2 MP3:
    特點(diǎn):音質(zhì)好葫笼,壓縮比比較高,被大量軟件和硬件支持拗馒。
    適用:適合用于比較高要求的音樂欣賞路星。
    1.3 caf:
    特點(diǎn):適用于幾乎iOS中所有的編碼格式。

  2. 編碼格式
    2.1 PCM
    PCM:脈沖編碼調(diào)制诱桂,是一種非壓縮音頻數(shù)字化技術(shù)洋丐,是一種未壓縮的原音重現(xiàn),數(shù)字模式下访诱,音頻的初始化信號(hào)是PCM.
    2.2 MP3
    2.3 AAC
    AAC:其實(shí)是“高級(jí)音頻編碼(advanced audio coding)”的縮寫垫挨,他是被設(shè)計(jì)用來(lái)取代MPC格式的。
    2.4 HE-AAC
    HE-AAC是AAC的一個(gè)超集触菜,這個(gè)“High efficiency”九榔,HE-AAC是專門為低比特率所優(yōu)化的一種音頻編碼格式。
    2.5 AMR
    AMR全稱是“Adaptive Multi-Rate”涡相,它也是另一個(gè)專門為“說話(speech)”所優(yōu)化的編碼格式哲泊,也是適合低比特率環(huán)境下采用。
    2.6 ALAC
    它全稱是“Apple Lossless”催蝗,這是一種沒有任何質(zhì)量損失的音頻編碼方式切威,也就是我們說的無(wú)損壓縮。
    2.7 IMA4
    IMA4:這是一個(gè)在16-bit音頻文件下按照4:1的壓縮比來(lái)進(jìn)行壓縮的格式丙号。

考慮到服務(wù)端要保證iOS端和安卓端的同樣的效果先朦,因此在iOS端錄音所生成的Caf格式錄音文件轉(zhuǎn)碼為Mp3后進(jìn)行上傳,這樣就保證兩端音頻播放的一致性犬缨。

功能實(shí)現(xiàn)核心代碼

因?yàn)槲視?huì)在文章的最后面附上完整的demo喳魏,因此這里只展示核心代碼部分,以及注意事項(xiàng)怀薛。

  • 創(chuàng)建錄音并設(shè)置參數(shù)
#pragma mark - 創(chuàng)建錄音
-(void)createRecorder{
    
    // Setup audio session
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    
    if ([session respondsToSelector:@selector(requestRecordPermission:)]) {
        
        [session requestRecordPermission:^(BOOL available) {
            
            if (available) {
            }
            else
            {
                dispatch_async(dispatch_get_main_queue(), ^{
                
                    [[[UIAlertView alloc] initWithTitle:@"無(wú)法錄音" message:@"請(qǐng)?jiān)凇霸O(shè)置-隱私-麥克風(fēng)”選項(xiàng)中允許xx訪問你的麥克風(fēng)" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil] show];
                    return ;
                });
            }
        }];
        
    }
    
    //錄音參數(shù)設(shè)置設(shè)置
    NSMutableDictionary *settingDic = [[NSMutableDictionary alloc] init];
    //設(shè)置錄音格式
    [settingDic setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
    //設(shè)置錄音采樣率(Hz) 如:AVSampleRateKey==8000/44100/96000(影響音頻的質(zhì)量)//11025.0
    [settingDic setValue:[NSNumber numberWithFloat:11025.0] forKey:AVSampleRateKey];
    //錄音通道數(shù)  1 或 2
    [settingDic setValue:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
    //線性采樣位數(shù)  8刺彩、16、24、32
    [settingDic setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
    //錄音的質(zhì)量
//    [settingDic setValue:[NSNumber numberWithInt:AVAudioQualityMin] forKey:AVEncoderAudioQualityKey];
    [settingDic setValue:[NSNumber numberWithInt:AVAudioQualityHigh] forKey:AVEncoderAudioQualityKey];
    
    //錄音文件最終地址
    _recordURL=[CDPAudioRecorder getAudioRecordFilePath];
    NSError *error=nil;
    
    //初始化AVAudioRecorder
    _recorder = [[AVAudioRecorder alloc] initWithURL:_recordURL settings:settingDic error:&error];
    //開啟音量分貝數(shù)監(jiān)測(cè)
    _recorder.meteringEnabled = YES;
    _recorder.delegate=self;

    if (_recorder&&[_recorder prepareToRecord]) {
        
    }
    else{
        DLog(@"CDPAudioRecorder錄音初始化失敗error:%@",error);
    }
}
  • 錄音后會(huì)生成Caf格式的文件创倔,然后把文件轉(zhuǎn)化為Mp3格式嗡害,
    現(xiàn)在最主流的就是用lame框架來(lái)實(shí)現(xiàn)啦
    不過lame只支持32位的,這對(duì)64位的很坑
    不過我們可以下載lame的源碼然后自己轉(zhuǎn)成64位的就可以用啦
    下面就是步驟畦攘,跟著動(dòng)起來(lái)吧霸妹!
    一、下載lame的最新版念搬。地址https://sourceforge.net/projects/lame/files/lame/
    這個(gè)就行啦

二抑堡、還需要下載一個(gè)腳本,地址https://github.com/kewlbear/lame-ios-build

三朗徊、這兩個(gè)就是我下載的兩個(gè)文件夾首妖,在桌面上

23011-37ba520e94644c33.png

四、打開lame-ios-build-master 文件爷恳,把里面的build-lame.sh 放到lame-3.99.5 文件夾中

23011-4abbd324556af223.png

五有缆、最重要的來(lái)啦。打開build-lame.sh文件温亲,找到如圖所示的地方棚壁,注釋很清楚啦,保存關(guān)閉

23011-97dfa49b36385464.png

六栈虚、打開終端袖外,cd到lame-3.99.5這個(gè)目錄下,就是下載lame源碼的目錄
輸入

chmod 777 build-lame.sh

再輸入

./build-lame.sh

然后等待編譯魂务,差不多不用1分鐘就編譯完了

七曼验、打開lame-3.99.5目錄,在里面會(huì)看到兩個(gè)文件夾

23011-653317a8338eab4e.png
thin-lame目錄下有幾個(gè)文件夾粘姜,里面放的是不同指令下的我們要用到的.h和.a文件
fat-lame目錄下則是不同指令下合并編譯出來(lái)的.h和.a文件鬓照,也就是我們最終會(huì)用到的

拿到我們想要的就可以去轉(zhuǎn)MP3啦

錄音轉(zhuǎn)換為mp3格式:

- (void)audio_PCMtoMP3 {
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *filePath = [path stringByAppendingPathComponent:@"CDPAudioFiles/CDPAudioRecord.caf"];
    NSString *audioPath = [LameTool audioToMP3:filePath isDeleteSourchFile:NO];
    if ([audioPath isEqualToString:@"fail"]) {
        NSLog(@"上傳失敗");
    } else {
        self.audioString = audioPath;
        [_recorder setRecordURL:[NSURL URLWithString:audioPath]];
    }
    NSLog(@"轉(zhuǎn)碼amr格式成功----文件地址為:%@",filePath);
}
+ (NSString *)audioToMP3: (NSString *)sourcePath isDeleteSourchFile:(BOOL)isDelete {
    
    // 輸入路徑
    NSString *inPath = sourcePath;
    // 判斷輸入路徑是否存在
    NSFileManager *fm = [NSFileManager defaultManager];
    if (![fm fileExistsAtPath:sourcePath]) {
        NSLog(@"文件不存在");
        return @"fail";
    }
    // 輸出路徑
    NSString *outPath = [[sourcePath stringByDeletingPathExtension] stringByAppendingString:@".mp3"];
    @try {
        int read, write;
        
        FILE *pcm = fopen([inPath cStringUsingEncoding:1], "rb");  //source 被轉(zhuǎn)換的音頻文件位置
        
        if(pcm == NULL) {
            NSLog(@"file not found");
            return @"fail";
        }
        fseek(pcm, 4*1024, SEEK_CUR);                                   //skip file header
        FILE *mp3 = fopen([outPath 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, 8000);//8000/11025.0//44100
//        lame_set_VBR(lame, vbr_default);
//        lame_init_params(lame);

        
        lame_t lame = lame_init();
        lame_set_num_channels(lame, 2);//設(shè)置1為單通道,默認(rèn)為2雙通道
        lame_set_in_samplerate(lame, 11025.0);//11025.0
        //lame_set_VBR(lame, vbr_default);
        lame_set_brate(lame, 16);
        lame_set_mode(lame, 3);
        lame_set_quality(lame, 2);
        lame_init_params(lame);

        
        do {
            //size_t size = (size_t)(2 * sizeof(short int));
            //read = fread(pcm_buffer, size, PCM_SIZE, pcm);
            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生成成功:");
        if (isDelete) {
            
            NSError *error;
            [fm removeItemAtPath:sourcePath error:&error];
            if (error == nil) {
                NSLog(@"刪除源文件成功");
            }
        }
        return outPath;
    }
}

注意事項(xiàng):這里的幾個(gè)參數(shù)配置:創(chuàng)建錄音的時(shí)候頻率為多少孤紧,轉(zhuǎn)化為mp3的時(shí)候就使用多少:
錄音:

//設(shè)置錄音采樣率(Hz) 如:AVSampleRateKey==8000/44100/96000(影響音頻的質(zhì)量)//11025.0
   [settingDic setValue:[NSNumber numberWithFloat:11025.0] forKey:AVSampleRateKey];
   //錄音通道數(shù)  1 或 2

轉(zhuǎn)化:

lame_t lame = lame_init();
        lame_set_num_channels(lame, 2);//設(shè)置1為單通道豺裆,默認(rèn)為2雙通道
        lame_set_in_samplerate(lame, 11025.0);//11025.0
        //lame_set_VBR(lame, vbr_default);
        lame_set_brate(lame, 16);
        lame_set_mode(lame, 3);
        lame_set_quality(lame, 2);
        lame_init_params(lame);

到此就結(jié)束了,簡(jiǎn)單的demo如下:

https://github.com/Wululu6/AudioRecordDemo.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末号显,一起剝皮案震驚了整個(gè)濱河市臭猜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌押蚤,老刑警劉巖获讳,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異活喊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門钾菊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)帅矗,“玉大人,你說我怎么就攤上這事煞烫』氪耍” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵滞详,是天一觀的道長(zhǎng)凛俱。 經(jīng)常有香客問我,道長(zhǎng)料饥,這世上最難降的妖魔是什么蒲犬? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮岸啡,結(jié)果婚禮上原叮,老公的妹妹穿的比我還像新娘。我一直安慰自己巡蘸,他們只是感情好奋隶,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著悦荒,像睡著了一般唯欣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上搬味,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天境氢,我揣著相機(jī)與錄音,去河邊找鬼身腻。 笑死产还,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嘀趟。 我是一名探鬼主播脐区,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼她按!你這毒婦竟也來(lái)了牛隅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤酌泰,失蹤者是張志新(化名)和其女友劉穎媒佣,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體陵刹,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡默伍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片也糊。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡炼蹦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狸剃,到底是詐尸還是另有隱情掐隐,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布钞馁,位于F島的核電站虑省,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏僧凰。R本人自食惡果不足惜探颈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望允悦。 院中可真熱鬧膝擂,春花似錦、人聲如沸隙弛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)全闷。三九已至叉寂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間总珠,已是汗流浹背屏鳍。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留局服,地道東北人钓瞭。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像淫奔,于是被迫代替她去往敵國(guó)和親山涡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容