iOS 录制音频文件,播放,转化成mp3上传

2019-09-18 21:57 来源:未知
在.h文件中添加两个方法//暂停计时- pauseTimer;//继续计时- continueTimer;在.m文件中实现两个方法- pauseTimer { //如果已被释放则return!isValid对应invalidate if (![self isValid]) return; //启动时间为很久以后 [self setFireDate:[NSDate distantFuture]];}- continueTimer { if (![self isValid]) return; //启动时间为现在 [self setFireDate:[NSDate date]];}
二、lame的使用

1、关于AVAudioRecorder的设置如下:

 _settings = [NSMutableDictionary dictionary]; [_settings setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey]; [_settings setObject:@(AudioSampleRateMedium) forKey:AVSampleRateKey]; [_settings setObject:@ forKey:AVNumberOfChannelsKey]; //双声道 [_settings setObject:@(AVAudioQualityHigh) forKey:AVEncoderAudioQualityKey];

这里要两点要注意1、录音格式一定要为pcm即 kAudioFormatLinearPCM;*** 2、音频声道要设置为双声道;***

2、转MP3的核心代码:

@try { int read, write; FILE *pcm = fopen([self.originalDataPath cStringUsingEncoding:1], "rb");//source fseek(pcm, 4*1024, SEEK_CUR); //skip file header FILE *mp3 = fopen([self.mp3DataPath cStringUsingEncoding:1], "wb"); //output 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, AudioSampleRateMedium); lame_set_VBR(lame, vbr_default); lame_init_params; 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; fclose; fclose; } @catch (NSException *exception) { NSLog(@"%@",[exception description]); } @finally { NSString *textValue = [NSString stringWithFormat:@"转换成功:%@", self.mp3DataPath]; NSLog(@"%@", textValue); [self excuteDelegateMethod:@"转码成功"]; }

这里有一点需要注意下:采样率的设置要和AVAudioRecorder设置的采样率保持一致,即AudioSampleRateMedium,当然也可以选择更高的采样率,这里使用的采样率大小是44100。(如果两者不一致会导致转换后的mp3文件有杂音或者播放节奏较快)。 转换的核心代码可以直接复制使用,这里的转换是在录音完成之后,再进行MP3的转换。更好的方式是一边录一边进行MP3的转换,当录音完成后,便可直接使用MP3格式的音频。边录边转换的代码已整理到demo中,具体使用情况可以参考demo。 大家如果觉得对自己有一丁点儿帮助的话,不需要为我打赏,只要您动动手指为我点个赞即可,谢谢!demo地址...

plist 配置

允许使用麦克风

图片 1

屏幕快照 2017-07-19 下午5.10.08.png

图片 2Key

图片 3HTML5格式支持.png那么需求就来了,由于AVAudioRecorder不能录制编码为MP3,所以就需要我们将录音后的音频文件格式进行转换(注意:AV Foundation和Core Audio提供对MP3数据解码的支持,但是不提供对其进行编码。所以我们要借助第三方库进行MP3编码)。如何转换?lame无疑是一个很好的选择,lame是一个开源音频压缩软件,目前是公认有损质量MP3中压缩效果最好的编码器。接下来直奔主题,介绍一下如何使用lame将音频转为MP3格式。

需要的类

1: 导入 AVFoundation 框架,使用:

  • AVAudioRecorder, 声音录制
  • AVAudioPlayer, 声音播放

2: 需要 lame 进行声音转化

- addTimerLabel { //这个是自己封装的创建label的方法! _timerLabel = [CommonLib createLabelFrame:CGRectMake(20, 120, kScreenWidth - 40, TimerLabelH) text:@"00:00:00" alignment:NSTextAlignmentCenter textColor:[UIColor greenColor] font:TimerLabelH]; [self.view addSubview:_timerLabel];}//要计时当然少不了计时器了,这里计时器设置成每秒更新,因为这里设定的最小时间单位是秒,若最小时间单位是毫秒,就把1.0,改成0.01!这个方法在你点击录音的时候调用- startTimer { _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateSecond:) userInfo:nil repeats:YES];}//执行更新UI的操作,每秒执行- updateSecond:(NSTimer *)timer { _second   ; if (_second == 1) { [self enbleBtn]; } //这个方法是把时间显示成时分秒的形式显示在label上 NSString *timerStr = [self convertTimeToString:_second]; _timerLabel.text = timerStr;} //规范时间格式- (NSString *)convertTimeToString:(NSInteger)second { NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"HH:mm:ss"]; NSDate *date = [formatter dateFromString:@"00:00:00"]; date = [date dateByAddingTimeInterval:second]; NSString *timeString = [formatter stringFromDate:date]; return timeString;}
一、使用lame的准备工作

首先去官网下载lame库,下载后需要将lame库进行编译。编译步骤如下:1、 在桌面上新建一个文件夹,然后将下载后的lame库文件解压命名为lame和编译脚本文件一同放到当前文件中,像这样:

图片 4lame.png现在最新版本是lame-3.99.5,如果上述步骤不按此操作,就需要修改build-lame.sh文件里的内容,否则由于路径问题导致无法编译成功。2、 打开终端,cd到lame-3.99.5目录中,运行脚本,开始编译。编译时间稍微有点长,编译成功后文件内容如下所示:图片 5lame.png

新增加的这几个文件夹分别包含了不同的cpu架构,这里就不详细介绍。如果要支持所有的cpu架构,只需要将fat-lame文件中的内容拖到项目中即可(lame.h和libmp3lame.a)。至此,准备工作完毕。

文章结束后实现:
  • 用户点击 录音按钮 录制声音
  • 松开 录音按钮 的时候,音频文件转换为 mp3 格式上传到服务器
  • 点击 播发按钮 播放之前录制的声音文件

苹果提供了AVAudioRecorder类来让我们进行音频录制,是录音变的非常的便捷!在使用AVAudioRecorder进行录音之前要做几样准备工作,① 、在iOS10及以上,调用系统功能需要在info.plist文件里添加相应的key,如图,在info.plist文件下添加Key: Privacy - Microphone Usage Description, Value值可以自己随便写哦!

继续说说录音的那些事儿。使用AVAudioRecorder实现录音功能时,API里有很多的编码格式可供选择,其中PCM数据是最原始的完全无损的音频数据,所以体积比较庞大,为了解决这个问题,则诞生了一系列的音频编码格式。比如MP3、AAC、OGG、WMA等。而现在主流的音频编码格式则是AAC。(关于AAC和MP3的比较,可以简单地参考这里)。 虽然AAC编码格式比MP3格式好一些,但是可被支持的范围却没MP3大。一些浏览器并不支持播放AAC格式的音频,见下图:

代码

示例代码:

import UIKit
import AVFoundation

class ViewController: UIViewController {

    private var session: AVAudioSession!

    private var recorder: AVAudioRecorder!
    private var player: AVAudioPlayer!

    private var pcmPath: String!
    private var mp3FilePath: String!

    private var recorderSetting: [String: AnyObject]!

    private var mp3FileURL: URL!

    private let avSampleRateKey = 44100

    override func viewDidLoad() {
        super.viewDidLoad()

        session = AVAudioSession.sharedInstance()
        try! session.setActive(true)

        let docDic = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]

        pcmPath = docDic   "/play.pcm"
        mp3FilePath = docDic   "/play.mp3"

        mp3FileURL = URL(fileURLWithPath: mp3FilePath)

        recorderSetting =
            [
                AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM),
                AVNumberOfChannelsKey: 2 as AnyObject, //录音的声道数,立体声为双声道
                AVEncoderAudioQualityKey : AVAudioQuality.max.rawValue as AnyObject,
                AVEncoderBitRateKey : 640000 as AnyObject,
                AVSampleRateKey : avSampleRateKey as AnyObject //录音器每秒采集的录音样本数
        ]
    }


    @IBAction func touchDown() {
        do {
            try session.setCategory(AVAudioSessionCategoryPlayAndRecord)

            recorder = try AVAudioRecorder(url: URL(string: pcmPath)!, settings: recorderSetting)
            recorder.isMeteringEnabled = true
            recorder.record()
        } catch let error {
            print("create recorder error: (error)")
        }
    }

    @IBAction func touchUp() {
        recorder.stop()

        DispatchQueue.global().async {
            let success = AudioTransform.transformToMp3(fromPath: self.pcmPath,
                                                        toMp3Path: self.mp3FilePath,
                                                        withAVSampleRateKey: Int32(self.avSampleRateKey))

            DispatchQueue.main.async {
                print("transform success")
                if success {
                    do {
                        let data = try Data(contentsOf: self.mp3FileURL!)
                        print("data: (data)")
                        DemoModel.uploadRecord(data: data) { (success, info) in

                        }
                    } catch let error {
                        print("upload audio error: (error)")
                    }
                }
            }
        }
    }

    @IBAction func play() {
        do {
            try session.setCategory(AVAudioSessionCategoryPlayback)

            player = try AVAudioPlayer(contentsOf: recorder.url)
            player.play()
        } catch let error {
            print("paly audio error: (error)")
        }
    }
}

