Changeset 476 for pjproject/trunk
- Timestamp:
- May 26, 2006 12:17:46 PM (19 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 3 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip-apps/src/pjsua/main.c
r422 r476 18 18 */ 19 19 #include <pjsua-lib/pjsua.h> 20 #include < stdlib.h> /* atoi */21 #include <stdio.h> 20 #include <pjsua-lib/pjsua_console_app.h> 21 22 22 23 23 #define THIS_FILE "main.c" 24 25 /* Current dialog */26 static int current_acc;27 static int current_call = -1;28 29 30 /*31 * Find next call.32 */33 static pj_bool_t find_next_call(void)34 {35 int i;36 37 for (i=current_call+1; i<(int)pjsua.max_calls; ++i) {38 if (pjsua.calls[i].inv != NULL) {39 current_call = i;40 return PJ_TRUE;41 }42 }43 44 for (i=0; i<current_call; ++i) {45 if (pjsua.calls[i].inv != NULL) {46 current_call = i;47 return PJ_TRUE;48 }49 }50 51 current_call = -1;52 return PJ_FALSE;53 }54 55 56 /*57 * Find previous call.58 */59 static pj_bool_t find_prev_call(void)60 {61 int i;62 63 for (i=current_call-1; i>=0; --i) {64 if (pjsua.calls[i].inv != NULL) {65 current_call = i;66 return PJ_TRUE;67 }68 }69 70 for (i=pjsua.max_calls-1; i>current_call; --i) {71 if (pjsua.calls[i].inv != NULL) {72 current_call = i;73 return PJ_TRUE;74 }75 }76 77 current_call = -1;78 return PJ_FALSE;79 }80 81 82 83 /*84 * Notify UI when invite state has changed.85 */86 void pjsua_ui_on_call_state(int call_index, pjsip_event *e)87 {88 pjsua_call *call = &pjsua.calls[call_index];89 90 PJ_UNUSED_ARG(e);91 92 if (call->inv->state == PJSIP_INV_STATE_DISCONNECTED) {93 94 PJ_LOG(3,(THIS_FILE, "Call %d is DISCONNECTED [reason=%d (%s)]",95 call_index,96 call->inv->cause,97 pjsip_get_status_text(call->inv->cause)->ptr));98 99 call->inv = NULL;100 if ((int)call->index == current_call) {101 find_next_call();102 }103 104 } else {105 106 PJ_LOG(3,(THIS_FILE, "Call %d state changed to %s",107 call_index,108 pjsua_inv_state_names[call->inv->state]));109 110 if (call && current_call==-1)111 current_call = call->index;112 113 }114 }115 116 /**117 * Notify UI when registration status has changed.118 */119 void pjsua_ui_on_reg_state(int acc_index)120 {121 PJ_UNUSED_ARG(acc_index);122 123 // Log already written.124 }125 126 127 /**128 * Incoming IM message (i.e. MESSAGE request)!129 */130 void pjsua_ui_on_pager(int call_index, const pj_str_t *from,131 const pj_str_t *to, const pj_str_t *text)132 {133 /* Note: call index may be -1 */134 PJ_UNUSED_ARG(call_index);135 PJ_UNUSED_ARG(to);136 137 PJ_LOG(3,(THIS_FILE,"MESSAGE from %.*s: %.*s",138 (int)from->slen, from->ptr,139 (int)text->slen, text->ptr));140 }141 142 143 /**144 * Typing indication145 */146 void pjsua_ui_on_typing(int call_index, const pj_str_t *from,147 const pj_str_t *to, pj_bool_t is_typing)148 {149 PJ_UNUSED_ARG(call_index);150 PJ_UNUSED_ARG(to);151 152 PJ_LOG(3,(THIS_FILE, "IM indication: %.*s %s",153 (int)from->slen, from->ptr,154 (is_typing?"is typing..":"has stopped typing")));155 }156 157 158 /*159 * Print buddy list.160 */161 static void print_buddy_list(void)162 {163 int i;164 165 puts("Buddy list:");166 167 if (pjsua.buddy_cnt == 0)168 puts(" -none-");169 else {170 for (i=0; i<pjsua.buddy_cnt; ++i) {171 const char *status;172 173 if (pjsua.buddies[i].sub == NULL ||174 pjsua.buddies[i].status.info_cnt==0)175 {176 status = " ? ";177 }178 else if (pjsua.buddies[i].status.info[0].basic_open)179 status = " Online";180 else181 status = "Offline";182 183 printf(" [%2d] <%s> %s\n",184 i+1, status, pjsua.buddies[i].uri.ptr);185 }186 }187 puts("");188 }189 190 191 /*192 * Print account status.193 */194 static void print_acc_status(int acc_index)195 {196 char reg_status[128];197 198 if (pjsua.acc[acc_index].regc == NULL) {199 pj_ansi_strcpy(reg_status, " -not registered to server-");200 201 } else if (pjsua.acc[acc_index].reg_last_err != PJ_SUCCESS) {202 pj_strerror(pjsua.acc[acc_index].reg_last_err, reg_status, sizeof(reg_status));203 204 } else if (pjsua.acc[acc_index].reg_last_code>=200 &&205 pjsua.acc[acc_index].reg_last_code<=699) {206 207 pjsip_regc_info info;208 const pj_str_t *status_str;209 210 pjsip_regc_get_info(pjsua.acc[acc_index].regc, &info);211 212 status_str = pjsip_get_status_text(pjsua.acc[acc_index].reg_last_code);213 pj_ansi_snprintf(reg_status, sizeof(reg_status),214 "%s (%.*s;expires=%d)",215 status_str->ptr,216 (int)info.client_uri.slen,217 info.client_uri.ptr,218 info.next_reg);219 220 } else {221 pj_ansi_sprintf(reg_status, "in progress (%d)",222 pjsua.acc[acc_index].reg_last_code);223 }224 225 printf("[%2d] Registration status: %s\n", acc_index, reg_status);226 printf(" Online status: %s\n",227 (pjsua.acc[acc_index].online_status ? "Online" : "Invisible"));228 }229 230 /*231 * Show a bit of help.232 */233 static void keystroke_help(void)234 {235 int i;236 237 printf(">>>>\n");238 239 for (i=0; i<pjsua.acc_cnt; ++i)240 print_acc_status(i);241 242 print_buddy_list();243 244 //puts("Commands:");245 puts("+=============================================================================+");246 puts("| Call Commands: | IM & Presence: | Misc: |");247 puts("| | | |");248 puts("| m Make new call | i Send IM | o Send OPTIONS |");249 puts("| M Make multiple calls | s Subscribe presence | rr (Re-)register |");250 puts("| a Answer call | u Unsubscribe presence | ru Unregister |");251 puts("| h Hangup call (ha=all) | t ToGgle Online status | |");252 puts("| H Hold call | | |");253 puts("| v re-inVite (release hold) +--------------------------+-------------------+");254 puts("| ] Select next dialog | Conference Command | |");255 puts("| [ Select previous dialog | cl List ports | d Dump status |");256 puts("| x Xfer call | cc Connect port | dd Dump detailed |");257 puts("| # Send DTMF string | cd Disconnect port | dc Dump config |");258 puts("+------------------------------+--------------------------+-------------------+");259 puts("| q QUIT |");260 puts("+=============================================================================+");261 }262 263 264 /*265 * Input simple string266 */267 static pj_bool_t simple_input(const char *title, char *buf, pj_size_t len)268 {269 char *p;270 271 printf("%s (empty to cancel): ", title); fflush(stdout);272 fgets(buf, len, stdin);273 274 /* Remove trailing newlines. */275 for (p=buf; ; ++p) {276 if (*p=='\r' || *p=='\n') *p='\0';277 else if (!*p) break;278 }279 280 if (!*buf)281 return PJ_FALSE;282 283 return PJ_TRUE;284 }285 286 287 #define NO_NB -2288 struct input_result289 {290 int nb_result;291 char *uri_result;292 };293 294 295 /*296 * Input URL.297 */298 static void ui_input_url(const char *title, char *buf, int len,299 struct input_result *result)300 {301 result->nb_result = NO_NB;302 result->uri_result = NULL;303 304 print_buddy_list();305 306 printf("Choices:\n"307 " 0 For current dialog.\n"308 " -1 All %d buddies in buddy list\n"309 " [1 -%2d] Select from buddy list\n"310 " URL An URL\n"311 " <Enter> Empty input (or 'q') to cancel\n"312 , pjsua.buddy_cnt, pjsua.buddy_cnt);313 printf("%s: ", title);314 315 fflush(stdout);316 fgets(buf, len, stdin);317 len = strlen(buf);318 319 /* Left trim */320 while (pj_isspace(*buf)) {321 ++buf;322 --len;323 }324 325 /* Remove trailing newlines */326 while (len && (buf[len-1] == '\r' || buf[len-1] == '\n'))327 buf[--len] = '\0';328 329 if (len == 0 || buf[0]=='q')330 return;331 332 if (pj_isdigit(*buf) || *buf=='-') {333 334 int i;335 336 if (*buf=='-')337 i = 1;338 else339 i = 0;340 341 for (; i<len; ++i) {342 if (!pj_isdigit(buf[i])) {343 puts("Invalid input");344 return;345 }346 }347 348 result->nb_result = atoi(buf);349 350 if (result->nb_result >= 0 && result->nb_result <= (int)pjsua.buddy_cnt) {351 return;352 }353 if (result->nb_result == -1)354 return;355 356 puts("Invalid input");357 result->nb_result = NO_NB;358 return;359 360 } else {361 pj_status_t status;362 363 if ((status=pjsua_verify_sip_url(buf)) != PJ_SUCCESS) {364 pjsua_perror(THIS_FILE, "Invalid URL", status);365 return;366 }367 368 result->uri_result = buf;369 }370 }371 372 static void conf_list(void)373 {374 unsigned i, count;375 pjmedia_conf_port_info info[PJSUA_MAX_CALLS];376 377 printf("Conference ports:\n");378 379 count = PJ_ARRAY_SIZE(info);380 pjmedia_conf_get_ports_info(pjsua.mconf, &count, info);381 for (i=0; i<count; ++i) {382 char txlist[PJSUA_MAX_CALLS*4+10];383 int j;384 pjmedia_conf_port_info *port_info = &info[i];385 386 txlist[0] = '\0';387 for (j=0; j<pjsua.max_calls+PJSUA_CONF_MORE_PORTS; ++j) {388 char s[10];389 if (port_info->listener[j]) {390 pj_ansi_sprintf(s, "#%d ", j);391 pj_ansi_strcat(txlist, s);392 }393 }394 printf("Port #%02d[%2dKHz/%dms] %20.*s transmitting to: %s\n",395 port_info->slot,396 port_info->clock_rate/1000,397 port_info->samples_per_frame * 1000 / port_info->clock_rate,398 (int)port_info->name.slen,399 port_info->name.ptr,400 txlist);401 402 }403 puts("");404 }405 406 407 static void ui_console_main(void)408 {409 char menuin[10];410 char buf[128];411 char text[128];412 int i, count;413 char *uri;414 struct input_result result;415 416 417 /* If user specifies URI to call, then call the URI */418 if (pjsua.uri_to_call.slen) {419 pjsua_make_call( current_acc, pjsua.uri_to_call.ptr, NULL);420 }421 422 keystroke_help();423 424 for (;;) {425 426 printf(">>> ");427 fflush(stdout);428 429 fgets(menuin, sizeof(menuin), stdin);430 431 switch (menuin[0]) {432 433 case 'm':434 /* Make call! : */435 printf("(You currently have %d calls)\n", pjsua.call_cnt);436 437 uri = NULL;438 ui_input_url("Make call", buf, sizeof(buf), &result);439 if (result.nb_result != NO_NB) {440 441 if (result.nb_result == -1 || result.nb_result == 0) {442 puts("You can't do that with make call!");443 continue;444 } else {445 uri = pjsua.buddies[result.nb_result-1].uri.ptr;446 }447 448 } else if (result.uri_result) {449 uri = result.uri_result;450 }451 452 pjsua_make_call( current_acc, uri, NULL);453 break;454 455 case 'M':456 /* Make multiple calls! : */457 printf("(You currently have %d calls)\n", pjsua.call_cnt);458 459 if (!simple_input("Number of calls", menuin, sizeof(menuin)))460 continue;461 462 count = atoi(menuin);463 if (count < 1)464 continue;465 466 ui_input_url("Make call", buf, sizeof(buf), &result);467 if (result.nb_result != NO_NB) {468 if (result.nb_result == -1 || result.nb_result == 0) {469 puts("You can't do that with make call!");470 continue;471 }472 uri = pjsua.buddies[result.nb_result-1].uri.ptr;473 } else {474 uri = result.uri_result;475 }476 477 for (i=0; i<atoi(menuin); ++i) {478 pj_status_t status;479 480 status = pjsua_make_call(current_acc, uri, NULL);481 if (status != PJ_SUCCESS)482 break;483 }484 break;485 486 case 'i':487 /* Send instant messaeg */488 489 /* i is for call index to send message, if any */490 i = -1;491 492 /* Make compiler happy. */493 uri = NULL;494 495 /* Input destination. */496 ui_input_url("Send IM to", buf, sizeof(buf), &result);497 if (result.nb_result != NO_NB) {498 499 if (result.nb_result == -1) {500 puts("You can't send broadcast IM like that!");501 continue;502 503 } else if (result.nb_result == 0) {504 505 i = current_call;506 507 } else {508 uri = pjsua.buddies[result.nb_result-1].uri.ptr;509 }510 511 } else if (result.uri_result) {512 uri = result.uri_result;513 }514 515 516 /* Send typing indication. */517 if (i != -1)518 pjsua_call_typing(i, PJ_TRUE);519 else520 pjsua_im_typing(current_acc, uri, PJ_TRUE);521 522 /* Input the IM . */523 if (!simple_input("Message", text, sizeof(text))) {524 /*525 * Cancelled.526 * Send typing notification too, saying we're not typing.527 */528 if (i != -1)529 pjsua_call_typing(i, PJ_FALSE);530 else531 pjsua_im_typing(current_acc, uri, PJ_FALSE);532 continue;533 }534 535 /* Send the IM */536 if (i != -1)537 pjsua_call_send_im(i, text);538 else539 pjsua_im_send(current_acc, uri, text);540 541 break;542 543 case 'a':544 545 if (current_call == -1 ||546 pjsua.calls[current_call].inv->role != PJSIP_ROLE_UAS ||547 pjsua.calls[current_call].inv->state >= PJSIP_INV_STATE_CONNECTING)548 {549 puts("No pending incoming call");550 fflush(stdout);551 continue;552 553 } else {554 pj_status_t status;555 pjsip_tx_data *tdata;556 557 if (!simple_input("Answer with code (100-699)", buf, sizeof(buf)))558 continue;559 560 if (atoi(buf) < 100)561 continue;562 563 /*564 * Must check again!565 * Call may have been disconnected while we're waiting for566 * keyboard input.567 */568 if (current_call == -1) {569 puts("Call has been disconnected");570 fflush(stdout);571 continue;572 }573 574 status = pjsip_inv_answer(pjsua.calls[current_call].inv,575 atoi(buf),576 NULL, NULL, &tdata);577 if (status == PJ_SUCCESS)578 status = pjsip_inv_send_msg(pjsua.calls[current_call].inv,579 tdata);580 581 if (status != PJ_SUCCESS)582 pjsua_perror(THIS_FILE, "Unable to create/send response",583 status);584 }585 586 break;587 588 589 case 'h':590 591 if (current_call == -1) {592 puts("No current call");593 fflush(stdout);594 continue;595 596 } else if (menuin[1] == 'a') {597 598 /* Hangup all calls */599 pjsua_call_hangup_all();600 601 } else {602 603 /* Hangup current calls */604 pjsua_call_hangup(current_call);605 }606 break;607 608 case ']':609 case '[':610 /*611 * Cycle next/prev dialog.612 */613 if (menuin[0] == ']') {614 find_next_call();615 616 } else {617 find_prev_call();618 }619 620 if (current_call != -1) {621 char url[PJSIP_MAX_URL_SIZE];622 int len;623 const pjsip_uri *u;624 625 u = pjsua.calls[current_call].inv->dlg->remote.info->uri;626 len = pjsip_uri_print(0, u, url, sizeof(url)-1);627 if (len < 1) {628 pj_ansi_strcpy(url, "<uri is too long>");629 } else {630 url[len] = '\0';631 }632 633 PJ_LOG(3,(THIS_FILE,"Current dialog: %s", url));634 635 } else {636 PJ_LOG(3,(THIS_FILE,"No current dialog"));637 }638 break;639 640 case 'H':641 /*642 * Hold call.643 */644 if (current_call != -1) {645 646 pjsua_call_set_hold(current_call);647 648 } else {649 PJ_LOG(3,(THIS_FILE, "No current call"));650 }651 break;652 653 case 'v':654 /*655 * Send re-INVITE (to release hold, etc).656 */657 if (current_call != -1) {658 659 pjsua_call_reinvite(current_call);660 661 } else {662 PJ_LOG(3,(THIS_FILE, "No current call"));663 }664 break;665 666 case 'x':667 /*668 * Transfer call.669 */670 if (current_call == -1) {671 672 PJ_LOG(3,(THIS_FILE, "No current call"));673 674 } else {675 int call = current_call;676 677 ui_input_url("Transfer to URL", buf, sizeof(buf), &result);678 679 /* Check if call is still there. */680 681 if (call != current_call) {682 puts("Call has been disconnected");683 continue;684 }685 686 if (result.nb_result != NO_NB) {687 if (result.nb_result == -1 || result.nb_result == 0)688 puts("You can't do that with transfer call!");689 else690 pjsua_call_xfer( current_call,691 pjsua.buddies[result.nb_result-1].uri.ptr);692 693 } else if (result.uri_result) {694 pjsua_call_xfer( current_call, result.uri_result);695 }696 }697 break;698 699 case '#':700 /*701 * Send DTMF strings.702 */703 if (current_call == -1) {704 705 PJ_LOG(3,(THIS_FILE, "No current call"));706 707 } else if (pjsua.calls[current_call].session == NULL) {708 709 PJ_LOG(3,(THIS_FILE, "Media is not established yet!"));710 711 } else {712 pj_str_t digits;713 int call = current_call;714 pj_status_t status;715 716 if (!simple_input("DTMF strings to send (0-9*#A-B)", buf,717 sizeof(buf)))718 {719 break;720 }721 722 if (call != current_call) {723 puts("Call has been disconnected");724 continue;725 }726 727 digits = pj_str(buf);728 status = pjmedia_session_dial_dtmf(pjsua.calls[current_call].session, 0,729 &digits);730 if (status != PJ_SUCCESS) {731 pjsua_perror(THIS_FILE, "Unable to send DTMF", status);732 } else {733 puts("DTMF digits enqueued for transmission");734 }735 }736 break;737 738 case 's':739 case 'u':740 /*741 * Subscribe/unsubscribe presence.742 */743 ui_input_url("(un)Subscribe presence of", buf, sizeof(buf), &result);744 if (result.nb_result != NO_NB) {745 if (result.nb_result == -1) {746 int i;747 for (i=0; i<pjsua.buddy_cnt; ++i)748 pjsua.buddies[i].monitor = (menuin[0]=='s');749 } else if (result.nb_result == 0) {750 puts("Sorry, can only subscribe to buddy's presence, "751 "not from existing call");752 } else {753 pjsua.buddies[result.nb_result-1].monitor = (menuin[0]=='s');754 }755 756 pjsua_pres_refresh(current_acc);757 758 } else if (result.uri_result) {759 puts("Sorry, can only subscribe to buddy's presence, "760 "not arbitrary URL (for now)");761 }762 763 break;764 765 case 'r':766 switch (menuin[1]) {767 case 'r':768 /*769 * Re-Register.770 */771 pjsua_regc_update(current_acc, PJ_TRUE);772 break;773 case 'u':774 /*775 * Unregister776 */777 pjsua_regc_update(current_acc, PJ_FALSE);778 break;779 }780 break;781 782 case 't':783 pjsua.acc[current_acc].online_status =784 !pjsua.acc[current_acc].online_status;785 printf("Setting %s online status to %s\n",786 pjsua.acc[current_acc].local_uri.ptr,787 (pjsua.acc[current_acc].online_status?"online":"offline"));788 pjsua_pres_refresh(current_acc);789 break;790 791 case 'c':792 switch (menuin[1]) {793 case 'l':794 conf_list();795 break;796 case 'c':797 case 'd':798 {799 char src_port[10], dst_port[10];800 pj_status_t status;801 const char *src_title, *dst_title;802 803 conf_list();804 805 src_title = (menuin[1]=='c'?806 "Connect src port #":807 "Disconnect src port #");808 dst_title = (menuin[1]=='c'?809 "To dst port #":810 "From dst port #");811 812 if (!simple_input(src_title, src_port, sizeof(src_port)))813 break;814 815 if (!simple_input(dst_title, dst_port, sizeof(dst_port)))816 break;817 818 if (menuin[1]=='c') {819 status = pjmedia_conf_connect_port(pjsua.mconf,820 atoi(src_port),821 atoi(dst_port),822 0);823 } else {824 status = pjmedia_conf_disconnect_port(pjsua.mconf,825 atoi(src_port),826 atoi(dst_port));827 }828 if (status == PJ_SUCCESS) {829 puts("Success");830 } else {831 puts("ERROR!!");832 }833 }834 break;835 }836 break;837 838 case 'd':839 if (menuin[1] == 'c') {840 char settings[2000];841 int len;842 843 len = pjsua_dump_settings(settings, sizeof(settings));844 if (len < 1)845 PJ_LOG(3,(THIS_FILE, "Error: not enough buffer"));846 else847 PJ_LOG(3,(THIS_FILE,848 "Dumping configuration (%d bytes):\n%s\n",849 len, settings));850 } else {851 pjsua_dump(menuin[1]=='d');852 }853 break;854 855 case 'q':856 goto on_exit;857 858 default:859 if (menuin[0] != '\n' && menuin[0] != '\r') {860 printf("Invalid input %s", menuin);861 }862 keystroke_help();863 break;864 }865 }866 867 on_exit:868 ;869 }870 871 872 /*****************************************************************************873 * This is a very simple PJSIP module, whose sole purpose is to display874 * incoming and outgoing messages to log. This module will have priority875 * higher than transport layer, which means:876 *877 * - incoming messages will come to this module first before reaching878 * transaction layer.879 *880 * - outgoing messages will come to this module last, after the message881 * has been 'printed' to contiguous buffer by transport layer and882 * appropriate transport instance has been decided for this message.883 *884 */885 886 /* Notification on incoming messages */887 static pj_bool_t console_on_rx_msg(pjsip_rx_data *rdata)888 {889 PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n"890 "%s\n"891 "--end msg--",892 rdata->msg_info.len,893 pjsip_rx_data_get_info(rdata),894 rdata->pkt_info.src_name,895 rdata->pkt_info.src_port,896 rdata->msg_info.msg_buf));897 898 /* Always return false, otherwise messages will not get processed! */899 return PJ_FALSE;900 }901 902 /* Notification on outgoing messages */903 static pj_status_t console_on_tx_msg(pjsip_tx_data *tdata)904 {905 906 /* Important note:907 * tp_info field is only valid after outgoing messages has passed908 * transport layer. So don't try to access tp_info when the module909 * has lower priority than transport layer.910 */911 912 PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n"913 "%s\n"914 "--end msg--",915 (tdata->buf.cur - tdata->buf.start),916 pjsip_tx_data_get_info(tdata),917 tdata->tp_info.dst_name,918 tdata->tp_info.dst_port,919 tdata->buf.start));920 921 /* Always return success, otherwise message will not get sent! */922 return PJ_SUCCESS;923 }924 925 /* The module instance. */926 static pjsip_module console_msg_logger =927 {928 NULL, NULL, /* prev, next. */929 { "mod-pjsua-log", 13 }, /* Name. */930 -1, /* Id */931 PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */932 NULL, /* load() */933 NULL, /* start() */934 NULL, /* stop() */935 NULL, /* unload() */936 &console_on_rx_msg, /* on_rx_request() */937 &console_on_rx_msg, /* on_rx_response() */938 &console_on_tx_msg, /* on_tx_request. */939 &console_on_tx_msg, /* on_tx_response() */940 NULL, /* on_tsx_state() */941 942 };943 944 945 946 /*****************************************************************************947 * Console application custom logging:948 */949 950 951 static FILE *log_file;952 953 954 static void app_log_writer(int level, const char *buffer, int len)955 {956 /* Write to both stdout and file. */957 958 if (level <= pjsua.app_log_level)959 pj_log_write(level, buffer, len);960 961 if (log_file) {962 fwrite(buffer, len, 1, log_file);963 fflush(log_file);964 }965 }966 967 968 pj_status_t app_logging_init(void)969 {970 /* Redirect log function to ours */971 972 pj_log_set_log_func( &app_log_writer );973 974 /* If output log file is desired, create the file: */975 976 if (pjsua.log_filename) {977 log_file = fopen(pjsua.log_filename, "wt");978 if (log_file == NULL) {979 PJ_LOG(1,(THIS_FILE, "Unable to open log file %s",980 pjsua.log_filename));981 return -1;982 }983 }984 985 return PJ_SUCCESS;986 }987 988 989 void app_logging_shutdown(void)990 {991 /* Close logging file, if any: */992 993 if (log_file) {994 fclose(log_file);995 log_file = NULL;996 }997 }998 999 /*****************************************************************************1000 * Error display:1001 */1002 1003 /*1004 * Display error message for the specified error code.1005 */1006 void pjsua_perror(const char *sender, const char *title,1007 pj_status_t status)1008 {1009 char errmsg[PJ_ERR_MSG_SIZE];1010 1011 pj_strerror(status, errmsg, sizeof(errmsg));1012 1013 PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status));1014 }1015 1016 1017 1018 24 1019 25 /***************************************************************************** … … 1023 29 { 1024 30 31 pjsua_config cfg; 32 1025 33 /* Init default settings. */ 1026 pjsua_default ();34 pjsua_default_config(&cfg); 1027 35 1028 36 1029 /* Initialize pjsua (to create pool etc). 1030 */ 1031 if (pjsua_init() != PJ_SUCCESS) 1032 return 1; 37 /* Create PJLIB and memory pool */ 38 pjsua_create(); 1033 39 1034 40 1035 41 /* Parse command line arguments: */ 1036 if (pjsua_parse_args(argc, argv ) != PJ_SUCCESS)42 if (pjsua_parse_args(argc, argv, &cfg) != PJ_SUCCESS) 1037 43 return 1; 1038 44 1039 45 1040 46 /* Init logging: */ 1041 if ( app_logging_init() != PJ_SUCCESS)47 if (pjsua_console_app_logging_init(&cfg) != PJ_SUCCESS) 1042 48 return 1; 1043 49 50 51 /* Init pjsua */ 52 if (pjsua_init(&cfg, &console_callback) != PJ_SUCCESS) 53 return 1; 1044 54 1045 55 /* Register message logger to print incoming and outgoing 1046 56 * messages. 1047 57 */ 1048 pjsip_endpt_register_module(pjsua.endpt, &console_msg_logger); 58 pjsip_endpt_register_module(pjsua.endpt, 59 &pjsua_console_app_msg_logger); 1049 60 1050 61 … … 1062 73 1063 74 /* Start UI console main loop: */ 1064 ui_console_main();75 pjsua_console_app_main(); 1065 76 1066 77 … … 1070 81 1071 82 /* Close logging: */ 1072 app_logging_shutdown();83 pjsua_console_app_logging_shutdown(); 1073 84 1074 85 -
pjproject/trunk/pjsip/build/pjsua_lib.dsp
r360 r476 92 92 # Begin Source File 93 93 94 SOURCE="..\src\pjsua-lib\pjsua_console_app.c" 95 # End Source File 96 # Begin Source File 97 94 98 SOURCE="..\src\pjsua-lib\pjsua_core.c" 95 99 # End Source File … … 97 101 98 102 SOURCE="..\src\pjsua-lib\pjsua_im.c" 103 # End Source File 104 # Begin Source File 105 106 SOURCE="..\src\pjsua-lib\pjsua_imp.h" 99 107 # End Source File 100 108 # Begin Source File … … 118 126 SOURCE="..\include\pjsua-lib\pjsua.h" 119 127 # End Source File 128 # Begin Source File 129 130 SOURCE="..\include\pjsua-lib\pjsua_console_app.h" 131 # End Source File 120 132 # End Group 121 133 # End Target -
pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
r452 r476 49 49 */ 50 50 #ifndef PJSUA_MAX_BUDDIES 51 # define PJSUA_MAX_BUDDIES 3251 # define PJSUA_MAX_BUDDIES 256 52 52 #endif 53 53 … … 62 62 63 63 /** 64 * Aditional ports to be allocated in the conference ports for non-call65 * streams.66 */67 #define PJSUA_CONF_MORE_PORTS 368 69 70 /**71 64 * Maximum accounts. 72 65 */ 73 66 #ifndef PJSUA_MAX_ACC 74 # define PJSUA_MAX_ACC 867 # define PJSUA_MAX_ACC 32 75 68 #endif 76 69 77 78 /**79 * Maximum credentials.80 */81 #ifndef PJSUA_MAX_CRED82 # define PJSUA_MAX_CRED PJSUA_MAX_ACC83 #endif84 70 85 71 … … 141 127 142 128 /** 129 * Account configuration. 130 */ 131 struct pjsua_acc_config 132 { 133 /** SIP URL for account ID (mandatory) */ 134 pj_str_t id; 135 136 /** Registrar URI (mandatory) */ 137 pj_str_t reg_uri; 138 139 /** Optional contact URI */ 140 pj_str_t contact; 141 142 /** Service proxy (default: none) */ 143 pj_str_t proxy; 144 145 /** Default timeout (mandatory) */ 146 pj_int32_t reg_timeout; 147 148 /** Number of credentials. */ 149 unsigned cred_count; 150 151 /** Array of credentials. */ 152 pjsip_cred_info cred_info[4]; 153 154 }; 155 156 157 /** 158 * @see pjsua_acc_config 159 */ 160 typedef struct pjsua_acc_config pjsua_acc_config; 161 162 163 /** 143 164 * Account 144 165 */ … … 146 167 { 147 168 int index; /**< Index in accounts array. */ 148 pj_str_t local_uri; /**< Uri in From: header. */149 169 pj_str_t user_part; /**< User part of local URI. */ 150 170 pj_str_t host_part; /**< Host part of local URI. */ 151 pj_str_t contact_uri; /**< Uri in Contact: header. */ 152 153 pj_str_t reg_uri; /**< Registrar URI. */ 171 154 172 pjsip_regc *regc; /**< Client registration session. */ 155 pj_int32_t reg_timeout; /**< Default timeout. */156 173 pj_timer_entry reg_timer; /**< Registration timer. */ 157 174 pj_status_t reg_last_err; /**< Last registration error. */ 158 175 int reg_last_code; /**< Last status last register. */ 159 176 160 pj_str_t proxy; /**< Proxy URL. */161 177 pjsip_route_hdr route_set; /**< Route set. */ 162 178 … … 168 184 169 185 186 /** 187 * @see pjsua_acc 188 */ 170 189 typedef struct pjsua_acc pjsua_acc; 190 191 192 /** 193 * PJSUA settings. 194 */ 195 struct pjsua_config 196 { 197 /** SIP UDP signaling port. Set to zero to disable UDP signaling, 198 * which in this case application must manually add a transport 199 * to SIP endpoint. 200 * (default: 5060) 201 */ 202 unsigned udp_port; 203 204 /** Optional hostname or IP address to publish as the host part of 205 * Contact header. This must be specified if UDP transport is 206 * disabled. 207 * (default: NULL) 208 */ 209 pj_str_t sip_host; 210 211 /** Optional port number to publish in the port part of Contact header. 212 * This must be specified if UDP transport is disabled. 213 * (default: 0) 214 */ 215 unsigned sip_port; 216 217 /** Start of RTP port. Set to zero to prevent pjsua from creating 218 * media transports, which in this case application must manually 219 * create media transport for each calls. 220 * (default: 4000) 221 */ 222 unsigned start_rtp_port; 223 224 /** Maximum calls to support (default: 4) */ 225 unsigned max_calls; 226 227 /** Maximum slots in the conference bridge (default: 0/calculated 228 * as max_calls*2 229 */ 230 unsigned conf_ports; 231 232 /** Number of worker threads (default: 1) */ 233 unsigned thread_cnt; 234 235 /** First STUN server IP address. When STUN is configured, then the 236 * two STUN server settings must be fully set. 237 * (default: none) 238 */ 239 pj_str_t stun_srv1; 240 241 /** First STUN port number */ 242 unsigned stun_port1; 243 244 /** Second STUN server IP address */ 245 pj_str_t stun_srv2; 246 247 /** Second STUN server port number */ 248 unsigned stun_port2; 249 250 /** Internal clock rate (to be applied to sound devices and conference 251 * bridge, default is 0/follows the codec, or 44100 for MacOS). 252 */ 253 unsigned clock_rate; 254 255 /** Do not use sound device (default: 0). */ 256 pj_bool_t null_audio; 257 258 /** WAV file to load for auto_play (default: NULL) */ 259 pj_str_t wav_file; 260 261 /** Auto play WAV file for calls? (default: no) */ 262 pj_bool_t auto_play; 263 264 /** Auto loopback calls? (default: no) */ 265 pj_bool_t auto_loop; 266 267 /** Automatically put calls to conference? (default: no) */ 268 pj_bool_t auto_conf; 269 270 /** Speex codec complexity? (default: 10) */ 271 unsigned complexity; 272 273 /** Speex codec quality? (default: 10) */ 274 unsigned quality; 275 276 /** Codec ptime? (default: 0 (follows the codec)) */ 277 unsigned ptime; 278 279 /** Number of additional codecs/"--add-codec" with pjsua (default: 0) */ 280 unsigned codec_cnt; 281 282 /** Additional codecs/"--add-codec" options */ 283 pj_str_t codec_arg[32]; 284 285 /** SIP status code to be automatically sent to incoming calls 286 * (default: 100). 287 */ 288 unsigned auto_answer; 289 290 /** Periodic time to refresh call with re-INVITE (default: 0) 291 */ 292 unsigned uas_refresh; 293 294 /** Maximum incoming call duration (default: 3600) */ 295 unsigned uas_duration; 296 297 /** Outbound proxy (default: none) */ 298 pj_str_t outbound_proxy; 299 300 /** URI to call. */ 301 pj_str_t uri_to_call; 302 303 /** Number of SIP accounts */ 304 unsigned acc_cnt; 305 306 /** SIP accounts configuration */ 307 pjsua_acc_config acc_config[32]; 308 309 /** Logging verbosity (default: 5). */ 310 unsigned log_level; 311 312 /** Logging to be displayed to stdout (default: 4) */ 313 unsigned app_log_level; 314 315 /** Log decoration */ 316 unsigned log_decor; 317 318 /** Optional log filename (default: NULL) */ 319 pj_str_t log_filename; 320 321 /** Number of buddies in address book (default: 0) */ 322 unsigned buddy_cnt; 323 324 /** Buddies URI */ 325 pj_str_t buddy_uri[256]; 326 }; 327 328 329 /** 330 * @see pjsua_config 331 */ 332 typedef struct pjsua_config pjsua_config; 333 334 335 336 /** 337 * Application callbacks. 338 */ 339 struct pjsua_callback 340 { 341 /** 342 * Notify UI when invite state has changed. 343 */ 344 void (*on_call_state)(int call_index, pjsip_event *e); 345 346 /** 347 * Notify UI when registration status has changed. 348 */ 349 void (*on_reg_state)(int acc_index); 350 351 /** 352 * Notify UI on incoming pager (i.e. MESSAGE request). 353 * Argument call_index will be -1 if MESSAGE request is not related to an 354 * existing call. 355 */ 356 void (*on_pager)(int call_index, const pj_str_t *from, 357 const pj_str_t *to, const pj_str_t *txt); 358 359 /** 360 * Notify UI about typing indication. 361 */ 362 void (*on_typing)(int call_index, const pj_str_t *from, 363 const pj_str_t *to, pj_bool_t is_typing); 364 365 }; 366 367 /** 368 * @see pjsua_callback 369 */ 370 typedef struct pjsua_callback pjsua_callback; 171 371 172 372 … … 179 379 pj_pool_t *pool; /**< pjsua's private pool. */ 180 380 pjsip_module mod; /**< pjsua's PJSIP module. */ 381 181 382 383 /* Config: */ 384 pjsua_config config; /**< PJSUA configs */ 385 386 /* Application callback: */ 387 pjsua_callback cb; /**< Application callback. */ 182 388 183 389 /* Media: */ 184 int start_rtp_port;/**< Start of RTP port to try. */185 390 pjmedia_endpt *med_endpt; /**< Media endpoint. */ 186 unsigned clock_rate; /**< Internal clock rate. */187 391 pjmedia_conf *mconf; /**< Media conference. */ 188 pj_bool_t null_audio; /**< Null audio flag. */189 pj_bool_t no_mic; /**< Disable microphone. */190 char *wav_file; /**< WAV file name to play. */191 392 unsigned wav_slot; /**< WAV player slot in bridge */ 192 393 pjmedia_port *file_port; /**< WAV player port. */ 193 pjmedia_port *null_port; /**< NULL port. */ 194 pj_bool_t auto_play; /**< Auto play file for calls? */ 195 pj_bool_t auto_loop; /**< Auto loop RTP stream? */ 196 pj_bool_t auto_conf; /**< Auto put to conference? */ 197 int complexity; /**< Codec complexity. */ 198 int quality; /**< Codec quality. */ 199 int ptime; /**< Codec ptime in msec. */ 200 201 202 /* Codec arguments: */ 203 int codec_cnt; /**< Number of --add-codec args. */ 204 pj_str_t codec_arg[32]; /**< Array of --add-codec args. */ 205 pj_status_t (*codec_deinit[32])(void); /**< Array of funcs. */ 206 207 /* User Agent behaviour: */ 208 int auto_answer; /**< Automatically answer in calls. */ 209 int uas_refresh; /**< Time to re-INVITE. */ 210 int uas_duration; /**< Max call duration. */ 394 211 395 212 396 /* Account: */ 213 pj_bool_t has_acc; /**< Any --id cmdline? */214 int acc_cnt; /**< Number of client registrations */215 397 pjsua_acc acc[PJSUA_MAX_ACC]; /** Client regs array. */ 216 398 217 399 218 /* Authentication credentials: */219 220 int cred_count; /**< Number of credentials. */221 pjsip_cred_info cred_info[10]; /**< Array of credentials. */222 223 224 400 /* Threading (optional): */ 225 int thread_cnt; /**< Thread count. */226 401 pj_thread_t *threads[8]; /**< Thread instances. */ 227 402 pj_bool_t quit_flag; /**< To signal thread to quit. */ 228 403 229 404 /* Transport (UDP): */ 230 pj_uint16_t sip_port; /**< SIP signaling port. */231 405 pj_sock_t sip_sock; /**< SIP UDP socket. */ 232 406 pj_sockaddr_in sip_sock_name; /**< Public/STUN UDP socket addr. */ 233 407 234 pj_str_t outbound_proxy;/**< Outbound proxy. */235 236 237 /* STUN: */238 pj_str_t stun_srv1;239 int stun_port1;240 pj_str_t stun_srv2;241 int stun_port2;242 243 244 /* Logging: */245 int log_level; /**< Logging verbosity. */246 int app_log_level; /**< stdout log verbosity. */247 unsigned log_decor; /**< Log decoration. */248 char *log_filename; /**< Log filename. */249 250 408 251 409 /* PJSUA Calls: */ 252 pj_str_t uri_to_call; /**< URI to call. */253 int max_calls; /**< Max nb of calls. */254 410 int call_cnt; /**< Number of calls. */ 255 411 pjsua_call calls[PJSUA_MAX_CALLS]; /** Calls array. */ … … 274 430 * Initialize pjsua settings with default parameters. 275 431 */ 276 void pjsua_default(void); 277 278 279 /** 280 * Display error message for the specified error code. 281 */ 282 void pjsua_perror(const char *sender, const char *title, 283 pj_status_t status); 284 285 286 /** 287 * Initialize pjsua application. Application can call this before parsing 288 * application settings. 432 PJ_DECL(void) pjsua_default_config(pjsua_config *cfg); 433 434 435 /** 436 * Test configuration. 437 */ 438 PJ_DECL(pj_status_t) pjsua_test_config(const pjsua_config *cfg, 439 char *errmsg, 440 int len); 441 442 443 /** 444 * Create pjsua application. 445 * This initializes pjlib/pjlib-util, and creates memory pool factory to 446 * be used by application. 447 */ 448 PJ_DECL(pj_status_t) pjsua_create(void); 449 450 451 /** 452 * Initialize pjsua application with the specified settings. 289 453 * 290 454 * This will initialize all libraries, create endpoint instance, and register 291 * pjsip modules. Transport will NOT be created however.455 * pjsip modules. 292 456 * 293 457 * Application may register module after calling this function. 294 458 */ 295 pj_status_t pjsua_init(void); 459 PJ_DECL(pj_status_t) pjsua_init(const pjsua_config *cfg, 460 const pjsua_callback *cb); 296 461 297 462 … … 303 468 * process, if registration is configured. 304 469 */ 305 pj_status_tpjsua_start(void);470 PJ_DECL(pj_status_t) pjsua_start(void); 306 471 307 472 … … 309 474 * Destroy pjsua. 310 475 */ 311 pj_status_t pjsua_destroy(void); 312 313 314 /** 315 * Find account for incoming request. 316 */ 317 int pjsua_find_account_for_incoming(pjsip_rx_data *rdata); 318 319 320 /** 321 * Find account for outgoing request. 322 */ 323 int pjsua_find_account_for_outgoing(const pj_str_t *url); 476 PJ_DECL(pj_status_t) pjsua_destroy(void); 324 477 325 478 … … 329 482 330 483 /** 331 * Init pjsua call module.332 */333 pj_status_t pjsua_call_init(void);334 335 /**336 484 * Make outgoing call. 337 485 */ 338 pj_status_t pjsua_make_call(int acc_index, 339 const char *cstr_dest_uri, 340 int *p_call_index); 341 342 343 /** 344 * Handle incoming invite request. 345 */ 346 pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata); 486 PJ_DECL(pj_status_t) pjsua_make_call(int acc_index, 487 const char *cstr_dest_uri, 488 int *p_call_index); 347 489 348 490 … … 350 492 * Answer call. 351 493 */ 352 voidpjsua_call_answer(int call_index, int code);494 PJ_DECL(void) pjsua_call_answer(int call_index, int code); 353 495 354 496 /** 355 497 * Hangup call. 356 498 */ 357 voidpjsua_call_hangup(int call_index);499 PJ_DECL(void) pjsua_call_hangup(int call_index); 358 500 359 501 … … 361 503 * Put call on-hold. 362 504 */ 363 voidpjsua_call_set_hold(int call_index);505 PJ_DECL(void) pjsua_call_set_hold(int call_index); 364 506 365 507 … … 367 509 * Send re-INVITE (to release hold). 368 510 */ 369 voidpjsua_call_reinvite(int call_index);511 PJ_DECL(void) pjsua_call_reinvite(int call_index); 370 512 371 513 … … 373 515 * Transfer call. 374 516 */ 375 voidpjsua_call_xfer(int call_index, const char *dest);517 PJ_DECL(void) pjsua_call_xfer(int call_index, const char *dest); 376 518 377 519 … … 379 521 * Send instant messaging inside INVITE session. 380 522 */ 381 voidpjsua_call_send_im(int call_index, const char *text);523 PJ_DECL(void) pjsua_call_send_im(int call_index, const char *text); 382 524 383 525 … … 385 527 * Send IM typing indication inside INVITE session. 386 528 */ 387 voidpjsua_call_typing(int call_index, pj_bool_t is_typing);529 PJ_DECL(void) pjsua_call_typing(int call_index, pj_bool_t is_typing); 388 530 389 531 /** 390 532 * Terminate all calls. 391 533 */ 392 voidpjsua_call_hangup_all(void);534 PJ_DECL(void) pjsua_call_hangup_all(void); 393 535 394 536 … … 398 540 399 541 /** 400 * Initialize client registration session.401 *402 * @param app_callback Optional callback403 */404 pj_status_t pjsua_regc_init(int acc_index);405 406 /**407 542 * Update registration or perform unregistration. If renew argument is zero, 408 543 * this will start unregistration process. 409 544 */ 410 voidpjsua_regc_update(int acc_index, pj_bool_t renew);545 PJ_DECL(void) pjsua_regc_update(int acc_index, pj_bool_t renew); 411 546 412 547 … … 418 553 419 554 /** 420 * Init presence.421 */422 pj_status_t pjsua_pres_init();423 424 /**425 555 * Refresh both presence client and server subscriptions. 426 556 */ 427 void pjsua_pres_refresh(int acc_index); 428 429 /** 430 * Terminate all subscriptions 431 */ 432 void pjsua_pres_shutdown(void); 557 PJ_DECL(void) pjsua_pres_refresh(int acc_index); 433 558 434 559 /** 435 560 * Dump presence subscriptions. 436 561 */ 437 voidpjsua_pres_dump(pj_bool_t detail);562 PJ_DECL(void) pjsua_pres_dump(pj_bool_t detail); 438 563 439 564 … … 448 573 449 574 450 /**451 * Init IM module handler to handle incoming MESSAGE outside dialog.452 */453 pj_status_t pjsua_im_init();454 455 456 /**457 * Create Accept header for MESSAGE.458 */459 pjsip_accept_hdr* pjsua_im_create_accept(pj_pool_t *pool);460 575 461 576 /** 462 577 * Send IM outside dialog. 463 578 */ 464 pj_status_tpjsua_im_send(int acc_index, const char *dst_uri,465 const char *text);579 PJ_DECL(pj_status_t) pjsua_im_send(int acc_index, const char *dst_uri, 580 const char *text); 466 581 467 582 … … 469 584 * Send typing indication outside dialog. 470 585 */ 471 pj_status_t pjsua_im_typing(int acc_index, const char *dst_uri, 472 pj_bool_t is_typing); 473 474 475 /** 476 * Private: check if we can accept the message. 477 * If not, then p_accept header will be filled with a valid 478 * Accept header. 479 */ 480 pj_bool_t pjsua_im_accept_pager(pjsip_rx_data *rdata, 481 pjsip_accept_hdr **p_accept_hdr); 482 483 /** 484 * Private: process pager message. 485 * This may trigger pjsua_ui_on_pager() or pjsua_ui_on_typing(). 486 */ 487 void pjsua_im_process_pager(int call_id, const pj_str_t *from, 488 const pj_str_t *to, pjsip_rx_data *rdata); 489 490 491 /***************************************************************************** 492 * User Interface API. 493 * 494 * The UI API specifies functions that will be called by pjsua upon 495 * occurence of various events. 496 */ 497 498 /** 499 * Notify UI when invite state has changed. 500 */ 501 void pjsua_ui_on_call_state(int call_index, pjsip_event *e); 502 503 /** 504 * Notify UI when registration status has changed. 505 */ 506 void pjsua_ui_on_reg_state(int acc_index); 507 508 /** 509 * Notify UI on incoming pager (i.e. MESSAGE request). 510 * Argument call_index will be -1 if MESSAGE request is not related to an 511 * existing call. 512 */ 513 void pjsua_ui_on_pager(int call_index, const pj_str_t *from, 514 const pj_str_t *to, const pj_str_t *txt); 515 516 517 /** 518 * Notify UI about typing indication. 519 */ 520 void pjsua_ui_on_typing(int call_index, const pj_str_t *from, 521 const pj_str_t *to, pj_bool_t is_typing); 586 PJ_DECL(pj_status_t) pjsua_im_typing(int acc_index, const char *dst_uri, 587 pj_bool_t is_typing); 588 522 589 523 590 … … 533 600 * Parse arguments (pjsua_opt.c). 534 601 */ 535 pj_status_t pjsua_parse_args(int argc, char *argv[]); 602 PJ_DECL(pj_status_t) pjsua_parse_args(int argc, char *argv[], 603 pjsua_config *cfg); 536 604 537 605 /** 538 606 * Load settings from a file. 539 607 */ 540 pj_status_t pjsua_load_settings(const char *filename); 608 PJ_DECL(pj_status_t) pjsua_load_settings(const char *filename, 609 pjsua_config *cfg); 541 610 542 611 /** 543 612 * Dump settings. 544 613 */ 545 int pjsua_dump_settings(char *buf, pj_size_t max); 614 PJ_DECL(int) pjsua_dump_settings(const pjsua_config *cfg, 615 char *buf, pj_size_t max); 546 616 547 617 /** 548 618 * Save settings to a file. 549 619 */ 550 pj_status_t pjsua_save_settings(const char *filename); 620 PJ_DECL(pj_status_t) pjsua_save_settings(const char *filename, 621 const pjsua_config *cfg); 551 622 552 623 … … 555 626 * @return PJ_SUCCESS if valid. 556 627 */ 557 pj_status_tpjsua_verify_sip_url(const char *c_url);628 PJ_DECL(pj_status_t) pjsua_verify_sip_url(const char *c_url); 558 629 559 630 /* 560 631 * Dump application states. 561 632 */ 562 void pjsua_dump(pj_bool_t detail); 633 PJ_DECL(void) pjsua_dump(pj_bool_t detail); 634 635 /** 636 * Display error message for the specified error code. 637 */ 638 PJ_DECL(void) pjsua_perror(const char *sender, const char *title, 639 pj_status_t status); 640 641 563 642 564 643 -
pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c
r219 r476 485 485 486 486 /* Decrement pending transaction counter. */ 487 pj_assert(regc->pending_tsx > 0); 487 488 --regc->pending_tsx; 488 489 … … 610 611 cseq_hdr->cseq = cseq; 611 612 612 /* Send. */ 613 /* Increment pending transaction first, since transaction callback 614 * may be called even before send_request() returns! 615 */ 616 ++regc->pending_tsx; 613 617 status = pjsip_endpt_send_request(regc->endpt, tdata, -1, regc, &tsx_callback); 614 if (status ==PJ_SUCCESS)615 ++regc->pending_tsx;618 if (status!=PJ_SUCCESS) 619 --regc->pending_tsx; 616 620 617 621 return status; -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
r452 r476 19 19 #include <pjsua-lib/pjsua.h> 20 20 #include <pj/log.h> 21 21 #include "pjsua_imp.h" 22 22 23 23 /* … … 57 57 } else { 58 58 PJ_LOG(3,(THIS_FILE, "Refreshing call %d", call->index)); 59 schedule_call_timer(call,e,REFRESH_CALL_TIMER,pjsua.uas_refresh); 59 schedule_call_timer(call,e,REFRESH_CALL_TIMER, 60 pjsua.config.uas_refresh); 60 61 pjsua_call_reinvite(call->index); 61 62 } … … 127 128 * Make outgoing call. 128 129 */ 129 pj_status_tpjsua_make_call(int acc_index,130 const char *cstr_dest_uri,131 int *p_call_index)130 PJ_DEF(pj_status_t) pjsua_make_call(int acc_index, 131 const char *cstr_dest_uri, 132 int *p_call_index) 132 133 { 133 134 pj_str_t dest_uri; … … 135 136 pjmedia_sdp_session *offer; 136 137 pjsip_inv_session *inv = NULL; 137 int call_index = -1;138 unsigned call_index; 138 139 pjsip_tx_data *tdata; 139 140 pj_status_t status; … … 144 145 145 146 /* Find free call slot. */ 146 for (call_index=0; call_index<pjsua. max_calls; ++call_index) {147 for (call_index=0; call_index<pjsua.config.max_calls; ++call_index) { 147 148 if (pjsua.calls[call_index].inv == NULL) 148 149 break; 149 150 } 150 151 151 if (call_index == pjsua. max_calls) {152 if (call_index == pjsua.config.max_calls) { 152 153 PJ_LOG(3,(THIS_FILE, "Error: too many calls!")); 153 154 return PJ_ETOOMANY; … … 162 163 /* Create outgoing dialog: */ 163 164 status = pjsip_dlg_create_uac( pjsip_ua_instance(), 164 &pjsua. acc[acc_index].local_uri,165 &pjsua. acc[acc_index].contact_uri,165 &pjsua.config.acc_config[acc_index].id, 166 &pjsua.config.acc_config[acc_index].contact, 166 167 &dest_uri, &dest_uri, 167 168 &dlg); … … 205 206 206 207 /* Set credentials: */ 207 208 pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count, 209 pjsua.cred_info); 208 if (pjsua.config.acc_config[acc_index].cred_count) { 209 pjsua_acc_config *acc_cfg = &pjsua.config.acc_config[acc_index]; 210 pjsip_auth_clt_set_credentials( &dlg->auth_sess, 211 acc_cfg->cred_count, 212 acc_cfg->cred_info); 213 } 210 214 211 215 … … 226 230 pjsua_perror(THIS_FILE, "Unable to send initial INVITE request", 227 231 status); 232 233 /* Upon failure to send first request, both dialog and invite 234 * session would have been cleared. 235 */ 236 inv = NULL; 237 dlg = NULL; 228 238 goto on_error; 229 239 } … … 243 253 if (inv != NULL) { 244 254 pjsip_inv_terminate(inv, PJSIP_SC_OK, PJ_FALSE); 245 } else {255 } else if (dlg) { 246 256 pjsip_dlg_terminate(dlg); 247 257 } … … 251 261 } 252 262 return status; 263 } 264 265 266 /** 267 * Answer call. 268 */ 269 PJ_DEF(void) pjsua_call_answer(int call_index, int code) 270 { 271 pjsip_tx_data *tdata; 272 pj_status_t status; 273 274 PJ_ASSERT_ON_FAIL(call_index >= 0 && 275 call_index < (int)pjsua.config.max_calls, 276 return); 277 278 if (pjsua.calls[call_index].inv == NULL) { 279 PJ_LOG(3,(THIS_FILE, "Call %d already disconnected")); 280 return; 281 } 282 283 status = pjsip_inv_answer(pjsua.calls[call_index].inv, 284 code, NULL, NULL, &tdata); 285 if (status == PJ_SUCCESS) 286 status = pjsip_inv_send_msg(pjsua.calls[call_index].inv, 287 tdata); 288 289 if (status != PJ_SUCCESS) 290 pjsua_perror(THIS_FILE, "Unable to create/send response", 291 status); 292 253 293 } 254 294 … … 266 306 pjsip_inv_session *inv = NULL; 267 307 int acc_index; 268 int call_index = -1;308 unsigned call_index; 269 309 pjmedia_sdp_session *answer; 270 310 pj_status_t status; … … 313 353 314 354 /* Find free call slot. */ 315 for (call_index=0; call_index < pjsua. max_calls; ++call_index) {355 for (call_index=0; call_index < pjsua.config.max_calls; ++call_index) { 316 356 if (pjsua.calls[call_index].inv == NULL) 317 357 break; … … 354 394 355 395 status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, 356 &pjsua. acc[acc_index].contact_uri,396 &pjsua.config.acc_config[acc_index].contact, 357 397 &dlg); 358 398 if (status != PJ_SUCCESS) { … … 388 428 389 429 status = pjsip_inv_initial_answer(inv, rdata, 390 (pjsua. auto_answer ? pjsua.auto_answer391 430 (pjsua.config.auto_answer ? 431 pjsua.config.auto_answer : 100), 392 432 NULL, NULL, &response); 393 433 if (status != PJ_SUCCESS) { … … 401 441 * because SDP negotiation has failed. 402 442 */ 403 if (pjsua. auto_answer/100 == 2)443 if (pjsua.config.auto_answer/100 == 2) 404 444 st_code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE; 405 445 else … … 416 456 } 417 457 418 if (pjsua. auto_answer < 200) {458 if (pjsua.config.auto_answer < 200) { 419 459 PJ_LOG(3,(THIS_FILE, 420 460 "\nIncoming call!!\n" … … 433 473 (int)dlg->local.info_str.slen, 434 474 dlg->local.info_str.ptr, 435 pjsua. auto_answer,436 pjsip_get_status_text(pjsua. auto_answer)->ptr ));475 pjsua.config.auto_answer, 476 pjsip_get_status_text(pjsua.config.auto_answer)->ptr )); 437 477 } 438 478 … … 440 480 441 481 /* Schedule timer to refresh. */ 442 if (pjsua. uas_refresh > 0) {482 if (pjsua.config.uas_refresh > 0) { 443 483 schedule_call_timer( &pjsua.calls[call_index], 444 484 &pjsua.calls[call_index].refresh_tm, 445 485 REFRESH_CALL_TIMER, 446 pjsua. uas_refresh);486 pjsua.config.uas_refresh); 447 487 } 448 488 449 489 /* Schedule timer to hangup call. */ 450 if (pjsua. uas_duration > 0) {490 if (pjsua.config.uas_duration > 0) { 451 491 schedule_call_timer( &pjsua.calls[call_index], 452 492 &pjsua.calls[call_index].hangup_tm, 453 493 HANGUP_CALL_TIMER, 454 pjsua. uas_duration);494 pjsua.config.uas_duration); 455 495 } 456 496 … … 551 591 552 592 553 pjsua_ui_on_call_state(call->index, e); 593 if (pjsua.cb.on_call_state) 594 (*pjsua.cb.on_call_state)(call->index, e); 554 595 555 596 /* call->inv may be NULL now */ … … 966 1007 } 967 1008 968 if (pjsua. null_audio)1009 if (pjsua.config.null_audio) 969 1010 return; 970 1011 … … 984 1025 985 1026 /* Override ptime, if this option is specified. */ 986 if (pjsua. ptime) {1027 if (pjsua.config.ptime) { 987 1028 sess_info.stream_info[0].param->setting.frm_per_pkt = (pj_uint8_t) 988 (pjsua.ptime / sess_info.stream_info[0].param->info.frm_ptime); 1029 (pjsua.config.ptime / 1030 sess_info.stream_info[0].param->info.frm_ptime); 989 1031 if (sess_info.stream_info[0].param->setting.frm_per_pkt==0) 990 1032 sess_info.stream_info[0].param->setting.frm_per_pkt = 1; … … 1038 1080 * port 1039 1081 */ 1040 if (pjsua. auto_play && pjsua.wav_file&&1082 if (pjsua.config.auto_play && pjsua.config.wav_file.slen && 1041 1083 call->inv->role == PJSIP_ROLE_UAS) 1042 1084 { … … 1046 1088 1047 1089 } 1048 if (pjsua. auto_loop && call->inv->role == PJSIP_ROLE_UAS) {1090 if (pjsua.config.auto_loop && call->inv->role == PJSIP_ROLE_UAS) { 1049 1091 1050 1092 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, … … 1052 1094 1053 1095 } 1054 if (pjsua. auto_conf) {1055 inti;1096 if (pjsua.config.auto_conf) { 1097 unsigned i; 1056 1098 1057 1099 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0); 1058 1100 pjmedia_conf_connect_port( pjsua.mconf, call->conf_slot, 0, 0); 1059 1101 1060 for (i=0; i < pjsua. max_calls; ++i) {1102 for (i=0; i < pjsua.config.max_calls; ++i) { 1061 1103 1062 1104 if (!pjsua.calls[i].session) … … 1074 1116 * the sound device port (port zero) in the main conference bridge. 1075 1117 */ 1076 if (pjsua. auto_play == 0 && pjsua.auto_loop == 0 &&1077 pjsua. auto_conf == 0)1118 if (pjsua.config.auto_play == 0 && pjsua.config.auto_loop == 0 && 1119 pjsua.config.auto_conf == 0) 1078 1120 { 1079 1121 pjmedia_conf_connect_port( pjsua.mconf, 0, call->conf_slot, 0); … … 1128 1170 * Hangup call. 1129 1171 */ 1130 voidpjsua_call_hangup(int call_index)1172 PJ_DEF(void) pjsua_call_hangup(int call_index) 1131 1173 { 1132 1174 pjsua_call *call; … … 1178 1220 * Put call on-Hold. 1179 1221 */ 1180 voidpjsua_call_set_hold(int call_index)1222 PJ_DEF(void) pjsua_call_set_hold(int call_index) 1181 1223 { 1182 1224 pjmedia_sdp_session *sdp; … … 1219 1261 * re-INVITE. 1220 1262 */ 1221 voidpjsua_call_reinvite(int call_index)1263 PJ_DEF(void) pjsua_call_reinvite(int call_index) 1222 1264 { 1223 1265 pjmedia_sdp_session *sdp; … … 1266 1308 * Transfer call. 1267 1309 */ 1268 voidpjsua_call_xfer(int call_index, const char *dest)1310 PJ_DEF(void) pjsua_call_xfer(int call_index, const char *dest) 1269 1311 { 1270 1312 pjsip_evsub *sub; … … 1318 1360 * Send instant messaging inside INVITE session. 1319 1361 */ 1320 voidpjsua_call_send_im(int call_index, const char *str)1362 PJ_DECL(void) pjsua_call_send_im(int call_index, const char *str) 1321 1363 { 1322 1364 pjsua_call *call; … … 1374 1416 * Send IM typing indication inside INVITE session. 1375 1417 */ 1376 voidpjsua_call_typing(int call_index, pj_bool_t is_typing)1418 PJ_DECL(void) pjsua_call_typing(int call_index, pj_bool_t is_typing) 1377 1419 { 1378 1420 pjsua_call *call; … … 1416 1458 * Terminate all calls. 1417 1459 */ 1418 voidpjsua_call_hangup_all(void)1419 { 1420 inti;1421 1422 for (i=0; i<pjsua. max_calls; ++i) {1460 PJ_DEF(void) pjsua_call_hangup_all(void) 1461 { 1462 unsigned i; 1463 1464 for (i=0; i<pjsua.config.max_calls; ++i) { 1423 1465 pjsip_tx_data *tdata; 1424 1466 int st_code; -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
r452 r476 18 18 */ 19 19 #include <pjsua-lib/pjsua.h> 20 #include "pjsua_imp.h" 20 21 21 22 /* … … 44 45 * Init default application parameters. 45 46 */ 46 void pjsua_default(void)47 PJ_DEF(void) pjsua_default_config(pjsua_config *cfg) 47 48 { 48 49 unsigned i; 49 50 50 51 /* Normally need another thread for console application, because main 52 * thread will be blocked in fgets(). 53 */ 54 pjsua.thread_cnt = 1; 55 56 57 /* Default transport settings: */ 58 pjsua.sip_port = 5060; 59 60 61 /* Default we start RTP at port 4000 */ 62 pjsua.start_rtp_port = 4000; 63 64 65 /* Default logging settings: */ 66 pjsua.log_level = 5; 67 pjsua.app_log_level = 4; 68 pjsua.log_decor = PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME | 69 PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE; 70 71 72 /* Default call settings. */ 73 pjsua.uas_refresh = -1; 74 pjsua.uas_duration = -1; 75 76 /* Default: do not use STUN: */ 77 pjsua.stun_port1 = pjsua.stun_port2 = 0; 78 79 /* Default for media: */ 51 pj_memset(cfg, 0, sizeof(pjsua_config)); 52 53 cfg->thread_cnt = 1; 54 cfg->udp_port = 5060; 55 cfg->start_rtp_port = 4000; 56 cfg->max_calls = 4; 57 cfg->conf_ports = 0; 58 80 59 #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 81 60 pjsua.clock_rate = 44100; 82 61 #endif 83 pjsua.complexity = -1; 84 pjsua.quality = 4; 62 63 cfg->complexity = 10; 64 cfg->quality = 10; 65 66 cfg->auto_answer = 100; 67 cfg->uas_duration = 3600; 68 69 /* Default logging settings: */ 70 cfg->log_level = 5; 71 cfg->app_log_level = 4; 72 cfg->log_decor = PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME | 73 PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE; 74 75 76 /* Also init logging settings in pjsua.config, because log 77 * may be written before pjsua_init() is called. 78 */ 79 pjsua.config.log_level = 5; 80 pjsua.config.app_log_level = 4; 85 81 86 82 87 83 /* Init accounts: */ 88 pjsua.acc_cnt = 1;89 84 for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) { 90 pjsua.acc[i].index = i; 91 pjsua.acc[i].local_uri = pj_str(PJSUA_LOCAL_URI); 92 pjsua.acc[i].reg_timeout = 55; 93 pjsua.acc[i].online_status = PJ_TRUE; 94 pj_list_init(&pjsua.acc[i].route_set); 95 pj_list_init(&pjsua.acc[i].pres_srv_list); 96 } 97 98 /* Init call array: */ 99 for (i=0; i<PJ_ARRAY_SIZE(pjsua.calls); ++i) { 100 pjsua.calls[i].index = i; 101 pjsua.calls[i].refresh_tm._timer_id = -1; 102 pjsua.calls[i].hangup_tm._timer_id = -1; 103 pjsua.calls[i].conf_slot = 0; 104 } 105 106 /* Default max nb of calls. */ 107 pjsua.max_calls = 4; 108 109 /* Init server presence subscription list: */ 110 111 112 } 113 85 cfg->acc_config[i].reg_timeout = 55; 86 } 87 } 88 89 90 #define strncpy_with_null(dst,src,len) \ 91 do { \ 92 strncpy(dst, src, len); \ 93 dst[len-1] = '\0'; \ 94 } while (0) 95 96 97 98 PJ_DEF(pj_status_t) pjsua_test_config( const pjsua_config *cfg, 99 char *errmsg, 100 int len) 101 { 102 unsigned i; 103 104 /* If UDP port is zero, then sip_host and sip_port must be specified */ 105 if (cfg->udp_port == 0) { 106 if (cfg->sip_host.slen==0 || cfg->sip_port==0) { 107 strncpy_with_null(errmsg, 108 "sip_host and sip_port must be specified", 109 len); 110 return -1; 111 } 112 } 113 114 if (cfg->max_calls < 1) { 115 strncpy_with_null(errmsg, 116 "max_calls needs to be at least 1", 117 len); 118 return -1; 119 } 120 121 /* STUN */ 122 if (cfg->stun_srv1.slen || cfg->stun_port1 || cfg->stun_port2 || 123 cfg->stun_srv2.slen) 124 { 125 if (cfg->stun_port1 == 0) { 126 strncpy_with_null(errmsg, "stun_port1 required", len); 127 return -1; 128 } 129 if (cfg->stun_srv1.slen == 0) { 130 strncpy_with_null(errmsg, "stun_srv1 required", len); 131 return -1; 132 } 133 if (cfg->stun_port2 == 0) { 134 strncpy_with_null(errmsg, "stun_port2 required", len); 135 return -1; 136 } 137 if (cfg->stun_srv2.slen == 0) { 138 strncpy_with_null(errmsg, "stun_srv2 required", len); 139 return -1; 140 } 141 } 142 143 /* Verify accounts */ 144 for (i=0; i<cfg->acc_cnt; ++i) { 145 const pjsua_acc_config *acc_cfg = &cfg->acc_config[i]; 146 unsigned j; 147 148 if (acc_cfg->id.slen == 0) { 149 strncpy_with_null(errmsg, "missing account ID", len); 150 return -1; 151 } 152 153 if (acc_cfg->id.slen == 0) { 154 strncpy_with_null(errmsg, "missing registrar URI", len); 155 return -1; 156 } 157 158 if (acc_cfg->reg_timeout == 0) { 159 strncpy_with_null(errmsg, "missing registration timeout", len); 160 return -1; 161 } 162 163 164 for (j=0; j<acc_cfg->cred_count; ++j) { 165 166 if (acc_cfg->cred_info[j].scheme.slen == 0) { 167 strncpy_with_null(errmsg, "missing auth scheme in account", 168 len); 169 return -1; 170 } 171 172 if (acc_cfg->cred_info[j].realm.slen == 0) { 173 strncpy_with_null(errmsg, "missing realm in account", len); 174 return -1; 175 } 176 177 if (acc_cfg->cred_info[j].username.slen == 0) { 178 strncpy_with_null(errmsg, "missing username in account", len); 179 return -1; 180 } 181 182 } 183 } 184 185 return PJ_SUCCESS; 186 } 114 187 115 188 … … 153 226 154 227 228 static int PJ_THREAD_FUNC pjsua_poll(void *arg) 229 { 230 pj_status_t last_err = 0; 231 232 PJ_UNUSED_ARG(arg); 233 234 do { 235 pj_time_val timeout = { 0, 10 }; 236 pj_status_t status; 237 238 status = pjsip_endpt_handle_events (pjsua.endpt, &timeout); 239 if (status != PJ_SUCCESS && status != last_err) { 240 last_err = status; 241 pjsua_perror(THIS_FILE, "handle_events() returned error", status); 242 } 243 } while (!pjsua.quit_flag); 244 245 return 0; 246 } 247 248 249 250 #define pjsua_has_stun() (pjsua.config.stun_port1 && \ 251 pjsua.config.stun_port2) 252 253 254 /* 255 * Create and initialize SIP socket (and possibly resolve public 256 * address via STUN, depending on config). 257 */ 258 static pj_status_t create_sip_udp_sock(int port, 259 pj_sock_t *p_sock, 260 pj_sockaddr_in *p_pub_addr) 261 { 262 pj_sock_t sock; 263 pj_status_t status; 264 265 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); 266 if (status != PJ_SUCCESS) { 267 pjsua_perror(THIS_FILE, "socket() error", status); 268 return status; 269 } 270 271 status = pj_sock_bind_in(sock, 0, (pj_uint16_t)port); 272 if (status != PJ_SUCCESS) { 273 pjsua_perror(THIS_FILE, "bind() error", status); 274 pj_sock_close(sock); 275 return status; 276 } 277 278 if (pjsua_has_stun()) { 279 status = pj_stun_get_mapped_addr(&pjsua.cp.factory, 1, &sock, 280 &pjsua.config.stun_srv1, 281 pjsua.config.stun_port1, 282 &pjsua.config.stun_srv2, 283 pjsua.config.stun_port2, 284 p_pub_addr); 285 if (status != PJ_SUCCESS) { 286 pjsua_perror(THIS_FILE, "STUN resolve error", status); 287 pj_sock_close(sock); 288 return status; 289 } 290 291 } else { 292 293 const pj_str_t *hostname = pj_gethostname(); 294 struct pj_hostent he; 295 296 status = pj_gethostbyname(hostname, &he); 297 if (status != PJ_SUCCESS) { 298 pjsua_perror(THIS_FILE, "Unable to resolve local host", status); 299 pj_sock_close(sock); 300 return status; 301 } 302 303 pj_memset(p_pub_addr, 0, sizeof(pj_sockaddr_in)); 304 p_pub_addr->sin_family = PJ_AF_INET; 305 p_pub_addr->sin_port = pj_htons((pj_uint16_t)port); 306 p_pub_addr->sin_addr = *(pj_in_addr*)he.h_addr; 307 } 308 309 *p_sock = sock; 310 return PJ_SUCCESS; 311 } 312 313 155 314 /* 156 * Initialize sockets and optionally get the public address via STUN.157 * /158 static pj_status_t init_sockets(pj_bool_t sip, 159 315 * Create RTP and RTCP socket pair, and possibly resolve their public 316 * address via STUN. 317 */ 318 static pj_status_t create_rtp_rtcp_sock(pjmedia_sock_info *skinfo) 160 319 { 161 320 enum { 162 321 RTP_RETRY = 100 163 322 }; 164 enum {165 SIP_SOCK,166 RTP_SOCK,167 RTCP_SOCK,168 };169 323 int i; 170 324 static pj_uint16_t rtp_port; 171 pj_sock_t sock[3]; 172 pj_sockaddr_in mapped_addr[3]; 325 pj_sockaddr_in mapped_addr[2]; 173 326 pj_status_t status = PJ_SUCCESS; 327 pj_sock_t sock[2]; 174 328 175 329 if (rtp_port == 0) 176 rtp_port = (pj_uint16_t)pjsua. start_rtp_port;177 178 for (i=0; i< 3; ++i)330 rtp_port = (pj_uint16_t)pjsua.config.start_rtp_port; 331 332 for (i=0; i<2; ++i) 179 333 sock[i] = PJ_INVALID_SOCKET; 180 181 /* Create and bind SIP UDP socket. */182 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[SIP_SOCK]);183 if (status != PJ_SUCCESS) {184 pjsua_perror(THIS_FILE, "socket() error", status);185 goto on_error;186 }187 188 if (sip) {189 status = pj_sock_bind_in(sock[SIP_SOCK], 0, pjsua.sip_port);190 if (status != PJ_SUCCESS) {191 pjsua_perror(THIS_FILE, "bind() error", status);192 goto on_error;193 }194 } else {195 status = pj_sock_bind_in(sock[SIP_SOCK], 0, 0);196 if (status != PJ_SUCCESS) {197 pjsua_perror(THIS_FILE, "bind() error", status);198 goto on_error;199 }200 }201 334 202 335 … … 205 338 206 339 /* Create and bind RTP socket. */ 207 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[ RTP_SOCK]);340 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[0]); 208 341 if (status != PJ_SUCCESS) { 209 342 pjsua_perror(THIS_FILE, "socket() error", status); 210 goto on_error;211 } 212 213 status = pj_sock_bind_in(sock[ RTP_SOCK], 0, rtp_port);343 return status; 344 } 345 346 status = pj_sock_bind_in(sock[0], 0, rtp_port); 214 347 if (status != PJ_SUCCESS) { 215 pj_sock_close(sock[ RTP_SOCK]);216 sock[ RTP_SOCK] = PJ_INVALID_SOCKET;348 pj_sock_close(sock[0]); 349 sock[0] = PJ_INVALID_SOCKET; 217 350 continue; 218 351 } 219 352 220 353 /* Create and bind RTCP socket. */ 221 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[ RTCP_SOCK]);354 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[1]); 222 355 if (status != PJ_SUCCESS) { 223 356 pjsua_perror(THIS_FILE, "socket() error", status); 224 goto on_error; 225 } 226 227 status = pj_sock_bind_in(sock[RTCP_SOCK], 0, (pj_uint16_t)(rtp_port+1)); 357 pj_sock_close(sock[0]); 358 return status; 359 } 360 361 status = pj_sock_bind_in(sock[1], 0, (pj_uint16_t)(rtp_port+1)); 228 362 if (status != PJ_SUCCESS) { 229 pj_sock_close(sock[ RTP_SOCK]);230 sock[ RTP_SOCK] = PJ_INVALID_SOCKET;231 232 pj_sock_close(sock[ RTCP_SOCK]);233 sock[ RTCP_SOCK] = PJ_INVALID_SOCKET;363 pj_sock_close(sock[0]); 364 sock[0] = PJ_INVALID_SOCKET; 365 366 pj_sock_close(sock[1]); 367 sock[1] = PJ_INVALID_SOCKET; 234 368 continue; 235 369 } … … 239 373 * and make sure that the mapped RTCP port is adjacent with the RTP. 240 374 */ 241 if (pjsua.stun_port1 == 0) { 375 if (pjsua_has_stun()) { 376 status=pj_stun_get_mapped_addr(&pjsua.cp.factory, 2, sock, 377 &pjsua.config.stun_srv1, 378 pjsua.config.stun_port1, 379 &pjsua.config.stun_srv2, 380 pjsua.config.stun_port2, 381 mapped_addr); 382 if (status != PJ_SUCCESS) { 383 pjsua_perror(THIS_FILE, "STUN resolve error", status); 384 goto on_error; 385 } 386 387 if (pj_ntohs(mapped_addr[1].sin_port) == 388 pj_ntohs(mapped_addr[0].sin_port)+1) 389 { 390 /* Success! */ 391 break; 392 } 393 394 pj_sock_close(sock[0]); 395 sock[0] = PJ_INVALID_SOCKET; 396 397 pj_sock_close(sock[1]); 398 sock[1] = PJ_INVALID_SOCKET; 399 400 } else { 242 401 const pj_str_t *hostname; 243 402 pj_sockaddr_in addr; … … 255 414 } 256 415 257 for (i=0; i< 3; ++i)416 for (i=0; i<2; ++i) 258 417 pj_memcpy(&mapped_addr[i], &addr, sizeof(addr)); 259 418 260 if (sip) { 261 mapped_addr[SIP_SOCK].sin_port = 262 pj_htons((pj_uint16_t)pjsua.sip_port); 263 } 264 mapped_addr[RTP_SOCK].sin_port=pj_htons((pj_uint16_t)rtp_port); 265 mapped_addr[RTCP_SOCK].sin_port=pj_htons((pj_uint16_t)(rtp_port+1)); 419 mapped_addr[0].sin_port=pj_htons((pj_uint16_t)rtp_port); 420 mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(rtp_port+1)); 266 421 break; 267 268 } else { 269 status=pj_stun_get_mapped_addr(&pjsua.cp.factory, 3, sock, 270 &pjsua.stun_srv1, pjsua.stun_port1, 271 &pjsua.stun_srv2, pjsua.stun_port2, 272 mapped_addr); 273 if (status != PJ_SUCCESS) { 274 pjsua_perror(THIS_FILE, "STUN error", status); 275 goto on_error; 276 } 277 278 if (pj_ntohs(mapped_addr[2].sin_port) == 279 pj_ntohs(mapped_addr[1].sin_port)+1) 280 { 281 break; 282 } 283 284 pj_sock_close(sock[RTP_SOCK]); 285 sock[RTP_SOCK] = PJ_INVALID_SOCKET; 286 287 pj_sock_close(sock[RTCP_SOCK]); 288 sock[RTCP_SOCK] = PJ_INVALID_SOCKET; 289 } 290 } 291 292 if (sock[RTP_SOCK] == PJ_INVALID_SOCKET) { 422 } 423 } 424 425 if (sock[0] == PJ_INVALID_SOCKET) { 293 426 PJ_LOG(1,(THIS_FILE, 294 427 "Unable to find appropriate RTP/RTCP ports combination")); … … 296 429 } 297 430 298 if (sip) { 299 pjsua.sip_sock = sock[SIP_SOCK]; 300 pj_memcpy(&pjsua.sip_sock_name, 301 &mapped_addr[SIP_SOCK], 302 sizeof(pj_sockaddr_in)); 303 } else { 304 pj_sock_close(sock[0]); 305 } 306 307 skinfo->rtp_sock = sock[RTP_SOCK]; 431 432 skinfo->rtp_sock = sock[0]; 308 433 pj_memcpy(&skinfo->rtp_addr_name, 309 &mapped_addr[ RTP_SOCK], sizeof(pj_sockaddr_in));310 311 skinfo->rtcp_sock = sock[ RTCP_SOCK];434 &mapped_addr[0], sizeof(pj_sockaddr_in)); 435 436 skinfo->rtcp_sock = sock[1]; 312 437 pj_memcpy(&skinfo->rtcp_addr_name, 313 &mapped_addr[RTCP_SOCK], sizeof(pj_sockaddr_in)); 314 315 if (sip) { 316 PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d", 317 pj_inet_ntoa(pjsua.sip_sock_name.sin_addr), 318 pj_ntohs(pjsua.sip_sock_name.sin_port))); 319 } 438 &mapped_addr[1], sizeof(pj_sockaddr_in)); 439 320 440 PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s:%d", 321 441 pj_inet_ntoa(skinfo->rtp_addr_name.sin_addr), … … 329 449 330 450 on_error: 331 for (i=0; i<3; ++i) { 332 if (sip && i==0) 333 continue; 451 for (i=0; i<2; ++i) { 334 452 if (sock[i] != PJ_INVALID_SOCKET) 335 453 pj_sock_close(sock[i]); … … 340 458 341 459 342 /* 343 * Initialize stack. 344 */ 345 static pj_status_t init_stack(void) 460 /** 461 * Create pjsua application. 462 * This initializes pjlib/pjlib-util, and creates memory pool factory to 463 * be used by application. 464 */ 465 PJ_DEF(pj_status_t) pjsua_create(void) 346 466 { 347 467 pj_status_t status; 348 468 469 /* Init PJLIB: */ 470 471 status = pj_init(); 472 if (status != PJ_SUCCESS) { 473 pjsua_perror(THIS_FILE, "pj_init() error", status); 474 return status; 475 } 476 477 /* Init PJLIB-UTIL: */ 478 479 status = pjlib_util_init(); 480 if (status != PJ_SUCCESS) { 481 pjsua_perror(THIS_FILE, "pjlib_util_init() error", status); 482 return status; 483 } 484 485 /* Init memory pool: */ 486 487 /* Init caching pool. */ 488 pj_caching_pool_init(&pjsua.cp, &pj_pool_factory_default_policy, 0); 489 490 /* Create memory pool for application. */ 491 pjsua.pool = pj_pool_create(&pjsua.cp.factory, "pjsua", 4000, 4000, NULL); 492 493 /* Must create endpoint to initialize SIP parser. */ 349 494 /* Create global endpoint: */ 350 495 351 { 352 const pj_str_t *hostname; 353 const char *endpt_name; 354 355 /* Endpoint MUST be assigned a globally unique name. 356 * The name will be used as the hostname in Warning header. 357 */ 358 359 /* For this implementation, we'll use hostname for simplicity */ 360 hostname = pj_gethostname(); 361 endpt_name = hostname->ptr; 362 363 /* Create the endpoint: */ 364 365 status = pjsip_endpt_create(&pjsua.cp.factory, endpt_name, 366 &pjsua.endpt); 496 status = pjsip_endpt_create(&pjsua.cp.factory, 497 pj_gethostname()->ptr, 498 &pjsua.endpt); 499 if (status != PJ_SUCCESS) { 500 pjsua_perror(THIS_FILE, "Unable to create SIP endpoint", status); 501 return status; 502 } 503 504 /* Must create media endpoint too */ 505 status = pjmedia_endpt_create(&pjsua.cp.factory, 506 pjsip_endpt_get_ioqueue(pjsua.endpt), 0, 507 &pjsua.med_endpt); 508 if (status != PJ_SUCCESS) { 509 pjsua_perror(THIS_FILE, 510 "Media stack initialization has returned error", 511 status); 512 return status; 513 } 514 515 516 return PJ_SUCCESS; 517 } 518 519 520 521 /* 522 * Init media. 523 */ 524 static pj_status_t init_media(void) 525 { 526 int i; 527 unsigned options; 528 unsigned clock_rate; 529 unsigned samples_per_frame; 530 pj_str_t codec_id; 531 pj_status_t status; 532 533 /* Register all codecs */ 534 #if PJMEDIA_HAS_SPEEX_CODEC 535 /* Register speex. */ 536 status = pjmedia_codec_speex_init(pjsua.med_endpt, 537 PJMEDIA_SPEEX_NO_UWB, 538 pjsua.config.quality, 539 pjsua.config.complexity ); 540 if (status != PJ_SUCCESS) { 541 pjsua_perror(THIS_FILE, "Error initializing Speex codec", 542 status); 543 return status; 544 } 545 546 /* Set "speex/16000/1" to have highest priority */ 547 codec_id = pj_str("speex/16000/1"); 548 pjmedia_codec_mgr_set_codec_priority( 549 pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 550 &codec_id, 551 PJMEDIA_CODEC_PRIO_HIGHEST); 552 553 #endif /* PJMEDIA_HAS_SPEEX_CODEC */ 554 555 #if PJMEDIA_HAS_GSM_CODEC 556 /* Register GSM */ 557 status = pjmedia_codec_gsm_init(pjsua.med_endpt); 558 if (status != PJ_SUCCESS) { 559 pjsua_perror(THIS_FILE, "Error initializing GSM codec", 560 status); 561 return status; 562 } 563 #endif /* PJMEDIA_HAS_GSM_CODEC */ 564 565 #if PJMEDIA_HAS_G711_CODEC 566 /* Register PCMA and PCMU */ 567 status = pjmedia_codec_g711_init(pjsua.med_endpt); 568 if (status != PJ_SUCCESS) { 569 pjsua_perror(THIS_FILE, "Error initializing G711 codec", 570 status); 571 return status; 572 } 573 #endif /* PJMEDIA_HAS_G711_CODEC */ 574 575 #if PJMEDIA_HAS_L16_CODEC 576 /* Register L16 family codecs, but disable all */ 577 status = pjmedia_codec_l16_init(pjsua.med_endpt, 0); 578 if (status != PJ_SUCCESS) { 579 pjsua_perror(THIS_FILE, "Error initializing L16 codecs", 580 status); 581 return status; 582 } 583 584 /* Disable ALL L16 codecs */ 585 codec_id = pj_str("L16"); 586 pjmedia_codec_mgr_set_codec_priority( 587 pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 588 &codec_id, 589 PJMEDIA_CODEC_PRIO_DISABLED); 590 591 #endif /* PJMEDIA_HAS_L16_CODEC */ 592 593 594 /* Enable those codecs that user put with "--add-codec", and move 595 * the priority to top 596 */ 597 for (i=0; i<(int)pjsua.config.codec_cnt; ++i) { 598 pjmedia_codec_mgr_set_codec_priority( 599 pjmedia_endpt_get_codec_mgr(pjsua.med_endpt), 600 &pjsua.config.codec_arg[i], 601 PJMEDIA_CODEC_PRIO_HIGHEST); 602 } 603 604 605 /* Init options for conference bridge. */ 606 options = 0; 607 608 /* Calculate maximum number of ports, if it's not specified */ 609 if (pjsua.config.conf_ports == 0) { 610 pjsua.config.conf_ports = 3 * pjsua.config.max_calls; 611 } 612 613 /* Init conference bridge. */ 614 clock_rate = pjsua.config.clock_rate ? pjsua.config.clock_rate : 16000; 615 samples_per_frame = clock_rate * 10 / 1000; 616 status = pjmedia_conf_create(pjsua.pool, 617 pjsua.config.conf_ports, 618 clock_rate, 619 1, /* mono */ 620 samples_per_frame, 621 16, 622 options, 623 &pjsua.mconf); 624 if (status != PJ_SUCCESS) { 625 pjsua_perror(THIS_FILE, 626 "Media stack initialization has returned error", 627 status); 628 return status; 629 } 630 631 /* Create WAV file player if required: */ 632 633 if (pjsua.config.wav_file.slen) { 634 pj_str_t port_name; 635 636 /* Create the file player port. */ 637 status = pjmedia_wav_player_port_create( pjsua.pool, 638 pjsua.config.wav_file.ptr, 639 0, 0, -1, NULL, 640 &pjsua.file_port); 367 641 if (status != PJ_SUCCESS) { 368 pjsua_perror(THIS_FILE, "Unable to create SIP endpoint", status); 642 pjsua_perror(THIS_FILE, 643 "Error playing media file", 644 status); 369 645 return status; 370 646 } 371 } 372 647 648 /* Add port to conference bridge: */ 649 port_name = pjsua.config.wav_file; 650 status = pjmedia_conf_add_port(pjsua.mconf, pjsua.pool, 651 pjsua.file_port, 652 &port_name, 653 &pjsua.wav_slot); 654 if (status != PJ_SUCCESS) { 655 pjsua_perror(THIS_FILE, 656 "Unable to add file player to conference bridge", 657 status); 658 return status; 659 } 660 } 661 662 663 return PJ_SUCCESS; 664 } 665 666 667 /* 668 * Copy configuration. 669 */ 670 static void copy_config(pj_pool_t *pool, pjsua_config *dst, 671 const pjsua_config *src) 672 { 673 unsigned i; 674 675 /* Plain memcpy */ 676 pj_memcpy(dst, src, sizeof(pjsua_config)); 677 678 /* Duplicate strings */ 679 pj_strdup_with_null(pool, &dst->sip_host, &src->sip_host); 680 pj_strdup_with_null(pool, &dst->stun_srv1, &src->stun_srv1); 681 pj_strdup_with_null(pool, &dst->stun_srv2, &src->stun_srv2); 682 pj_strdup_with_null(pool, &dst->wav_file, &src->wav_file); 683 684 for (i=0; i<src->codec_cnt; ++i) { 685 pj_strdup_with_null(pool, &dst->codec_arg[i], &src->codec_arg[i]); 686 } 687 688 pj_strdup_with_null(pool, &dst->outbound_proxy, &src->outbound_proxy); 689 pj_strdup_with_null(pool, &dst->uri_to_call, &src->uri_to_call); 690 691 for (i=0; i<src->acc_cnt; ++i) { 692 pjsua_acc_config *dst_acc = &dst->acc_config[i]; 693 const pjsua_acc_config *src_acc = &src->acc_config[i]; 694 unsigned j; 695 696 pj_strdup_with_null(pool, &dst_acc->id, &src_acc->id); 697 pj_strdup_with_null(pool, &dst_acc->reg_uri, &src_acc->reg_uri); 698 pj_strdup_with_null(pool, &dst_acc->contact, &src_acc->contact); 699 pj_strdup_with_null(pool, &dst_acc->proxy, &src_acc->proxy); 700 701 for (j=0; j<src_acc->cred_count; ++j) { 702 pj_strdup_with_null(pool, &dst_acc->cred_info[j].realm, 703 &src_acc->cred_info[j].realm); 704 pj_strdup_with_null(pool, &dst_acc->cred_info[j].scheme, 705 &src_acc->cred_info[j].scheme); 706 pj_strdup_with_null(pool, &dst_acc->cred_info[j].username, 707 &src_acc->cred_info[j].username); 708 pj_strdup_with_null(pool, &dst_acc->cred_info[j].data, 709 &src_acc->cred_info[j].data); 710 } 711 } 712 713 pj_strdup_with_null(pool, &dst->log_filename, &src->log_filename); 714 715 for (i=0; i<src->buddy_cnt; ++i) { 716 pj_strdup_with_null(pool, &dst->buddy_uri[i], &src->buddy_uri[i]); 717 } 718 } 719 720 721 /* 722 * Initialize pjsua application. 723 * This will initialize all libraries, create endpoint instance, and register 724 * pjsip modules. 725 */ 726 PJ_DECL(pj_status_t) pjsua_init(const pjsua_config *cfg, 727 const pjsua_callback *cb) 728 { 729 char errmsg[80]; 730 unsigned i; 731 pj_status_t status; 732 733 734 /* Init accounts: */ 735 for (i=0; i<PJ_ARRAY_SIZE(pjsua.acc); ++i) { 736 pjsua.acc[i].index = i; 737 pjsua.acc[i].online_status = PJ_TRUE; 738 pj_list_init(&pjsua.acc[i].route_set); 739 pj_list_init(&pjsua.acc[i].pres_srv_list); 740 } 741 742 /* Init call array: */ 743 for (i=0; i<PJ_ARRAY_SIZE(pjsua.calls); ++i) { 744 pjsua.calls[i].index = i; 745 pjsua.calls[i].refresh_tm._timer_id = -1; 746 pjsua.calls[i].hangup_tm._timer_id = -1; 747 pjsua.calls[i].conf_slot = 0; 748 } 749 750 /* Copy configuration */ 751 copy_config(pjsua.pool, &pjsua.config, cfg); 752 753 /* Copy callback */ 754 pj_memcpy(&pjsua.cb, cb, sizeof(pjsua_callback)); 755 756 /* Test configuration */ 757 if (pjsua_test_config(&pjsua.config, errmsg, sizeof(errmsg))) { 758 PJ_LOG(1,(THIS_FILE, "Error in configuration: %s", errmsg)); 759 return -1; 760 } 761 762 763 /* Init PJLIB logging: */ 764 765 pj_log_set_level(pjsua.config.log_level); 766 pj_log_set_decor(pjsua.config.log_decor); 767 768 769 /* Create SIP UDP socket */ 770 if (pjsua.config.udp_port) { 771 772 status = create_sip_udp_sock( pjsua.config.udp_port, 773 &pjsua.sip_sock, 774 &pjsua.sip_sock_name); 775 if (status != PJ_SUCCESS) 776 return status; 777 778 pj_strdup2_with_null(pjsua.pool, &pjsua.config.sip_host, 779 pj_inet_ntoa(pjsua.sip_sock_name.sin_addr)); 780 pjsua.config.sip_port = pj_ntohs(pjsua.sip_sock_name.sin_port); 781 782 } else { 783 784 /* Check that SIP host and port is configured */ 785 if (cfg->sip_host.slen == 0 || cfg->sip_port == 0) { 786 PJ_LOG(1,(THIS_FILE, 787 "Error: sip_host and sip_port must be specified")); 788 return PJ_EINVAL; 789 } 790 791 pjsua.sip_sock = PJ_INVALID_SOCKET; 792 } 793 794 795 /* Init media endpoint */ 796 status = init_media(); 797 if (status != PJ_SUCCESS) 798 return status; 799 800 801 /* Init RTP sockets, only when UDP transport is enabled */ 802 for (i=0; pjsua.config.start_rtp_port && i<pjsua.config.max_calls; ++i) { 803 status = create_rtp_rtcp_sock(&pjsua.calls[i].skinfo); 804 if (status != PJ_SUCCESS) { 805 unsigned j; 806 for (j=0; j<i; ++j) { 807 pjmedia_transport_udp_close(pjsua.calls[j].med_tp); 808 } 809 return status; 810 } 811 status = pjmedia_transport_udp_attach(pjsua.med_endpt, NULL, 812 &pjsua.calls[i].skinfo, 813 &pjsua.calls[i].med_tp); 814 } 815 816 /* Init PJSIP : */ 373 817 374 818 /* Initialize transaction layer: */ … … 428 872 } 429 873 430 /* Done */431 432 return PJ_SUCCESS;433 434 435 on_error:436 pjsip_endpt_destroy(pjsua.endpt);437 pjsua.endpt = NULL;438 return status;439 }440 441 442 static int PJ_THREAD_FUNC pjsua_poll(void *arg)443 {444 pj_status_t last_err = 0;445 446 PJ_UNUSED_ARG(arg);447 448 do {449 pj_time_val timeout = { 0, 10 };450 pj_status_t status;451 452 status = pjsip_endpt_handle_events (pjsua.endpt, &timeout);453 if (status != PJ_SUCCESS && status != last_err) {454 last_err = status;455 pjsua_perror(THIS_FILE, "handle_events() returned error", status);456 }457 } while (!pjsua.quit_flag);458 459 return 0;460 }461 462 /*463 * Initialize pjsua application.464 * This will initialize all libraries, create endpoint instance, and register465 * pjsip modules.466 */467 pj_status_t pjsua_init(void)468 {469 pj_status_t status;470 471 /* Init PJLIB logging: */472 473 pj_log_set_level(pjsua.log_level);474 pj_log_set_decor(pjsua.log_decor);475 476 477 /* Init PJLIB: */478 479 status = pj_init();480 if (status != PJ_SUCCESS) {481 pjsua_perror(THIS_FILE, "pj_init() error", status);482 return status;483 }484 485 /* Init PJLIB-UTIL: */486 487 status = pjlib_util_init();488 if (status != PJ_SUCCESS) {489 pjsua_perror(THIS_FILE, "pjlib_util_init() error", status);490 return status;491 }492 493 /* Init memory pool: */494 495 /* Init caching pool. */496 pj_caching_pool_init(&pjsua.cp, &pj_pool_factory_default_policy, 0);497 498 /* Create memory pool for application. */499 pjsua.pool = pj_pool_create(&pjsua.cp.factory, "pjsua", 4000, 4000, NULL);500 501 502 /* Init PJSIP : */503 504 status = init_stack();505 if (status != PJ_SUCCESS) {506 pj_caching_pool_destroy(&pjsua.cp);507 pjsua_perror(THIS_FILE, "Stack initialization has returned error",508 status);509 return status;510 }511 512 513 874 /* Init core SIMPLE module : */ 514 875 … … 531 892 pjsua_im_init(); 532 893 533 534 /* Init media endpoint: */535 536 status = pjmedia_endpt_create(&pjsua.cp.factory,537 pjsip_endpt_get_ioqueue(pjsua.endpt), 0,538 &pjsua.med_endpt);539 if (status != PJ_SUCCESS) {540 pj_caching_pool_destroy(&pjsua.cp);541 pjsua_perror(THIS_FILE,542 "Media stack initialization has returned error",543 status);544 return status;545 }546 894 547 895 /* Done. */ 548 896 return PJ_SUCCESS; 897 898 on_error: 899 pj_caching_pool_destroy(&pjsua.cp); 900 return status; 549 901 } 550 902 … … 557 909 pjsip_uri *uri; 558 910 pjsip_sip_uri *sip_uri; 559 intacc_index;911 unsigned acc_index; 560 912 561 913 uri = rdata->msg_info.to->uri; 562 914 563 /* Just return account #0if To URI is not SIP: */915 /* Just return last account if To URI is not SIP: */ 564 916 if (!PJSIP_URI_SCHEME_IS_SIP(uri) && 565 917 !PJSIP_URI_SCHEME_IS_SIPS(uri)) 566 918 { 567 return 0;919 return pjsua.config.acc_cnt; 568 920 } 569 921 … … 572 924 573 925 /* Find account which has matching username and domain. */ 574 for (acc_index=0; acc_index < pjsua. acc_cnt; ++acc_index) {926 for (acc_index=0; acc_index < pjsua.config.acc_cnt; ++acc_index) { 575 927 576 928 pjsua_acc *acc = &pjsua.acc[acc_index]; … … 585 937 586 938 /* No matching, try match domain part only. */ 587 for (acc_index=0; acc_index < pjsua. acc_cnt; ++acc_index) {939 for (acc_index=0; acc_index < pjsua.config.acc_cnt; ++acc_index) { 588 940 589 941 pjsua_acc *acc = &pjsua.acc[acc_index]; … … 595 947 } 596 948 597 /* Still no match, just return account #0*/598 return 0;949 /* Still no match, just return last account */ 950 return pjsua.config.acc_cnt; 599 951 } 600 952 … … 611 963 } 612 964 613 614 /*615 * Init media.616 */617 static pj_status_t init_media(void)618 {619 int i;620 unsigned options;621 unsigned clock_rate;622 unsigned samples_per_frame;623 pj_str_t codec_id;624 pj_status_t status;625 626 /* Register all codecs */627 #if PJMEDIA_HAS_SPEEX_CODEC628 /* Register speex. */629 status = pjmedia_codec_speex_init(pjsua.med_endpt,630 PJMEDIA_SPEEX_NO_UWB,631 pjsua.quality, pjsua.complexity );632 if (status != PJ_SUCCESS) {633 pjsua_perror(THIS_FILE, "Error initializing Speex codec",634 status);635 return status;636 }637 638 /* Set "speex/16000/1" to have highest priority */639 codec_id = pj_str("speex/16000/1");640 pjmedia_codec_mgr_set_codec_priority(641 pjmedia_endpt_get_codec_mgr(pjsua.med_endpt),642 &codec_id,643 PJMEDIA_CODEC_PRIO_HIGHEST);644 645 #endif /* PJMEDIA_HAS_SPEEX_CODEC */646 647 #if PJMEDIA_HAS_GSM_CODEC648 /* Register GSM */649 status = pjmedia_codec_gsm_init(pjsua.med_endpt);650 if (status != PJ_SUCCESS) {651 pjsua_perror(THIS_FILE, "Error initializing GSM codec",652 status);653 return status;654 }655 #endif /* PJMEDIA_HAS_GSM_CODEC */656 657 #if PJMEDIA_HAS_G711_CODEC658 /* Register PCMA and PCMU */659 status = pjmedia_codec_g711_init(pjsua.med_endpt);660 if (status != PJ_SUCCESS) {661 pjsua_perror(THIS_FILE, "Error initializing G711 codec",662 status);663 return status;664 }665 #endif /* PJMEDIA_HAS_G711_CODEC */666 667 #if PJMEDIA_HAS_L16_CODEC668 /* Register L16 family codecs, but disable all */669 status = pjmedia_codec_l16_init(pjsua.med_endpt, 0);670 if (status != PJ_SUCCESS) {671 pjsua_perror(THIS_FILE, "Error initializing L16 codecs",672 status);673 return status;674 }675 676 /* Disable ALL L16 codecs */677 codec_id = pj_str("L16");678 pjmedia_codec_mgr_set_codec_priority(679 pjmedia_endpt_get_codec_mgr(pjsua.med_endpt),680 &codec_id,681 PJMEDIA_CODEC_PRIO_DISABLED);682 683 #endif /* PJMEDIA_HAS_L16_CODEC */684 685 686 /* Enable those codecs that user put with "--add-codec", and move687 * the priority to top688 */689 for (i=0; i<pjsua.codec_cnt; ++i) {690 pjmedia_codec_mgr_set_codec_priority(691 pjmedia_endpt_get_codec_mgr(pjsua.med_endpt),692 &pjsua.codec_arg[i],693 PJMEDIA_CODEC_PRIO_HIGHEST);694 }695 696 697 /* Init options for conference bridge. */698 options = 0;699 if (pjsua.no_mic)700 options |= PJMEDIA_CONF_NO_MIC;701 702 /* Init conference bridge. */703 clock_rate = pjsua.clock_rate ? pjsua.clock_rate : 16000;704 samples_per_frame = clock_rate * 10 / 1000;705 status = pjmedia_conf_create(pjsua.pool,706 pjsua.max_calls+PJSUA_CONF_MORE_PORTS,707 clock_rate,708 1, /* mono */709 samples_per_frame,710 16,711 options,712 &pjsua.mconf);713 if (status != PJ_SUCCESS) {714 pjsua_perror(THIS_FILE,715 "Media stack initialization has returned error",716 status);717 return status;718 }719 720 /* Add NULL port to the bridge. */721 status = pjmedia_null_port_create( pjsua.pool, clock_rate,722 1, /* mono */723 samples_per_frame, 16,724 &pjsua.null_port);725 pjmedia_conf_add_port( pjsua.mconf, pjsua.pool, pjsua.null_port,726 &pjsua.null_port->info.name, NULL );727 728 /* Create WAV file player if required: */729 730 if (pjsua.wav_file) {731 pj_str_t port_name;732 733 /* Create the file player port. */734 status = pjmedia_wav_player_port_create( pjsua.pool, pjsua.wav_file,735 0, 0, -1, NULL,736 &pjsua.file_port);737 if (status != PJ_SUCCESS) {738 pjsua_perror(THIS_FILE,739 "Error playing media file",740 status);741 return status;742 }743 744 /* Add port to conference bridge: */745 status = pjmedia_conf_add_port(pjsua.mconf, pjsua.pool,746 pjsua.file_port,747 pj_cstr(&port_name, pjsua.wav_file),748 &pjsua.wav_slot);749 if (status != PJ_SUCCESS) {750 pjsua_perror(THIS_FILE,751 "Unable to add file player to conference bridge",752 status);753 return status;754 }755 }756 757 758 return PJ_SUCCESS;759 }760 965 761 966 … … 764 969 * This will start the registration process, if registration is configured. 765 970 */ 766 pj_status_tpjsua_start(void)971 PJ_DEF(pj_status_t) pjsua_start(void) 767 972 { 768 973 int i; /* Must be signed */ 769 pjsip_transport *udp_transport;770 974 pj_status_t status = PJ_SUCCESS; 771 975 772 /*773 * Init media subsystem (codecs, conference bridge, et all).774 */775 status = init_media();776 if (status != PJ_SUCCESS)777 return status;778 779 /* Init sockets (STUN etc): */780 for (i=0; i<(int)pjsua.max_calls; ++i) {781 status = init_sockets(i==0, &pjsua.calls[i].skinfo);782 if (status == PJ_SUCCESS)783 status = pjmedia_transport_udp_attach(pjsua.med_endpt, NULL,784 &pjsua.calls[i].skinfo,785 &pjsua.calls[i].med_tp);786 if (status != PJ_SUCCESS) {787 pjsua_perror(THIS_FILE, "init_sockets() has returned error",788 status);789 --i;790 if (i >= 0)791 pj_sock_close(pjsua.sip_sock);792 while (i >= 0) {793 pjmedia_transport_udp_close(pjsua.calls[i].med_tp);794 }795 return status;796 }797 }798 976 799 977 /* Add UDP transport: */ 800 801 { 978 if (pjsua.sip_sock > 0) { 979 802 980 /* Init the published name for the transport. 803 981 * Depending whether STUN is used, this may be the STUN mapped … … 806 984 pjsip_host_port addr_name; 807 985 808 addr_name.host.ptr = pj_inet_ntoa(pjsua.sip_sock_name.sin_addr); 809 addr_name.host.slen = pj_ansi_strlen(addr_name.host.ptr); 810 addr_name.port = pj_ntohs(pjsua.sip_sock_name.sin_port); 986 addr_name.host = pjsua.config.sip_host; 987 addr_name.port = pjsua.config.sip_port; 811 988 812 989 /* Create UDP transport from previously created UDP socket: */ … … 814 991 status = pjsip_udp_transport_attach( pjsua.endpt, pjsua.sip_sock, 815 992 &addr_name, 1, 816 &udp_transport);993 NULL); 817 994 if (status != PJ_SUCCESS) { 818 995 pjsua_perror(THIS_FILE, "Unable to start UDP transport", … … 822 999 } 823 1000 824 /* Initialize Contact URI, if one is not specified: */ 825 for (i=0; i<pjsua.acc_cnt; ++i) { 826 1001 /* The last account is default account to be used when nothing match 1002 * any configured accounts. 1003 */ 1004 { 1005 char buf[80]; 1006 pj_str_t tmp; 1007 pjsua_acc_config *acc_cfg = 1008 &pjsua.config.acc_config[pjsua.config.acc_cnt]; 1009 1010 tmp.ptr = buf; 1011 tmp.slen = pj_ansi_sprintf(tmp.ptr, "<sip:%s:%d>", 1012 pjsua.config.sip_host.ptr, 1013 pjsua.config.sip_port); 1014 1015 pj_strdup_with_null( pjsua.pool, &acc_cfg->id, &tmp); 1016 acc_cfg->contact = acc_cfg->id; 1017 } 1018 1019 1020 /* Initialize accounts: */ 1021 for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { 1022 1023 pjsua_acc_config *acc_cfg = &pjsua.config.acc_config[i]; 1024 pjsua_acc *acc = &pjsua.acc[i]; 827 1025 pjsip_uri *uri; 828 1026 pjsip_sip_uri *sip_uri; … … 830 1028 /* Need to parse local_uri to get the elements: */ 831 1029 832 uri = pjsip_parse_uri(pjsua.pool, pjsua.acc[i].local_uri.ptr,833 pjsua.acc[i].local_uri.slen, 0);1030 uri = pjsip_parse_uri(pjsua.pool, acc_cfg->id.ptr, 1031 acc_cfg->id.slen, 0); 834 1032 if (uri == NULL) { 835 1033 pjsua_perror(THIS_FILE, "Invalid local URI", … … 853 1051 sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri); 854 1052 855 pjsua.acc[i].user_part = sip_uri->user;856 pjsua.acc[i].host_part = sip_uri->host;857 858 if (pjsua.acc[i].contact_uri.slen == 0 &&859 pjsua.acc[i].local_uri.slen) 860 {1053 acc->user_part = sip_uri->user; 1054 acc->host_part = sip_uri->host; 1055 1056 /* Build Contact header */ 1057 1058 if (acc_cfg->contact.slen == 0) { 861 1059 char contact[128]; 1060 const char *addr; 1061 int port; 862 1062 int len; 1063 1064 addr = pjsua.config.sip_host.ptr; 1065 port = pjsua.config.sip_port; 863 1066 864 1067 /* The local Contact is the username@ip-addr, where … … 874 1077 /* With the user part. */ 875 1078 len = pj_ansi_snprintf(contact, sizeof(contact), 876 "<sip:%.*s@% .*s:%d>",1079 "<sip:%.*s@%s:%d>", 877 1080 (int)sip_uri->user.slen, 878 1081 sip_uri->user.ptr, 879 (int)udp_transport->local_name.host.slen, 880 udp_transport->local_name.host.ptr, 881 udp_transport->local_name.port); 1082 addr, port); 882 1083 } else { 883 1084 … … 885 1086 886 1087 len = pj_ansi_snprintf(contact, sizeof(contact), 887 "<sip:%.*s:%d>", 888 (int)udp_transport->local_name.host.slen, 889 udp_transport->local_name.host.ptr, 890 udp_transport->local_name.port); 1088 "<sip:%s:%d>", 1089 addr, port); 891 1090 } 892 1091 … … 898 1097 /* Duplicate Contact uri. */ 899 1098 900 pj_strdup2(pjsua.pool, &pjsua.acc[i].contact_uri, contact); 901 902 } 903 } 904 905 /* If outbound_proxy is specified, put it in the route_set: */ 906 907 if (pjsua.outbound_proxy.slen) { 908 909 pjsip_route_hdr *route; 910 const pj_str_t hname = { "Route", 5 }; 911 int parsed_len; 912 913 route = pjsip_parse_hdr( pjsua.pool, &hname, 914 pjsua.outbound_proxy.ptr, 915 pjsua.outbound_proxy.slen, 916 &parsed_len); 917 if (route == NULL) { 918 pjsua_perror(THIS_FILE, "Invalid outbound proxy URL", 919 PJSIP_EINVALIDURI); 920 return PJSIP_EINVALIDURI; 921 } 922 923 for (i=0; i<pjsua.acc_cnt; ++i) { 924 pj_list_push_front(&pjsua.acc[i].route_set, route); 925 } 926 } 1099 pj_strdup2(pjsua.pool, &acc_cfg->contact, contact); 1100 1101 } 1102 1103 1104 /* Build route-set for this account */ 1105 if (pjsua.config.outbound_proxy.slen) { 1106 pj_str_t hname = { "Route", 5}; 1107 pjsip_route_hdr *r; 1108 pj_str_t tmp; 1109 1110 pj_strdup_with_null(pjsua.pool, &tmp, &pjsua.config.outbound_proxy); 1111 r = pjsip_parse_hdr(pjsua.pool, &hname, tmp.ptr, tmp.slen, NULL); 1112 pj_list_push_back(&acc->route_set, r); 1113 } 1114 1115 if (acc_cfg->proxy.slen) { 1116 pj_str_t hname = { "Route", 5}; 1117 pjsip_route_hdr *r; 1118 pj_str_t tmp; 1119 1120 pj_strdup_with_null(pjsua.pool, &tmp, &acc_cfg->proxy); 1121 r = pjsip_parse_hdr(pjsua.pool, &hname, tmp.ptr, tmp.slen, NULL); 1122 pj_list_push_back(&acc->route_set, r); 1123 } 1124 } 1125 1126 927 1127 928 1128 929 1129 /* Create worker thread(s), if required: */ 930 1130 931 for (i=0; i< pjsua.thread_cnt; ++i) {1131 for (i=0; i<(int)pjsua.config.thread_cnt; ++i) { 932 1132 status = pj_thread_create( pjsua.pool, "pjsua", &pjsua_poll, 933 1133 NULL, 0, 0, &pjsua.threads[i]); … … 945 1145 946 1146 /* Create client registration session: */ 947 for (i=0; i< pjsua.acc_cnt; ++i) {1147 for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { 948 1148 status = pjsua_regc_init(i); 949 1149 if (status != PJ_SUCCESS) … … 956 1156 } 957 1157 1158 1159 /* Init buddies */ 1160 for (i=0; i<(int)pjsua.config.buddy_cnt; ++i) { 1161 pjsua.buddies[i].uri = pjsua.config.buddy_uri[i]; 1162 } 1163 pjsua.buddy_cnt = pjsua.config.buddy_cnt; 958 1164 959 1165 /* Find account for outgoing preence subscription */ … … 987 1193 * Destroy pjsua. 988 1194 */ 989 pj_status_tpjsua_destroy(void)1195 PJ_DEF(pj_status_t) pjsua_destroy(void) 990 1196 { 991 1197 int i; /* Must be signed */ … … 1001 1207 1002 1208 /* Unregister, if required: */ 1003 for (i=0; i< pjsua.acc_cnt; ++i) {1209 for (i=0; i<(int)pjsua.config.acc_cnt; ++i) { 1004 1210 if (pjsua.acc[i].regc) { 1005 1211 pjsua_regc_update(i, 0); … … 1008 1214 1009 1215 /* Wait worker threads to quit: */ 1010 for (i=0; i< pjsua.thread_cnt; ++i) {1216 for (i=0; i<(int)pjsua.config.thread_cnt; ++i) { 1011 1217 1012 1218 if (pjsua.threads[i]) { … … 1030 1236 pjmedia_port_destroy(pjsua.file_port); 1031 1237 1032 /* Destroy null port. */1033 if (pjsua.null_port)1034 pjmedia_port_destroy(pjsua.null_port);1035 1036 1238 1037 1239 /* Shutdown all codecs: */ … … 1054 1256 1055 1257 /* Close transports */ 1056 for (i=0; i<pjsua.call_cnt; ++i) {1258 for (i=0; pjsua.config.start_rtp_port && i<(int)pjsua.config.max_calls; ++i) { 1057 1259 pjmedia_transport_udp_close(pjsua.calls[i].med_tp); 1058 1260 } -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_im.c
r300 r476 153 153 text.slen = rdata->msg_info.msg->body->len; 154 154 155 pjsua_ui_on_pager(call_index, from, to, &text); 155 if (pjsua.cb.on_pager) 156 (*pjsua.cb.on_pager)(call_index, from, to, &text); 156 157 157 158 } else { … … 170 171 } 171 172 172 pjsua_ui_on_typing(call_index, from, to, is_typing); 173 if (pjsua.cb.on_typing) 174 (*pjsua.cb.on_typing)(call_index, from, to, is_typing); 173 175 } 174 176 … … 270 272 * Send IM outside dialog. 271 273 */ 272 pj_status_tpjsua_im_send(int acc_index, const char *dst_uri,273 const char *str)274 PJ_DEF(pj_status_t) pjsua_im_send(int acc_index, const char *dst_uri, 275 const char *str) 274 276 { 275 277 pjsip_tx_data *tdata; … … 282 284 283 285 /* Create request. */ 284 status = pjsip_endpt_create_request( pjsua.endpt, &pjsip_message_method, 285 &dst, &pjsua.acc[acc_index].local_uri, 286 &dst, NULL, NULL, -1, NULL, &tdata); 286 status = pjsip_endpt_create_request(pjsua.endpt, &pjsip_message_method, 287 &dst, 288 &pjsua.config.acc_config[acc_index].id, 289 &dst, NULL, NULL, -1, NULL, &tdata); 287 290 if (status != PJ_SUCCESS) { 288 291 pjsua_perror(THIS_FILE, "Unable to create request", status); … … 296 299 /* Add contact. */ 297 300 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*) 298 299 300 &pjsua.acc[acc_index].contact_uri));301 pjsip_generic_string_hdr_create(tdata->pool, 302 &STR_CONTACT, 303 &pjsua.config.acc_config[acc_index].contact)); 301 304 302 305 /* Duplicate text. … … 331 334 * Send typing indication outside dialog. 332 335 */ 333 pj_status_tpjsua_im_typing(int acc_index, const char *dst_uri,334 pj_bool_t is_typing)336 PJ_DEF(pj_status_t) pjsua_im_typing(int acc_index, const char *dst_uri, 337 pj_bool_t is_typing) 335 338 { 336 339 const pj_str_t dst = pj_str((char*)dst_uri); … … 340 343 /* Create request. */ 341 344 status = pjsip_endpt_create_request( pjsua.endpt, &pjsip_message_method, 342 &dst, &pjsua.acc[acc_index].local_uri, 345 &dst, 346 &pjsua.config.acc_config[acc_index].id, 343 347 &dst, NULL, NULL, -1, NULL, &tdata); 344 348 if (status != PJ_SUCCESS) { -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c
r424 r476 18 18 */ 19 19 #include <pjsua-lib/pjsua.h> 20 #include "pjsua_imp.h" 20 21 21 22 /* … … 81 82 { 82 83 int acc_index; 84 pjsua_acc_config *acc_config; 83 85 pjsip_method *req_method = &rdata->msg_info.msg->line.req.method; 84 86 pjsua_srv_pres *uapres; … … 97 99 /* Find which account for the incoming request. */ 98 100 acc_index = pjsua_find_account_for_incoming(rdata); 101 acc_config = &pjsua.config.acc_config[acc_index]; 99 102 100 103 /* Create UAS dialog: */ 101 status = pjsip_dlg_create_uas( 102 &pjsua.acc[acc_index].contact_uri,103 104 status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, 105 &acc_config->contact, 106 &dlg); 104 107 if (status != PJ_SUCCESS) { 105 108 pjsua_perror(THIS_FILE, … … 307 310 { 308 311 int acc_index; 312 pjsua_acc_config *acc_config; 309 313 pjsip_dialog *dlg; 310 314 pjsip_tx_data *tdata; … … 312 316 313 317 acc_index = pjsua.buddies[index].acc_index; 318 acc_config = &pjsua.config.acc_config[acc_index]; 314 319 315 320 status = pjsip_dlg_create_uac( pjsip_ua_instance(), 316 & pjsua.acc[acc_index].local_uri,317 & pjsua.acc[acc_index].contact_uri,321 &acc_config->id, 322 &acc_config->contact, 318 323 &pjsua.buddies[index].uri, 319 324 NULL, &dlg); … … 324 329 } 325 330 326 pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count, 327 pjsua.cred_info); 331 if (acc_config->cred_count) { 332 pjsip_auth_clt_set_credentials( &dlg->auth_sess, 333 acc_config->cred_count, 334 acc_config->cred_info); 335 } 328 336 329 337 status = pjsip_pres_create_uac( dlg, &pres_callback, … … 427 435 * Refresh presence 428 436 */ 429 voidpjsua_pres_refresh(int acc_index)437 PJ_DEF(void) pjsua_pres_refresh(int acc_index) 430 438 { 431 439 refresh_client_subscription(); … … 442 450 int i; 443 451 444 for (acc_index=0; acc_index< pjsua.acc_cnt; ++acc_index) {452 for (acc_index=0; acc_index<(int)pjsua.config.acc_cnt; ++acc_index) { 445 453 pjsua.acc[acc_index].online_status = 0; 446 454 } … … 450 458 } 451 459 452 for (acc_index=0; acc_index< pjsua.acc_cnt; ++acc_index) {460 for (acc_index=0; acc_index<(int)pjsua.config.acc_cnt; ++acc_index) { 453 461 pjsua_pres_refresh(acc_index); 454 462 } … … 472 480 int count = 0; 473 481 474 for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) {482 for (acc_index=0; acc_index < (int)pjsua.config.acc_cnt; ++acc_index) { 475 483 476 484 if (!pj_list_empty(&pjsua.acc[acc_index].pres_srv_list)) { … … 507 515 PJ_LOG(3,(THIS_FILE, "Dumping pjsua server subscriptions:")); 508 516 509 for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) {517 for (acc_index=0; acc_index < (int)pjsua.config.acc_cnt; ++acc_index) { 510 518 511 519 PJ_LOG(3,(THIS_FILE, " %.*s", 512 (int)pjsua. acc[acc_index].local_uri.slen,513 pjsua. acc[acc_index].local_uri.ptr));520 (int)pjsua.config.acc_config[acc_index].id.slen, 521 pjsua.config.acc_config[acc_index].id.ptr)); 514 522 515 523 if (pj_list_empty(&pjsua.acc[acc_index].pres_srv_list)) { -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_reg.c
r268 r476 60 60 acc->regc = NULL; 61 61 PJ_LOG(3,(THIS_FILE, "%s: unregistration success", 62 acc->local_uri.ptr));62 pjsua.config.acc_config[acc->index].id.ptr)); 63 63 } else { 64 64 PJ_LOG(3, (THIS_FILE, 65 65 "%s: registration success, status=%d (%s), " 66 66 "will re-register in %d seconds", 67 acc->local_uri.ptr,67 pjsua.config.acc_config[acc->index].id.ptr, 68 68 param->code, 69 69 pjsip_get_status_text(param->code)->ptr, … … 78 78 acc->reg_last_code = param->code; 79 79 80 pjsua_ui_on_reg_state(acc->index); 80 if (pjsua.cb.on_reg_state) 81 (*pjsua.cb.on_reg_state)(acc->index); 81 82 } 82 83 … … 85 86 * Update registration. If renew is false, then unregistration will be performed. 86 87 */ 87 voidpjsua_regc_update(int acc_index, pj_bool_t renew)88 PJ_DECL(void) pjsua_regc_update(int acc_index, pj_bool_t renew) 88 89 { 89 90 pj_status_t status = 0; … … 130 131 pj_status_t pjsua_regc_init(int acc_index) 131 132 { 133 pjsua_acc_config *acc_config; 132 134 pj_status_t status; 133 135 134 if (pjsua.acc[acc_index].reg_uri.slen == 0) { 136 acc_config = &pjsua.config.acc_config[acc_index]; 137 138 if (acc_config->reg_uri.slen == 0) { 135 139 PJ_LOG(3,(THIS_FILE, "Registrar URI is not specified")); 136 140 return PJ_SUCCESS; … … 152 156 153 157 status = pjsip_regc_init( pjsua.acc[acc_index].regc, 154 & pjsua.acc[acc_index].reg_uri,155 & pjsua.acc[acc_index].local_uri,156 & pjsua.acc[acc_index].local_uri,157 1, & pjsua.acc[acc_index].contact_uri,158 pjsua.acc[acc_index].reg_timeout);158 &acc_config->reg_uri, 159 &acc_config->id, 160 &acc_config->id, 161 1, &acc_config->contact, 162 acc_config->reg_timeout); 159 163 if (status != PJ_SUCCESS) { 160 164 pjsua_perror(THIS_FILE, … … 164 168 } 165 169 166 pjsip_regc_set_credentials( pjsua.acc[acc_index].regc, 167 pjsua.cred_count, 168 pjsua.cred_info ); 170 if (acc_config->cred_count) { 171 pjsip_regc_set_credentials( pjsua.acc[acc_index].regc, 172 acc_config->cred_count, 173 acc_config->cred_info ); 174 } 169 175 170 176 pjsip_regc_set_route_set( pjsua.acc[acc_index].regc, -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_settings.c
r438 r476 60 60 puts (""); 61 61 puts ("SIP Account options:"); 62 puts (" --registrar=url Set the URL of registrar server"); 62 63 puts (" --id=url Set the URL of local ID (used in From header)"); 63 puts (" --contact=url O verride the Contact information");64 puts (" --proxy=url Set the URL of proxy server");65 puts (" ");66 puts (" SIP Account Registration Options:");67 puts (" -- registrar=url Set the URL of registrar server");68 puts (" --reg-timeout= secs Set registration interval to secs (default 3600)");64 puts (" --contact=url Optionally override the Contact information"); 65 puts (" --proxy=url Optional URL of proxy server to visit"); 66 puts (" --realm=string Set realm"); 67 puts (" --username=string Set authentication username"); 68 puts (" --password=string Set authentication password"); 69 puts (" --reg-timeout=SEC Optional registration interval (default 55)"); 69 70 puts (""); 70 71 puts ("SIP Account Control:"); 71 72 puts (" --next-account Add more account"); 72 puts ("");73 puts ("Authentication options:");74 puts (" --realm=string Set realm");75 puts (" --username=string Set authentication username");76 puts (" --password=string Set authentication password");77 puts (" --next-cred Add more credential");78 73 puts (""); 79 74 puts ("Transport Options:"); … … 87 82 puts (" --clock-rate=N Override sound device clock rate"); 88 83 puts (" --null-audio Use NULL audio device"); 89 puts (" --no-mic Disable microphone device");90 84 puts (" --play-file=file Play WAV file in conference bridge"); 91 85 puts (" --auto-play Automatically play the file (to incoming calls only)"); … … 114 108 * Verify that valid SIP url is given. 115 109 */ 116 pj_status_tpjsua_verify_sip_url(const char *c_url)110 PJ_DEF(pj_status_t) pjsua_verify_sip_url(const char *c_url) 117 111 { 118 112 pjsip_uri *p; … … 215 209 216 210 /* Parse arguments. */ 217 pj_status_t pjsua_parse_args(int argc, char *argv[]) 211 PJ_DEF(pj_status_t) pjsua_parse_args(int argc, char *argv[], 212 pjsua_config *cfg) 218 213 { 219 214 int c; 220 215 int option_index; 221 216 enum { OPT_CONFIG_FILE, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL, 222 OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO, OPT_NO_MIC,217 OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO, 223 218 OPT_LOCAL_PORT, OPT_PROXY, OPT_OUTBOUND_PROXY, OPT_REGISTRAR, 224 219 OPT_REG_TIMEOUT, OPT_ID, OPT_CONTACT, … … 230 225 OPT_PLAY_FILE, OPT_RTP_PORT, OPT_ADD_CODEC, 231 226 OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME, 232 OPT_NEXT_ACCOUNT, OPT_ NEXT_CRED, OPT_MAX_CALLS, OPT_UAS_REFRESH,227 OPT_NEXT_ACCOUNT, OPT_MAX_CALLS, OPT_UAS_REFRESH, 233 228 OPT_UAS_DURATION, 234 229 }; … … 242 237 { "clock-rate", 1, 0, OPT_CLOCK_RATE}, 243 238 { "null-audio", 0, 0, OPT_NULL_AUDIO}, 244 { "no-mic", 0, 0, OPT_NO_MIC},245 239 { "local-port", 1, 0, OPT_LOCAL_PORT}, 246 240 { "proxy", 1, 0, OPT_PROXY}, … … 270 264 { "ptime", 1, 0, OPT_PTIME}, 271 265 { "next-account",0,0, OPT_NEXT_ACCOUNT}, 272 { "next-cred", 0, 0, OPT_NEXT_CRED},273 266 { "max-calls", 1, 0, OPT_MAX_CALLS}, 274 267 { "uas-refresh",1, 0, OPT_UAS_REFRESH}, … … 277 270 }; 278 271 pj_status_t status; 279 pjsua_acc *cur_acc;280 pjsip_cred_info *cur_cred;272 pjsua_acc_config *cur_acc; 273 char errmsg[80]; 281 274 char *config_file = NULL; 275 unsigned i; 282 276 283 277 /* Run pj_getopt once to see if user specifies config file to read. */ 284 while ((c=pj_getopt_long(argc, argv, "", long_options, &option_index)) != -1) { 278 while ((c=pj_getopt_long(argc, argv, "", long_options, 279 &option_index)) != -1) 280 { 285 281 switch (c) { 286 282 case OPT_CONFIG_FILE: … … 298 294 } 299 295 300 301 cur_acc = &pjsua.acc[0]; 302 cur_cred = &pjsua.cred_info[0]; 296 cfg->acc_cnt = 0; 297 cur_acc = &cfg->acc_config[0]; 303 298 304 299 … … 307 302 */ 308 303 pj_optind = 0; 309 while((c=pj_getopt_long(argc, argv, "", long_options,&option_index))!=-1) {304 while((c=pj_getopt_long(argc,argv, "", long_options,&option_index))!=-1) { 310 305 char *p; 311 306 pj_str_t tmp; … … 315 310 316 311 case OPT_LOG_FILE: 317 pjsua.log_filename = pj_optarg;312 cfg->log_filename = pj_str(pj_optarg); 318 313 break; 319 314 … … 326 321 return PJ_EINVAL; 327 322 } 323 cfg->log_level = c; 328 324 pj_log_set_level( c ); 329 325 break; 330 326 331 327 case OPT_APP_LOG_LEVEL: 332 pjsua.app_log_level = pj_strtoul(pj_cstr(&tmp, pj_optarg));333 if ( pjsua.app_log_level < 0 || pjsua.app_log_level > 6) {328 cfg->app_log_level = pj_strtoul(pj_cstr(&tmp, pj_optarg)); 329 if (cfg->app_log_level < 0 || cfg->app_log_level > 6) { 334 330 PJ_LOG(1,(THIS_FILE, 335 331 "Error: expecting integer value 0-6 " … … 348 344 349 345 case OPT_NULL_AUDIO: 350 pjsua.null_audio = 1; 351 break; 352 353 case OPT_NO_MIC: 354 pjsua.no_mic = 1; 346 cfg->null_audio = 1; 355 347 break; 356 348 … … 362 354 return PJ_EINVAL; 363 355 } 364 pjsua.clock_rate = (int)lval;356 cfg->clock_rate = lval; 365 357 break; 366 358 … … 373 365 return PJ_EINVAL; 374 366 } 375 pjsua.sip_port = (pj_uint16_t)lval;367 cfg->udp_port = (pj_uint16_t)lval; 376 368 break; 377 369 … … 393 385 return PJ_EINVAL; 394 386 } 395 pjsua.outbound_proxy = pj_str(pj_optarg);387 cfg->outbound_proxy = pj_str(pj_optarg); 396 388 break; 397 389 … … 423 415 return PJ_EINVAL; 424 416 } 425 cur_acc->local_uri = pj_str(pj_optarg); 426 pjsua.has_acc = 1; 417 cur_acc->id = pj_str(pj_optarg); 427 418 break; 428 419 … … 434 425 return PJ_EINVAL; 435 426 } 436 cur_acc->contact _uri= pj_str(pj_optarg);427 cur_acc->contact = pj_str(pj_optarg); 437 428 break; 438 429 439 430 case OPT_NEXT_ACCOUNT: /* Add more account. */ 440 pjsua.acc_cnt++;441 cur_acc = & pjsua.acc[pjsua.acc_cnt - 1];431 cfg->acc_cnt++; 432 cur_acc = &cfg->acc_config[cfg->acc_cnt - 1]; 442 433 break; 443 434 444 435 case OPT_USERNAME: /* Default authentication user */ 445 if (pjsua.cred_count==0) pjsua.cred_count=1; 446 cur_cred->username = pj_str(pj_optarg); 436 cur_acc->cred_info[0].username = pj_str(pj_optarg); 447 437 break; 448 438 449 439 case OPT_REALM: /* Default authentication realm. */ 450 if (pjsua.cred_count==0) pjsua.cred_count=1; 451 cur_cred->realm = pj_str(pj_optarg); 440 cur_acc->cred_info[0].realm = pj_str(pj_optarg); 452 441 break; 453 442 454 443 case OPT_PASSWORD: /* authentication password */ 455 if (pjsua.cred_count==0) pjsua.cred_count=1; 456 cur_cred->data_type = 0; 457 cur_cred->data = pj_str(pj_optarg); 458 break; 459 460 case OPT_NEXT_CRED: /* Next credential */ 461 pjsua.cred_count++; 462 cur_cred = &pjsua.cred_info[pjsua.cred_count - 1]; 444 cur_acc->cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; 445 cur_acc->cred_info[0].data = pj_str(pj_optarg); 463 446 break; 464 447 … … 467 450 if (p) { 468 451 *p = '\0'; 469 pjsua.stun_srv1 = pj_str(pj_optarg);470 pjsua.stun_port1 = pj_strtoul(pj_cstr(&tmp, p+1));471 if ( pjsua.stun_port1 < 1 || pjsua.stun_port1 > 65535) {452 cfg->stun_srv1 = pj_str(pj_optarg); 453 cfg->stun_port1 = pj_strtoul(pj_cstr(&tmp, p+1)); 454 if (cfg->stun_port1 < 1 || cfg->stun_port1 > 65535) { 472 455 PJ_LOG(1,(THIS_FILE, 473 456 "Error: expecting port number with " … … 476 459 } 477 460 } else { 478 pjsua.stun_port1 = 3478;479 pjsua.stun_srv1 = pj_str(pj_optarg);461 cfg->stun_port1 = 3478; 462 cfg->stun_srv1 = pj_str(pj_optarg); 480 463 } 481 464 break; … … 485 468 if (p) { 486 469 *p = '\0'; 487 pjsua.stun_srv2 = pj_str(pj_optarg);488 pjsua.stun_port2 = pj_strtoul(pj_cstr(&tmp,p+1));489 if ( pjsua.stun_port2 < 1 || pjsua.stun_port2 > 65535) {470 cfg->stun_srv2 = pj_str(pj_optarg); 471 cfg->stun_port2 = pj_strtoul(pj_cstr(&tmp,p+1)); 472 if (cfg->stun_port2 < 1 || cfg->stun_port2 > 65535) { 490 473 PJ_LOG(1,(THIS_FILE, 491 474 "Error: expecting port number with " … … 494 477 } 495 478 } else { 496 pjsua.stun_port2 = 3478;497 pjsua.stun_srv2 = pj_str(pj_optarg);479 cfg->stun_port2 = 3478; 480 cfg->stun_srv2 = pj_str(pj_optarg); 498 481 } 499 482 break; … … 506 489 return -1; 507 490 } 508 if ( pjsua.buddy_cnt == PJSUA_MAX_BUDDIES) {491 if (cfg->buddy_cnt == PJSUA_MAX_BUDDIES) { 509 492 PJ_LOG(1,(THIS_FILE, 510 493 "Error: too many buddies in buddy list.")); 511 494 return -1; 512 495 } 513 pjsua.buddies[pjsua.buddy_cnt++].uri= pj_str(pj_optarg);496 cfg->buddy_uri[cfg->buddy_cnt++] = pj_str(pj_optarg); 514 497 break; 515 498 516 499 case OPT_AUTO_PLAY: 517 pjsua.auto_play = 1;500 cfg->auto_play = 1; 518 501 break; 519 502 520 503 case OPT_AUTO_LOOP: 521 pjsua.auto_loop = 1;504 cfg->auto_loop = 1; 522 505 break; 523 506 524 507 case OPT_AUTO_CONF: 525 pjsua.auto_conf = 1;508 cfg->auto_conf = 1; 526 509 break; 527 510 528 511 case OPT_PLAY_FILE: 529 pjsua.wav_file = pj_optarg;512 cfg->wav_file = pj_str(pj_optarg); 530 513 break; 531 514 532 515 case OPT_RTP_PORT: 533 pjsua.start_rtp_port = my_atoi(pj_optarg);534 if ( pjsua.start_rtp_port < 1 || pjsua.start_rtp_port > 65535) {516 cfg->start_rtp_port = my_atoi(pj_optarg); 517 if (cfg->start_rtp_port < 1 || cfg->start_rtp_port > 65535) { 535 518 PJ_LOG(1,(THIS_FILE, 536 519 "Error: rtp-port argument value " … … 541 524 542 525 case OPT_ADD_CODEC: 543 pjsua.codec_arg[pjsua.codec_cnt++] = pj_str(pj_optarg);526 cfg->codec_arg[cfg->codec_cnt++] = pj_str(pj_optarg); 544 527 break; 545 528 546 529 case OPT_COMPLEXITY: 547 pjsua.complexity = my_atoi(pj_optarg);548 if ( pjsua.complexity < 0 || pjsua.complexity > 10) {530 cfg->complexity = my_atoi(pj_optarg); 531 if (cfg->complexity < 0 || cfg->complexity > 10) { 549 532 PJ_LOG(1,(THIS_FILE, 550 533 "Error: invalid --complexity (expecting 0-10")); … … 554 537 555 538 case OPT_QUALITY: 556 pjsua.quality = my_atoi(pj_optarg);557 if ( pjsua.quality < 0 || pjsua.quality > 10) {539 cfg->quality = my_atoi(pj_optarg); 540 if (cfg->quality < 0 || cfg->quality > 10) { 558 541 PJ_LOG(1,(THIS_FILE, 559 542 "Error: invalid --quality (expecting 0-10")); … … 563 546 564 547 case OPT_PTIME: 565 pjsua.ptime = my_atoi(pj_optarg);566 if ( pjsua.ptime < 10 || pjsua.ptime > 1000) {548 cfg->ptime = my_atoi(pj_optarg); 549 if (cfg->ptime < 10 || cfg->ptime > 1000) { 567 550 PJ_LOG(1,(THIS_FILE, 568 551 "Error: invalid --ptime option")); … … 572 555 573 556 case OPT_AUTO_ANSWER: 574 pjsua.auto_answer = my_atoi(pj_optarg);575 if ( pjsua.auto_answer < 100 || pjsua.auto_answer > 699) {557 cfg->auto_answer = my_atoi(pj_optarg); 558 if (cfg->auto_answer < 100 || cfg->auto_answer > 699) { 576 559 PJ_LOG(1,(THIS_FILE, 577 560 "Error: invalid code in --auto-answer " … … 582 565 583 566 case OPT_MAX_CALLS: 584 pjsua.max_calls = my_atoi(pj_optarg);585 if ( pjsua.max_calls < 1 || pjsua.max_calls > 255) {567 cfg->max_calls = my_atoi(pj_optarg); 568 if (cfg->max_calls < 1 || cfg->max_calls > 255) { 586 569 PJ_LOG(1,(THIS_FILE,"Too many calls for max-calls (1-255)")); 587 570 return -1; … … 590 573 591 574 case OPT_UAS_REFRESH: 592 pjsua.uas_refresh = my_atoi(pj_optarg);593 if ( pjsua.uas_refresh < 1) {575 cfg->uas_refresh = my_atoi(pj_optarg); 576 if (cfg->uas_refresh < 1) { 594 577 PJ_LOG(1,(THIS_FILE, 595 578 "Invalid value for --uas-refresh (must be >0)")); … … 599 582 600 583 case OPT_UAS_DURATION: 601 pjsua.uas_duration = my_atoi(pj_optarg);602 if ( pjsua.uas_duration < 1) {584 cfg->uas_duration = my_atoi(pj_optarg); 585 if (cfg->uas_duration < 1) { 603 586 PJ_LOG(1,(THIS_FILE, 604 587 "Invalid value for --uas-duration " … … 611 594 612 595 if (pj_optind != argc) { 613 int i;614 596 615 597 if (pjsua_verify_sip_url(argv[pj_optind]) != PJ_SUCCESS) { … … 617 599 return -1; 618 600 } 619 pjsua.uri_to_call = pj_str(argv[pj_optind]);601 cfg->uri_to_call = pj_str(argv[pj_optind]); 620 602 pj_optind++; 621 603 622 604 /* Add URI to call to buddy list if it's not already there */ 623 for (i=0; i< pjsua.buddy_cnt; ++i) {624 if (pj_stricmp(& pjsua.buddies[i].uri, &pjsua.uri_to_call)==0)605 for (i=0; i<cfg->buddy_cnt; ++i) { 606 if (pj_stricmp(&cfg->buddy_uri[i], &cfg->uri_to_call)==0) 625 607 break; 626 608 } 627 if (i == pjsua.buddy_cnt && pjsua.buddy_cnt < PJSUA_MAX_BUDDIES) {628 pjsua.buddies[pjsua.buddy_cnt++].uri = pjsua.uri_to_call;609 if (i == cfg->buddy_cnt && cfg->buddy_cnt < PJSUA_MAX_BUDDIES) { 610 cfg->buddy_uri[cfg->buddy_cnt++] = cfg->uri_to_call; 629 611 } 630 612 } … … 633 615 PJ_LOG(1,(THIS_FILE, "Error: unknown options %s", argv[pj_optind])); 634 616 return PJ_EINVAL; 617 } 618 619 if (cfg->acc_config[0].id.slen && cfg->acc_cnt==0) 620 cfg->acc_cnt = 1; 621 622 for (i=0; i<cfg->acc_cnt; ++i) { 623 if (cfg->acc_config[i].cred_info[0].username.slen || 624 cfg->acc_config[i].cred_info[0].realm.slen) 625 { 626 cfg->acc_config[i].cred_count = 1; 627 cfg->acc_config[i].cred_info[0].scheme = pj_str("digest"); 628 } 629 } 630 631 if (pjsua_test_config(cfg, errmsg, sizeof(errmsg)) != PJ_SUCCESS) { 632 PJ_LOG(1,(THIS_FILE, "Error: %s", errmsg)); 633 return -1; 635 634 } 636 635 … … 832 831 * Dump application states. 833 832 */ 834 voidpjsua_dump(pj_bool_t detail)833 PJ_DEF(void) pjsua_dump(pj_bool_t detail) 835 834 { 836 835 char buf[128]; … … 859 858 860 859 } else { 861 inti;862 863 for (i=0; i<pjsua. max_calls; ++i) {860 unsigned i; 861 862 for (i=0; i<pjsua.config.max_calls; ++i) { 864 863 865 864 pjsua_call *call = &pjsua.calls[i]; … … 918 917 * Load settings. 919 918 */ 920 pj_status_t pjsua_load_settings(const char *filename) 919 PJ_DECL(pj_status_t) pjsua_load_settings(const char *filename, 920 pjsua_config *cfg) 921 921 { 922 922 int argc = 3; … … 924 924 925 925 argv[3] = (char*)filename; 926 return pjsua_parse_args(argc, argv );926 return pjsua_parse_args(argc, argv, cfg); 927 927 } 928 928 … … 934 934 { 935 935 char line[128]; 936 pjsua_acc *acc = &pjsua.acc[acc_index];936 pjsua_acc_config *acc_cfg = &pjsua.config.acc_config[acc_index]; 937 937 938 938 … … 942 942 943 943 /* Identity */ 944 if (acc ->local_uri.slen) {944 if (acc_cfg->id.slen) { 945 945 pj_ansi_sprintf(line, "--id %.*s\n", 946 (int)acc ->local_uri.slen,947 acc ->local_uri.ptr);946 (int)acc_cfg->id.slen, 947 acc_cfg->id.ptr); 948 948 pj_strcat2(result, line); 949 949 } 950 950 951 951 /* Registrar server */ 952 if (acc ->reg_uri.slen) {952 if (acc_cfg->reg_uri.slen) { 953 953 pj_ansi_sprintf(line, "--registrar %.*s\n", 954 (int)acc ->reg_uri.slen,955 acc ->reg_uri.ptr);954 (int)acc_cfg->reg_uri.slen, 955 acc_cfg->reg_uri.ptr); 956 956 pj_strcat2(result, line); 957 957 958 958 pj_ansi_sprintf(line, "--reg-timeout %u\n", 959 acc ->reg_timeout);959 acc_cfg->reg_timeout); 960 960 pj_strcat2(result, line); 961 961 } … … 963 963 964 964 /* Proxy */ 965 if (acc ->proxy.slen) {965 if (acc_cfg->proxy.slen) { 966 966 pj_ansi_sprintf(line, "--proxy %.*s\n", 967 (int)acc ->proxy.slen,968 acc ->proxy.ptr);967 (int)acc_cfg->proxy.slen, 968 acc_cfg->proxy.ptr); 969 969 pj_strcat2(result, line); 970 970 } 971 972 if (acc_cfg->cred_info[0].realm.slen) { 973 pj_ansi_sprintf(line, "--realm %.*s\n", 974 (int)acc_cfg->cred_info[0].realm.slen, 975 acc_cfg->cred_info[0].realm.ptr); 976 pj_strcat2(result, line); 977 } 978 979 if (acc_cfg->cred_info[0].username.slen) { 980 pj_ansi_sprintf(line, "--username %.*s\n", 981 (int)acc_cfg->cred_info[0].username.slen, 982 acc_cfg->cred_info[0].username.ptr); 983 pj_strcat2(result, line); 984 } 985 986 if (acc_cfg->cred_info[0].data.slen) { 987 pj_ansi_sprintf(line, "--password %.*s\n", 988 (int)acc_cfg->cred_info[0].data.slen, 989 acc_cfg->cred_info[0].data.ptr); 990 pj_strcat2(result, line); 991 } 992 971 993 } 972 994 … … 976 998 * Dump settings. 977 999 */ 978 int pjsua_dump_settings(char *buf, pj_size_t max) 979 { 980 int acc_index; 981 int i; 1000 PJ_DEF(int) pjsua_dump_settings(const pjsua_config *config, 1001 char *buf, pj_size_t max) 1002 { 1003 unsigned acc_index; 1004 unsigned i; 982 1005 pj_str_t cfg; 983 1006 char line[128]; … … 992 1015 pj_strcat2(&cfg, "#\n# Logging options:\n#\n"); 993 1016 pj_ansi_sprintf(line, "--log-level %d\n", 994 pjsua.log_level);1017 config->log_level); 995 1018 pj_strcat2(&cfg, line); 996 1019 997 1020 pj_ansi_sprintf(line, "--app-log-level %d\n", 998 pjsua.app_log_level);1021 config->app_log_level); 999 1022 pj_strcat2(&cfg, line); 1000 1023 1001 if ( pjsua.log_filename) {1024 if (config->log_filename.slen) { 1002 1025 pj_ansi_sprintf(line, "--log-file %s\n", 1003 pjsua.log_filename);1026 config->log_filename.ptr); 1004 1027 pj_strcat2(&cfg, line); 1005 1028 } … … 1007 1030 1008 1031 /* Save account settings. */ 1009 if (pjsua.has_acc) { 1010 for (acc_index=0; acc_index < pjsua.acc_cnt; ++acc_index) { 1011 1012 save_account_settings(acc_index, &cfg); 1013 1014 if (acc_index < pjsua.acc_cnt-1) 1015 pj_strcat2(&cfg, "--next-account\n"); 1016 } 1017 } 1018 1019 /* Credentials. */ 1020 for (i=0; i<pjsua.cred_count; ++i) { 1021 1022 pj_ansi_sprintf(line, "#\n# Credential %d:\n#\n", i); 1032 for (acc_index=0; acc_index < config->acc_cnt; ++acc_index) { 1033 1034 save_account_settings(acc_index, &cfg); 1035 1036 if (acc_index < config->acc_cnt-1) 1037 pj_strcat2(&cfg, "--next-account\n"); 1038 } 1039 1040 1041 pj_strcat2(&cfg, "#\n# Network settings:\n#\n"); 1042 1043 /* Outbound proxy */ 1044 if (config->outbound_proxy.slen) { 1045 pj_ansi_sprintf(line, "--outbound %.*s\n", 1046 (int)config->outbound_proxy.slen, 1047 config->outbound_proxy.ptr); 1023 1048 pj_strcat2(&cfg, line); 1024 1025 if (pjsua.cred_info[i].realm.slen) { 1026 pj_ansi_sprintf(line, "--realm %.*s\n", 1027 (int)pjsua.cred_info[i].realm.slen, 1028 pjsua.cred_info[i].realm.ptr); 1029 pj_strcat2(&cfg, line); 1030 } 1031 1032 pj_ansi_sprintf(line, "--username %.*s\n", 1033 (int)pjsua.cred_info[i].username.slen, 1034 pjsua.cred_info[i].username.ptr); 1049 } 1050 1051 1052 /* Transport. */ 1053 pj_ansi_sprintf(line, "--local-port %d\n", config->udp_port); 1054 pj_strcat2(&cfg, line); 1055 1056 1057 /* STUN */ 1058 if (config->stun_port1) { 1059 pj_ansi_sprintf(line, "--use-stun1 %.*s:%d\n", 1060 (int)config->stun_srv1.slen, 1061 config->stun_srv1.ptr, 1062 config->stun_port1); 1035 1063 pj_strcat2(&cfg, line); 1036 1037 pj_ansi_sprintf(line, "--password %.*s\n", 1038 (int)pjsua.cred_info[i].data.slen, 1039 pjsua.cred_info[i].data.ptr); 1064 } 1065 1066 if (config->stun_port2) { 1067 pj_ansi_sprintf(line, "--use-stun2 %.*s:%d\n", 1068 (int)config->stun_srv2.slen, 1069 config->stun_srv2.ptr, 1070 config->stun_port2); 1040 1071 pj_strcat2(&cfg, line); 1041 1042 if (i < pjsua.cred_count-1) 1043 pj_strcat2(&cfg, "--next-cred\n"); 1044 } 1045 1046 1047 pj_strcat2(&cfg, "#\n# Network settings:\n#\n"); 1048 1049 /* Outbound proxy */ 1050 if (pjsua.outbound_proxy.slen) { 1051 pj_ansi_sprintf(line, "--outbound %.*s\n", 1052 (int)pjsua.outbound_proxy.slen, 1053 pjsua.outbound_proxy.ptr); 1072 } 1073 1074 1075 pj_strcat2(&cfg, "#\n# Media settings:\n#\n"); 1076 1077 1078 /* Media */ 1079 if (config->null_audio) 1080 pj_strcat2(&cfg, "--null-audio\n"); 1081 if (config->auto_play) 1082 pj_strcat2(&cfg, "--auto-play\n"); 1083 if (config->auto_loop) 1084 pj_strcat2(&cfg, "--auto-loop\n"); 1085 if (config->auto_conf) 1086 pj_strcat2(&cfg, "--auto-conf\n"); 1087 if (config->wav_file.slen) { 1088 pj_ansi_sprintf(line, "--play-file %s\n", 1089 config->wav_file.ptr); 1054 1090 pj_strcat2(&cfg, line); 1055 1091 } 1056 1057 1058 /* Transport. */1059 pj_ansi_sprintf(line, "--local-port %d\n", pjsua.sip_port);1060 pj_strcat2(&cfg, line);1061 1062 1063 /* STUN */1064 if (pjsua.stun_port1) {1065 pj_ansi_sprintf(line, "--use-stun1 %.*s:%d\n",1066 (int)pjsua.stun_srv1.slen,1067 pjsua.stun_srv1.ptr,1068 pjsua.stun_port1);1069 pj_strcat2(&cfg, line);1070 }1071 1072 if (pjsua.stun_port2) {1073 pj_ansi_sprintf(line, "--use-stun2 %.*s:%d\n",1074 (int)pjsua.stun_srv2.slen,1075 pjsua.stun_srv2.ptr,1076 pjsua.stun_port2);1077 pj_strcat2(&cfg, line);1078 }1079 1080 1081 pj_strcat2(&cfg, "#\n# Media settings:\n#\n");1082 1083 1084 /* Media */1085 if (pjsua.null_audio)1086 pj_strcat2(&cfg, "--null-audio\n");1087 if (pjsua.auto_play)1088 pj_strcat2(&cfg, "--auto-play\n");1089 if (pjsua.auto_loop)1090 pj_strcat2(&cfg, "--auto-loop\n");1091 if (pjsua.auto_conf)1092 pj_strcat2(&cfg, "--auto-conf\n");1093 if (pjsua.wav_file) {1094 pj_ansi_sprintf(line, "--play-file %s\n",1095 pjsua.wav_file);1096 pj_strcat2(&cfg, line);1097 }1098 1092 /* Media clock rate. */ 1099 if ( pjsua.clock_rate) {1093 if (config->clock_rate) { 1100 1094 pj_ansi_sprintf(line, "--clock-rate %d\n", 1101 pjsua.clock_rate);1095 config->clock_rate); 1102 1096 pj_strcat2(&cfg, line); 1103 1097 } … … 1106 1100 /* Encoding quality and complexity */ 1107 1101 pj_ansi_sprintf(line, "--quality %d\n", 1108 pjsua.quality);1102 config->quality); 1109 1103 pj_strcat2(&cfg, line); 1110 1104 pj_ansi_sprintf(line, "--complexity %d\n", 1111 pjsua.complexity);1105 config->complexity); 1112 1106 pj_strcat2(&cfg, line); 1113 1107 1114 1108 /* ptime */ 1115 if ( pjsua.ptime) {1109 if (config->ptime) { 1116 1110 pj_ansi_sprintf(line, "--ptime %d\n", 1117 pjsua.ptime);1111 config->ptime); 1118 1112 pj_strcat2(&cfg, line); 1119 1113 } … … 1121 1115 /* Start RTP port. */ 1122 1116 pj_ansi_sprintf(line, "--rtp-port %d\n", 1123 pjsua.start_rtp_port);1117 config->start_rtp_port); 1124 1118 pj_strcat2(&cfg, line); 1125 1119 1126 1120 /* Add codec. */ 1127 for (i=0; i< pjsua.codec_cnt; ++i) {1121 for (i=0; i<config->codec_cnt; ++i) { 1128 1122 pj_ansi_sprintf(line, "--add-codec %s\n", 1129 pjsua.codec_arg[i].ptr);1123 config->codec_arg[i].ptr); 1130 1124 pj_strcat2(&cfg, line); 1131 1125 } … … 1134 1128 1135 1129 /* Auto-answer. */ 1136 if ( pjsua.auto_answer != 0) {1130 if (config->auto_answer != 0) { 1137 1131 pj_ansi_sprintf(line, "--auto-answer %d\n", 1138 pjsua.auto_answer);1132 config->auto_answer); 1139 1133 pj_strcat2(&cfg, line); 1140 1134 } … … 1142 1136 /* Max calls. */ 1143 1137 pj_ansi_sprintf(line, "--max-calls %d\n", 1144 pjsua.max_calls);1138 config->max_calls); 1145 1139 pj_strcat2(&cfg, line); 1146 1140 1147 1141 /* Uas-refresh. */ 1148 if ( pjsua.uas_refresh > 0) {1142 if (config->uas_refresh > 0) { 1149 1143 pj_ansi_sprintf(line, "--uas-refresh %d\n", 1150 pjsua.uas_refresh);1144 config->uas_refresh); 1151 1145 pj_strcat2(&cfg, line); 1152 1146 } 1153 1147 1154 1148 /* Uas-duration. */ 1155 if ( pjsua.uas_duration > 0) {1149 if (config->uas_duration > 0) { 1156 1150 pj_ansi_sprintf(line, "--uas-duration %d\n", 1157 pjsua.uas_duration);1151 config->uas_duration); 1158 1152 pj_strcat2(&cfg, line); 1159 1153 } … … 1162 1156 1163 1157 /* Add buddies. */ 1164 for (i=0; i< pjsua.buddy_cnt; ++i) {1158 for (i=0; i<config->buddy_cnt; ++i) { 1165 1159 pj_ansi_sprintf(line, "--add-buddy %.*s\n", 1166 (int) pjsua.buddies[i].uri.slen,1167 pjsua.buddies[i].uri.ptr);1160 (int)config->buddy_uri[i].slen, 1161 config->buddy_uri[i].ptr); 1168 1162 pj_strcat2(&cfg, line); 1169 1163 } … … 1177 1171 * Save settings. 1178 1172 */ 1179 pj_status_t pjsua_save_settings(const char *filename) 1173 PJ_DEF(pj_status_t) pjsua_save_settings(const char *filename, 1174 const pjsua_config *config) 1180 1175 { 1181 1176 pj_str_t cfg; … … 1196 1191 1197 1192 1198 cfg.slen = pjsua_dump_settings(c fg.ptr, 3800);1193 cfg.slen = pjsua_dump_settings(config, cfg.ptr, 3800); 1199 1194 if (cfg.slen < 1) { 1200 1195 pj_pool_release(pool);
Note: See TracChangeset
for help on using the changeset viewer.