iOS录音和播放的那些事儿:几个奇葩的需求

最近在做的项目中,需要在iPhone上接上带麦耳机(苹果叫Headset,不带麦耳机叫Headphone),然后实现同步录音和播放。这个功能实现之后,需要改变录音、播放的输入源。

对于实现同步录音和播放功能,肯定就要使用到底层的接口,用AVAudioRecorder/AVAudioPlayer是无法实现的。

我研究了iOS声音处理的知识之后,发现自己实现太过麻烦,需要用到至少包括AudioQueue/AudioBuffer等等,然后还有各种复杂的C Struct、回调函数、回调处理等等,非常麻烦,一不小心就出错,很难找到出错的地方。于是我在网上找了一个比较著名的封闭好的库,Novocaine。它对声音的输入、输出都实现的比较好,也提供了很简单明确的回调函数,我只要修改一下回调函数就可以了,这里不表。

后面项目需要确定能否实现一种输入/输出方式:在插入带麦克风的耳机时,能够让声音从耳机麦克风输入,然后同步的从手机内置扬声器播放。

在手机插入带麦耳机后,输入源共有2个:内置麦克风(Build-In Microphone)、耳机麦克风(Wired Microphone);输出源有3个:打电话时用的,在上面的那个输出(Built-In Receiver)、耳机(Wired Headphones)和放音乐时用的内置扬声器(Built-In Speaker)。

查了苹果的文档后发现,根据苹果的产品策略,用户在插入带麦耳机后,会自动将输入源切换到耳机麦克风,将输出源切换到耳机。而且,在输入源是耳机麦克风的时候,将输出源切换到耳机是强制的。这句话比较绕,我举个例子。假如现在输入源是耳机麦克风,那么输入源只能是耳机。而如果将输入源切换到手机内置麦克风(这是可以实现的)的时候,则可以将输出源切换到手机。

苹果认为,插入耳机代表用户只想从耳机听声音。为了保护用户的隐私,苹果不允许开发者随便换输出源。也就是说,虽然苹果提供了3种方法用于切换输出源(都比较繁琐,后面可能会再写一篇博客),但在用户插入耳机,并且我们需要输入源是耳机麦克风的情况下,是无法将输出源切换到内置扬声器的。这里有更详细的说明:http://stackoverflow.com/questions/5931799/redirecting-audio-output-to-phone-speaker-and-mic-input-to-headphones

第二个问题是,需要在耳机插入的状态下,将输入源调整为手机内置麦克风,而输出源仍然保持为耳机。

在千能(不是万能)的AVAudioSession类里,提供了几个很好的方法:

打印当前正在工作的输入/输入源:

NSArray* input = [[AVAudioSession sharedInstance] currentRoute].inputs;
NSArray* output = [[AVAudioSession sharedInstance] currentRoute].outputs;
NSLog(@"current intput:%@",input);
NSLog(@"current output:%@",output);

打印现在可用的输入源:

NSArray* availableInputs = [[AVAudioSession sharedInstance] availableInputs];
NSLog(@"available inputs:%@",availableInputs);

AVAudioSession没有提供可用的输出源的列表。

将耳机插入之后,打印可用的输入源,结果如下:

2015-01-26 17:45:40.747 PregNotice[605:6d13] available inputs:(

"<AVAudioSessionPortDescription: 0x16dc2de0, type = MicrophoneBuiltIn; name = iPhone \U9ea6\U514b\U98ce; UID = Built-In Microphone; selectedDataSource = \U4e0b>",

"<AVAudioSessionPortDescription: 0x16f40e80, type = MicrophoneWired; name = \U8033\U673a\U9ea6\U514b\U98ce; UID = Wired Microphone; selectedDataSource = (null)>"

)

可以看出,现在可用的输入源包括内置麦克风和耳机麦克风(Wired Microphone)。我们通过以下方法改变输入源:

NSArray* inputArray = [[AVAudioSession sharedInstance] availableInputs];
for (AVAudioSessionPortDescription* desc in inputArray) {
    if ([desc.portType isEqualToString:AVAudioSessionPortBuiltInMic]) {
        NSError* error;
        [[AVAudioSession sharedInstance] setPreferredInput:desc error:&error];
    }
}

同样,在需要切换回来时,检查desc.portType是不是AVAudioSessionPortHeadsetMic,如果是,调整回来。

需要注意的是,使用这个方法会触发AVAudioSessionRouteChangeNotification通知,而插入耳机后,也会调用这个通知。我在测试的时候,为了检查耳机插入的动作,监听了这个通知,然后在通知回调方法里通过上面方法修改了输入源,导致又触发了通知,所以插入1次耳机导致了2次调用。

关于声音,AVAudioSession,还有很多需要了解的。有兴趣的同学,需要搞定iOS声音的同学,一定要好好学学。

时间: 2024-10-08 02:38:16

