最近要做一个类似对讲的功能,所以需要用到录音上传,然后再播放的功能。

一、音频格式分析

因为之前没研究过音频这块,所以很多音频格式都是第一次见。

  • AAC:
    AAC其实是“高级音频编码(advanced audio coding)”的缩写,它是被设计用来取代MP3格式的。你可能会想,它压缩了原始的声音,导致容量占用少但是质量肯定会有所下降。不过这些质量的损失 取决于声音比特率的大小,当比特率合适的时候,这些损失人耳是很难听出来的。事实上,aac比mp3有更好的压缩率,特别是在比特率低于128bit/s 的时候。
  • HE-AAC:
    HE-AAC是AAC的一个超集,这个“HE”代表的是“High efficiency”。 HE-AAC是专门为低比特率所优化的一种音频编码格式,比如streaming audio就特别适合使用这种编码格式。
  • AMR:
    AMR全称是“Adaptive Multi-Rate”,它也是另一个专门为“说话(speech)”所优化的编码格式,也是适合低比特率环境下采用。
  • ALAC:
    它全称是“Apple Lossless”,这是一种没有任何质量损失的音频编码方式,也就是我们说的无损压缩。在实际使用过程中,它能够压缩40%-60%的原始数据。这种编码格式的解码速度非常快,这对iphone或者ipod这种小型设备来说非常适合。
  • iLBC:
    这是另一种专门为说话所设计的音频编码格式,它非常适合于IP电话等其它需要流式音频的场合。
  • IMA4:
    这是一个在16-bit音频文件下按照4:1的压缩比来进行压缩的格式。这是iphone上面一种非常重要的编码格式。

    它的中文意思是基于线性脉冲编码调制,用于将模拟声音数据转换成数字声音数据。简而言之,就是意味着无压缩数据。由于数据是非压缩的,它可以非常快的播放,并且当空间不是问题时,这是在iphone上面首选的音频编码方式。
  • μ-law
    and a-law: 就我所知道的,这种编码是交替的编码模拟数据为数字格式数据,但是在speech优化方面比linear PCM更好。
  • MP3:
    这种格式是我们都知道也喜欢的,虽然很多年过去了,但MP3到目前为止仍然是一种非常流行的编码格式,它也能被iphone很好地支持。
  • LPCM也很早就被定义在DVD播放机
    的标准内,为了和CD有所区别,DVD的的采样规格为16bit/48KHz,随着技术的发展,DVD的的采样规格更提升到24bit/96KHz,以达 到更高的播放品质,用96KHz/24bit方式记录的音频信号所能达到的频率上限是96÷2= 48KHz,而它的最大动态范围将可以达到24×6=144dB。从指标上就可以看出:它的声音比CD要好得多。pcm编码的最大的优点就是音质好,最大的缺点就是体数据量大。

录制音频需要选择音频的编码方式以及文件的格式。因为这个功能是项目中新添加的,所以格式和编码方式都还没有确定,所以我也只是写了个小Demo测试一下。所以我用的是aac的文件格式,而编码方式的话,因为在网上找到一些这样的说法:

文件格式选好以后,还是有很多的参数可以自己设定的,比特率、采样率和位宽等。当然,选用合适的音频格式还是比较重要,因为不同的格式之间文件大小差异还是比较明显的。就以AAC和LPCM对比为例,采样率同为44100Hz,默认的AAC一分钟的大小约为500kB,但是16bit位宽的LPCM就可以达到5MB。但作为我用于录音的用途,这么大的录音文件,估计录不了多少,用户就会骂我的程序怎么占用这么多空间了。录音务求能够听得出咬字清晰,不需要追求无损的音质。因此,我就选择了AAC格式,同时更小的空间占用也便于上传。

所以呢,我也选择aac的这些参数测试了一下,录制20多秒的音频,文件大小差不多是200多KB,非常小。

二、代码部分

首先需要导入两个框架,AVFoundation.framework与CoreAudio.framework ,网上有的讲解是用另外两个框架,

AudioToolbox.framework 和AVFoundation.framework,其中导入AVFoundation.framework就够了,这里需要用到AVFoundation.framework
框架中的三个对象,AVAudioRecorder、AVAudioPlayer、AVAudioSession 。

录音的大致过程是:先设置AVAudioSession的参数,录音的时候配置AVAudioRecorder的设置,然后开始录音。

录音按钮的操作:

