当前位置: 移动技术网 > IT编程>移动开发>IOS > iOS多媒体音频(下)-录音及其播放的实例

iOS多媒体音频(下)-录音及其播放的实例

2019年07月24日  | 移动技术网IT编程  | 我要评论

白天鹅图库,曾仕强易经下载,在网上兼职

上一篇中总结了ios中音效和音频播放的最基本使用方法,其中音频的播放控制是使用avfoundation.framework框架中的avaudioplayer播放器对象来实现的,而这里音频的录制则是使用了同样框架下的一个叫avaudiorecorder的录音机对象来实现,这两个类的用法流程非常类似,类的属性和方法也类似,例如:播放器中需要获取音频文件的url,而录音机要在沙盒中docuemnt目录下创建一个音频文件路径url;

播放器有isplaying变量判断是否正在播放,录音机中有isrecording变量表示是否正在录制;currenttime在播放器中表示播放时间,在录音机中则表示录音时间;播放器通过preparetoplay方法加载文件到缓冲区,录音机通过preparetorecord创建缓冲区;播放音频有play方法,音频录制有record方法,另外都有pause暂停方法和stop停止方法等等,具体可直接打开两个类的头文件详细了解。

这里实现最基本的录音流程以及录音过程的控制,并通过之前使用的avaudioplayer来播放录制好的音频。注意ios录制的音频为caf格式,如果需要通用化可以通过lame等插件将caf格式音频转成mp3格式。

录音

这里实现开始录音,暂停,继续以及停止录音。

创建文件目录

ios沙盒内胡要有三个目录:documents目录,tmp目录以及library目录,其中documents目录用来存放用户的应用程序数据,需要定期备份的数据要放在这里,和plist文件存储一样,我们要找到存放文件的路径,然后在该路径下放一个我们的文件,因此要自定义一个带后缀的文件名,将获得的路径和文件名拼在一起记得到我们的文件的绝对路径:

// 文件名
#define filename_caf @"demorecord.caf"
// 录音文件绝对路径
@property (nonatomic, copy) nsstring *filepathcaf;

// 获取沙盒document文件路径
nsstring *sandboxpath = [nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes) lastobject];
// 拼接录音文件绝对路径
_filepathcaf = [sandboxpath stringbyappendingpathcomponent:filename_caf];

创建音频会话

录音前要创建一个音频会话,同时要设置录音类型,提供的类型有以下几种:

  • avf_export nsstring *const avaudiosessioncategoryambient; // 用于录制背景声音,像雨声、汽车引擎发动噪音等,可和其他音乐混合
  • avf_export nsstring *const avaudiosessioncategorysoloambient; // 也是背景声音,但其他音乐会被强制停止
  • avf_export nsstring *const avaudiosessioncategoryplayback; // 音轨
  • avf_export nsstring *const avaudiosessioncategoryrecord; // 录音
  • avf_export nsstring *const avaudiosessioncategoryplayandrecord; // 录音和回放
  • avf_export nsstring *const avaudiosessioncategoryaudioprocessing; // 用于底层硬件编码信号处理等
  • avf_export nsstring *const avaudiosessioncategorymultiroute; // 内置硬件相关,ios 6.0以上可用

常用的是avaudiosessioncategoryplayandrecord类型,便于录音后播放。

// 创建音频会话
avaudiosession *audiosession=[avaudiosession sharedinstance];
// 设置录音类别(这里选用录音后可回放录音类型)
[audiosession setcategory:avaudiosessioncategoryplayandrecord error:nil];
[audiosession setactive:yes error:nil];

录音设置

录音前要根据需要对录音进行一些相应的基本设置,例如录音格式(linearpcm)、采样率、通道数等等,设置保存在一个字典内并作为初始化录音机的一个参数。

// 录音设置
-(nsdictionary *)getaudiosetting{
  // linearpcm 是ios的一种无损编码格式,但是体积较为庞大
  // 录音设置信息字典
  nsmutabledictionary *recordsettings = [[nsmutabledictionary alloc] init];
  // 录音格式
  [recordsettings setvalue :@(kaudioformatlinearpcm) forkey: avformatidkey];
  // 采样率
  [recordsettings setvalue :@11025.0 forkey: avsampleratekey];
  // 通道数(双通道)
  [recordsettings setvalue :@2 forkey: avnumberofchannelskey];
  // 每个采样点位数(有8、16、24、32)
  [recordsettings setvalue :@16 forkey: avlinearpcmbitdepthkey];
  // 采用浮点采样
  [recordsettings setvalue:@yes forkey:avlinearpcmisfloatkey];
  // 音频质量
  [recordsettings setvalue:@(avaudioqualitymedium) forkey:avencoderaudioqualitykey];
  // 其他可选的设置
  // ... ...

  return recordsettings;
}

