我正在获得一个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”被调用,但如果应用程序被最小化则不会。但是,当应用程序恢复时,它会处理收到的所有数据,同时最小化。
我将voip标签添加到info.plist中。我的CFReadStreamSetProperty返回true。我在设备上运行而不是模拟器。它仍然无法正常工作,所以我不知道我的问题是什么。我可能只是做了一些愚蠢的事情,但几乎没有任何网上可以检查我的代码。
编辑:我无法测试任何答案,因为我不再处理这个项目而且无法访问mac / iOs sdk。如果有类似问题的人发现下面的答案之一有用,请告诉我,我会投票给他最好的答案。答案 0 :(得分:28)
如果你想让你的VOIP应用程序在后台运行,除了plist文件中的那些基本设置,你需要一个TCP套接字,其属性设置为VOIP,而iOS系统将为你处理这个套接字,当你的应用程序输入背景,每个东西都是'睡眠',除了tcp socket。如果VOIP服务器发送一些认为TCP套接字的数据,你的应用程序将被唤醒10秒。在此期间,您可以发布本地通知。
只能将Tcp套接字设置为VOIP套接字。但据我所知,大多数VOIP应用程序都基于UDP套接字。如果您不想将控制套接字与数据套接字分开。你应该创建另一个专注于“唤醒”你的应用程序的tcp套接字,根据我的个人经验,很难保持这个“清醒”信号和真正的sip控制信号同步,应用程序总是会错过sip邀请请求。
因此,最好的方法是将sip控件单独与UDP数据套接字分开,使其成为tcp套接字,这是最佳解决方案,但绝不使用tcp套接字来传输语音数据。
另一种肮脏的方式:让应用程序始终保持清醒状态。 正如我所说,每个TCP单应用程序收到认为'VOIP'tcp套接字,将使应用程序保持唤醒10秒,所以在此持续时间结束时(9秒后),您可以向服务器发送响应以请求另一个信号,当下一个信号到达时,应用程序将再次唤醒,9秒后,再次发送响应。继续这样做,你的应用程序将永远清醒。
答案 1 :(得分:5)
我遇到了完全相同的情况 我的问题是我已经将多个套接字配置为Voip套接字。
你可以在Apple's documentations about voip看到他们说:
“为VoIP使用配置一个应用程序的套接字”
我猜他们只是根据一个插座唤醒你的应用程序。
提到的所有其他内容仍然是正确的:
答案 2 :(得分:3)
我也面临同样的问题。但在我的情况下,除非发生网络变化,否则一切正常。我使用苹果“可达性”类来检测网络变化。如果应用程序处于后台,有时我的套接字正在工作,即使我手动切换我的网络以进行以下操作。
过了一段时间,再说一遍我手动尝试网络切换。似乎我的应用程序没有检测到网络更改。我阅读了下面的苹果文档。我肯定做错了(或)误解了第3步和第6步。
实施VoIP应用有几个要求:
<强> 1。将UIBackgroundModes键添加到应用程序的Info.plist文件中。将此键的值设置为包含voip字符串的数组。
配置其中一个应用程序的套接字以供VoIP使用。
在移至后台之前,请调用setKeepAliveTimeout:handler:方法来安装要定期执行的处理程序。您的应用可以使用此处理程序来维护其服务连接。
配置音频会话以处理与主动使用之间的转换。
<强> 5。为了确保在iPhone上获得更好的用户体验,请使用Core Telephony框架调整与基于单元的电话呼叫相关的行为;请参阅核心电话框架参考。
答案 3 :(得分:0)
您可能需要在Info.plist中设置<key>UIBackgroundModes</key><array><string>audio</string></array>
,并且在切换应用之前需要确保音频会话处于活动/正在运行状态(假设您不会突然开始录制/播放音乐/当你的应用在后台播放时。)
The docs说“音频”可让您在后台播放音频,但这可能也适用于录制音频。如果它不起作用,你可以尝试一些事情:
答案 4 :(得分:-1)
您的申请代表中是否有'applicationDidEnterBackground:'。我很确定我已经读过某个地方(我找不到),你需要为ios定义它以识别你支持背景模式。您不需要在其中实现任何内容。
e.g。
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}