注意需要为 录制按钮 实现:

  • touchDown 事件(按住按钮触发)
  • touchUpInside 事件(松开按钮触发)

转化为 mp3 代码:

#import "lame.h"

@implementation AudioTransform

  (BOOL)transformToMp3FromPath:(NSString *)originalPath
                     toMp3Path:(NSString *)mp3Path
           withAVSampleRateKey:(int)rateKey {
    @try {
        int read, write;

        FILE *pcm = fopen([originalPath cStringUsingEncoding:1], "rb");  //source
        fseek(pcm, 4*1024, SEEK_CUR);                                    //skip file header
        FILE *mp3 = fopen([mp3Path cStringUsingEncoding:1], "wb");       //output

        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, rateKey);
        lame_set_VBR(lame, vbr_default);
        lame_init_params(lame);

        do {
            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);

            fwrite(mp3_buffer, write, 1, mp3);

        } while (read != 0);

        lame_close(lame);
        fclose(mp3);
        fclose(pcm);
    }
    @catch (NSException *exception) {
        NSLog(@"%@",[exception description]);
        return false;
    }
    @finally {
        return true;
    }

}


@end

注意:需要使用 lame 这个小插件实现转化,lame下载地址。你也可以直接使用Demo内的 fat-lame 里面是已经编译好的文件 (转化文件是用 Objective-C 写的,在 Swift 项目中需要一个bridge 文件)

