(转)KVAudioStreamer - 基于AudioToolBox的开源音频流媒体播放器
原贴的地址:https://www.jianshu.com/p/7b40f0e8b6bb
在iOS上,播放音频一般使用AVAudioPlayer进行音频播放,但是AVAudioPlayer并不支持流媒体播放,换言之,AVAudioPlayer只能播放本地音频,当遇到网络音频的时候,都是先下载到整个音频文件,然后再播放(微信语音就是先下载再播放),但是有些使用场景要求音频使用流媒体播放,提高用户体验,像音乐软件,在线音频教育软件的一些音频课程都要求流媒体播放。
项目git地址
1 开发初衷
目前开源的流媒体播放器有很多,例如AudioStreamer、DOUAudioStreamer,但是这两个开源库或多或少都有点瑕疵,并且都是在很久以前开发的,并不满足我的要求,所以决定自己开发一个流媒体播放器,并回馈一下开源社区。
2 KVAudioStreamer介绍
KVAudioStreamer采用AudioToolBox框架开发,使用C接口开发将更容易自主定制,当然,相对的也增加了开发难度。KVAudioStreamer内部代码结构清晰,由于开源时间晚于AudioStreamer和DOUAudioStreamer,所以使用的API都是最新的。
2.1 AudioQueue介绍
我使用的是AudioQueue进行音频播放,AudioToolBox播放音频主要涉及到以下API(仅仅列出,连参数都没有放上去):
//AudioFileStreamID,用于音频数据解析
extern OSStatus AudioFileStreamOpen (); //打开文件流,获取文件流id extern OSStatus AudioFileStreamParseBytes(); //解析数据,将会传入一个C语言方法,获取解析结果 extern OSStatus AudioFileStreamClose(); //关闭文件流 extern OSStatus AudioFileStreamGetProperty(); //获取文件信息 //AudioQueueBufferRef,用于音频缓存数据存储 extern OSStatus AudioQueueEnqueueBuffer(); //放进音频队列 extern OSStatus AudioQueueFreeBuffer(); //释放缓存区数据 //AudioQueueRef,用于音频播放 extern OSStatus AudioQueueStart(); //开始播放 extern OSStatus AudioQueuePause(); //暂停播放 extern OSStatus AudioQueueStop(); //停止播放 extern OSStatus AudioQueueDispose(); //释放音频队列 //以下两个方法配合使用,来控制播放速率 extern OSStatus AudioQueueSetProperty(); //设置属性 extern OSStatus AudioQueueSetParameter(); //设置参数
AudioQueue的播放流程如下所示:
从上图可以看出,AudioQueue播放音频是一种生产者-消费者模式,所以KVAudioStreamer也采用生产者-消费者的设计模式进行框架搭建,内部代码逻辑清晰,充分解耦,方便开发者学习以及修改(这一点自认为优于AudioStreamer和DOUAudioStreamer)。
下图是KVAudioStreamer的代码结构,我已经将实现代码抽象成生产者和消费者:
本篇文章仅为KVAudioStreamer的介绍文档,关于AudioToolBox的使用问题将会在往后另一篇文章进行说明,造轮子的过程是痛并快乐着的,踩过无数的坑,在填坑的过程中也在不断成长,文章最后将会贴出当时学习AudioToolBox的参考文章,同时也感谢这些作者的付出。
2.2 功能介绍
KVAudioStreamer拥有以下功能:
- 支持多种音频格式(mp3、flac、wav、m4a...);
- 支持缓存功能;
- 支持定点播放;
- 多倍率播放。
KVAudioStreamer支持多种音频格式,经测试,目前音频格式中仅ape格式文件无法播放,另外对m4a音频文件只能做到流播放,无法使用seek操作,后续将会研究如何解决,如果开发者不需要播放m4a文件,那么KVAudioStreamer会是一个不错的选择。
支持缓存功能,针对网络文件,在完整缓存完毕将会通过代理事件通知开发者缓存成功,携带文件路径供开发者下一步操作(注:仅在完整缓存后才会自动缓存,如果播放网络文件时还未缓存成功就使用了seek操作,那么就不算完整缓存,因为内部使用了断点下载,如果seek后便无法保证文件的完整性,如果文件已经完整缓存成功,重复seek不会产生重复的网络请求,帮助用户节省流量)。
定点播放也是KVAudioStreamer的一大特色,支持从音频的某个位置开始播放,用于播放位置记忆功能。
多倍率播放,这也是音频播放的一个常用功能,建议区间(0,5),其实2倍速度播放,出来的声音就已经很鬼畜了。
3 如何集成
该项目已提交到github开源社区,并且提供cocoapod功能,可以直接通过git clone进行项目下载,里面包含一个完整的demo演示,demo里面同时提供了音频后台播放和锁屏控制的解决方案。
3.1 git地址
git地址
3.2 cocoapod集成
使用以下pod命令集成
pod 'KVAudioStreamer', ' 1.0.0'
4 如何使用
KVAudioStreamer的API设计遵从命名规范,坚持一切从简的设计原则,所以使用简单,上手快速。
4.1 初始化
self.streamer = [[KVAudioStreamer alloc] init];
self.streamer.delegate = self;
self.streamer.cacheEnable = YES; //开启缓存功能 //设置httpheader,音乐资源在阿里云OSS开启了防盗链,需要在这里设置referer,如果没有防盗链,那么不需要设置 self.streamer.httpHeaders = @{@"Referer" : @"kevinrefer"};
4.2 设置音频路径
[self.streamer resetAudioURL:self.filepath]; //音频路径需遵从以下规则
KVAudioStreamer通过音频路径来进行本地以及网络文件的区分,所以务必遵从该规则:如果是本地文件,需以file://
开头,网络文件需以http
开头,如果音频资源是https,开发者可以自行修改http请求文件中的代码,KVAudioStreamer使用NSURLSession
作为网络请求框架,处理网络请求的代码全部封装在这里,无需改动其他代码:
4.3 播放控制
- 播放
[self.streamer play];
- 定点播放
[self.streamer playAtTime:60];
- 暂停
[self.streamer pause];
- seek
[self.streamer seekToTime:60];
- 停止
[self.streamer stop];
- 设置音量
self.streamer.volume = 0.5;
- 设置倍速
self.streamer.playRate = 0.5;
4.4 代理通知
KVAudioStreamer使用代理事件进行事件通知,总共有六个代理方法。
- 播放状态改变通知,将会在这个代理方法里面接收到流媒体播放过程的各种状态变化。
- (void)audioStreamer:(KVAudioStreamer*)streamer playStatusChange:(KVAudioStreamerPlayStatus)status;
所有的状态,如下所示:
typedef NS_ENUM(NSInteger, KVAudioStreamerPlayStatus) {KVAudioStreamerPlayStatusIdle, //闲置状态KVAudioStreamerPlayStatusBuffering, //缓冲中 KVAudioStreamerPlayStatusPlaying, //播放 KVAudioStreamerPlayStatusPause, //暂停 KVAudioStreamerPlayStatusFinish, //完成播放 KVAudioStreamerPlayStatusStop //停止 };
- 音频时长改变通知,KVAudioStreamer内部计算时长使用了三种方法,只有一种能够拿到确切的时长,如果获取不到将会使用另外两种方法进行计算,得出的为近似的音频时长。
- (void)audioStreamer:(KVAudioStreamer *)streamer durationChange:(float)duration;
近似时长通知,注意:该方法有可能调用多次。
- (void)audioStreamer:(KVAudioStreamer *)streamer estimateDurationChange:(float)estimateDuration;
- 播放进度通知,内部使用定时器监听播放进度。
- (void)audioStreamer:(KVAudioStreamer *)streamer playAtTime:(long)location;
- 缓存完成通知,如果开启了缓存功能,并且文件完整缓存成功,将会回调这个方法,返回YES,将会删除该缓存文件。
- (BOOL)audioStreamer:(KVAudioStreamer *)streamer cacheCompleteWithRelativePath:(NSString*)relativePath cachepath:(NSString*)cachepath;
- 错误通知,内部报错将会回调该方法。
- (void)audioStreamer:(KVAudioStreamer *)streamer didFailWithErrorType:(KVAudioStreamerErrorType)errorType msg:(NSString*)msg error:(NSError*)error
4.5 使用注意事项
由于KVAudioStreamer使用了定时器进行播放时长监听,所以在适当(不使用)的时候手动释放流媒体播放器。
- (void)dealloc {[self.streamer releaseStreamer]; //释放流媒体self.streamer = nil; }
5 写在最后
造轮子的确很辛苦,过程中遇到了很多问题,挠破头皮才一一解决,不过最后还是没能解决m4a文件的播放seek问题,等待以后有空闲时间再慢慢研究。
KVAudioStreamer使用到的核心技术:
- AudioToolBox框架
- GCD串行队列,音频数据解析都在串行队列中顺序执行
- 线程锁(pthread_mutex_t),用于解决多线程资源共享问题
- 线程条件变量(pthread_cond_t),由于音频数据的解析后是在子线程连续填充缓存区的,在AudioQueue还未播放完成时缓存区是无法使用的,线程就必须等待,所以使用了条件变量进行线程的等待以及唤醒,避免过多的CPU资源占用
以下文章为本人在学习AudioToolBox时的参考文章,当然,里面或多或少有些坑,再次感谢这些作者的付出,往后有时间将会写一篇文章完整讲解AudioToolBox的使用。
http://www.cocoachina.com/ios/20170721/19969.html
https://www.jianshu.com/p/05b6e9bc4060
http://blog.csdn.net/cairo123/article/details/53839980
项目git地址
作者:佳木秀林
链接:https://www.jianshu.com/p/7b40f0e8b6bb
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
转载于:https://www.cnblogs.com/iOSDeng/p/9378255.html
(转)KVAudioStreamer - 基于AudioToolBox的开源音频流媒体播放器相关推荐
- 最简单的基于FFMPEG+SDL的音频播放器 ver2 (采用SDL2.0)
===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...
- android 流播放器开发,GitHub - youcoding98/FastVideo: 基于Android平台的移动流媒体播放器的开发...
基于Android平台的移动流媒体播放器的开发 主页界面如下 第一部分 课题相关介绍 与普通播放器相比,流媒体播放器最主要的不同点在于其能够实现实时的视频播放,用户可以实现边加载边播放,不需要一次全下 ...
- 最简单的基于FFMPEG+SDL的音频播放器:拆分-解码器和播放器
===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...
- 最简单的基于FFMPEG+SDL的音频播放器 拆分-解码器和播放器
===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...
- 最简单的基于FFMPEG+SDL的音频播放器
===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...
- 最简单的基于FFMPEG SDL的音频播放器
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! ==== ...
- 一个基于Directshow实现的音频播放器,支持歌词显示
之前在VC知识库上下载了一个基于Directshow做的音乐播放器,带歌词显示功能,觉得挺酷的.我下载了代码,编译了工程之后,运行起来的界面效果如下: 这个播放器支持的功能有: 支持播放MP3/AAC ...
- android第三方开源音频播放器,Android第三方开源SeekBarCompat:音乐类播放器等APP进度条常用...
Android第三方开源SeekBarCompat:音乐类播放器等APP进度条常用 Android平台原生的SeekBar设计简单,然而,比如现在流行的一些音乐播放器的播放进度控制条,如果直接使 ...
- linux开源视频播放器_什么定义了Linux的顶级开源音乐播放器?
linux开源视频播放器 在我撰写此音乐专栏的两年左右的时间里,Linux发烧友的世界得到了发展. 出现了新的Linux发行版和开源音频播放器,旧的已经消失了,随着高质量的数字下载,新的和高质量的播放 ...
最新文章
- 收集一些好的技术文档
- 热潮下的冷思考,人工智能即将改变的三大领域
- mongodb msi安装包_跟我快速学数据存储:MongoDB非关系型数据库
- Leetcode--149. 直线上最多的点数
- 斐波那契数java实现_斐波那契数列Java实现[剑指offer]
- PHP 隐藏真实下载地址
- 安卓学习第一课——电话拨号器
- web.xml filter 不包含_Elasticsearch 之 Filter 与 Query 有啥不同?
- 通证指数:ChaiNext系列指数基金上线
- CVE-2022-21999 Windows Print Spooler(打印服务)特权提升漏洞
- Riot Game前高管:游戏玩家将成为Web3真正粉丝的15大原因
- Android多点触控最佳实践
- Gluster-Heketi-Kubernetes 安装步骤(以DaemonSet形式安装) Ubuntu 16.04
- [杂言]打坐一定要盘腿么?
- 零基础做油管搬运二创项目的正确方式,短视频小白玩家套利的可能
- HADOOP读写性能测试
- Django 教程之数据库模型
- preg_replace_callback函数的使用
- 黑暗堵神传服务器维护是什么意思,黑暗之光————5月7日维护更新公告
- NOJ - 2070 马尔扎哈的疑惑
热门文章
- Imageproplus识别孔隙
- 酒店智能门锁方案功能及其特点介绍
- APP自动化简单理解(在python中实现简单的app自动化框架)
- Python进阶并发基础--线程,全局解释器锁GIL由来,如何更好的利用Python线程,
- 老路用得上的商学课-81-100学习(读书)笔记
- Java高手速成 | 高质量代码编写最佳实践
- 蝴蝶为花碎,花却随风飞
- Distinctive Image Features from Scale-Invariant Keypoints-SIFT算法译文
- 机器学习(六)--------python实现朴素贝叶斯对email分类
- 队内基本伺服系统与传感系统