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. 生肖年(switch练习)

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  2. tmux简要介绍

    什么是tmux tmux全称terminal multiplexer,是一个终端复用软件.它可以帮助我们方便地管理多个终端会话. 下面介绍tmux中涉及到的一些名词 window 窗口 pane 窗格 ...

  3. JavaWeb的国际化(17/4/8)

      国际化的缺点: 因为文字不同,所以带来的排版问题一样严重,通常都是重新在写一个网站反而更加清晰,快捷 1:需要从浏览器中获取到浏览器语言(Accept-Language) 2:利用locale获取 ...

  4. 内嵌的Component调用外部的方法

    如果一个内嵌的Component控件需要调用外部定义的方法,用outerDocument.方法名来调用,前提是该方法是public的.如:<mx:DataGridColumn headerTex ...

  5. 纯净CentOS7.2 yum源配置与使用yum 安装系统工具net-tools

    本节我们来讲CentOS 的yum 源配置 一.yum 简介 yum,是Yellow dog Updater, Modified 的简称,是杜克大学为了提高RPM 软件包安装性而开发的一种软件包管理器 ...

  6. 谈谈一些有趣的CSS题目(十五)-- 奇妙的 background-clip: text

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  7. Spring Boot快速建立HelloWorld项目

    Spring Boot使我们更容易去创建基于Spring的独立和产品级的可以”即时运行“的应用和服务.支持约定大于配置,目的是尽可能快地构建和运行Spring应用. 构建环境 JDK 6+ Maven ...

  8. 【Java SE】如何用Java实现直接选择排序

    摘要:直接选择排序属于选择排序的一种,但是它的排序算法比冒泡排序的速度要快一些,由于它的算法比较简单,所以也比较适合初学者学习掌握. 适宜人群:有一定Java SE基础,明白Java的数据类型,数组的 ...

  9. 开源框架是如何通过JMX来做监控的(一) - JMX简介和Standard MBean

    相关文章目录: 开源框架是如何通过JMX来做监控的(一) - JMX简介和Standard MBean 开源框架是如何通过JMX来做监控的(二) - Druid连接池的监控 相信很多做Java开发的同 ...

  10. C语言解析17monipdb.dat(http://www.ipip.net/)免费数据库

    官方给的链接打不开,而且里面的逻辑,每次都会打开文件,所以自己做了点个修改,发上来,借大家参考: #include <stdio.h> #include <stdlib.h> ...