我正在获得一个VOIP套接字在iOS应用程序的后台运行。
我的连接工作正常,但是当我的应用程序进入后台时它不会被唤醒。但是,如果我重新打开应用程序,它会响应它在休眠时收到的任何消息。
我这样设置我的流:
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
(CFStringRef) @"test.iusealocaltestserver.com",
5060,
&myReadStream,
&myWriteStream);
CFReadStreamSetProperty ( myReadStream,
kCFStreamNetworkServiceType,
kCFStreamNetworkServiceTypeVoIP
);
CFSocketNativeHandle native;
CFDataRef nativeProp = CFReadStreamCopyProperty(myReadStream, kCFStreamPropertySocketNativeHandle);
CFDataGetBytes(nativeProp, CFRangeMake(0, CFDataGetLength(nativeProp)), (UInt8 *)&native);
CFRelease(nativeProp);
CFSocketRef theSocket = CFSocketCreateWithNative(kCFAllocatorDefault, native, 0, NULL, NULL);
CFSocketGetContext(theSocket,&theContext);
CFOptionFlags readStreamEvents = kCFStreamEventHasBytesAvailable |
kCFStreamEventErrorOccurred |
kCFStreamEventEndEncountered |
kCFStreamEventOpenCompleted;
CFReadStreamSetClient(myReadStream,
readStreamEvents,
(CFReadStreamClientCallBack)&MyCFReadStreamCallback,
(CFStreamClientContext *)(&theContext));
CFReadStreamScheduleWithRunLoop(myReadStream, CFRunLoopGetCurrent(),
kCFRunLoopCommonModes);
然后我的回调设置如下:
static void MyCFReadStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void *pInfo);
static void MyCFReadStreamCallback (CFReadStreamRef stream, CFStreamEventType type, void *pInfo)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(@"Callback Happened");
[pool release];
}
当我接收到数据并且应用程序打开时,"Callback Happened"正在被调用,但如果应用程序被最小化,则不会。不过,当应用程序重新启动时,它会在最小化状态下处理接收到的任何数据。
我在info.plist中添加了voip标签。我的CFReadStreamSetProperty返回true。我在一个设备上运行,而不是模拟器。但它仍然不起作用,所以我不知道我的问题是什么。我可能只是做了一些愚蠢的事情,但是网上几乎没有什么东西可以检查我的代码。
编辑:我不能测试任何答案,因为我不再在这个项目上工作,没有访问mac/iOs sdk。如果有人有类似的问题,发现下面的答案有用,让我知道,我会投票给最好的答案。
如果你想让你的VOIP应用程序在后台运行,除了plist文件中的那些基本设置,你需要一个TCP套接字,它的属性被设置为VOIP,然后iOS系统会为你照顾这个套接字,当你的应用程序进入后台时,所有的东西都是'睡眠',除了TCP套接字。如果VOIP服务器通过TCP套接字发送一些数据,您的应用程序将被唤醒10秒。在此期间,您可以发布本地通知。
只能设置Tcp套接字为VOIP套接字。但据我所知,大多数VOIP应用都是基于UDP套接字的。如果不想将控制套接字与数据套接字分开,请使用。你应该创建另一个TCP套接字,它专注于唤醒你的应用程序,从我个人的经验来看,保持这个唤醒信号和真正的sip控制信号同步是非常困难的,应用程序总是错过sip邀请请求。
所以,最好的方法是将sip控制单从UDP数据套接字中分离出来,使其作为tcp套接字,这是最好的解决方案,但永远不要使用tcp套接字来传输语音数据。另一种肮脏的方式:使应用程序一直处于唤醒状态。正如我所说的,应用程序接收到的每个TCP单个认为'VOIP' TCP套接字,将使应用程序保持唤醒10秒,因此在此持续时间结束时(9秒后),您可以向服务器发送响应以请求另一个信号,当下一个信号到达时,应用程序将再次唤醒,9秒后,再次发送响应。继续这样做,您的应用程序将永远处于唤醒状态。
我被完全相同的场景困住了。
我的问题是,我已经配置了多个套接字作为Voip套接字。
你可以在苹果关于voip的文件中看到,他们说:
"为VoIP使用配置一个应用程序的套接字"
我猜他们只会根据一个套接字唤醒你的应用程序。
所有提到的东西仍然是正确的:
- kCFStreamNetworkServiceTypeVoIP
- 的信息。plist’UIBackgroundModes: voip, audio
- 的信息。plist' UIRequiresPersistentWifi key
- 不能在模拟器上工作
我也面临同样的问题。但在我的情况下,一切都很好,除非网络发生变化。我使用苹果的"可达性"类来检测网络变化。如果应用程序在后台运行,即使我手动切换网络,我的套接字也能正常工作。
- wifi -> 3g
- 3g -> wifi
过了一段时间,让我们再说一遍,我正在手动尝试网络切换。没有什么是快乐的,似乎我的应用程序是不检测网络的变化。我读了下面的苹果文档。我肯定做错了(或)没理解第三步和第六步。
实现VoIP应用程序有几个要求:
1。添加UIBackgroundModes键到你的应用的Info。plist文件。
设置该键的值为包含voip字符串的数组。为VoIP使用配置一个应用的套接字
在移动到后台之前,调用setKeepAliveTimeout:handler:方法来安装一个要定期执行的处理程序。你的应用可以使用这个处理程序来维护它的服务连接。
配置你的音频会话来处理转换到和从活跃使用
5。为了确保在iPhone上获得更好的用户体验,请使用Core Telephony框架来调整与手机通话相关的行为;
- 为确保您的VoIP应用程序的良好性能,请使用系统配置框架来检测网络变化并允许您的应用程序尽可能多地休眠。
您可能需要在Info中设置<key>UIBackgroundModes</key><array><string>audio</string></array>
。在切换应用程序之前,你需要确保音频会话是活动的/正在运行的/无论什么(假设你不会突然开始录制/播放音乐/当你的应用程序在后台时)。
文档说"audio"可以让你在后台播放音频,但这可能也适用于录制音频。如果它不起作用,您可以尝试以下几种方法:
- 设置"voip"one_answers"audio"。
- 播放沉默(这可能是最容易做到与音频队列API)。
你的应用程序委托中有'applicationDidEnterBackground:'吗?我很确定我在某个地方读到过(我找不到)你需要定义它让ios识别你支持后台模式。你不需要在里面实现任何东西。
。
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}