blob: 739d88adb9c1bd72954d0be0d873019e2d736be0 [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 {
154 int i, timeout = KEEP_ALIVE_INTERVAL;
155
156 if (!pj_thread_is_registered())
157 {
158 pj_thread_register("ipjsua", a_thread_desc, &a_thread);
159 }
160
161 for (i = 0; i < (int)pjsua_acc_get_count(); ++i) {
162 if (pjsua_acc_is_valid(i)) {
163 pjsua_acc_config acc_cfg;
164
165 pjsua_acc_get_config(i, &acc_cfg);
166 if (!acc_cfg.reg_uri.slen)
167 continue;
168 if (acc_cfg.reg_timeout < timeout) {
169 acc_cfg.reg_timeout = timeout;
170 pjsua_acc_modify(i, &acc_cfg);
171 } else {
172 pjsua_acc_set_registration(i, PJ_TRUE);
173 }
174 }
175 }
176}
177
178- (void)applicationDidEnterBackground:(UIApplication *)application
179{
180 // 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.
181 // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
182 [self performSelectorOnMainThread:@selector(keepAlive) withObject:nil waitUntilDone:YES];
183 [application setKeepAliveTimeout:KEEP_ALIVE_INTERVAL handler: ^{
184 [self performSelectorOnMainThread:@selector(keepAlive) withObject:nil waitUntilDone:YES];
185 }];
186}
187
188- (void)applicationWillEnterForeground:(UIApplication *)application
189{
190 // 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.
191}
192
193- (void)applicationDidBecomeActive:(UIApplication *)application
194{
195 // 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.
196}
197
198- (void)applicationWillTerminate:(UIApplication *)application
199{
200 // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
201}
202
203
204pj_bool_t showNotification(pjsua_call_id call_id)
205{
206 // Create a new notification
207 UILocalNotification* alert = [[UILocalNotification alloc] init];
208 if (alert)
209 {
210 alert.repeatInterval = 0;
211 alert.alertBody = @"Incoming call received...";
212 /* This action just brings the app to the FG, it doesn't
213 * automatically answer the call (unless you specify the
214 * --auto-answer option).
215 */
216 alert.alertAction = @"Activate app";
217
218 [[UIApplication sharedApplication] presentLocalNotificationNow:alert];
219 }
220
221 return PJ_FALSE;
222}
223
224@end