iOS 使用AudioQueue進行錄音

一般情況下,如果我們只需要實現(xiàn)簡單的錄音功能,那我們可以使用AVAudioRecorder這個類就可以了变秦,優(yōu)點是容易使用,系統(tǒng)已經(jīng)幫我們把功能都封裝好了席爽,缺點就是難以做更加細致的控制意荤。
我們項目里由于涉及到音頻數(shù)據(jù)編碼,所以使用的是AudioQueue來實現(xiàn)只锻。

實現(xiàn)原理:
首先看下蘋果官方提供的原理圖:

image.png

我們可以看到其實AudioQueue就是一個處理輸入和輸出過程玖像。
AudioQueue有一個緩沖區(qū)隊列,硬件設(shè)備采集到數(shù)據(jù)后炬藤,填充到緩沖區(qū)御铃,然后我們通過回調(diào)函數(shù)拿到緩沖區(qū)的數(shù)據(jù),依次寫入文件或者進行其他操作沈矿。

實現(xiàn)步驟:
先定義好用到的參數(shù):

@interface YTAudioRecordManager() {
    AudioQueueRef audioQRef;       //音頻隊列對象指針
    AudioStreamBasicDescription recordFormat;   //音頻流配置
    AudioQueueBufferRef audioBuffers[YBufferCount];  //音頻流緩沖區(qū)對象
}

@property(nonatomic,strong)NSString* recordFileName;  //音頻目錄
@property(nonatomic,assign)AudioFileID recordFileID;   //音頻文件標識  用于關(guān)聯(lián)音頻文件
@property(nonatomic,assign)SInt64 recordPacket;  //錄音文件的當前包

配置好音頻流的采集參數(shù)以及要寫入的文件路勁:

-  (void)initFormat {
    recordFormat.mSampleRate =  YDefaultSampleRate;  //采樣率
    recordFormat.mChannelsPerFrame = YDefalutChannel; //聲道數(shù)量
    //編碼格式
    recordFormat.mFormatID = kAudioFormatLinearPCM;
    recordFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
    //每采樣點占用位數(shù)
    recordFormat.mBitsPerChannel = YBitsPerChannel;
    //每幀的字節(jié)數(shù)
    recordFormat.mBytesPerFrame = (recordFormat.mBitsPerChannel / 8) * recordFormat.mChannelsPerFrame;
    //每包的字節(jié)數(shù)
    recordFormat.mBytesPerPacket = recordFormat.mBytesPerFrame;
    //每幀的字節(jié)數(shù)
    recordFormat.mFramesPerPacket = 1;
}
- (void)initFile {
    self.recordFileName = [YTRecordFileManager cacheFileWidthPath:@"tempRecordPath" Name:@"tempRecord.wav"] ;
    NSLog(@"recordFile:%@",_recordFileName);
}

設(shè)計音頻流輸入信息和回調(diào)發(fā)方法上真,關(guān)聯(lián)文件路徑和AudioFileID,

- (void)initAudio {
    //設(shè)置音頻輸入信息和回調(diào)
    OSStatus status = AudioQueueNewInput(&recordFormat, inputBufferHandler, (__bridge void *)(self), NULL, NULL, 0, &audioQRef);
    
    if( status != kAudioSessionNoError )
    {
        NSLog(@"初始化出錯");
        return ;
    }
    
    
    CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, (CFStringRef)self.recordFileName, NULL);
    //創(chuàng)建音頻文件
    AudioFileCreateWithURL(url, kAudioFileCAFType, &recordFormat, kAudioFileFlags_EraseFile,&_recordFileID);
    CFRelease(url);
    
    //計算估算的緩存區(qū)大小
    int frames = [self computeRecordBufferSize:&recordFormat seconds:YBufferDurationSeconds];
    int bufferByteSize = frames * recordFormat.mBytesPerFrame;
    //        NSLog(@"緩存區(qū)大小%d",bufferByteSize);
    //創(chuàng)建緩沖器
    for (int i = 0; i < YBufferCount; i++){
        AudioQueueAllocateBuffer(audioQRef, bufferByteSize, &audioBuffers[i]);
        AudioQueueEnqueueBuffer(audioQRef, audioBuffers[i], 0, NULL);
    }
    
    self.recordPacket = 0;
}

