天天看點

iOS錄音、播放、WAV以及caf轉成MP3上傳背景

錄音、播放、轉碼

    • 錄音
    • 播放
    • 轉成MP3
    • base64轉碼
    • caf轉碼MP3
    • 調用
    • 分享心得:

錄音

#import <AVFoundation/AVFoundation.h>
#import "lame.h" // 轉成MP3需要該檔案

@interface RecorderTestController ()<AVAudioRecorderDelegate,AVAudioPlayerDelegate>
{
  AVAudioPlayer * player;// 音頻播放
}
@property (nonatomic,strong) AVAudioRecorder * audioRecorder; // 錄音工具
           

開始錄音,下面這部分代碼可以直接複制使用

-(void)startRecordcase{
    //删除上次生成的檔案,保留最新檔案
   NSFileManager *fileManager = [NSFileManager defaultManager];
   //預設就是wav格式,是無損的
    if ([fileManager fileExistsAtPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"testRecorder.WAV"]]) {
        [fileManager removeItemAtPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"testRecorder.WAV"] error:nil];
    
    }
    //錄音設定
    NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
   //設定錄音格式 AVFormatIDKey==kAudioFormatLinearPCM
    [recordSetting setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
   //設定錄音采樣率(Hz) 如:AVSampleRateKey==8000/44100/96000(影響音頻的品質), 采樣率必須要設為11025才能使轉化成mp3格式後不會失真
     [recordSetting setValue:[NSNumber numberWithFloat:8000] forKey:AVSampleRateKey];
     //錄音通道數 1 或 2 ,要轉換成mp3格式必須為雙通道
     [recordSetting setValue:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
    //線性采樣位數 8、16、24、32
    [recordSetting setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
    //錄音的品質
    [recordSetting setValue:[NSNumber numberWithInt:AVAudioQualityMax] forKey:AVEncoderAudioQualityKey];
    [recordSetting setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsNonInterleaved]; //交叉的
    // 設定錄制音頻采用高位優先的記錄格式
    [recordSetting setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
    // 設定采樣信号采用浮點數
    [recordSetting setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
    //存儲錄音檔案
    NSURL * recordUrl = [NSURL URLWithString:[NSTemporaryDirectory()stringByAppendingPathComponent:@"testRecorder.WAV"]];
    //初始化錄音對象
    NSError * error;
    self.audioRecorder = [[AVAudioRecorder alloc] initWithURL:recordUrl settings:recordSetting error:&error];

    if (error) {
        NSLog(@"%@",error.description);
        return;
    }
    self.audioRecorder.delegate = self;
    //開啟音量檢測
    self.audioRecorder.meteringEnabled = YES;
    AVAudioSession * audioSession = [AVAudioSession sharedInstance];//得到音頻會話單例對象
    //如果不是正在錄音
    if (![self.audioRecorder isRecording]) {
        [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];//設定類别,表示該應用同時支援播放和錄音
        [audioSession setActive:YES error:nil];//激活目前應用的音頻會話,此時會阻斷背景音樂的播放.
        [self.audioRecorder prepareToRecord];//準備錄音
        [self.audioRecorder record];//開始錄音
    }
}
//結束錄音
- (void)endRecord
{
    [self.audioRecorder stop];  //錄音停止
}
//錄音結束後代理
-(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
    [[AVAudioSession sharedInstance] setActive:NO error:nil];//一定要在錄音停止以後再關閉音頻會話管理(否則會報錯),此時會延續背景音樂播放
    if (!flag) return;
}
           

播放

- (void)playWav{
//擷取錄音資料
NSData * wavData = [NSData dataWithContentsOfFile:[NSTemporaryDirectory() stringByAppendingPathComponent:@"testRecorder.WAV"]];
NSError * error;

player = [[AVAudioPlayer alloc]initWithData:wavData error:&error];
    player.delegate = self;
    if (error) {
    NSLog(@"語音播放失敗,%@",error);
    return;

}

//播放器的聲音會自動切到receiver,是以聽起來特别小,如果需要從speaker出聲,需要自己設定。
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
// 單獨設定音樂的音量(預設1.0,可設定範圍為0.0至1.0,兩個極端為靜音、系統音量):
player.volume = 1.0;
//    修改左右聲道的平衡(預設0.0,可設定範圍為-1.0至1.0,兩個極端分别為隻有左聲道、隻有右聲道):
player.pan = -1;
//    設定播放速度(預設1.0,可設定範圍為0.5至2.0,兩個極端分别為一半速度、兩倍速度):
player.rate = 2.0;
//    設定循環播放(預設1,若設定值大于0,則為相應的循環次數,設定為-1可以實作無限循環):
player.numberOfLoops = 0;
//調用prepareToPlay方法,這樣可以提前擷取需要的硬體支援,并加載音頻到緩沖區。在調用play方法時,減少開始播放的延遲。
[player prepareToPlay];
//    開始播放音樂:
[player play];
}

//播放完成代理
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
    if (flag) {
		//調用pause或stop來暫停播放,這裡的stop方法的效果也隻是暫停播放,不同之處是stop會撤銷prepareToPlay方法所做的準備。
		[player stop];
		player = nil;
    }
}
           

轉成MP3

-(void)convertToMp3SouceFilePathName:(NSString *)sourcePath isDeleteSourchFile:(BOOL)isDelete
{
    // 輸入路徑
    NSString *inPath = sourcePath;
    // 判斷輸入路徑是否存在
    NSFileManager *fm = [NSFileManager defaultManager];
    if (![fm fileExistsAtPath:sourcePath]) {
        NSLog(@"檔案不存在");
    }
    // 輸出路徑
    NSString *outPath = [[sourcePath stringByDeletingPathExtension] stringByAppendingString:@".MP3"];
    @try {
        int read, write;
        
        FILE *pcm = fopen([inPath cStringUsingEncoding:1], "rb");  //source 被轉換的音頻檔案位置
        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);// 采樣率
        lame_set_num_channels(lame, 2);//通道
        lame_set_quality(lame, 0);//品質 品質範圍0~9。0最好。9最差
        lame_set_VBR(lame, vbr_default);
        lame_set_brate(lame, 8); //設定壓縮比例 預設壓縮比例是11
        lame_init_params(lame);
        do {
            size_t size = (size_t)(2 * sizeof(short int));
            read = (int)fread(pcm_buffer, size, 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;
    }
}
           

base64轉碼

-(NSString *)recordmp3ToBASE64; // mp3格式 base64轉碼
{
    NSString *strdatamp3 = [self convertToMp3SouceFilePathName:[NSTemporaryDirectory() stringByAppendingPathComponent:@"testRecorder.WAV"] isDeleteSourchFile:YES]; // 調用轉碼方法 轉成MP3
    NSData *mp3Data = [[NSData dataWithContentsOfFile:strdatamp3] base64EncodedDataWithOptions:0];
    
    NSString * encodedRecordStr = [[NSString alloc]initWithData:mp3Data encoding:NSUTF8StringEncoding];
    
    return encodedRecordStr;
}
           

caf轉碼MP3

以上就是整個錄音的過程,其中錄音檔案的名稱以及字尾是可以更改的,字尾可以更改為caf格式。

testRecorder.WAV可以更改為testRecorder.caf。更改之後就是caf轉MP3,可以根據項目要求進行格式更換。

調用

完成以上工作之後,就可以在使用的地方直接調用了。必須完成以上代碼!!!

比如開始錄音:

[self startRecordcase];

結束錄音:

[self endRecord];

播放錄音:

[self playWav];

通過接口上傳錄音:

[self recordmp3ToBASE64];

分享心得:

以上就是我在項目上使用的方法。其實在第一次寫轉碼的時候出現了轉碼之後的檔案全部是雜音的問題。找了很長時間才找到原因。

第一:

[recordSetting setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsNonInterleaved]; //交叉的錄制
// 設定錄制音頻采用高位優先的記錄格式
[recordSetting setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
// 設定采樣信号采用浮點數
[recordSetting setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
           

以上三種參數必須設定為No,轉碼之後的MP3檔案就都是雜音。

第二:轉成MP3需要lame檔案。是以必須下載下傳lame檔案。這個在網上是都可以搜到。下載下傳下來的lame檔案包含了兩個,如下圖所示:

iOS錄音、播放、WAV以及caf轉成MP3上傳背景

繼續閱讀