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的应用的更多相关文章

  1. DOUAudioStreamer 中的DOUAudioFileProvider理解笔记

    概览 DOUAudioFileProvider读取音频文件local,ipod-library,remote audiofile(通过DOUSimpleHTTPRequest封装的CFHTTPMess ...

  2. Python Twisted、Reactor

    catalogue . Twisted理论基础 . 异步编程模式与Reactor . Twisted网络编程 . reactor进程管理编程 . Twisted并发连接 1. Twisted理论基础 ...

  3. 【转】Python Twisted介绍

    Python Twisted介绍 作者:Jessica McKellar 原文链接 Twisted是用Python实现的基于事件驱动的网络引擎框架.Twisted诞生于2000年初,在当时的网络游戏开 ...

  4. Python Twisted介绍

    原文链接:http://www.aosabook.org/en/twisted.html 作者:Jessica McKellar Twisted是用Python实现的基于事件驱动的网络引擎框架.Twi ...

  5. Linux系统时间与RTC时间【转】

    http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3637782 Linux的RTC驱动相对还是比较简单的,可以将它作为一个普通的字符 ...

  6. Python开源框架

    info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...

  7. kqueue例子

    网络服务器通常都使用epoll进行异步IO处理,而开发者通常使用mac,为了方便开发,我把自己的handy库移植到了mac平台上.移植过程中,网上居然没有搜到kqueue的使用例子,让我惊讶不已.为了 ...

  8. 可扩展的事件复用技术:epoll和kqueue

    通常来说我喜欢Linux更甚于BSD系统,但是我真的想在Linux上拥有BSD的kqueue功能. 什么是事件复用技术 假设你有一个简单的web服务器,并且那里已经打开了两个socket连接.当服务器 ...

  9. 在Mac OS X Yosemite 10.10.3 中搭建第一个 ASP.NET 5 Web 项目

    终于有时间在 Mac 上安装一下 ASP.NET 5,网上有许多教程,但是多数的时间比较早了,版本不是最新,搭着 Build 2015 的春风,我也实践一下 Mac OS X 上的 ASP.NET 5 ...

随机推荐

  1. R中基本统计图

    一.条形图 1.安装包install.packages("vcd"); library(vcd);count<-table(Arthritis$Improved);#tabl ...

  2. 一个 Vue + Node + MongoDB 博客系统

    源码 耗时半载(半个月)的大项目终于完成了.这是一个博客系统,使用 Vue 做前端框架,Node + express 做后端,数据库使用的是 MongoDB.实现了用户注册.用户登录.博客管理(文章的 ...

  3. sqoop关系型数据迁移原理以及map端内存为何不会爆掉窥探

    序:map客户端使用jdbc向数据库发送查询语句,将会拿到所有数据到map的客户端,安装jdbc的原理,数据全部缓存在内存中,但是内存没有出现爆掉情况,这是因为1.3以后,对jdbc进行了优化,改进j ...

  4. 如何使用HTML5自定义数据属性

    在本文中,我将向你介绍如何使用HTML5自定义数据属性.我还将向你介绍一些开发人员在工作中经常使用的优秀实例. 为什么需要自定义数据属性? 很多时候我们需要存储一些与不同DOM元素相关联的信息.这些信 ...

  5. PHP 安装 phpredis 扩展(二)

    本文主要介绍为 PHP 安装 phpredis 扩展,并用 PHP 代码连接 Redis 服务器. 一.安装 phpredis 扩展 1. Linux.macOS 下安装 #. 下载.解压.安装.编译 ...

  6. TOMCAT的框架结构

    Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选.对于一个初学者来说,可以这样 ...

  7. VMWare下ubuntu无法全屏的问题解决

    遇到的情况: 在VMWare中,安装ubuntu 最新版操作系统(16.04).运行该系统,发现ubuntu系统在虚拟机中,只能居中显示,全屏也只能占一半显示屏幕.怎么看,怎么不舒服. 分析问题: 一 ...

  8. 使用了UnityEditor中的API,打包时却不能打包UnityEditor的问题

    前段时间写了一篇名叫<Unity使用Windows弹窗保存图片>的文章 然而现在项目进入了测试阶段 就在发布的时候,这个地方出问题了 问题出在using UnityEditor; 如上文章 ...

  9. Volley使用指南

    1.什么是Volley 在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(A ...

  10. Java中的StringTokenizer类

    /*//在java.util中的StringTokenizer类可以分析一个字符串并将字符串分解成可被独立使用的单词//1.StringTokenizer(String s)-----------为字 ...