创建录音机对象

录音机对象的创建主要是利用上面的保存路径和录音设置进行初始化得到:

// 懒加载录音机对象get方法
- (avaudiorecorder *)audiorecorder {
  if (!_audiorecorder) {
    // 保存录音文件的路径url
    nsurl *url = [nsurl urlwithstring:_filepathcaf];
    // 创建录音格式设置setting
    nsdictionary *setting = [self getaudiosetting];
    // error
    nserror *error=nil;

    _audiorecorder = [[avaudiorecorder alloc]initwithurl:url settings:setting error:&error];
    _audiorecorder.delegate = self;
    _audiorecorder.meteringenabled = yes;// 监控声波
    if (error) {
      nslog(@"创建录音机对象时发生错误,错误信息:%@",error.localizeddescription);
      return nil;
    }
  }
  return _audiorecorder;
}

录音控制方法

录音过程控制主要是开始录音、暂停、继续和停止录音,其中开始录音和继续录音都是record方法。

// 开始录音或者继续录音
- (ibaction)startorresumerecord {
  // 注意调用audiorecorder的get方法
  if (![self.audiorecorder isrecording]) {
    // 如果该路径下的音频文件录制过则删除
    [self deleterecord];
    // 开始录音,会取得用户使用麦克风的同意
    [_audiorecorder record];
  }
}

// 录音暂停
- (ibaction)pauserecord {
  if (_audiorecorder) {
    [_audiorecorder pause];
  }
}

// 结束录音
- (ibaction)stoprecord {
  [_audiorecorder stop];
}

录音播放

录音的播放很简单,就是之前avaudioplayer音频播放的简单应用,播放的路径即我们录音时创建好的音频路径。但这里注意为了保证每次都播放最新录制的音频,播放器的get方法要每次重新创建初始化。

// audioplayer懒加载getter方法
- (avaudioplayer *)audioplayer {
  _audiorecorder = null; // 每次都创建新的播放器,删除旧的

  // 资源路径
  nsurl *url = [nsurl fileurlwithpath:_filepathcaf];

  // 初始化播放器,注意这里的url参数只能为本地文件路径,不支持http url
  nserror *error = nil;
  _audioplayer = [[avaudioplayer alloc]initwithcontentsofurl:url error:&error];

  //设置播放器属性
  _audioplayer.numberofloops = 0;// 不循环
  _audioplayer.delegate = self;
  _audioplayer.volume = 0.5; // 音量
  [_audioplayer preparetoplay];// 加载音频文件到缓存【这个函数在调用play函数时会自动调用】

  if(error){
    nslog(@"初始化播放器过程发生错误,错误信息:%@",error.localizeddescription);
    return nil;
  }

  return _audioplayer;
}

// 播放录制好的音频
- (ibaction)playrecordedaudio {
  // 没有文件不播放
  if (![[nsfilemanager defaultmanager] fileexistsatpath:self.filepathcaf]) return;
  // 播放最新的录音
  [self.audioplayer play];
}

完整源码和demo下载

//
// viewcontroller.m
// iosrecorderdemo
//
// created by xinhou jiang on 29/12/16.
// copyright © 2016年 xinhou jiang. all rights reserved.
//

#import "viewcontroller.h"
#import <avfoundation/avfoundation.h>

// 文件名
#define filename_caf @"demorecord.caf"

@interface viewcontroller ()

// 录音文件绝对路径
@property (nonatomic, copy) nsstring *filepathcaf;
// 录音机对象
@property (nonatomic, strong) avaudiorecorder *audiorecorder;
// 播放器对象,和上一章音频播放的方法相同,只不过这里简单播放即可
@property (nonatomic, strong) avaudioplayer *audioplayer;
// 用一个processview显示声波波动情况
@property (nonatomic, weak) iboutlet uiprogressview *processview;
// 用一个label显示录制时间
@property (nonatomic, weak) iboutlet uilabel *recordtime;
// ui刷新监听器
@property (nonatomic, strong) nstimer *timer;