iOS录音和播放的那些事儿:几个奇葩的需求的相关文章

Swift实现iOS录音与播放音频功能

作用AVPLayer:可以用来播放在线及本地音视频AVAudioSession:音频会话,主要用来管理音频设置与硬件交互使用时需要导入 #import <AVFoundation/AVFoundation.h> AVAudioSession中配置选项: AVAudioSessionCategory 注意:除了 AVAudioSessionCategoryMultiRoute 外,其他的 Category 都遵循 last in wins 原则,即最后接入的音频设备作为输入或输出的主设备. 1.

iOS开发–音频播放、录音、视频播放、拍照、视频录制

概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像头的操作都提供了多套API.在今天的文章中将会对这些内容进行一一介绍: 音频 在iOS中音频播放从形式上可以分为音效播放和音乐播放.前者主要指的是一些短音频播放,通常作为点缀音频,对于这类音频不需要进行进度.循环等控制.后者指的是一些较长的音频,通常是主音频,对于这些音频的播放通常需要进行精确的控制

iOS 实时录音和播放

需求:最近公司需要做一个楼宇对讲的功能:门口机(连接WIFI)拨号对室内机(对应的WIFI)的设备进行呼叫,室内机收到呼叫之后将对收到的数据进行UDP广播的转发,手机(连接对应的WIFI)收到视频流之后,实时的展示视频数据(手机可以接听,挂断,手机接听之后,室内机不展示视频,只是进行转发.) 简单点说就是手机客户端需要做一个类似于直播平台的软件,可以实时的展示视频,实时的播放接收到的声音数据,并且实时将手机麦克风收到的声音回传给室内机,室内机负责转发给门口机. 这篇文章介绍iOS怎么进行实时的录

IOS关于录音,播放实现总结

//音频录制(标准过程5,9更新) 准备:导入AVFoundation框架及头文件 1 设置会话类型,允许播放及录音AVAudioSession *audioSession = [AVAudioSession sharedInstance]; [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; 2 激活会话类别[audioSession setActive:YES error:nil]; 3 封装字典

iOS 音频缓存播放思路

基础 先来简单了解一下一些基础的音频知识. 目前我们在计算机上进行音频播放都需要依赖于音频文件,音频文件的生成过程是将声音信息采样.量化和编码产生的数字信号的过程,人耳所能听到的声音,最低的频率是从20Hz起一直到最高频率20KHZ,因此音频文件格式的最大带宽是20KHZ.根据奈奎斯特的理论,只有采样频率高于声音信号最高频率的两倍时,才能把数字信号表示的声音还原成为原来的声音,所以音频文件的采样率一般在40~50KHZ,比如最常见的CD音质采样率44.1KHZ. 对声音进行采样.量化过程被称为脉

总结iOS开发中的断点续传那些事儿

前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很浪费时间有木有.所以呢,项目中实现大文件下载的时候,断点续传功能是必不可少了.当然咯,断点续传有一种特殊的情况,就是我们的应用呗用户kill掉或者应用crash,要实现应用重启之后的断点续传,这种情况就是我们将要解决的问题. 断点续传的原理 要实现断点续传,服务器必须是要支持的.目前最常见的两种方式

iOS开发-音乐播放

现在的各种App大行其道,其实常用也就是围绕着吃喝玩乐基本的需求,视频,音乐在智能手机出现之前更是必不可少的功能,每个手机都会有一个自带的音乐播放器,当然公众也有自己的需求所以也就造就了各种音乐播放软件,自己下午闲来无事简单的写了一个随机播放音乐的Demo,iOS中有三种播放音频的方式AVAudioPlayer.音频服务.音频队列.另外两种暂时没有用到,就简单的练手了一下AVAudioPlayer,还是开始正题吧: 1.新建项目或者在原有项目重新弄一个页面,先看页面: 2.导入几首自己喜欢的歌曲

iOS AVPlayer 后台播放问题自动停止问题 防止应用被后台挂起方法

iOS AVPlayer 后台播放问题自动停止问题 防止应用被后台挂起方法 2016-09-08 16:16 1597人阅读 评论(0) 收藏 举报  分类: iOS 开发笔记(37)  版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 1.创建播放器时创建AVAudioSession [objc] view plain copy AVAudioSession *session = [AVAudioSessionsharedInstance]; [session setCa

Android开发教程 录音和播放

首先要了解andriod开发中andriod多媒体框架包含了什么,它包含了获取和编码多种音频格式的支持,因此你几耍轻松把音频合并到你的应用中,若设备支持,使用MediaRecorder APIs便可以完成录音. 本文将会为你展示一下,如何写一个应用从设备上的microphone获取音频,并进行保存和回放.注意哈Android模拟器,是不具有录音的功能的,不过呢真实的设备一般都具有此功能. 如何进行音频获取 从设备获取音频比回放音频或视频要复杂一点,但是也还算简单: 创建一个android.med