開始錄音

{  
    //當有音頻設(shè)備(比如播放音樂)導致改變時 需要配置
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    [[AVAudioSession sharedInstance] setActive:YES error:nil];
    //開始錄音
    OSStatus status = AudioQueueStart(audioQRef, NULL);
    if( status != kAudioSessionNoError )
    {
        NSLog(@"開始出錯");
        return;
    }
    self.isRecording = true;
    

    
}

回調(diào)函數(shù)處理:

void inputBufferHandler(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime,UInt32 inNumPackets, const AudioStreamPacketDescription *inPacketDesc)
{
    YTAudioRecordManager *audioManager = [YTAudioRecordManager sharedManager];
    if (inNumPackets > 0) {
        //寫入文件
        AudioFileWritePackets(audioManager.recordFileID, FALSE, inBuffer->mAudioDataByteSize,inPacketDesc, audioManager.recordPacket, &inNumPackets, inBuffer->mAudioData);
    //記錄位置
        audioManager.recordPacket += inNumPackets;
   //此處可以對音頻數(shù)據(jù)進行采集羹膳,以供其他處理睡互。
    }
    if (audioManager.isRecording) {
       //把Buffer重新插回AudioQueue內(nèi)置的Buffer隊列中,以便循環(huán)使用
        AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
    }
    
}

停止錄音:

- (void)stopRecord
{
    if (self.isRecording)
    {
        self.isRecording = NO;
        //停止錄音隊列和移陵像,這里無需考慮成功與否
        AudioQueueStop(audioQRef, true);
        AudioFileClose(_recordFileID);
    
    }
}

對象釋放的時候銷毀:

- (void)dealloc {
    AudioQueueDispose(audioQRef, TRUE);
    AudioFileClose(_recordFileID);
}

將錄制好的本地音頻進行播放:使用AudioQueue進行音頻播放

github地址:https://github.com/yitezh/YTPressRecordView

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末就珠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子醒颖,更是在濱河造成了極大的恐慌妻怎,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泞歉,死亡現(xiàn)場離奇詭異逼侦,居然都是意外死亡,警方通過查閱死者的電腦和手機腰耙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門榛丢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人挺庞,你說我怎么就攤上這事晰赞。” “怎么了选侨?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵掖鱼,是天一觀的道長。 經(jīng)常有香客問我援制,道長锨用,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任隘谣,我火速辦了婚禮增拥,結(jié)果婚禮上啄巧,老公的妹妹穿的比我還像新娘。我一直安慰自己掌栅,他們只是感情好秩仆,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著猾封,像睡著了一般澄耍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晌缘,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天齐莲,我揣著相機與錄音,去河邊找鬼磷箕。 笑死选酗,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的岳枷。 我是一名探鬼主播芒填,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼空繁!你這毒婦竟也來了殿衰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤盛泡,失蹤者是張志新(化名)和其女友劉穎闷祥,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體傲诵,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡凯砍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掰吕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡颅痊,死狀恐怖殖熟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情斑响,我是刑警寧澤菱属,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站舰罚,受9級特大地震影響纽门,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜营罢,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一赏陵、第九天 我趴在偏房一處隱蔽的房頂上張望饼齿。 院中可真熱鬧,春花似錦蝙搔、人聲如沸缕溉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽证鸥。三九已至,卻和暖如春勤晚,著一層夾襖步出監(jiān)牢的瞬間枉层,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工赐写, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鸟蜡,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓血淌,卻偏偏與公主長得像矩欠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子悠夯,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345