@end

@implementation viewcontroller

- (void)viewdidload {
  [super viewdidload];
  // 初始化工作
  [self initdata];
}

// 初始化
- (void)initdata {
  // 获取沙盒document文件路径
  nsstring *sandboxpath = [nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes) lastobject];
  // 拼接录音文件绝对路径
  _filepathcaf = [sandboxpath stringbyappendingpathcomponent:filename_caf];

  // 1.创建音频会话
  avaudiosession *audiosession=[avaudiosession sharedinstance];
  // 设置录音类别(这里选用录音后可回放录音类型)
  [audiosession setcategory:avaudiosessioncategoryplayandrecord error:nil];
  [audiosession setactive:yes error:nil];

  // 2.开启定时器
  [self timer];
}

#pragma mark -录音设置工具函数
// 懒加载录音机对象get方法
- (avaudiorecorder *)audiorecorder {
  if (!_audiorecorder) {
    // 保存录音文件的路径url
    nsurl *url = [nsurl urlwithstring:_filepathcaf];
    // 创建录音格式设置setting
    nsdictionary *setting = [self getaudiosetting];
    // error
    nserror *error=nil;

    _audiorecorder = [[avaudiorecorder alloc]initwithurl:url settings:setting error:&error];
    _audiorecorder.delegate = self;
    _audiorecorder.meteringenabled = yes;// 监控声波
    if (error) {
      nslog(@"创建录音机对象时发生错误,错误信息:%@",error.localizeddescription);
      return nil;
    }
  }
  return _audiorecorder;
}

// audioplayer懒加载getter方法
- (avaudioplayer *)audioplayer {
  _audiorecorder = null; // 每次都创建新的播放器,删除旧的

  // 资源路径
  nsurl *url = [nsurl fileurlwithpath:_filepathcaf];

  // 初始化播放器,注意这里的url参数只能为本地文件路径,不支持http url
  nserror *error = nil;
  _audioplayer = [[avaudioplayer alloc]initwithcontentsofurl:url error:&error];

  //设置播放器属性
  _audioplayer.numberofloops = 0;// 不循环
  _audioplayer.delegate = self;
  _audioplayer.volume = 0.5; // 音量
  [_audioplayer preparetoplay];// 加载音频文件到缓存【这个函数在调用play函数时会自动调用】

  if(error){
    nslog(@"初始化播放器过程发生错误,错误信息:%@",error.localizeddescription);
    return nil;
  }

  return _audioplayer;
}

// 计时器get方法
- (nstimer *)timer {
  if (!_timer) {
    _timer = [nstimer scheduledtimerwithtimeinterval:0.1f repeats:yes block:^(nstimer * _nonnull timer) {
      if(_audiorecorder) {
        // 1.更新录音时间,单位秒
        int curinterval = [_audiorecorder currenttime];
        _recordtime.text = [nsstring stringwithformat:@"%02d:%02d",curinterval/60,curinterval%60];
        // 2.声波显示
        //更新声波值
        [self.audiorecorder updatemeters];
        //第一个通道的音频,音频强度范围:[-160~0],这里调整到0~160
        float power = [self.audiorecorder averagepowerforchannel:0] + 160;
        [_processview setprogress:power/160.0];
      }
    }];
  }
  return _timer;
}

// 录音设置
-(nsdictionary *)getaudiosetting{
  // linearpcm 是ios的一种无损编码格式,但是体积较为庞大
  // 录音设置信息字典
  nsmutabledictionary *recordsettings = [[nsmutabledictionary alloc] init];
  // 录音格式
  [recordsettings setvalue :@(kaudioformatlinearpcm) forkey: avformatidkey];
  // 采样率
  [recordsettings setvalue :@11025.0 forkey: avsampleratekey];
  // 通道数(双通道)
  [recordsettings setvalue :@2 forkey: avnumberofchannelskey];
  // 每个采样点位数(有8、16、24、32)
  [recordsettings setvalue :@16 forkey: avlinearpcmbitdepthkey];
  // 采用浮点采样
  [recordsettings setvalue:@yes forkey:avlinearpcmisfloatkey];
  // 音频质量
  [recordsettings setvalue:@(avaudioqualitymedium) forkey:avencoderaudioqualitykey];
  // 其他可选的设置
  // ... ...

  return recordsettings;
}