- (IBAction)recordAction:(id)sender {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error1;
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error1]; if (toggle) {
toggle = NO; [_startButton setTitle:@"停止" forState:UIControlStateNormal]; _playButton.enabled = toggle;
_playButton.hidden = !toggle; NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
//设置录音格式 AVFormatIDKey==kAudioFormatLinearPCM
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
//设置录音采样率(Hz) 如:AVSampleRateKey==8000/44100/96000(影响音频的质量)
[recordSetting setValue:[NSNumber numberWithFloat:44100] forKey:AVSampleRateKey];
//录音通道数 1 或 2
[recordSetting setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];
//线性采样位数 8、16、24、32
[recordSetting setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
//录音的质量
[recordSetting setValue:[NSNumber numberWithInt:AVAudioQualityHigh] forKey:AVEncoderAudioQualityKey]; NSString *strUrl = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@.aac", strUrl,[self getCurrentTimeLong]]];
fileURL = url; [audioSession setActive:YES error:&error1];
//初始化
recorder = [[AVAudioRecorder alloc]initWithURL:url settings:recordSetting error:&error1];
//开启音量检测
recorder.meteringEnabled = YES;
recorder.delegate = self; //the subsstems so that when we actually say "record" it starts right away.
[recorder prepareToRecord];
//Start the actual Recording
[recorder record]; } else{
toggle = YES;
[audioSession setActive:NO error:&error1];
[_startButton setTitle:@"开始" forState:UIControlStateNormal ];
_playButton.enabled = toggle;
_playButton.hidden = !toggle; NSLog(@"Using File called: %@",fileURL);
//Stop the recorder.
[recorder stop];
}
}

这里开始录音和结束录音都是同一个按钮。主要是设置AVAudioSession的活动状态。

播放录音操作如下:

- (IBAction)playAction:(id)sender {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error1;
[audioSession setCategory:AVAudioSessionCategorySoloAmbient error:&error1];
[audioSession setActive:YES error:&error1]; // NSURL *URL = [[NSURL alloc] initWithString:[[NSBundle mainBundle] pathForResource:@"1408341057084" ofType:@"aac"]]; NSError *error3;
avPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error3];
avPlayer.volume = 1.0f;
[avPlayer prepareToPlay];
[avPlayer play];
NSLog(@"duration:%f",avPlayer.duration);
}

这里当时遇到一个问题,一开始avPlayer 我是在该方法里中初始化的,结果还没有开始播放就已经被释放咯,因为用的arc。然后改成实例变量之后,就OK咯。

.h文件代码如下:

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreAudio/CoreAudioTypes.h> @interface RootViewController : UIViewController<AVAudioRecorderDelegate>
{
BOOL toggle;
NSURL *fileURL;
AVAudioRecorder *recorder;
NSError *error;
AVAudioPlayer * avPlayer;
} @property (weak, nonatomic) IBOutlet UIButton *startButton;
@property (weak, nonatomic) IBOutlet UIButton *playButton; - (IBAction)recordAction:(id)sender;
- (IBAction)playAction:(id)sender; @end

.m文件代码如下:

//
// RootViewController.m
// Audio_Test
//
// Created by MacOS on 14-8-18.
// Copyright (c) 2014年 MacOS. All rights reserved.
// #import "RootViewController.h" @interface RootViewController () @end @implementation RootViewController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
} - (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib. toggle = YES;
_playButton.hidden = YES; } - (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} - (IBAction)recordAction:(id)sender {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error1;
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error1]; if (toggle) {
toggle = NO; [_startButton setTitle:@"停止" forState:UIControlStateNormal]; _playButton.enabled = toggle;
_playButton.hidden = !toggle; NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
//设置录音格式 AVFormatIDKey==kAudioFormatLinearPCM
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
//设置录音采样率(Hz) 如:AVSampleRateKey==8000/44100/96000(影响音频的质量)
[recordSetting setValue:[NSNumber numberWithFloat:44100] forKey:AVSampleRateKey];
//录音通道数 1 或 2
[recordSetting setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];
//线性采样位数 8、16、24、32
[recordSetting setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
//录音的质量
[recordSetting setValue:[NSNumber numberWithInt:AVAudioQualityHigh] forKey:AVEncoderAudioQualityKey]; NSString *strUrl = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@.aac", strUrl,[self getCurrentTimeLong]]];
fileURL = url; [audioSession setActive:YES error:&error1];
//初始化
recorder = [[AVAudioRecorder alloc]initWithURL:url settings:recordSetting error:&error1];
//开启音量检测
recorder.meteringEnabled = YES;
recorder.delegate = self; //the subsstems so that when we actually say "record" it starts right away.
[recorder prepareToRecord];
//Start the actual Recording
[recorder record]; } else{
toggle = YES;
[audioSession setActive:NO error:&error1];
[_startButton setTitle:@"开始" forState:UIControlStateNormal ];
_playButton.enabled = toggle;
_playButton.hidden = !toggle; NSLog(@"Using File called: %@",fileURL);
//Stop the recorder.
[recorder stop];
}
} /**
* 播放录音
*
* @param sender 播放按钮
*/
- (IBAction)playAction:(id)sender {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error1;
[audioSession setCategory:AVAudioSessionCategorySoloAmbient error:&error1];
[audioSession setActive:YES error:&error1]; // NSURL *URL = [[NSURL alloc] initWithString:[[NSBundle mainBundle] pathForResource:@"1408341057084" ofType:@"aac"]]; NSError *error3;
avPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error3];
avPlayer.volume = 1.0f;
[avPlayer prepareToPlay];
[avPlayer play];
NSLog(@"duration:%f",avPlayer.duration);
} - (NSString *)getCurrentTimeLong
{
NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0];
NSTimeInterval a=[dat timeIntervalSince1970]*1000;
//为字符型
NSString *timeString = [NSString stringWithFormat:@"%f", a];
return [timeString substringToIndex:13];
} @end

