前言

自从微信推出语音聊天后,人们的通讯方式发生了巨大变化,硬是把智能手机变成了对讲机。之后也成为了各种实时通讯软件不可或缺的功能。前一阵子微信公众号中展开了一场“发送语音消息利弊”的“讨论”。本文将针对语音录制和播放的实现进行分解。

1.语音录制动作分解

1)按下按钮,开始录制,显示录音指示界面;

2)手指上滑,暂停录制,显示“松开手指取消发送”,如果这个时候松开手指,取消录制,并不会发送;

3)手指滑回录制按钮位置,继续录音;

4)松开手指,录音完成,发送;

5)录制时长小于1秒,显示时间太短,不发送;

6)录制时长超过60秒,自动结束录制,并自动发送。

2.语音录制实现

目前,大多数实时iOS通讯软件采用.caf格式存储和发送语音文件。因为这个格式在保证声音质量的前提下体积更小。安卓大多数采用amr格式,所以要播放安卓发送过来的语音还需要转码,这个后面讲。

要录制语音,当然要用到苹果自带的AVFoundation中的AVAudioRecorder和AVAudioSession。关于这个框架的详细知识不在本文的讨论范围中。需要了解的可自行搜索。

代码中如何操作才可以开始录音呢?这里贴一段代码,写了注释。

- (void)startRecord {AVAudioSession *audioSession = [AVAudioSession sharedInstance];NSError *err = nil;//设置AVAudioSession[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&err];if(err) {return;}//设置录音输入源UInt32 doChangeDefaultRoute = 1;AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof (doChangeDefaultRoute), &doChangeDefaultRoute);err = nil;[audioSession setActive:YES error:&err];if(err) {return;}//设置文件保存路径和名称NSString *fileName = [NSString stringWithFormat:@"/voice-%5.2f.caf", [[NSDate date] timeIntervalSince1970] ];self.recordPath = [self.recordPath stringByAppendingPathComponent:fileName];NSURL *recordedFile = [NSURL fileURLWithPath:self.recordPath];NSDictionary *dic = [self recordingSettings];//初始化AVAudioRecordererr = nil;_recorder = [[AVAudioRecorder alloc] initWithURL:recordedFile settings:dic error:&err];if(_recorder == nil) {return;}//准备和开始录音[_recorder prepareToRecord];self.recorder.meteringEnabled = YES;[self.recorder record];[_recorder recordForDuration:0];if (self.levelTimer) {[self.levelTimer invalidate];self.levelTimer = nil;}self.levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.0001 target: self selector: @selector(levelTimerCallback:) userInfo: nil repeats: YES];
}

结束录音的核心代码就是调用AVAudioRecorder的stop方法:

[self.recorder stop];

录音结束后,打开沙盒,找到自己设置的路径,就可以看到以.caf后缀的语音文件。

3.语音播放

语音播放主要用到AVFoundation中的AVAudioPlayer。代码中要想播放一段语音文件,那么首先得知道这段语音的文件路径。这个路径在录音之后需要记录下来,然后在播放的时候拿到路径,调用相关方法就可以了。又要上代码了,播放的核心代码如下:

        _audioPlayer = [[AVAudioPlayer alloc] initWithData:audioData error:&audioPlayerError];if (!_audioPlayer || !audioData) {[self setAudioPlayerState:LGAudioPlayerStateCancel];return;}[[UIDevice currentDevice] setProximityMonitoringEnabled:YES];[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(proximityStateChanged:) name:UIDeviceProximityStateDidChangeNotification object:nil];_audioPlayer.volume = 1.0f;_audioPlayer.delegate = self;[_audioPlayer prepareToPlay];[self setAudioPlayerState:LGAudioPlayerStatePlaying];[_audioPlayer play];

其中的URLString就是语音文件的路径。

那么停止播放呢?和停止录制一样,调用stop方法

