1

My application is primarily a client for a server that really doesn't have a connection to the internet. It connects to a Polycom codec and manages the video calls between 2 endpoints. So my application can send commands like end call, volume up, etc... However my problem is this. I need some kind of notification when an incoming call happens and the application is not in the foreground. Since the server does not have internet access APNS/push notifications will not work for me. I have looked into doing something like this. Which does seem to keep my client running however I cannot do an alert since my application is in the background.

So besides the basics of how to fix my problem my questions are:

Can I bring my application to the foreground using the technique listed in the link (doing something like what I'm doing below). I can see from the logs that this code keeps my code running. I know my while loop is not right and in the end I would need KVO but regardless that shouldn't effect the answer. (one thing I dont understand is this keeps my whole application running as opposed to just the class I have in there bcClient?)

- (void)applicationDidEnterBackground:(UIApplication *)application
{    
     [bcClient connect];
     bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
     
     // Start the long-running task and return immediately.
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  
          while(1) {   
               sleep(3);
               NSLog(@"held join %d",bcClient.heldjoin);

               if (bcClient.heldjoin == 602 || bcClient.heldjoin == 604 || bcClient.heldjoin == 513) {
                    NSLog(@"incoming call");
               }
          }   
     });           
}

If I cannot bring my application to the foreground then is there anyways to push a notification locally (without the need for a APNS server)?

I have a feeling none of this is possible but I figured I would ask.

Community
  • 1
  • 1
owen gerig
  • 6,165
  • 6
  • 52
  • 91

1 Answers1

0

Here is my answer. This keeps my client application running in the background and shows a notification when a call comes in.

AppDelegate.h

@interface CameleonAppDelegate : NSObject <UIApplicationDelegate> {

    CrestronClient *cClient;
    CrestronControllerValues *CCV;
    RootViewController *rootViewController;
    CrestronValues *crestronValues;

    UIBackgroundTaskIdentifier bgTask;
    dispatch_block_t expirationHandler;
    UIApplication*    app;
    BOOL showedCall;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
-(void)save;
-(void)load;
- (void)backgroundHandler;
@end

AppDelegate.m (just didFinishLaunchingWithOptions and applicationDidEnterBackground)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{    
     app = [UIApplication sharedApplication];
     expirationHandler = ^{

          [app endBackgroundTask:bgTask];
          bgTask = UIBackgroundTaskInvalid;


          bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
     };


    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    NSArray *keys = [NSArray arrayWithObjects:@"IPaddress", @"PortNumber",@"IPID", nil];

    NSArray *objs = [NSArray arrayWithObjects:@"10.8.40.64", @"41794",@"3", nil];

    //10.8.30.143       10.8.40.64

    NSDictionary *dict = [NSDictionary dictionaryWithObjects:objs forKeys:keys];

    [defaults registerDefaults:dict];

     CCV = [CrestronControllerValues sharedManager];

    [CCV setIpAddress:[defaults stringForKey:@"IPaddress"]];
    [CCV setPortNumber:[defaults stringForKey:@"PortNumber"]];
    [CCV setIPID:[defaults stringForKey:@"IPID"]];


    cClient = [CrestronClient sharedManager];


     rootViewController = [[RootViewController alloc]initWithNibName:@"RootViewController" bundle:nil];
     self.window.rootViewController = rootViewController;
     [self.window makeKeyAndVisible];   

    return YES;
}


- (void)applicationDidEnterBackground:(UIApplication *)application
{
     showedCall = FALSE;
     BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];
     if (backgroundAccepted)
     {
          NSLog(@"VOIP backgrounding accepted");
     }


     bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
          [app endBackgroundTask:bgTask];
          bgTask = UIBackgroundTaskInvalid;
     }];


     // Start the long-running task
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

          while (1) {
               sleep(4);
               //NSLog(@"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);

               if ([rootViewController isIncomingCall] && showedCall != TRUE) {
                    UILocalNotification *localNotif = [[UILocalNotification alloc] init];
                    if (localNotif) {
                         localNotif.alertBody = [NSString stringWithFormat:@"Incoming Call."];
                         localNotif.alertAction = NSLocalizedString(@"Accept Call", nil);
                         localNotif.soundName = @"alarmsound.caf";
                         localNotif.applicationIconBadgeNumber = 1;
                         [application presentLocalNotificationNow:localNotif];
                         [localNotif release];
                    }
                    showedCall = TRUE;
               }
          }
     });           
}
- (void)backgroundHandler {

     NSLog(@"### -->VOIP backgrounding callback");


     bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
          [app endBackgroundTask:bgTask];
          bgTask = UIBackgroundTaskInvalid;
     }];

     // Start the long-running task 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

          while (1) {
               NSLog(@"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
               [rootViewController isIncomingCall];
               sleep(1);
          }   
     });
}
owen gerig
  • 6,165
  • 6
  • 52
  • 91
  • Owen, with this code will your application keep running in the background indefinately? – Gruntcakes Dec 05 '11 at 21:41
  • seems to, havnt tested it completely. i have heard reports that on a device it might timeout after 10mins. i need to test that – owen gerig Dec 06 '11 at 01:09
  • Owen, did you test the time out? – Cyprian Dec 12 '11 at 18:20
  • no not yet, broke my ipad recently so till i get it repaired im sol. ask again next week if you remember, other wise ill post am update when i get a chance to test – owen gerig Dec 12 '11 at 18:44
  • @Cyprian no i cannot get this to work past 10mins, did u have any luck in finding a solution? – owen gerig Jan 06 '12 at 15:54
  • @Owen I also had 10 mins results with that, the only thing that worked for me was to play a sound. But dunno if they will allow it in the app store. – Cyprian Jan 06 '12 at 20:29
  • @Cyprian check out my new post and see if it helps http://stackoverflow.com/questions/8748874/gcdasyncsocket-background-voip (give me 10mins to update it though) – owen gerig Jan 06 '12 at 21:00