DOUAudioStreamer 中kqueue的应用
DOUAudioStreamer是一个基于Core Audio的流式音频播放器,其中的DOUAudioEventLoop通过kqueue来控制音频的各种状态。
kqueue简介(详情请看官方manual)
kqueue的功能类似epoll,多用于后台多个socket连接时的I/O复用,注册感兴趣的event,把描述符链表交给内核,然后就等待。一旦有某个或多个事件发生,内核就把 一个只包含有发生了事件的描述符的链表通知给进程,由此避免了每次函数返回的时候都要去遍历整个链表(相较与select和poll)。尽管对于只打开了几个描述符的进程而言这点改进算不得什么,但对于那些打开了几千个文件描述符的程序来说,这种性能改进就相当显著了。
在DOUAudioStreamer中kqueue系统调用生成一个之关联的唯一的描述符,通过kevent来注册和监听音频播放的各种状态的变化,以及变化后(即感兴趣的event发生后)的各种处理。
typedef NS_ENUM(uint64_t, event_type) {
event_play, //播放
event_pause, //暂停
event_stop, //停止
event_seek, //手动选择播放位置
event_streamer_changed, //更换了streamer
event_provider_events,
event_finalizing, //dealloc中发送event,正在释放
#if TARGET_OS_IPHONE
event_interruption_begin,
event_interruption_end,
event_old_device_unavailable, //最后一步
#endif /* TARGET_OS_IPHONE */
event_first = event_play,
#if TARGET_OS_IPHONE
event_last = event_old_device_unavailable,
#else /* TARGET_OS_IPHONE */
event_last = event_finalizing,
#endif /* TARGET_OS_IPHONE */
event_timeout
};
init中初始化过程中的_setupAudioSession(也可以[AVAudioSession sharedInstance] 来设置)
AudioSessionInitialize(NULL, NULL, audio_session_interruption_listener, (__bridge void *)self); //注册被其他应用打断,或其他应用音频播放停止后的处理
//设置MediaPlayback属性可在后台播放声音,也可以避免一些不插耳机时无声的问题
UInt32 audioCategory = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory); AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, audio_route_change_listener, (__bridge void *)self); AudioSessionSetActive(TRUE);
kevent相关的操作
/**
* 官方manual中
The EV_SET() macro is provided for ease of initializing a kevent structure.
EVFILT_USER
Establishes a user event identified by ident which is not associated with any kernel mechanism but is triggered by user level code.
*
*
**/ //相当于register各种感兴趣事件
- (void)_enableEvents
{
for (uint64_t event = event_first; event <= event_last; ++event) {
struct kevent kev;
/**从event_play到event_old_device_unavailable,监听 EV_ADD--添加event,EV_ENABLE--事件被触发后允许返回,EV_CLEAR--返回事件后,重新设置event的状态 **/
EV_SET(&kev, event, EVFILT_USER, EV_ADD | EV_ENABLE | EV_CLEAR, , , NULL);
kevent(_kq, &kev, , NULL, , NULL);
}
} - (void)_sendEvent:(event_type)event
{
[self _sendEvent:event userData:NULL];
} - (void)_sendEvent:(event_type)event userData:(void *)userData
{
struct kevent kev;
//EVFILT_USER通过NOTE_TRIGGER来触发
EV_SET(&kev, event, EVFILT_USER, , NOTE_TRIGGER, , userData);
kevent(_kq, &kev, , NULL, , NULL);
} - (event_type)_waitForEvent
{
return [self _waitForEventWithTimeout:NSUIntegerMax];
}
//kevent监听着感兴趣的事件,一有可用事件就返回事件类型
- (event_type)_waitForEventWithTimeout:(NSUInteger)timeout
{
struct timespec _ts;
struct timespec *ts = NULL;
if (timeout != NSUIntegerMax) {
ts = &_ts; ts->tv_sec = timeout / ;
ts->tv_nsec = (timeout % ) * ;
} while () {
struct kevent kev;
int n = kevent(_kq, NULL, , &kev, , ts);
if (n > ) {
if (kev.filter == EVFILT_USER &&
kev.ident >= event_first &&
kev.ident <= event_last) {
_lastKQUserData = kev.udata;
return kev.ident;
}
}
else {
break;
}
} return event_timeout;
}
最后 _waitForEventWithTimeout / _waitForEvent 被 event_loop_main线程方法中的_eventLoop不断调用,通过_waitForEvent返回的event_type来继续在_handleEvent中处理各种状态需要的操作;
另外_handleEvent中用的是if-else,switch语句是不是性能更好一点,
DOUAudioStreamer 中kqueue的应用的更多相关文章
- DOUAudioStreamer 中的DOUAudioFileProvider理解笔记
概览 DOUAudioFileProvider读取音频文件local,ipod-library,remote audiofile(通过DOUSimpleHTTPRequest封装的CFHTTPMess ...
- Python Twisted、Reactor
catalogue . Twisted理论基础 . 异步编程模式与Reactor . Twisted网络编程 . reactor进程管理编程 . Twisted并发连接 1. Twisted理论基础 ...
- 【转】Python Twisted介绍
Python Twisted介绍 作者:Jessica McKellar 原文链接 Twisted是用Python实现的基于事件驱动的网络引擎框架.Twisted诞生于2000年初,在当时的网络游戏开 ...
- Python Twisted介绍
原文链接:http://www.aosabook.org/en/twisted.html 作者:Jessica McKellar Twisted是用Python实现的基于事件驱动的网络引擎框架.Twi ...
- Linux系统时间与RTC时间【转】
http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3637782 Linux的RTC驱动相对还是比较简单的,可以将它作为一个普通的字符 ...
- Python开源框架
info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...
- kqueue例子
网络服务器通常都使用epoll进行异步IO处理,而开发者通常使用mac,为了方便开发,我把自己的handy库移植到了mac平台上.移植过程中,网上居然没有搜到kqueue的使用例子,让我惊讶不已.为了 ...
- 可扩展的事件复用技术:epoll和kqueue
通常来说我喜欢Linux更甚于BSD系统,但是我真的想在Linux上拥有BSD的kqueue功能. 什么是事件复用技术 假设你有一个简单的web服务器,并且那里已经打开了两个socket连接.当服务器 ...
- 在Mac OS X Yosemite 10.10.3 中搭建第一个 ASP.NET 5 Web 项目
终于有时间在 Mac 上安装一下 ASP.NET 5,网上有许多教程,但是多数的时间比较早了,版本不是最新,搭着 Build 2015 的春风,我也实践一下 Mac OS X 上的 ASP.NET 5 ...
随机推荐
- java复习(1)---java与C++区别
[系列说明]java复习系列适宜有过java学习或C++基础或了解java初步知识的人阅读,目的是为了帮助学习过java但是好久没用已经遗忘了的童鞋快速捡起来.或者教给想快速学习java的童鞋如何应用 ...
- cocos2d-x - C++/Lua交互
使用tolua++将自定义的C++类嵌入,让lua脚本使用 一般过程: 自定义类 -> 使用tolua++工具编译到LuaCoco2d.cpp中 -> lua调用 步骤一:自定义一个C++ ...
- stm32的定时器学习
看了几篇博客之后,对这个定时器也有了一些认识,其实和51差不多,就是配置定时器的时候多了几个步骤而已. 其中很好的一片是:http://blog.sina.com.cn/s/blog_49cb4249 ...
- ClickHouse 快速入门
ClickHouse 是什么 ClickHouse 是一个开源的面向联机分析处理(OLAP, On-Line Analytical Processing) 的列式存储数据库管理系统. 在一个 &quo ...
- Javascript一道面试题
实现一个函数,运算结果可以满足如下预期结果: add(1)(2) // 3add(1, 2, 3)(10) // 16 add(1)(2)(3)(4)(5) // 15 function add () ...
- 【转】QQ传输文件原理参考(来自互联网)
QQ的文件发送是怎样的过程呢?通常,发送文件的计算机首先要通过消息服务器将其IP地址发送给接收计算机,当接收计算机同意接收的确认消息反馈到消息服务器后,消息服务器将据此设置好文件传输对话.随即,发送计 ...
- 一条sql语句引发mysql不停创建临时表的问题解决..coping to tmp table on desk
(不懂临时表的先看 MySQL临时表 ) 首先,临时表只在当前连接可见,当关闭连接时,Mysql会自动删除表并释放所有空间.因此在不同的连接中可以创建同名的临时表,并且操作属于本连接的临时表. ...
- LESS的一点自己的理解(1)
写前端的时间也不短了,Less也用过几次,都是现学现用,没有仔细的梳理过,今天就有条理的梳理下.参考文章是一篇不错的哦.下面会附上链接的,废话不多说,开始正题. 首先应该说下什么是Less,Less是 ...
- 2017云计算开源峰会 你是想听Linux谈开源还是想听OpenStack谈开源?
2017年,善于把握机遇的企业们不是正在开源,就是走在去开源的路上-- 开源是不是就意味着免费? 开源企业就是要当"活雷锋"? 开源项目究竟如何运作?如何参与开源社区? 如何获得最 ...
- TreeSet小练习
package 练习.test1; import java.util.Iterator; import java.util.TreeSet; /* 需求:将字符串中的数值进行排序. 例如String ...