- (void)stopAudioPlayer {if (_audioPlayer) {_audioPlayer.playing ? [_audioPlayer stop] : nil;_audioPlayer.delegate = nil;_audioPlayer = nil;[[LGAudioPlayer sharePlayer] setAudioPlayerState:LGAudioPlayerStateCancel];}
}

4.amr文件转码

前面说过,很多安卓手机发送语音采用amr格式,而amr文件在iOS中不能被直接播放,这就需要转码。这里推荐两个amr转wave的工具(注:转成wave格式就可以在iOS中播放了),可以在github上搜索:

1.iOS-amr,好久没更新了

2.amrFileCodec,也是个老代码

5.语音发送

语音录制完成之后,需要把语音消息发送出去。发送语音分为两个步骤:语音文件上传;语音消息发送。

5.1 语音文件上传

上传方法当然很简单,用AFN或者ASI就可以。这里要说的是语音消息的上传机制。

语音文件转成二进制数据,上传至服务器成功后,服务器会返回一个文件在服务器的存储“地址”,暂且把这个“地址”命名为partUrl,这个partUrl可以是一个完整的URL,也可以是URL的一部分。一般情况下,为了安全考虑,partUrl是一个URL除过协议部分和域名部分的其余部分。例如完整的URL是“http://blog.csdn.net/gang544043963/article/details/52266903”,那么这个partUrl就是“gang544043963/article/details/52266903”。我们拿到服务器返回的这个partUrl之后呢,把它组装成一条要发送的消息发送出去。这样,一个语音发送的动作就完成了。

5.2 语音消息下载与缓存

当接收别人发来的语音消息时,首先接收到的是不包含语音文件的XML数据,这串数据中就包含5.1提到的partUrl。然后解析出partUrl,再用约定好的规则进行拼接,形成完整的URL,用这个URL就可以下载相应的语音文件。

语音缓存可以借鉴SDWebImage缓存图片的方法。URL中会包含‘文件名’部分,用‘文件名’作为下载要缓存语音文件的真实文件名。

6.扬声器切换

播放语音的时候,手机贴近耳朵,自动切换听筒播放;远离耳朵,自动切换为扬声器播放。这个功能实现其实很简单,iOS系统自动检测贴近(proximity)动作,并发送通知。我们只需要监听这个通知,并在响应方法中切换AVAudioSession的Category。

添加监听:

[[UIDevice currentDevice] setProximityMonitoringEnabled:YES];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(proximityStateChanged:) name:UIDeviceProximityStateDidChangeNotification object:nil];

响应方法中切换扬声器:

- (void)proximityStateChanged:(NSNotification *)notification {if ([[UIDevice currentDevice] proximityState] == YES) {[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];}else {[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];}
}

结束语

本文从代码角度讲解了语音录制和播放的实现,仅供入行不久的同行和想快速上手的同学参考。为方便使用和快速集成,我封装了两个框架,一个语音录制,一个语音播放,放在一个Demo中,并上传至github。欢迎使用并提出改进意见。

附上仓库地址:LGAudioKit

如果对您有帮助,请动动食指点个star鼓励一下,谢谢!