图片 6

屏幕快照 2017-07-19 下午5.33.17.png

录制完声音后,如果播放的时候发现 声音变小
在播放声音的方法内设置:

try! session.setCategory(AVAudioSessionCategoryPlayback)

录制声音的方法内设置:

try! session.setCategory(AVAudioSessionCategoryPlayAndRecord)

Demo 地址

参考链接:
音频的文件格式和数据格式/)

3️⃣ 、为了知道你正在录音,肯定得搞个录音的计时器吧!首先搞个label显示时间

下面附上NSTimer的Category,怎么创建Category呢,右击New Files -> ObjectC - Files -> File Type选择Category, Class 选择NSTimer ,File文件名自己随便取

② 、进行权限验证,如下代码:

//设置后台播放,下面这段是录音和播放录音的设置_session = [AVAudioSession sharedInstance];NSError *sessionError;[_session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];//判断后台有没有播放if (_session == nil) { SIMEILog(@"Error creating sessing:%@", [sessionError description]);} else {//关闭其他音频播放,把自己设为活跃状态 [_session setActive:YES error:nil];} if (![_timer isValid]) { [self startTimer];} else { //这个方法是写了一个NSTimer的拓展类 Category,具体方法在下面附上代码 [_timer continueTimer];}//设置AVAudioRecorderif (!self.recorder) { NSDictionary *settings = @{AVFormatIDKey : @(kAudioFormatLinearPCM), AVSampleRateKey : @, AVNumberOfChannelsKey :@2, AVEncoderBitDepthHintKey : @16, AVEncoderAudioQualityKey : @(AVAudioQualityHigh)}; //开始录音,将所获取到得录音存到文件里 _recordUrl是存放录音的文件路径,在下面附上 self.recorder = [[AVAudioRecorder alloc] initWithURL:_recordUrl settings:settings error:nil]; /* * settings 参数 1.AVNumberOfChannelsKey 通道数 通常为双声道 值2 2.AVSampleRateKey 采样率 单位HZ 通常设置成44100 也就是44.1k,采样率必须要设为11025才能使转化成mp3格式后不会失真 3.AVLinearPCMBitDepthKey 比特率 8 16 24 32 4.AVEncoderAudioQualityKey 声音质量 ① AVAudioQualityMin = 0, 最小的质量 ② AVAudioQualityLow = 0x20, 比较低的质量 ③ AVAudioQualityMedium = 0x40, 中间的质量 ④ AVAudioQualityHigh = 0x60,高的质量 ⑤ AVAudioQualityMax = 0x7F 最好的质量 5.AVEncoderBitRateKey 音频编码的比特率 单位Kbps 传输的速率 一般设置128000 也就是128kbps */ } //准备记录录音 [_recorder prepareToRecord]; //开启仪表计数功能,必须开启这个功能,才能检测音频值 [_recorder setMeteringEnabled:YES]; //启动或者恢复记录的录音文件 [_recorder record];

一般导入后Library Search Paths 就会自动添加上lame文件在工程中的路径,若没有添加上,就自己手动添加上,否则会报错!!!

导入成功后,就开始使用lame转换mp3了,一大段的C代码,C语言好的同学看着就比较得心应手了

//因为录音文件比较大,所以我们把它存在Temp文件里,Temp文件里的文件在app重启的时候会自动删除_recordFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent: @"record.caf"]; //创建临时文件来存放录音文件_recordUrl = [NSURL fileURLWithPath:self.recordFilePath];

好了以上就是录音和转mp3的主要代码了,最后说一下,这个demo上传github的时候出了点问题,所以如果要demo的同学把邮箱留一下哈!若是对你有帮助的话,随手点个赞哦

版权声明:本文由彩民之家高手论坛发布于编程技术,转载请注明出处:iOS 录制音频文件,播放,转化成mp3上传