iOS Voip Socket不会在后台运行

时间:2011-07-06 18:59:03

标签: objective-c ios4 voip background-process cfreadstream

我正在获得一个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。如果有类似问题的人发现下面的答案之一有用,请告诉我,我会投票给他最好的答案。

5 个答案:

答案 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使用配置一个应用程序的套接字”

我猜他们只是根据一个插座唤醒你的应用程序。

提到的所有其他内容仍然是正确的:

  • kCFStreamNetworkServiceTypeVoIP
  • 'info.plist'UIBackgroundModes:voip,audio
  • 'info.plist'UIRequiresPersistentWifi key
  • 不适用于模拟器

答案 2 :(得分:3)

我也面临同样的问题。但在我的情况下,除非发生网络变化,否则一切正常。我使用苹果“可达性”类来检测网络变化。如果应用程序处于后台,有时我的套接字正在工作,即使我手动切换我的网络以进行以下操作。

  1. wifi - > 3克
  2. 3g - >无线网络
  3. 过了一段时间,再说一遍我手动尝试网络切换。似乎我的应用程序没有检测到网络更改。我阅读了下面的苹果文档。我肯定做错了(或)误解了第3步和第6步。

    实施VoIP应用有几个要求:

    <强> 1。将UIBackgroundModes键添加到应用程序的Info.plist文件中。将此键的值设置为包含voip字符串的数组。

    1. 配置其中一个应用程序的套接字以供VoIP使用。

    2. 在移至后台之前,请调用setKeepAliveTimeout:handler:方法来安装要定期执行的处理程序。您的应用可以使用此处理程序来维护其服务连接。

    3. 配置音频会话以处理与主动使用之间的转换。

    4. <强> 5。为了确保在iPhone上获得更好的用户体验,请使用Core Telephony框架调整与基于单元的电话呼叫相关的行为;请参阅核心电话框架参考。

      1. 为确保您的VoIP应用程序具有良好的性能,请使用系统配置框架检测网络更改并允许您的应用尽可能多地休眠。

答案 3 :(得分:0)

您可能需要在Info.plist中设置<key>UIBackgroundModes</key><array><string>audio</string></array>,并且在切换应用之前需要确保音频会话处于活动/正在运行状态(假设您不会突然开始录制/播放音乐/当你的应用在后台播放时。)

The docs说“音频”可让您在后台播放音频,但这可能也适用于录制音频。如果它不起作用,你可以尝试一些事情:

  • 同时设置“voip”和“audio”。
  • 播放静音(这可能最容易使用音频队列API)。

答案 4 :(得分:-1)

您的申请代表中是否有'applicationDidEnterBackground:'。我很确定我已经读过某个地方(我找不到),你需要为ios定义它以识别你支持背景模式。您不需要在其中实现任何内容。

e.g。

- (void)applicationDidEnterBackground:(UIApplication *)application
{
}