zoukankan      html  css  js  c++  java
  • swift 录音 AVAudioRecorder

    2018年05月16日 15:22:44 msmwncx阅读数:548

    https://blog.csdn.net/msmwncx/article/details/80336973

    版权声明:本文为博主原创文章,未经博主允许不得转载。如有问题,请联系QQ547394765 https://blog.csdn.net/msmwncx/article/details/80336973

    距离上次写博客已经好久好久了ZZZzzzzzzz。

    首先交代下用处,做的IM项目,需要语音聊天,研究了下AVAudioRecorder。

    其实挺简单的,主要步骤就是 创建一个recorder -> recorder.record() -> recorder.stop() 

    不多说 上代码

    func createRecord(path: String) {

            if self.recorder != nil {

                self.resetRecorder()

            }

            let url = URL(fileURLWithPath: path)

            self.cafPathStr = path

            self.mp3PathStr = self.recordFileCaf2Mp3(cafPath: path)

            let setting = self.recordSetting()

            do {

                self.recorder = try AVAudioRecorder(url: url, settings: setting)

                self.recorder?.delegate = self

                self.recorder?.isMeteringEnabled = true

            } catch {

                XMPPAudioLog("create recorder error:")

            }

        }

        func startRecord(path: String) {

            guard self.recorder == nil else {

                EdoAssertionFailure("should reset recorder before start record")

                return

            }

            if self.recorder == nil {

                self.createRecord(path: path)

            }

            guard let _ = self.recorder else {

                assertionFailure("ChatAudio: recorder could not be nil")

                return

            }

    //if isRecording, should stop first

            if let _ = self.recorder?.isRecording {

                self.recorder?.stop()

            }

    //stop all player

            self.stopAllMusic()

            let audioSession = AVAudioSession.sharedInstance()

            do {

              try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)

                if let isRecorder = self.recorder?.isRecording, isRecorder == false {

                    self.recorder?.record()

                }

            } catch {

            }

        }

    这里的mp3PathStr是转换成MP3格式的路径

    这里是一些配置还有大小以及mp3路径的转换方法

    func recordSetting() -> [String: Any] {

            var recordSetting = [String: Any]()

    //format of record

    /****

             kAudioFormatMPEG4AAC压缩格式能在显著减小文件的同时,保证音频的质量。

             ****/

            recordSetting[AVFormatIDKey] = NSNumber(value: kAudioFormatLinearPCM)

    //sampling rate of record

    /******

             采样率越高,文件越大,质量越好,反之,文件小,质量相对差一些,但是低于普通的音频,人耳并不能明显的分辨出好坏。最终选取哪一种采样率,由我们的耳朵来判断。建议使用标准的采样率,8000160002205044100

             *****/

            recordSetting[AVSampleRateKey] = NSNumber(value: 8000)

    //The quality of record

            recordSetting[AVEncoderAudioQualityKey] = NSNumber(value: AVAudioQuality.high.rawValue)

    //线性采样位数  8162432

            recordSetting[AVLinearPCMBitDepthKey] = NSNumber(value: 8)

    //录音通道数  1 2

    /****

             AVNumberOfChannelsKey用于指定记录音频的通道数。1为单声道,2为立体声。

             ***/

            recordSetting[AVNumberOfChannelsKey] = NSNumber(value: 2)

            return recordSetting

        }

        func fileSizeAtPath(path: String) -> String {

            if FileManager.default.fileExists(atPath: path) {

                let attributes = try? FileManager.default.attributesOfItem(atPath: path)

                if let attrs = attributes, let size = attrs[FileAttributeKey(rawValue:"NSFileSize")] as? Int64 {

                    return ByteCountFormatter.string(fromByteCount: size, countStyle: ByteCountFormatter.CountStyle.file)

                }

            }

            return "0 KB"

        }

        func recordFileCaf2Mp3(cafPath: String) -> String {

            var mp3Path = cafPath

            if cafPath.hasSuffix(".caf") {

                mp3Path = cafPath.replacingOccurrences(of: "caf", with: "mp3", options: NSString.CompareOptions.caseInsensitive, range: Range(cafPath.index(cafPath.startIndex, offsetBy: cafPath.count - 3)..<cafPath.endIndex))

            }

            return mp3Path

        }

     由于我这边是要做语音聊天,所以每次结束都会把recorder销毁掉 

    func deleteRecording() {

            guard let recorder = self.recorder, recorder.isRecording == false else {

                assertionFailure("ChatAudio: recorder must be stopped")

                return

            }

            self.recorder?.deleteRecording()

            self.resetRecorder()

        }

    func resetRecorder() {

            self.recorder?.stop()

            self.recorder = nil

            self.mp3PathStr = ""

            self.cafPathStr = ""

        }

    emmmm 好像就这么多了  具体一些缘由 为什么这么写什么的 可以参考一下apple的官方资料

    然后就是转MP3

    转mp3我是用的lame.h 和 libmp3lame.a 然后遇到一个什么 libmp3lame.a 不支持bitcode什么的问题 于是用以下解决

    1.http://sourceforge.net/projects/lame/files/lame/3.99/ 下载lame的最新版本并解压

    2.https://github.com/kewlbear/lame-ios-build   下载build的脚本 下载之后得到lame-build.sh拷贝到刚才解压后的文件夹

    3.用一些编辑器按照注释修改lame-build.sh 如下图pastedGraphic.png

    4.cd 到1解压的目录下 执行脚本 chmod 777 lame-build.sh 等待1分钟左右就编译完成了

    5.里边生成fat-lame目录和thin-lame目录,分别存放合并所有指令集的静态库,以及各指令集的静态库. 具体用哪个里边的lame.h和libmp3lame.a 我就忘记了。。。试一下吧。

    然后就是转MP3文件了

    我查了下资料,前人大部分都是用的OC写的 于是我用了一个OC文件转译了一下

    + (BOOL)audio_PCMtoMP3:(NSString *)cafPath mp3Path:(NSString *)mp3Path {

        @try {

            int read, write;

            FILE *pcm = fopen([cafPath cStringUsingEncoding:1], "rb");  //source 被转换的音频文件位置

            fseek(pcm, 4*1024, SEEK_CUR);                                   //skip file header

            FILE *mp3 = fopen([mp3Path 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();

            //should be equle with AVSampleRateKey

            lame_set_in_samplerate(lame, 8000.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]);

            return NO;

        }

        @finally {

            NSLog(@"MP3生成成功: %@",mp3Path);

            return YES;

        }

    }

    注意里边有一句

          lame_set_in_samplerate(lame, 8000.0);

    这里的8000要与recorder设置里的采样率一致,否则会变声。(我感觉一些app的变音就是这么来的,有兴趣可以试试,开始我设置的采样率是8000,这里写的是44100,然后声音特别细)

  • 相关阅读:
    Tomcat自动部署
    java环境配置
    django-crispy-forms入门指南
    hibernate级联删除
    bzoj1659: [Usaco2006 Mar]Lights Out 关灯
    bzoj1658: [Usaco2006 Mar]Water Slides 滑水
    bzoj5470 / P4578 [FJOI2018]所罗门王的宝藏(差分约束)
    P2864 [USACO06JAN]树林The Grove
    bzoj1651 / P2859 [USACO06FEB]摊位预订Stall Reservations
    bzoj1647 / P1985 [USACO07OPEN]翻转棋
  • 原文地址:https://www.cnblogs.com/sundaysme/p/10386572.html
Copyright © 2011-2022 走看看