Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 1 | // pjsua_wince.cpp : Defines the entry point for the application. |
| 2 | // |
| 3 | |
| 4 | #include "stdafx.h" |
| 5 | #include "pjsua_wince.h" |
| 6 | #include <commctrl.h> |
| 7 | #include <pjsua-lib/pjsua.h> |
| 8 | |
| 9 | #define MAX_LOADSTRING 100 |
| 10 | |
| 11 | // Global Variables: |
| 12 | static HINSTANCE hInst; |
| 13 | static HWND hMainWnd; |
| 14 | static HWND hwndCB; |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 15 | static HWND hwndGlobalStatus, hwndURI, hwndCallStatus; |
| 16 | static HWND hwndActionButton, hwndExitButton; |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 17 | |
Benny Prijono | 8a74445 | 2007-05-10 20:40:57 +0000 | [diff] [blame] | 18 | |
| 19 | |
| 20 | // |
| 21 | // Basic config. |
| 22 | // |
| 23 | #define SIP_PORT 5060 |
| 24 | |
| 25 | |
| 26 | // |
| 27 | // Destination URI (to make call, or to subscribe presence) |
| 28 | // |
| 29 | #define SIP_DST_URI "sip:192.168.0.7:5061" |
| 30 | |
| 31 | // |
| 32 | // Account |
| 33 | // |
| 34 | #define HAS_SIP_ACCOUNT 0 // 0 to disable registration |
| 35 | #define SIP_DOMAIN "server" |
| 36 | #define SIP_REALM "server" |
| 37 | #define SIP_USER "user" |
| 38 | #define SIP_PASSWD "secret" |
| 39 | |
| 40 | // |
| 41 | // Outbound proxy for all accounts |
| 42 | // |
| 43 | #define SIP_PROXY NULL |
| 44 | //#define SIP_PROXY "sip:192.168.0.2;lr" |
| 45 | |
| 46 | |
| 47 | // |
| 48 | // Configure nameserver if DNS SRV is to be used with both SIP |
| 49 | // or STUN (for STUN see other settings below) |
| 50 | // |
| 51 | #define NAMESERVER NULL |
| 52 | //#define NAMESERVER "62.241.163.201" |
| 53 | |
| 54 | // |
| 55 | // STUN server |
Benny Prijono | f4e03a7 | 2007-10-12 23:29:27 +0000 | [diff] [blame] | 56 | #if 1 |
Benny Prijono | 8a74445 | 2007-05-10 20:40:57 +0000 | [diff] [blame] | 57 | // Use this to have the STUN server resolved normally |
| 58 | # define STUN_DOMAIN NULL |
Benny Prijono | f4e03a7 | 2007-10-12 23:29:27 +0000 | [diff] [blame] | 59 | # define STUN_SERVER "stun.fwdnet.net" |
Benny Prijono | 8a74445 | 2007-05-10 20:40:57 +0000 | [diff] [blame] | 60 | #elif 0 |
| 61 | // Use this to have the STUN server resolved with DNS SRV |
| 62 | # define STUN_DOMAIN "iptel.org" |
| 63 | # define STUN_SERVER NULL |
| 64 | #else |
| 65 | // Use this to disable STUN |
| 66 | # define STUN_DOMAIN NULL |
| 67 | # define STUN_SERVER NULL |
| 68 | #endif |
| 69 | |
| 70 | // |
| 71 | // Use ICE? |
| 72 | // |
| 73 | #define USE_ICE 1 |
| 74 | |
| 75 | |
| 76 | // |
| 77 | // Globals |
| 78 | // |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 79 | static pj_pool_t *g_pool; |
| 80 | static pj_str_t g_local_uri; |
| 81 | static int g_current_acc; |
| 82 | static int g_current_call = PJSUA_INVALID_ID; |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 83 | static int g_current_action; |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 84 | |
| 85 | enum |
| 86 | { |
| 87 | ID_GLOBAL_STATUS = 21, |
| 88 | ID_URI, |
| 89 | ID_CALL_STATUS, |
| 90 | ID_POLL_TIMER, |
| 91 | }; |
| 92 | |
| 93 | enum |
| 94 | { |
| 95 | ID_MENU_NONE = 64, |
| 96 | ID_MENU_CALL, |
| 97 | ID_MENU_ANSWER, |
| 98 | ID_MENU_DISCONNECT, |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 99 | ID_BTN_ACTION, |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 100 | }; |
| 101 | |
| 102 | |
| 103 | // Forward declarations of functions included in this code module: |
| 104 | static ATOM MyRegisterClass (HINSTANCE, LPTSTR); |
| 105 | BOOL InitInstance (HINSTANCE, int); |
| 106 | static void OnCreate (HWND hWnd); |
| 107 | static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); |
| 108 | |
| 109 | |
| 110 | |
| 111 | ///////////////////////////////////////////////////////////////////////////// |
| 112 | |
| 113 | static void OnError(const wchar_t *title, pj_status_t status) |
| 114 | { |
| 115 | char errmsg[PJ_ERR_MSG_SIZE]; |
| 116 | PJ_DECL_UNICODE_TEMP_BUF(werrmsg, PJ_ERR_MSG_SIZE); |
| 117 | |
| 118 | pj_strerror(status, errmsg, sizeof(errmsg)); |
| 119 | |
| 120 | MessageBox(NULL, PJ_STRING_TO_NATIVE(errmsg, werrmsg, PJ_ERR_MSG_SIZE), |
| 121 | title, MB_OK); |
| 122 | } |
| 123 | |
| 124 | |
| 125 | static void SetLocalURI(const char *uri, int len, bool enabled=true) |
| 126 | { |
| 127 | wchar_t tmp[128]; |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 128 | if (len==-1) len=pj_ansi_strlen(uri); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 129 | pj_ansi_to_unicode(uri, len, tmp, PJ_ARRAY_SIZE(tmp)); |
| 130 | SetDlgItemText(hMainWnd, ID_GLOBAL_STATUS, tmp); |
| 131 | EnableWindow(hwndGlobalStatus, enabled?TRUE:FALSE); |
| 132 | } |
| 133 | |
| 134 | |
| 135 | |
| 136 | static void SetURI(const char *uri, int len, bool enabled=true) |
| 137 | { |
| 138 | wchar_t tmp[128]; |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 139 | if (len==-1) len=pj_ansi_strlen(uri); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 140 | pj_ansi_to_unicode(uri, len, tmp, PJ_ARRAY_SIZE(tmp)); |
| 141 | SetDlgItemText(hMainWnd, ID_URI, tmp); |
| 142 | EnableWindow(hwndURI, enabled?TRUE:FALSE); |
| 143 | } |
| 144 | |
| 145 | |
| 146 | static void SetCallStatus(const char *state, int len) |
| 147 | { |
| 148 | wchar_t tmp[128]; |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 149 | if (len==-1) len=pj_ansi_strlen(state); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 150 | pj_ansi_to_unicode(state, len, tmp, PJ_ARRAY_SIZE(tmp)); |
| 151 | SetDlgItemText(hMainWnd, ID_CALL_STATUS, tmp); |
| 152 | } |
| 153 | |
| 154 | static void SetAction(int action, bool enable=true) |
| 155 | { |
| 156 | HMENU hMenu; |
| 157 | |
| 158 | hMenu = CommandBar_GetMenu(hwndCB, 0); |
| 159 | |
| 160 | RemoveMenu(hMenu, ID_MENU_NONE, MF_BYCOMMAND); |
| 161 | RemoveMenu(hMenu, ID_MENU_CALL, MF_BYCOMMAND); |
| 162 | RemoveMenu(hMenu, ID_MENU_ANSWER, MF_BYCOMMAND); |
| 163 | RemoveMenu(hMenu, ID_MENU_DISCONNECT, MF_BYCOMMAND); |
| 164 | |
| 165 | switch (action) { |
| 166 | case ID_MENU_NONE: |
| 167 | InsertMenu(hMenu, ID_EXIT, MF_BYCOMMAND, action, TEXT("None")); |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 168 | SetWindowText(hwndActionButton, TEXT("-")); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 169 | break; |
| 170 | case ID_MENU_CALL: |
| 171 | InsertMenu(hMenu, ID_EXIT, MF_BYCOMMAND, action, TEXT("Call")); |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 172 | SetWindowText(hwndActionButton, TEXT("&Call")); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 173 | break; |
| 174 | case ID_MENU_ANSWER: |
| 175 | InsertMenu(hMenu, ID_EXIT, MF_BYCOMMAND, action, TEXT("Answer")); |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 176 | SetWindowText(hwndActionButton, TEXT("&Answer")); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 177 | break; |
| 178 | case ID_MENU_DISCONNECT: |
| 179 | InsertMenu(hMenu, ID_EXIT, MF_BYCOMMAND, action, TEXT("Hangup")); |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 180 | SetWindowText(hwndActionButton, TEXT("&Hangup")); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 181 | break; |
| 182 | } |
| 183 | |
| 184 | EnableMenuItem(hMenu, action, MF_BYCOMMAND | (enable?MF_ENABLED:MF_GRAYED)); |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 185 | DrawMenuBar(hMainWnd); |
| 186 | |
| 187 | g_current_action = action; |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 188 | } |
| 189 | |
| 190 | |
| 191 | /* |
| 192 | * Handler when invite state has changed. |
| 193 | */ |
| 194 | static void on_call_state(pjsua_call_id call_id, pjsip_event *e) |
| 195 | { |
| 196 | pjsua_call_info call_info; |
| 197 | |
| 198 | PJ_UNUSED_ARG(e); |
| 199 | |
| 200 | pjsua_call_get_info(call_id, &call_info); |
| 201 | |
| 202 | if (call_info.state == PJSIP_INV_STATE_DISCONNECTED) { |
| 203 | |
| 204 | g_current_call = PJSUA_INVALID_ID; |
Benny Prijono | 8a74445 | 2007-05-10 20:40:57 +0000 | [diff] [blame] | 205 | SetURI(SIP_DST_URI, -1); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 206 | SetAction(ID_MENU_CALL); |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 207 | //SetCallStatus(call_info.state_text.ptr, call_info.state_text.slen); |
| 208 | SetCallStatus(call_info.last_status_text.ptr, call_info.last_status_text.slen); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 209 | |
| 210 | } else { |
Benny Prijono | edba079 | 2006-08-06 18:23:56 +0000 | [diff] [blame] | 211 | //if (g_current_call == PJSUA_INVALID_ID) |
| 212 | // g_current_call = call_id; |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 213 | |
| 214 | if (call_info.remote_contact.slen) |
| 215 | SetURI(call_info.remote_contact.ptr, call_info.remote_contact.slen, false); |
| 216 | else |
| 217 | SetURI(call_info.remote_info.ptr, call_info.remote_info.slen, false); |
Benny Prijono | edba079 | 2006-08-06 18:23:56 +0000 | [diff] [blame] | 218 | |
| 219 | if (call_info.state == PJSIP_INV_STATE_CONFIRMED) |
| 220 | SetAction(ID_MENU_DISCONNECT); |
| 221 | |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 222 | SetCallStatus(call_info.state_text.ptr, call_info.state_text.slen); |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | |
| 227 | /* |
| 228 | * Callback on media state changed event. |
| 229 | * The action may connect the call to sound device, to file, or |
| 230 | * to loop the call. |
| 231 | */ |
| 232 | static void on_call_media_state(pjsua_call_id call_id) |
| 233 | { |
| 234 | pjsua_call_info call_info; |
| 235 | |
| 236 | pjsua_call_get_info(call_id, &call_info); |
| 237 | |
| 238 | if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE) { |
| 239 | pjsua_conf_connect(call_info.conf_slot, 0); |
| 240 | pjsua_conf_connect(0, call_info.conf_slot); |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | |
| 245 | /** |
| 246 | * Handler when there is incoming call. |
| 247 | */ |
| 248 | static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, |
| 249 | pjsip_rx_data *rdata) |
| 250 | { |
| 251 | pjsua_call_info call_info; |
| 252 | |
| 253 | PJ_UNUSED_ARG(acc_id); |
| 254 | PJ_UNUSED_ARG(rdata); |
| 255 | |
| 256 | if (g_current_call != PJSUA_INVALID_ID) { |
Benny Prijono | edba079 | 2006-08-06 18:23:56 +0000 | [diff] [blame] | 257 | pj_str_t reason; |
| 258 | reason = pj_str("Another call is in progress"); |
| 259 | pjsua_call_answer(call_id, PJSIP_SC_BUSY_HERE, &reason, NULL); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 260 | return; |
| 261 | } |
| 262 | |
| 263 | g_current_call = call_id; |
| 264 | |
| 265 | pjsua_call_get_info(call_id, &call_info); |
| 266 | |
| 267 | SetAction(ID_MENU_ANSWER); |
| 268 | SetURI(call_info.remote_info.ptr, call_info.remote_info.slen, false); |
Benny Prijono | fd27c66 | 2006-08-09 11:59:26 +0000 | [diff] [blame] | 269 | pjsua_call_answer(call_id, 200, NULL, NULL); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 270 | } |
| 271 | |
| 272 | |
| 273 | /* |
| 274 | * Handler registration status has changed. |
| 275 | */ |
| 276 | static void on_reg_state(pjsua_acc_id acc_id) |
| 277 | { |
| 278 | PJ_UNUSED_ARG(acc_id); |
| 279 | |
| 280 | // Log already written. |
| 281 | } |
| 282 | |
| 283 | |
| 284 | /* |
| 285 | * Handler on buddy state changed. |
| 286 | */ |
| 287 | static void on_buddy_state(pjsua_buddy_id buddy_id) |
| 288 | { |
| 289 | } |
| 290 | |
| 291 | |
| 292 | /** |
| 293 | * Incoming IM message (i.e. MESSAGE request)! |
| 294 | */ |
| 295 | static void on_pager(pjsua_call_id call_id, const pj_str_t *from, |
| 296 | const pj_str_t *to, const pj_str_t *contact, |
| 297 | const pj_str_t *mime_type, const pj_str_t *text) |
| 298 | { |
| 299 | } |
| 300 | |
| 301 | |
| 302 | /** |
| 303 | * Received typing indication |
| 304 | */ |
| 305 | static void on_typing(pjsua_call_id call_id, const pj_str_t *from, |
| 306 | const pj_str_t *to, const pj_str_t *contact, |
| 307 | pj_bool_t is_typing) |
| 308 | { |
| 309 | } |
| 310 | |
| 311 | |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 312 | static BOOL OnInitStack(void) |
| 313 | { |
| 314 | pjsua_config cfg; |
| 315 | pjsua_logging_config log_cfg; |
| 316 | pjsua_media_config media_cfg; |
| 317 | pjsua_transport_config udp_cfg; |
| 318 | pjsua_transport_config rtp_cfg; |
| 319 | pjsua_transport_id transport_id; |
| 320 | pjsua_transport_info transport_info; |
Benny Prijono | 7c3741f | 2006-08-05 21:07:15 +0000 | [diff] [blame] | 321 | pj_str_t tmp; |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 322 | pj_status_t status; |
| 323 | |
| 324 | /* Create pjsua */ |
| 325 | status = pjsua_create(); |
| 326 | if (status != PJ_SUCCESS) { |
| 327 | OnError(TEXT("Error creating pjsua"), status); |
| 328 | return FALSE; |
| 329 | } |
| 330 | |
| 331 | /* Create global pool for application */ |
| 332 | g_pool = pjsua_pool_create("pjsua", 4000, 4000); |
| 333 | |
| 334 | /* Init configs */ |
| 335 | pjsua_config_default(&cfg); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 336 | pjsua_media_config_default(&media_cfg); |
| 337 | pjsua_transport_config_default(&udp_cfg); |
Benny Prijono | 8a74445 | 2007-05-10 20:40:57 +0000 | [diff] [blame] | 338 | udp_cfg.port = SIP_PORT; |
| 339 | |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 340 | pjsua_transport_config_default(&rtp_cfg); |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 341 | rtp_cfg.port = 40000; |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 342 | |
Benny Prijono | 4e05b47 | 2006-10-16 15:52:31 +0000 | [diff] [blame] | 343 | pjsua_logging_config_default(&log_cfg); |
| 344 | log_cfg.level = 5; |
| 345 | log_cfg.log_filename = pj_str("\\pjsua.txt"); |
| 346 | log_cfg.msg_logging = 1; |
| 347 | log_cfg.decor = pj_log_get_decor() | PJ_LOG_HAS_CR; |
| 348 | |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 349 | /* Setup media */ |
| 350 | media_cfg.clock_rate = 8000; |
Benny Prijono | 5da5043 | 2006-08-07 10:24:52 +0000 | [diff] [blame] | 351 | media_cfg.ec_options = PJMEDIA_ECHO_SIMPLE; |
Benny Prijono | fd27c66 | 2006-08-09 11:59:26 +0000 | [diff] [blame] | 352 | media_cfg.ec_tail_len = 256; |
Benny Prijono | edba079 | 2006-08-06 18:23:56 +0000 | [diff] [blame] | 353 | media_cfg.quality = 1; |
| 354 | media_cfg.ptime = 20; |
Benny Prijono | 8a74445 | 2007-05-10 20:40:57 +0000 | [diff] [blame] | 355 | media_cfg.enable_ice = USE_ICE; |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 356 | |
| 357 | /* Initialize application callbacks */ |
| 358 | cfg.cb.on_call_state = &on_call_state; |
| 359 | cfg.cb.on_call_media_state = &on_call_media_state; |
| 360 | cfg.cb.on_incoming_call = &on_incoming_call; |
| 361 | cfg.cb.on_reg_state = &on_reg_state; |
| 362 | cfg.cb.on_buddy_state = &on_buddy_state; |
| 363 | cfg.cb.on_pager = &on_pager; |
| 364 | cfg.cb.on_typing = &on_typing; |
| 365 | |
Benny Prijono | 8a74445 | 2007-05-10 20:40:57 +0000 | [diff] [blame] | 366 | if (SIP_PROXY) { |
| 367 | cfg.outbound_proxy_cnt = 1; |
| 368 | cfg.outbound_proxy[0] = pj_str(SIP_PROXY); |
| 369 | } |
| 370 | |
| 371 | if (NAMESERVER) { |
| 372 | cfg.nameserver_count = 1; |
| 373 | cfg.nameserver[0] = pj_str(NAMESERVER); |
| 374 | } |
| 375 | |
| 376 | if (NAMESERVER && STUN_DOMAIN) { |
| 377 | cfg.stun_domain = pj_str(STUN_DOMAIN); |
| 378 | } else if (STUN_SERVER) { |
| 379 | cfg.stun_host = pj_str(STUN_SERVER); |
| 380 | } |
| 381 | |
| 382 | |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 383 | /* Initialize pjsua */ |
| 384 | status = pjsua_init(&cfg, &log_cfg, &media_cfg); |
| 385 | if (status != PJ_SUCCESS) { |
| 386 | OnError(TEXT("Initialization error"), status); |
| 387 | return FALSE; |
| 388 | } |
| 389 | |
| 390 | /* Set codec priority */ |
Benny Prijono | edba079 | 2006-08-06 18:23:56 +0000 | [diff] [blame] | 391 | pjsua_codec_set_priority(pj_cstr(&tmp, "pcmu"), 240); |
| 392 | pjsua_codec_set_priority(pj_cstr(&tmp, "pcma"), 230); |
| 393 | pjsua_codec_set_priority(pj_cstr(&tmp, "speex/8000"), 190); |
Benny Prijono | fd27c66 | 2006-08-09 11:59:26 +0000 | [diff] [blame] | 394 | pjsua_codec_set_priority(pj_cstr(&tmp, "ilbc"), 189); |
Benny Prijono | edba079 | 2006-08-06 18:23:56 +0000 | [diff] [blame] | 395 | pjsua_codec_set_priority(pj_cstr(&tmp, "speex/16000"), 180); |
Benny Prijono | 7c3741f | 2006-08-05 21:07:15 +0000 | [diff] [blame] | 396 | pjsua_codec_set_priority(pj_cstr(&tmp, "speex/32000"), 0); |
Benny Prijono | fd27c66 | 2006-08-09 11:59:26 +0000 | [diff] [blame] | 397 | pjsua_codec_set_priority(pj_cstr(&tmp, "gsm"), 100); |
Benny Prijono | 7c3741f | 2006-08-05 21:07:15 +0000 | [diff] [blame] | 398 | |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 399 | |
| 400 | /* Add UDP transport and the corresponding PJSUA account */ |
| 401 | status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, |
| 402 | &udp_cfg, &transport_id); |
| 403 | if (status != PJ_SUCCESS) { |
| 404 | OnError(TEXT("Error starting SIP transport"), status); |
| 405 | return FALSE; |
| 406 | } |
| 407 | |
| 408 | pjsua_transport_get_info(transport_id, &transport_info); |
| 409 | |
| 410 | g_local_uri.ptr = (char*)pj_pool_alloc(g_pool, 128); |
| 411 | g_local_uri.slen = pj_ansi_sprintf(g_local_uri.ptr, |
| 412 | "<sip:%.*s:%d>", |
| 413 | (int)transport_info.local_name.host.slen, |
| 414 | transport_info.local_name.host.ptr, |
| 415 | transport_info.local_name.port); |
| 416 | |
| 417 | |
| 418 | /* Add local account */ |
| 419 | pjsua_acc_add_local(transport_id, PJ_TRUE, &g_current_acc); |
| 420 | pjsua_acc_set_online_status(g_current_acc, PJ_TRUE); |
| 421 | |
Benny Prijono | 8a74445 | 2007-05-10 20:40:57 +0000 | [diff] [blame] | 422 | /* Add account */ |
| 423 | if (HAS_SIP_ACCOUNT) { |
| 424 | pjsua_acc_config cfg; |
| 425 | |
| 426 | pjsua_acc_config_default(&cfg); |
| 427 | cfg.id = pj_str("sip:" SIP_USER "@" SIP_DOMAIN); |
| 428 | cfg.reg_uri = pj_str("sip:" SIP_DOMAIN); |
| 429 | cfg.cred_count = 1; |
| 430 | cfg.cred_info[0].realm = pj_str(SIP_REALM); |
| 431 | cfg.cred_info[0].scheme = pj_str("digest"); |
| 432 | cfg.cred_info[0].username = pj_str(SIP_USER); |
| 433 | cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; |
| 434 | cfg.cred_info[0].data = pj_str(SIP_PASSWD); |
| 435 | |
| 436 | status = pjsua_acc_add(&cfg, PJ_TRUE, &g_current_acc); |
| 437 | if (status != PJ_SUCCESS) { |
| 438 | pjsua_destroy(); |
| 439 | return PJ_FALSE; |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | /* Add buddy */ |
| 444 | if (SIP_DST_URI) { |
| 445 | pjsua_buddy_config bcfg; |
| 446 | |
| 447 | pjsua_buddy_config_default(&bcfg); |
| 448 | bcfg.uri = pj_str(SIP_DST_URI); |
| 449 | bcfg.subscribe = PJ_FALSE; |
| 450 | |
| 451 | pjsua_buddy_add(&bcfg, NULL); |
| 452 | } |
| 453 | |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 454 | /* Start pjsua */ |
| 455 | status = pjsua_start(); |
| 456 | if (status != PJ_SUCCESS) { |
| 457 | OnError(TEXT("Error starting pjsua"), status); |
| 458 | return FALSE; |
| 459 | } |
| 460 | |
| 461 | return TRUE; |
| 462 | } |
| 463 | |
| 464 | |
| 465 | ////////////////////////////////////////////////////////////////////////////// |
| 466 | |
| 467 | int WINAPI WinMain(HINSTANCE hInstance, |
| 468 | HINSTANCE hPrevInstance, |
| 469 | LPTSTR lpCmdLine, |
| 470 | int nCmdShow) |
| 471 | { |
| 472 | MSG msg; |
| 473 | HACCEL hAccelTable; |
| 474 | |
| 475 | |
| 476 | |
| 477 | // Perform application initialization: |
| 478 | if (!InitInstance (hInstance, nCmdShow)) |
| 479 | { |
| 480 | return FALSE; |
| 481 | } |
| 482 | |
| 483 | hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_PJSUA_WINCE); |
| 484 | |
| 485 | |
| 486 | // Main message loop: |
| 487 | while (GetMessage(&msg, NULL, 0, 0)) |
| 488 | { |
| 489 | if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) |
| 490 | { |
| 491 | TranslateMessage(&msg); |
| 492 | DispatchMessage(&msg); |
| 493 | } |
| 494 | } |
| 495 | |
| 496 | return msg.wParam; |
| 497 | } |
| 498 | |
| 499 | static ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass) |
| 500 | { |
| 501 | WNDCLASS wc; |
| 502 | |
| 503 | wc.style = CS_HREDRAW | CS_VREDRAW; |
| 504 | wc.lpfnWndProc = (WNDPROC) WndProc; |
| 505 | wc.cbClsExtra = 0; |
| 506 | wc.cbWndExtra = 0; |
| 507 | wc.hInstance = hInstance; |
| 508 | wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PJSUA_WINCE)); |
| 509 | wc.hCursor = 0; |
| 510 | wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); |
| 511 | wc.lpszMenuName = 0; |
| 512 | wc.lpszClassName = szWindowClass; |
| 513 | |
| 514 | return RegisterClass(&wc); |
| 515 | } |
| 516 | |
| 517 | |
Benny Prijono | 4ab9fbb | 2007-10-12 12:14:27 +0000 | [diff] [blame] | 518 | /* Callback upon NAT detection completion */ |
Benny Prijono | 3808af1 | 2007-10-18 01:40:44 +0000 | [diff] [blame] | 519 | static void nat_detect_cb(const pj_stun_nat_detect_result *res) |
Benny Prijono | 4ab9fbb | 2007-10-12 12:14:27 +0000 | [diff] [blame] | 520 | { |
Benny Prijono | 4ab9fbb | 2007-10-12 12:14:27 +0000 | [diff] [blame] | 521 | if (res->status != PJ_SUCCESS) { |
| 522 | char msg[250]; |
| 523 | pj_ansi_snprintf(msg, sizeof(msg), "NAT detection failed: %s", |
| 524 | res->status_text); |
| 525 | SetCallStatus(msg, pj_ansi_strlen(msg)); |
| 526 | } else { |
| 527 | char msg[250]; |
| 528 | pj_ansi_snprintf(msg, sizeof(msg), "NAT type is %s", |
| 529 | res->nat_type_name); |
| 530 | SetCallStatus(msg, pj_ansi_strlen(msg)); |
| 531 | } |
| 532 | } |
| 533 | |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 534 | |
| 535 | BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) |
| 536 | { |
| 537 | HWND hWnd; |
| 538 | TCHAR szTitle[MAX_LOADSTRING]; |
| 539 | TCHAR szWindowClass[MAX_LOADSTRING]; |
| 540 | |
| 541 | hInst = hInstance; |
| 542 | |
| 543 | /* Init stack */ |
| 544 | if (OnInitStack() == FALSE) |
| 545 | return FALSE; |
| 546 | |
| 547 | LoadString(hInstance, IDC_PJSUA_WINCE, szWindowClass, MAX_LOADSTRING); |
| 548 | MyRegisterClass(hInstance, szWindowClass); |
| 549 | |
| 550 | LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); |
| 551 | hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE, |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 552 | CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 200, |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 553 | NULL, NULL, hInstance, NULL); |
| 554 | |
| 555 | if (!hWnd) |
| 556 | { |
| 557 | return FALSE; |
| 558 | } |
| 559 | |
| 560 | hMainWnd = hWnd; |
| 561 | ShowWindow(hWnd, nCmdShow); |
| 562 | UpdateWindow(hWnd); |
| 563 | if (hwndCB) |
| 564 | CommandBar_Show(hwndCB, TRUE); |
| 565 | |
| 566 | SetTimer(hMainWnd, ID_POLL_TIMER, 50, NULL); |
Benny Prijono | 4ab9fbb | 2007-10-12 12:14:27 +0000 | [diff] [blame] | 567 | |
Benny Prijono | 3808af1 | 2007-10-18 01:40:44 +0000 | [diff] [blame] | 568 | pjsua_detect_nat_type(); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 569 | return TRUE; |
| 570 | } |
| 571 | |
| 572 | |
| 573 | static void OnCreate(HWND hWnd) |
| 574 | { |
| 575 | enum |
| 576 | { |
| 577 | X = 10, |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 578 | Y = 40, |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 579 | W = 220, |
| 580 | H = 30, |
| 581 | }; |
| 582 | |
| 583 | DWORD dwStyle; |
| 584 | |
| 585 | hMainWnd = hWnd; |
| 586 | |
| 587 | hwndCB = CommandBar_Create(hInst, hWnd, 1); |
| 588 | CommandBar_InsertMenubar(hwndCB, hInst, IDM_MENU, 0); |
| 589 | CommandBar_AddAdornments(hwndCB, 0, 0); |
| 590 | |
| 591 | // Create global status text |
| 592 | dwStyle = WS_CHILD | WS_VISIBLE | WS_DISABLED | ES_LEFT; |
| 593 | hwndGlobalStatus = CreateWindow( |
| 594 | TEXT("EDIT"), // Class name |
| 595 | NULL, // Window text |
| 596 | dwStyle, // Window style |
| 597 | X, // x-coordinate of the upper-left corner |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 598 | Y+0, // y-coordinate of the upper-left corner |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 599 | W, // Width of the window for the edit |
| 600 | // control |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 601 | H-5, // Height of the window for the edit |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 602 | // control |
| 603 | hWnd, // Window handle to the parent window |
| 604 | (HMENU) ID_GLOBAL_STATUS, // Control identifier |
| 605 | hInst, // Instance handle |
| 606 | NULL); // Specify NULL for this parameter when |
| 607 | // you create a control |
| 608 | SetLocalURI(g_local_uri.ptr, g_local_uri.slen, false); |
| 609 | |
| 610 | |
| 611 | // Create URI edit |
| 612 | dwStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER; |
| 613 | hwndURI = CreateWindow ( |
| 614 | TEXT("EDIT"), // Class name |
| 615 | NULL, // Window text |
| 616 | dwStyle, // Window style |
| 617 | X, // x-coordinate of the upper-left corner |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 618 | Y+H, // y-coordinate of the upper-left corner |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 619 | W, // Width of the window for the edit |
| 620 | // control |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 621 | H-5, // Height of the window for the edit |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 622 | // control |
| 623 | hWnd, // Window handle to the parent window |
| 624 | (HMENU) ID_URI, // Control identifier |
| 625 | hInst, // Instance handle |
| 626 | NULL); // Specify NULL for this parameter when |
| 627 | // you create a control |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 628 | |
| 629 | // Create action Button |
| 630 | hwndActionButton = CreateWindow( L"button", L"Action", |
| 631 | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, |
| 632 | X, Y+2*H, |
| 633 | 60, H-5, hWnd, |
| 634 | (HMENU) ID_BTN_ACTION, |
| 635 | hInst, NULL ); |
| 636 | |
| 637 | // Create exit button |
| 638 | hwndExitButton = CreateWindow( L"button", L"E&xit", |
| 639 | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, |
| 640 | X+70, Y+2*H, |
| 641 | 60, H-5, hWnd, |
| 642 | (HMENU) ID_EXIT, |
| 643 | hInst, NULL ); |
| 644 | |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 645 | |
| 646 | // Create call status edit |
| 647 | dwStyle = WS_CHILD | WS_VISIBLE | WS_DISABLED; |
| 648 | hwndCallStatus = CreateWindow ( |
| 649 | TEXT("EDIT"), // Class name |
| 650 | NULL, // Window text |
| 651 | dwStyle, // Window style |
| 652 | X, // x-coordinate of the upper-left corner |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 653 | Y+3*H, // y-coordinate of the upper-left corner |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 654 | W, // Width of the window for the edit |
| 655 | // control |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 656 | H-5, // Height of the window for the edit |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 657 | // control |
| 658 | hWnd, // Window handle to the parent window |
| 659 | (HMENU) ID_CALL_STATUS, // Control identifier |
| 660 | hInst, // Instance handle |
| 661 | NULL); // Specify NULL for this parameter when |
| 662 | // you create a control |
| 663 | SetCallStatus("Ready", 5); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 664 | SetAction(ID_MENU_CALL); |
Benny Prijono | 8a74445 | 2007-05-10 20:40:57 +0000 | [diff] [blame] | 665 | SetURI(SIP_DST_URI, -1); |
Benny Prijono | 39ea7f0 | 2006-09-14 13:52:29 +0000 | [diff] [blame] | 666 | SetFocus(hWnd); |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 667 | |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 668 | } |
| 669 | |
| 670 | |
| 671 | static void OnDestroy(void) |
| 672 | { |
| 673 | pjsua_destroy(); |
| 674 | } |
| 675 | |
| 676 | static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| 677 | { |
| 678 | int wmId, wmEvent; |
| 679 | |
| 680 | switch (message) { |
Benny Prijono | 39ea7f0 | 2006-09-14 13:52:29 +0000 | [diff] [blame] | 681 | case WM_KEYUP: |
| 682 | if (wParam==114) { |
| 683 | wParam = ID_MENU_CALL; |
| 684 | } else if (wParam==115) { |
| 685 | if (g_current_call == PJSUA_INVALID_ID) |
| 686 | wParam = ID_EXIT; |
| 687 | else |
| 688 | wParam = ID_MENU_DISCONNECT; |
| 689 | } else |
| 690 | break; |
| 691 | |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 692 | case WM_COMMAND: |
| 693 | wmId = LOWORD(wParam); |
| 694 | wmEvent = HIWORD(wParam); |
Benny Prijono | f20687a | 2006-08-04 18:27:19 +0000 | [diff] [blame] | 695 | if (wmId == ID_BTN_ACTION) |
| 696 | wmId = g_current_action; |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 697 | switch (wmId) |
| 698 | { |
| 699 | case ID_MENU_CALL: |
| 700 | if (g_current_call != PJSUA_INVALID_ID) { |
| 701 | MessageBox(NULL, TEXT("Can not make call"), |
| 702 | TEXT("You already have one call active"), MB_OK); |
| 703 | } |
| 704 | pj_str_t dst_uri; |
| 705 | wchar_t text[256]; |
| 706 | char tmp[256]; |
| 707 | pj_status_t status; |
| 708 | |
| 709 | GetWindowText(hwndURI, text, PJ_ARRAY_SIZE(text)); |
| 710 | pj_unicode_to_ansi(text, pj_unicode_strlen(text), |
| 711 | tmp, sizeof(tmp)); |
| 712 | dst_uri.ptr = tmp; |
| 713 | dst_uri.slen = pj_ansi_strlen(tmp); |
| 714 | status = pjsua_call_make_call(g_current_acc, |
| 715 | &dst_uri, 0, NULL, |
| 716 | NULL, &g_current_call); |
| 717 | if (status != PJ_SUCCESS) |
| 718 | OnError(TEXT("Unable to make call"), status); |
| 719 | break; |
| 720 | case ID_MENU_ANSWER: |
| 721 | if (g_current_call == PJSUA_INVALID_ID) |
| 722 | MessageBox(NULL, TEXT("Can not answer"), |
| 723 | TEXT("There is no call!"), MB_OK); |
Benny Prijono | edba079 | 2006-08-06 18:23:56 +0000 | [diff] [blame] | 724 | else |
| 725 | pjsua_call_answer(g_current_call, 200, NULL, NULL); |
Benny Prijono | 01f0154 | 2006-08-01 23:09:35 +0000 | [diff] [blame] | 726 | break; |
| 727 | case ID_MENU_DISCONNECT: |
| 728 | if (g_current_call == PJSUA_INVALID_ID) |
| 729 | MessageBox(NULL, TEXT("Can not disconnect"), |
| 730 | TEXT("There is no call!"), MB_OK); |
| 731 | else |
| 732 | pjsua_call_hangup(g_current_call, PJSIP_SC_DECLINE, NULL, NULL); |
| 733 | break; |
| 734 | case ID_EXIT: |
| 735 | DestroyWindow(hWnd); |
| 736 | break; |
| 737 | default: |
| 738 | return DefWindowProc(hWnd, message, wParam, lParam); |
| 739 | } |
| 740 | break; |
| 741 | |
| 742 | case WM_CREATE: |
| 743 | OnCreate(hWnd); |
| 744 | break; |
| 745 | |
| 746 | case WM_DESTROY: |
| 747 | OnDestroy(); |
| 748 | CommandBar_Destroy(hwndCB); |
| 749 | PostQuitMessage(0); |
| 750 | break; |
| 751 | |
| 752 | case WM_TIMER: |
| 753 | pjsua_handle_events(1); |
| 754 | break; |
| 755 | |
| 756 | default: |
| 757 | return DefWindowProc(hWnd, message, wParam, lParam); |
| 758 | } |
| 759 | return 0; |
| 760 | } |
| 761 | |