// 删除filepathcaf路径下的音频文件
-(void)deleterecord{
  nsfilemanager* filemanager=[nsfilemanager defaultmanager];
  if ([[nsfilemanager defaultmanager] fileexistsatpath:self.filepathcaf]) {
    // 文件已经存在
    if ([filemanager removeitematpath:self.filepathcaf error:nil]) {
      nslog(@"删除成功");
    }else {
      nslog(@"删除失败");
    }
  }else {
    return; // 文件不存在无需删除
  }
}

#pragma mark -录音流程控制函数
// 开始录音或者继续录音
- (ibaction)startorresumerecord {
  // 注意调用audiorecorder的get方法
  if (![self.audiorecorder isrecording]) {
    // 如果该路径下的音频文件录制过则删除
    [self deleterecord];
    // 开始录音,会取得用户使用麦克风的同意
    [_audiorecorder record];
  }
}

// 录音暂停
- (ibaction)pauserecord {
  if (_audiorecorder) {
    [_audiorecorder pause];
  }
}

// 结束录音
- (ibaction)stoprecord {
  [_audiorecorder stop];
}

#pragma mark -录音播放
// 播放录制好的音频
- (ibaction)playrecordedaudio {
  // 没有文件不播放
  if (![[nsfilemanager defaultmanager] fileexistsatpath:self.filepathcaf]) return;
  // 播放最新的录音
  [self.audioplayer play];
}

@end

demo下载:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

  • ios uicollectionview实现横向滚动

    现在使用卡片效果的app很多,之前公司让实现一种卡片效果,就写了一篇关于实现卡片的文章。文章最后附有demo实现上我选择了使用uicollectionview ... [阅读全文]
  • iOS UICollectionView实现横向滑动

    本文实例为大家分享了ios uicollectionview实现横向滑动的具体代码,供大家参考,具体内容如下uicollectionview的横向滚动,目前我使... [阅读全文]
  • iOS13适配深色模式(Dark Mode)的实现

    iOS13适配深色模式(Dark Mode)的实现

    好像大概也许是一年前, mac os系统发布了深色模式外观, 看着挺刺激, 时至今日用着也还挺爽的终于, 随着iphone11等新手机的发售, ios 13系统... [阅读全文]
  • ios 使用xcode11 新建项目工程的步骤详解

    ios 使用xcode11 新建项目工程的步骤详解

    xcode11新建项目工程,新增了scenedelegate这个类,转而将原appdelegate负责的对ui生命周期的处理担子接了过来。故此可以理解为:ios... [阅读全文]
  • iOS实现转盘效果

    本文实例为大家分享了ios实现转盘效果的具体代码,供大家参考,具体内容如下demo下载地址: ios转盘效果功能:实现了常用的ios转盘效果,轮盘抽奖效果的实现... [阅读全文]
  • iOS开发实现转盘功能

    本文实例为大家分享了ios实现转盘功能的具体代码,供大家参考,具体内容如下今天给同学们讲解一下一个转盘选号的功能,直接上代码直接看viewcontroller#... [阅读全文]
  • iOS实现轮盘动态效果

    本文实例为大家分享了ios实现轮盘动态效果的具体代码,供大家参考,具体内容如下一个常用的绘图,主要用来打分之类的动画,效果如下。主要是ios的绘图和动画,本来想... [阅读全文]
  • iOS实现九宫格连线手势解锁

    本文实例为大家分享了ios实现九宫格连线手势解锁的具体代码,供大家参考,具体内容如下demo下载地址:效果图:核心代码://// clockview.m// 手... [阅读全文]
  • iOS实现卡片堆叠效果

    本文实例为大家分享了ios实现卡片堆叠效果的具体代码,供大家参考,具体内容如下如图,这就是最终效果。去年安卓5.0发布的时候,当我看到安卓全新的material... [阅读全文]
  • iOS利用余弦函数实现卡片浏览工具

    iOS利用余弦函数实现卡片浏览工具

    本文实例为大家分享了ios利用余弦函数实现卡片浏览工具的具体代码,供大家参考,具体内容如下一、实现效果通过拖拽屏幕实现卡片移动,左右两侧的卡片随着拖动变小,中间... [阅读全文]
验证码:
移动技术网