IM软件中的语音录制与播放【iOS】相关推荐

  1. [语音录制与播放]stm32+adc+dac

    2020-12-13更新: 最近总有人私信我要原理图和代码,贴一下我的公众号吧,有问题可以到这里联系我:[Golang梦工厂],下方点击联系人即可添加我的个人vx(建了一个语音录制交流群,加我VX拉你 ...

  2. 即时通讯-语音录制及播放

    即时通讯 即时通信的要点就是消息内容不大,并且传输迅速,并且是即时到达,实时通知的. 所以我们对语音进行一些处理,语音处理的过程如下: 录制录音 获取数据 编码保存 接收数据 数据解码 播放录音 为什 ...

  3. android 调用系统自带录音实现,语音录制与播放

    相关权限: <uses-permission android:name="android.permission.RECORD_AUDIO"></uses-perm ...

  4. Flutter简单聊天界面布局及语音录制播放

    目录 前言: 注意事项: 用到的部分组件依赖及版本: 遇到的坑 遇到的坑1: 遇到的坑2: 遇到的坑3: 遇到的坑4: Fluuter语音录制及播放组件生命周期 Flutter录音组件生命周期图: F ...

  5. 音视频的流程:录制、播放、编码解码、上传下载等

    仿网易云音乐 安卓版-- https://github.com/aa112901/remusic Android本地视频播放器开发- http://blog.csdn.NET/jwzhangjie/a ...

  6. Android利用MedioRecorder使用仿微信语音录音以及播放(总结)

    今天模仿着微信的发送语音功能做了一下,现将步骤以及其中遇到的问题记录一下,以便以后查看. 实现功能:1.录制语音并显示到列表中:2.点击列表中的语音自动进行播放:3.录制语音时以及播放语音时的动画效果 ...

  7. 仿微信语音消息的录制和播放

    仿微信语音消息的录制和播放 一.简述 效果: 实现功能: 长按Button时改变Button显示文字,弹出Dialog(动态更新音量),动态生成录音文件,开始录音: 监听手指动作,规定区域.录音状态下 ...

  8. Android直播软件搭建中实用的录制编辑方案有哪些

    Android直播软件搭建中实用的录制编辑方案有哪些 经大量数据显示,直播已经发展成为一种全民参与.共享和生产的文化现象.它的火爆不仅丰富了大众的艺术审美水平和精神文化,而且也影响了一代人的世界观.人 ...

  9. vue项目中实现语音队列的依次播放

    vue项目中实现语音队列的依次播放 需求分析 通过长链接接收后台返回的消息数据,并进行语音的依次播放完整.长链接和语音播放功能在以往的文章中都有介绍.再次我们主要着重介绍语音依次播放的功能. 那怎样实 ...

最新文章

  1. 引以为戒,特斯拉Kubernetes控制台被黑客攻击
  2. 福布斯评科技未来五大趋势:电脑消失融入生活时间
  3. 基于事件驱动架构构建微服务第16部分:Azure Active Directory B2C
  4. 漫步最优化四——约束
  5. ShapeNet:超实时人脸特征点检测与形状拟合开源库
  6. 以太坊服务器是什么_OKEX区块链60讲 | 第33集:什么是以太坊?
  7. asp.net常用正则表达式
  8. docker on marathonmesos示例
  9. 【Computer Organization笔记13】指令流水中的结构冲突和数据冲突
  10. 15.软件架构设计:大型网站技术架构与业务架构融合之道 --- 技术架构与业务架构的融合
  11. jquery之父john resig见面会及jquery最新动态
  12. 如何用几何画板破解版制作正方体展开动画
  13. 2021Web前端人事面试题总结精选
  14. 同比和环比分别是什么,一分钟告诉你。
  15. 带你走进组件化(三)—— 曲径
  16. CSS选择器有哪几种?举例轻松理解CSS选择器
  17. oracle 热数据,ORACLE数据库热备份步骤解析
  18. Java后台微信点餐小程序开发最新版笔记,Springboot+Mysql+Freemarker+Bootstrap+微信小程序实现扫码点餐小程序,包含语音提示,微信消息推送,网页管理后台
  19. 机器翻译技术的含义、发展和应用
  20. 脑洞故事|万圣节的起源并非恶魔,而是M星系机器人!

热门文章

  1. 【在线图表生成】掌握这些图表,年终报表根本不用愁!
  2. 全国最新行政区划sql文件
  3. eclipse的outline窗口_【Eclipse】使用指南(5)快捷 Outline 视图
  4. 程序员不过愚人节???
  5. gcc/g++ 命令的常用选项
  6. php安全新闻早八点-高级持续渗透-第一季关于后门
  7. 解决idea maven reimport失效问题
  8. 敞开心扉,来聊聊跨域方式吧!
  9. 对k8s的背景知识汇总
  10. 产消合一。有感于华人新首富赵长鹏投资福布斯的话