首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络技术 > 网络基础 >

在iPhone程序中应用后台音乐播放和VoIP

2012-09-10 
在iPhone程序中使用后台音乐播放和VoIP原文: http://blog.toshsoft.de/index.php?/archives/4-Adding-Back

在iPhone程序中使用后台音乐播放和VoIP

原文: http://blog.toshsoft.de/index.php?/archives/4-Adding-Background-Audio-and-VoIP-to-your-iPhone-App.html

 Oct 5. 2010

今天,我会贴出关于iOS 后台任务中的Audio和VoIP的问题,也许你也会遇到同我一样的问题。

本教程使用C库处理sockets,而没有使用苹果的高级API。如果你向用苹果的API,请阅读苹果文档这里

首先,你需要在Info.plist文件中添加新的键UIBackgroundModes,表示你的后台任务类型,包括这两个值:

audio
voip

此外你需要保证,当你从后台恢复时所有的UDP sockets必须被重新open,因为它们不再有效,你会收到SIGPIPE错误。处理SIGPIPE的方法不止一个,其中一个方法就是设置socket选项,让它忽略SIGPIPE。

             // Ignore SIGPIPE because you will get it sometimes after going into zhe        int set = 1;        setsockopt(m_bsdSocket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(set)); 

 

setsockopt应该在socket实例创建之后就调用。

你也可以用异常处理的办法简单地忽略SIGPIPE(Matt Gallagher 有一个很好的例子 这里)。在StackOverflow上也能找到大量的源代码。无论如何你都要进行处理。如果你尝试读取一个断开的socket,你会得到EPIPE、ECONNRESET或ENOTCONN错误。

现在进入正题。在进行tcp socket连接之后,我们将一个读取流关联上去,然后将它(流)设置为kCFStreamNetworkServiceTypeVoIP,以便iOS认为它应该在socket上监听。现在,socket会报告收到数据,哪怕App进入后台,电话仍然是被监听的。示例代码如下:

     #if defined(__IPHONE_4_0) && !(TARGET_IPHONE_SIMULATOR)        // A read stream handle        CFReadStreamRef hReadStream;         // Only do this if it is a SipSocket we are watching        if (IsSipSocket(bsdSocket))        {                // Set it to non-blocking                int set = 1;                ioctl(bsdSocket, FIONBIO, reinterpret_cast<int>(&set));                                CFStreamCreatePairWithSocket (kCFAllocatorDefault, bsdSocket,                                                        &hReadStream, NULL);                if (CFReadStreamSetProperty(hReadStream,                                                        kCFStreamNetworkServiceType,                                                        kCFStreamNetworkServiceTypeVoIP) != TRUE)                {                        // An error occured, delete the stream                        if(hReadStream != NULL)                        {                                CFReadStreamClose(hReadStream);                                CFRelease(hReadStream);                                hReadStream = NULL;                        }                                                return -1;                }                                if (CFReadStreamOpen(hReadStream) != TRUE)                {                        // An error occured, delete the stream                        if(hReadStream != NULL)                        {                                CFReadStreamClose(hReadStream);                                CFRelease(hReadStream);                                hReadStream = NULL;                        }                         return -1;                }        }#endif 

重启或关闭socket时,对应的读取流也应被关闭。

     #if defined(__IPHONE_4_0) && !(TARGET_IPHONE_SIMULATOR)        if (hReadStream)        {                CFReadStreamClose(hReadStream);                CFRelease(hReadStream);                hReadStream = NULL;        }#endif 

这确实很简单,但我花了许多时间才抓住问题的关键。如往常一样,你可以随意使用和修改这些代码,但如果你觉得它们对你有用,或者发现错误,请留下你的意见。

 


热点排行