blob: 5bcf24098a835999e0d2dbdb528f9dd5b034e69e [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001//
2// ipjsuaAppDelegate.m
3// ipjsua
4//
5// Created by Liong Sauw Ming on 13/3/13.
6// Copyright (c) 2013 Teluu. All rights reserved.
7//
8
9#import "ipjsuaAppDelegate.h"
10#import <pjlib.h>
11#import <pjsua.h>
12#import <pj/log.h>
13
14#include "../../pjsua_app.h"
15#include "../../pjsua_app_config.h"
16
17#import "ipjsuaViewController.h"
18
19@implementation ipjsuaAppDelegate
20
21#define THIS_FILE "ipjsuaAppDelegate.m"
22
23#define KEEP_ALIVE_INTERVAL 600
24
25ipjsuaAppDelegate *app;
26static pjsua_app_cfg_t app_cfg;
27static bool isShuttingDown;
28static char **restartArgv;
29static int restartArgc;
30static pj_thread_desc a_thread_desc;
31static pj_thread_t *a_thread;
32
33static void displayMsg(const char *msg)
34{
35 NSString *str = [NSString stringWithFormat:@"%s", msg];
36 [app performSelectorOnMainThread:@selector(displayMsg:) withObject:str
37 waitUntilDone:NO];
38}
39
40static void pjsuaOnStartedCb(pj_status_t status, const char* msg)
41{
42 char errmsg[PJ_ERR_MSG_SIZE];
43
44 if (status != PJ_SUCCESS && (!msg || !*msg)) {
45 pj_strerror(status, errmsg, sizeof(errmsg));
46 PJ_LOG(3,(THIS_FILE, "Error: %s", errmsg));
47 msg = errmsg;
48 } else {
49 PJ_LOG(3,(THIS_FILE, "Started: %s", msg));
50 }
51
52 displayMsg(msg);
53}
54
55static void pjsuaOnStoppedCb(pj_bool_t restart,
56 int argc, char** argv)
57{
58 PJ_LOG(3,("ipjsua", "CLI %s request", (restart? "restart" : "shutdown")));
59 if (restart) {
60 displayMsg("Restarting..");
61 pj_thread_sleep(100);
62 app_cfg.argc = argc;
63 app_cfg.argv = argv;
64 } else {
65 displayMsg("Shutting down..");
66 pj_thread_sleep(100);
67 isShuttingDown = true;
68 }
69}
70
71static void pjsuaOnAppConfigCb(pjsua_app_config *cfg)
72{
73 PJ_UNUSED_ARG(cfg);
74}
75
76- (void)displayMsg:(NSString *)str
77{
78 app.viewController.textLabel.text = str;
79}
80
81- (void)pjsuaStart
82{
83 // TODO: read from config?
84 const char **argv = pjsua_app_def_argv;
85 int argc = PJ_ARRAY_SIZE(pjsua_app_def_argv) -1;
86 pj_status_t status;
87
88 isShuttingDown = false;
89 displayMsg("Starting..");
90
91 pj_bzero(&app_cfg, sizeof(app_cfg));
92 if (restartArgc) {
93 app_cfg.argc = restartArgc;
94 app_cfg.argv = restartArgv;
95 } else {
96 app_cfg.argc = argc;
97 app_cfg.argv = (char**)argv;
98 }
99 app_cfg.on_started = &pjsuaOnStartedCb;
100 app_cfg.on_stopped = &pjsuaOnStoppedCb;
101 app_cfg.on_config_init = &pjsuaOnAppConfigCb;
102
103 while (!isShuttingDown) {
104 status = pjsua_app_init(&app_cfg);
105 if (status != PJ_SUCCESS) {
106 char errmsg[PJ_ERR_MSG_SIZE];
107 pj_strerror(status, errmsg, sizeof(errmsg));
108 displayMsg(errmsg);
109 pjsua_app_destroy();
110 return;
111 }
112
113 status = pjsua_app_run(PJ_TRUE);
114 if (status != PJ_SUCCESS) {
115 char errmsg[PJ_ERR_MSG_SIZE];
116 pj_strerror(status, errmsg, sizeof(errmsg));
117 displayMsg(errmsg);
118 }
119
120 pjsua_app_destroy();
121 }
122
123 restartArgv = NULL;
124 restartArgc = 0;
125}
126
127- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
128{
129 self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
130 // Override point for customization after application launch.
131 if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
132 self.viewController = [[ipjsuaViewController alloc] initWithNibName:@"ipjsuaViewController_iPhone" bundle:nil];
133 } else {
134 self.viewController = [[ipjsuaViewController alloc] initWithNibName:@"ipjsuaViewController_iPad" bundle:nil];
135 }
136 self.window.rootViewController = self.viewController;
137 [self.window makeKeyAndVisible];
138
139 app = self;
140
141 /* Start pjsua app thread */
142 [NSThread detachNewThreadSelector:@selector(pjsuaStart) toTarget:self withObject:nil];
143
144 return YES;
145}
146
147- (void)applicationWillResignActive:(UIApplication *)application
148{
149 // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
150 // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
151}
152
153- (void)keepAlive {
Alexandre Lision94f06ba2013-12-09 16:28:33 -0500154 int i;
Tristan Matthews0a329cc2013-07-17 13:20:14 -0400155
156 if (!pj_thread_is_registered())
157 {
158 pj_thread_register("ipjsua", a_thread_desc, &a_thread);
159 }
160
Alexandre Lision94f06ba2013-12-09 16:28:33 -0500161 /* Since iOS requires that the minimum keep alive interval is 600s,
162 * application needs to make sure that the account's registration
163 * timeout is long enough.
164 */
Tristan Matthews0a329cc2013-07-17 13:20:14 -0400165 for (i = 0; i < (int)pjsua_acc_get_count(); ++i) {
166 if (pjsua_acc_is_valid(i)) {
Alexandre Lision94f06ba2013-12-09 16:28:33 -0500167 pjsua_acc_set_registration(i, PJ_TRUE);
Tristan Matthews0a329cc2013-07-17 13:20:14 -0400168 }
169 }
170}
171
172- (void)applicationDidEnterBackground:(UIApplication *)application
173{
174 // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
175 // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
176 [self performSelectorOnMainThread:@selector(keepAlive) withObject:nil waitUntilDone:YES];
177 [application setKeepAliveTimeout:KEEP_ALIVE_INTERVAL handler: ^{
178 [self performSelectorOnMainThread:@selector(keepAlive) withObject:nil waitUntilDone:YES];
179 }];
180}
181
182- (void)applicationWillEnterForeground:(UIApplication *)application
183{
184 // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
185}
186
187- (void)applicationDidBecomeActive:(UIApplication *)application
188{
189 // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
190}
191
192- (void)applicationWillTerminate:(UIApplication *)application
193{
194 // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
195}
196
197
198pj_bool_t showNotification(pjsua_call_id call_id)
199{
200 // Create a new notification
201 UILocalNotification* alert = [[UILocalNotification alloc] init];
202 if (alert)
203 {
204 alert.repeatInterval = 0;
205 alert.alertBody = @"Incoming call received...";
206 /* This action just brings the app to the FG, it doesn't
207 * automatically answer the call (unless you specify the
208 * --auto-answer option).
209 */
210 alert.alertAction = @"Activate app";
211
212 [[UIApplication sharedApplication] presentLocalNotificationNow:alert];
213 }
214
215 return PJ_FALSE;
216}
217
218@end