iOS 使用AVAudioPlayer开发录音功能的更多相关文章

  1. 在MAC上搭建cordova3.4.0的IOS和android开发环境

    Hello,大家好,今天给大家说说在mac上搭建cordova3.4.0的iOS和Android开发环境,首先下载cordova,地址:https://cordova.apache.org/#down ...

  2. iOS原生地图开发指南续——大头针与自定义标注

    iOS原生地图开发指南续——大头针与自定义标注 出自:http://www.sxt.cn/info-6042-u-7372.html 在上一篇博客中http://my.oschina.net/u/23 ...

  3. 从C#到Objective-C,循序渐进学习苹果开发(5)--利用XCode来进行IOS的程序开发

    本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.前面几篇随笔主要介绍C#和O ...

  4. iOS系统提供开发环境下命令行编译工具:xcodebuild

    iOS系统提供开发环境下命令行编译工具:xcodebuild[3] xcodebuild 在介绍xcodebuild之前,需要先弄清楚一些在XCode环境下的一些概念[4]: Workspace:简单 ...

  5. iOS原生地图开发详解

    在上一篇博客中:http://my.oschina.net/u/2340880/blog/414760.对iOS中的定位服务进行了详细的介绍与参数说明,在开发中,地位服务往往与地图框架结合使用,这篇博 ...

  6. iOS原生地图开发进阶——使用导航和附近兴趣点检索

    iOS原生地图开发进阶——使用导航和附近兴趣点检索 iOS中的mapKit框架对国际化的支持非常出色.在前些篇博客中,对这个地图框架的基础用法和标注与覆盖物的添加进行了详细的介绍,这篇博客将介绍两个更 ...

  7. iOS越狱程序开发

    iOS越狱程序开发http://www.docin.com/p-760246852.html

  8. 【转】针对iOS VS. Android开发游戏的优劣——2013-08-25 17

    http://game.dapps.net/gamedev/experience/8670.html 问题:如果你正在一个新工作室开发一款新的平板/手机游戏,你会选择iOS还是Android? 回答: ...

  9. 为iOS 7而开发 并支持iOS 6

    除了写这本“Developing an iOS 7 Edge”书之外,我还针对iOS 7更新了app,所以我想我应该和大家分享一下我的收获.如果你正在面向iOS 7系统更新应用,同时你的应用还支持iO ...

随机推荐

  1. struts框架从.jsp页面直接访问action

    <%@ page language="java" pageEncoding="UTF-8"%><%String path = request. ...

  2. 如果将Joomla网站搜索结果显示到一个“干净”页面

    有时候大家会发现Joomla网站自带的或者第三方的搜索功能时,搜索结果会显示在首页,和首页其它的模块如图片橱窗等显示在一起,非常混乱. 在这里教大家一个不需要修改代码的小技巧来解决这个问题,使搜索结果 ...

  3. TypeScript入门教程

    TypeScript是什么 TypeScript是JavaScript的一个超集 TypeScript需要编译为JavaScript才能运行(语法糖) TypeScript提供了类型系统,规范类似Ja ...

  4. jQuery CSS 类

    通过 jQuery,可以很容易地对 CSS 元素进行操作. jQuery 操作 CSS jQuery 拥有若干进行 CSS 操作的方法.我们将学习下面这些: addClass() - 向被选元素添加一 ...

  5. 安卓高级9 用原生intent分享

    大家都用过安卓app时发现有个分享按钮如下: 所以今天特此分享用用原生完成: package qianfeng.com.simplesharedemo; import android.content. ...

  6. 剑指Offer——毕业生求职网站汇总(干货)

    剑指Offer--毕业生求职网站汇总(干货) 致2017即将毕业的你~ 精品网站 牛客网:https://www.nowcoder.com 赛码网:http://www.acmcoder.com/ 招 ...

  7. 开源框架Volley的使用《一》

    转载本专栏每一篇博客请注明转载出处地址,尊重原创.此博客转载链接地址:小杨的博客 http://blog.csdn.net/qq_32059827/article/details/52785378 本 ...

  8. activiti 动态配置 activiti 监听引擎启动和初始化(高级源码篇)

    1.1.1. 前言 用户故事:现在有这样一个需求,第一个需求:公司的开发环境,测试环境以及线上环境,我们使用的数据库是不一样的,我们必须能够任意的切换数据库进行测试和发布,对数据库连接字符串我们需要加 ...

  9. Xcode7.3.1中通过最新的CocoaPod安装pop动画引擎

    CocoaPod是一个用ruby实现,用于方便的管理Xcode中第三方插件的管理器.用它我们可以很方便的安装和升级插件而不用担心破坏原有的项目. 而pop是一个用于实现App中动画的引擎,它是由Fac ...

  10. 一个 Linux 上分析死锁的简单方法

    简介 死锁 (deallocks): 是指两个或两个以上的进程(线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这 ...