Ignore:
Timestamp:
Jul 19, 2011 3:42:28 AM (13 years ago)
Author:
nanang
Message:

Re #1326: Initial code integration from branch 2.0-dev to trunk as "2.0-pre-alpha-svn".

Location:
pjproject/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk

  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c

    r3553 r3664  
    125125    pjmedia_port           *ring_port; 
    126126 
     127    int                     vcapture_dev, vrender_dev; 
    127128} app_config; 
    128129 
     
    137138static pj_str_t         uri_arg; 
    138139 
    139 static char some_buf[1024 * 3]; 
     140#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     141#   define SOME_BUF_SIZE        (1024 * 10) 
     142#else 
     143#   define SOME_BUF_SIZE        (1024 * 3) 
     144#endif 
     145 
     146static char some_buf[SOME_BUF_SIZE]; 
    140147 
    141148#ifdef STEREO_DEMO 
     
    195202    puts  ("  --no-color          Disable colorful logging"); 
    196203    puts  ("  --light-bg          Use dark colors for light background (default is dark bg)"); 
     204    puts  ("  --no-stderr         Disable stderr"); 
    197205 
    198206    puts  (""); 
     
    268276 
    269277    puts  (""); 
    270     puts  ("Media Options:"); 
     278    puts  ("Audio Options:"); 
    271279    puts  ("  --add-codec=name    Manually add codec (default is to enable all)"); 
    272280    puts  ("  --dis-codec=name    Disable codec (can be specified multiple times)"); 
     
    302310    puts  ("  --no-tones          Disable audible tones"); 
    303311    puts  ("  --jb-max-size       Specify jitter buffer maximum size, in frames (default=-1)"); 
     312    puts  ("  --extra-audio       Add one more audio stream"); 
     313 
     314#if PJSUA_HAS_VIDEO 
     315    puts  (""); 
     316    puts  ("Video Options:"); 
     317    puts  ("  --video             Enable video"); 
     318    puts  ("  --vcapture-dev=id   Video capture device ID (default=-1)"); 
     319    puts  ("  --vrender-dev=id    Video render device ID (default=-1)"); 
     320#endif 
    304321 
    305322    puts  (""); 
     
    377394    for (i=0; i<PJ_ARRAY_SIZE(cfg->buddy_cfg); ++i) 
    378395        pjsua_buddy_config_default(&cfg->buddy_cfg[i]); 
     396 
     397    cfg->vcapture_dev = PJSUA_INVALID_ID; 
     398    cfg->vrender_dev = PJSUA_INVALID_ID; 
    379399} 
    380400 
     
    510530    int option_index; 
    511531    enum { OPT_CONFIG_FILE=127, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL,  
    512            OPT_LOG_APPEND, OPT_COLOR, OPT_NO_COLOR, OPT_LIGHT_BG, 
     532           OPT_LOG_APPEND, OPT_COLOR, OPT_NO_COLOR, OPT_LIGHT_BG, OPT_NO_STDERR, 
    513533           OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO, OPT_SND_AUTO_CLOSE, 
    514534           OPT_LOCAL_PORT, OPT_IP_ADDR, OPT_PROXY, OPT_OUTBOUND_PROXY,  
     
    542562           OPT_AUTO_UPDATE_NAT,OPT_USE_COMPACT_FORM,OPT_DIS_CODEC, 
    543563           OPT_NO_FORCE_LR, 
    544            OPT_TIMER, OPT_TIMER_SE, OPT_TIMER_MIN_SE 
     564           OPT_TIMER, OPT_TIMER_SE, OPT_TIMER_MIN_SE, 
     565           OPT_VIDEO, OPT_EXTRA_AUDIO, 
     566           OPT_VCAPTURE_DEV, OPT_VRENDER_DEV, 
    545567    }; 
    546568    struct pj_getopt_option long_options[] = { 
     
    553575        { "no-color",   0, 0, OPT_NO_COLOR}, 
    554576        { "light-bg",           0, 0, OPT_LIGHT_BG}, 
     577        { "no-stderr",  0, 0, OPT_NO_STDERR}, 
    555578        { "help",       0, 0, OPT_HELP}, 
    556579        { "version",    0, 0, OPT_VERSION}, 
     
    661684        { "timer-min-se", 1, 0, OPT_TIMER_MIN_SE}, 
    662685        { "outb-rid",   1, 0, OPT_OUTB_RID}, 
     686        { "video",      0, 0, OPT_VIDEO}, 
     687        { "extra-audio",0, 0, OPT_EXTRA_AUDIO}, 
     688        { "vcapture-dev", 1, 0, OPT_VCAPTURE_DEV}, 
     689        { "vrender-dev",  1, 0, OPT_VRENDER_DEV}, 
    663690        { NULL, 0, 0, 0} 
    664691    }; 
     
    751778            pj_log_set_color(5, 0); 
    752779            pj_log_set_color(77, 0); 
     780            break; 
     781 
     782        case OPT_NO_STDERR: 
     783            freopen("/dev/null", "w", stderr); 
    753784            break; 
    754785 
     
    14181449            cfg->udp_cfg.qos_params.dscp_val = 0x18; 
    14191450            break; 
     1451        case OPT_VIDEO: 
     1452            ++cur_acc->max_video_cnt; 
     1453            cur_acc->vid_in_auto_show = PJ_TRUE; 
     1454            cur_acc->vid_out_auto_transmit = PJ_TRUE; 
     1455            PJ_TODO(implement_pjsua_option_for_vid_auto_show_and_transmit); 
     1456            break; 
     1457        case OPT_EXTRA_AUDIO: 
     1458            ++cur_acc->max_audio_cnt; 
     1459            break; 
     1460 
     1461        case OPT_VCAPTURE_DEV: 
     1462            cfg->vcapture_dev = atoi(pj_optarg); 
     1463            cur_acc->vid_cap_dev = cfg->vcapture_dev; 
     1464            break; 
     1465 
     1466        case OPT_VRENDER_DEV: 
     1467            cfg->vrender_dev = atoi(pj_optarg); 
     1468            cur_acc->vid_rend_dev = cfg->vrender_dev; 
     1469            break; 
     1470 
    14201471        default: 
    14211472            PJ_LOG(1,(THIS_FILE,  
     
    16621713    if (acc_cfg->mwi_enabled) 
    16631714        pj_strcat2(result, "--mwi\n"); 
     1715 
     1716    /* Video & extra audio */ 
     1717    for (i=0; i<acc_cfg->max_video_cnt; ++i) { 
     1718        pj_strcat2(result, "--video\n"); 
     1719    } 
     1720    for (i=1; i<acc_cfg->max_audio_cnt; ++i) { 
     1721        pj_strcat2(result, "--extra-audio\n"); 
     1722    } 
    16641723} 
    16651724 
     
    19862045    } 
    19872046 
     2047    if (config->vcapture_dev != PJSUA_INVALID_ID) { 
     2048        pj_ansi_sprintf(line, "--vcapture-dev %d\n", config->vcapture_dev); 
     2049        pj_strcat2(&cfg, line); 
     2050    } 
     2051    if (config->vrender_dev != PJSUA_INVALID_ID) { 
     2052        pj_ansi_sprintf(line, "--vrender-dev %d\n", config->vrender_dev); 
     2053        pj_strcat2(&cfg, line); 
     2054    } 
    19882055 
    19892056    /* ptime */ 
     
    25852652} 
    25862653 
     2654/* General processing for media state. "mi" is the media index */ 
     2655static void on_call_generic_media_state(pjsua_call_info *ci, unsigned mi, 
     2656                                         pj_bool_t *has_error) 
     2657{ 
     2658    const char *status_name[] = { 
     2659        "None", 
     2660        "Active", 
     2661        "Local hold", 
     2662        "Remote hold", 
     2663        "Error" 
     2664    }; 
     2665 
     2666    pj_assert(ci->media[mi].status <= PJ_ARRAY_SIZE(status_name)); 
     2667    pj_assert(PJSUA_CALL_MEDIA_ERROR == 4); 
     2668 
     2669    PJ_LOG(4,(THIS_FILE, "Call %d media %d [type=%s], status is %s", 
     2670              ci->id, mi, pjmedia_type_name(ci->media[mi].type), 
     2671              status_name[ci->media[mi].status])); 
     2672} 
     2673 
     2674/* Process audio media state. "mi" is the media index. */ 
     2675static void on_call_audio_state(pjsua_call_info *ci, unsigned mi, 
     2676                                pj_bool_t *has_error) 
     2677{ 
     2678    /* Stop ringback */ 
     2679    ring_stop(ci->id); 
     2680 
     2681    /* Connect ports appropriately when media status is ACTIVE or REMOTE HOLD, 
     2682     * otherwise we should NOT connect the ports. 
     2683     */ 
     2684    if (ci->media[mi].status == PJSUA_CALL_MEDIA_ACTIVE || 
     2685        ci->media[mi].status == PJSUA_CALL_MEDIA_REMOTE_HOLD) 
     2686    { 
     2687        pj_bool_t connect_sound = PJ_TRUE; 
     2688        pjsua_conf_port_id call_conf_slot; 
     2689 
     2690        call_conf_slot = ci->media[mi].stream.aud.conf_slot; 
     2691 
     2692        /* Loopback sound, if desired */ 
     2693        if (app_config.auto_loop) { 
     2694            pjsua_conf_connect(call_conf_slot, call_conf_slot); 
     2695            connect_sound = PJ_FALSE; 
     2696        } 
     2697 
     2698        /* Automatically record conversation, if desired */ 
     2699        if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) { 
     2700            pjsua_conf_connect(call_conf_slot, app_config.rec_port); 
     2701        } 
     2702 
     2703        /* Stream a file, if desired */ 
     2704        if ((app_config.auto_play || app_config.auto_play_hangup) &&  
     2705            app_config.wav_port != PJSUA_INVALID_ID) 
     2706        { 
     2707            pjsua_conf_connect(app_config.wav_port, call_conf_slot); 
     2708            connect_sound = PJ_FALSE; 
     2709        } 
     2710 
     2711        /* Put call in conference with other calls, if desired */ 
     2712        if (app_config.auto_conf) { 
     2713            pjsua_call_id call_ids[PJSUA_MAX_CALLS]; 
     2714            unsigned call_cnt=PJ_ARRAY_SIZE(call_ids); 
     2715            unsigned i; 
     2716 
     2717            /* Get all calls, and establish media connection between 
     2718             * this call and other calls. 
     2719             */ 
     2720            pjsua_enum_calls(call_ids, &call_cnt); 
     2721 
     2722            for (i=0; i<call_cnt; ++i) { 
     2723                if (call_ids[i] == ci->id) 
     2724                    continue; 
     2725                 
     2726                if (!pjsua_call_has_media(call_ids[i])) 
     2727                    continue; 
     2728 
     2729                pjsua_conf_connect(call_conf_slot, 
     2730                                   pjsua_call_get_conf_port(call_ids[i])); 
     2731                pjsua_conf_connect(pjsua_call_get_conf_port(call_ids[i]), 
     2732                                   call_conf_slot); 
     2733 
     2734                /* Automatically record conversation, if desired */ 
     2735                if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) { 
     2736                    pjsua_conf_connect(pjsua_call_get_conf_port(call_ids[i]),  
     2737                                       app_config.rec_port); 
     2738                } 
     2739 
     2740            } 
     2741 
     2742            /* Also connect call to local sound device */ 
     2743            connect_sound = PJ_TRUE; 
     2744        } 
     2745 
     2746        /* Otherwise connect to sound device */ 
     2747        if (connect_sound) { 
     2748            pjsua_conf_connect(call_conf_slot, 0); 
     2749            pjsua_conf_connect(0, call_conf_slot); 
     2750 
     2751            /* Automatically record conversation, if desired */ 
     2752            if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) { 
     2753                pjsua_conf_connect(call_conf_slot, app_config.rec_port); 
     2754                pjsua_conf_connect(0, app_config.rec_port); 
     2755            } 
     2756        } 
     2757    } 
     2758} 
     2759 
     2760/* Process video media state. "mi" is the media index. */ 
     2761static void on_call_video_state(pjsua_call_info *ci, unsigned mi, 
     2762                                pj_bool_t *has_error) 
     2763{ 
     2764} 
    25872765 
    25882766/* 
     
    25942772{ 
    25952773    pjsua_call_info call_info; 
     2774    unsigned mi; 
     2775    pj_bool_t has_error = PJ_FALSE; 
    25962776 
    25972777    pjsua_call_get_info(call_id, &call_info); 
    25982778 
    2599     /* Stop ringback */ 
    2600     ring_stop(call_id); 
    2601  
    2602     /* Connect ports appropriately when media status is ACTIVE or REMOTE HOLD, 
    2603      * otherwise we should NOT connect the ports. 
    2604      */ 
    2605     if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE || 
    2606         call_info.media_status == PJSUA_CALL_MEDIA_REMOTE_HOLD) 
    2607     { 
    2608         pj_bool_t connect_sound = PJ_TRUE; 
    2609  
    2610         /* Loopback sound, if desired */ 
    2611         if (app_config.auto_loop) { 
    2612             pjsua_conf_connect(call_info.conf_slot, call_info.conf_slot); 
    2613             connect_sound = PJ_FALSE; 
     2779    for (mi=0; mi<call_info.media_cnt; ++mi) { 
     2780        on_call_generic_media_state(&call_info, mi, &has_error); 
     2781 
     2782        switch (call_info.media[mi].type) { 
     2783        case PJMEDIA_TYPE_AUDIO: 
     2784            on_call_audio_state(&call_info, mi, &has_error); 
     2785            break; 
     2786        case PJMEDIA_TYPE_VIDEO: 
     2787            on_call_video_state(&call_info, mi, &has_error); 
     2788            break; 
    26142789        } 
    2615  
    2616         /* Automatically record conversation, if desired */ 
    2617         if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) { 
    2618             pjsua_conf_connect(call_info.conf_slot, app_config.rec_port); 
    2619         } 
    2620  
    2621         /* Stream a file, if desired */ 
    2622         if ((app_config.auto_play || app_config.auto_play_hangup) &&  
    2623             app_config.wav_port != PJSUA_INVALID_ID) 
    2624         { 
    2625             pjsua_conf_connect(app_config.wav_port, call_info.conf_slot); 
    2626             connect_sound = PJ_FALSE; 
    2627         } 
    2628  
    2629         /* Put call in conference with other calls, if desired */ 
    2630         if (app_config.auto_conf) { 
    2631             pjsua_call_id call_ids[PJSUA_MAX_CALLS]; 
    2632             unsigned call_cnt=PJ_ARRAY_SIZE(call_ids); 
    2633             unsigned i; 
    2634  
    2635             /* Get all calls, and establish media connection between 
    2636              * this call and other calls. 
    2637              */ 
    2638             pjsua_enum_calls(call_ids, &call_cnt); 
    2639  
    2640             for (i=0; i<call_cnt; ++i) { 
    2641                 if (call_ids[i] == call_id) 
    2642                     continue; 
    2643                  
    2644                 if (!pjsua_call_has_media(call_ids[i])) 
    2645                     continue; 
    2646  
    2647                 pjsua_conf_connect(call_info.conf_slot, 
    2648                                    pjsua_call_get_conf_port(call_ids[i])); 
    2649                 pjsua_conf_connect(pjsua_call_get_conf_port(call_ids[i]), 
    2650                                    call_info.conf_slot); 
    2651  
    2652                 /* Automatically record conversation, if desired */ 
    2653                 if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) { 
    2654                     pjsua_conf_connect(pjsua_call_get_conf_port(call_ids[i]),  
    2655                                        app_config.rec_port); 
    2656                 } 
    2657  
    2658             } 
    2659  
    2660             /* Also connect call to local sound device */ 
    2661             connect_sound = PJ_TRUE; 
    2662         } 
    2663  
    2664         /* Otherwise connect to sound device */ 
    2665         if (connect_sound) { 
    2666             pjsua_conf_connect(call_info.conf_slot, 0); 
    2667             pjsua_conf_connect(0, call_info.conf_slot); 
    2668  
    2669             /* Automatically record conversation, if desired */ 
    2670             if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) { 
    2671                 pjsua_conf_connect(call_info.conf_slot, app_config.rec_port); 
    2672                 pjsua_conf_connect(0, app_config.rec_port); 
    2673             } 
    2674         } 
    2675     } 
    2676  
    2677     /* Handle media status */ 
    2678     switch (call_info.media_status) { 
    2679     case PJSUA_CALL_MEDIA_ACTIVE: 
    2680         PJ_LOG(3,(THIS_FILE, "Media for call %d is active", call_id)); 
    2681         break; 
    2682  
    2683     case PJSUA_CALL_MEDIA_LOCAL_HOLD: 
    2684         PJ_LOG(3,(THIS_FILE, "Media for call %d is suspended (hold) by local", 
    2685                   call_id)); 
    2686         break; 
    2687  
    2688     case PJSUA_CALL_MEDIA_REMOTE_HOLD: 
    2689         PJ_LOG(3,(THIS_FILE,  
    2690                   "Media for call %d is suspended (hold) by remote", 
    2691                   call_id)); 
    2692         break; 
    2693  
    2694     case PJSUA_CALL_MEDIA_ERROR: 
    2695         PJ_LOG(3,(THIS_FILE, 
    2696                   "Media has reported error, disconnecting call")); 
    2697         { 
    2698             pj_str_t reason = pj_str("ICE negotiation failed"); 
    2699             pjsua_call_hangup(call_id, 500, &reason, NULL); 
    2700         } 
    2701         break; 
    2702  
    2703     case PJSUA_CALL_MEDIA_NONE: 
    2704         PJ_LOG(3,(THIS_FILE,  
    2705                   "Media for call %d is inactive", 
    2706                   call_id)); 
    2707         break; 
    2708  
    2709     default: 
    2710         pj_assert(!"Unhandled media status"); 
    2711         break; 
     2790    } 
     2791 
     2792    if (has_error) { 
     2793        pj_str_t reason = pj_str("Media failed"); 
     2794        pjsua_call_hangup(call_id, 500, &reason, NULL); 
    27122795    } 
    27132796} 
     
    30503133    PJ_PERROR(1,(THIS_FILE, status, 
    30513134                 "ICE keep alive failure for transport %d", index)); 
     3135} 
     3136 
     3137/* 
     3138 * Notification on sound device operation. 
     3139 */ 
     3140static pj_status_t on_snd_dev_operation(int operation) 
     3141{ 
     3142    PJ_LOG(3,(THIS_FILE, "Turning sound device %s", (operation? "ON":"OFF"))); 
     3143    return PJ_SUCCESS; 
     3144} 
     3145 
     3146/* Callback on media events */ 
     3147static void on_call_media_event(pjsua_call_id call_id, 
     3148                                unsigned med_idx, 
     3149                                pjmedia_event *event) 
     3150{ 
     3151    char event_name[5]; 
     3152    PJ_LOG(4,(THIS_FILE, "Event %s", 
     3153              pjmedia_fourcc_name(event->type, event_name))); 
    30523154} 
    30533155 
     
    31943296    puts("| dq  Dump curr. call quality  | cd  Disconnect port      | dc  Dump config   |"); 
    31953297    puts("|                              |  V  Adjust audio Volume  |  f  Save config   |"); 
    3196     puts("|  S  Send arbitrary REQUEST   | Cp  Codec priorities     |  f  Save config   |"); 
    3197     puts("+------------------------------+--------------------------+-------------------+"); 
     3298    puts("|  S  Send arbitrary REQUEST   | Cp  Codec priorities     |                   |"); 
     3299    puts("+-----------------------------------------------------------------------------+"); 
     3300#if PJSUA_HAS_VIDEO 
     3301    puts("| Video: \"vid help\" for more info                                             |"); 
     3302    puts("+-----------------------------------------------------------------------------+"); 
     3303#endif 
    31983304    puts("|  q  QUIT   L  ReLoad   sleep MS   echo [0|1|txt]     n: detect NAT type     |"); 
    31993305    puts("+=============================================================================+"); 
     
    32113317} 
    32123318 
     3319/* Help screen for video */ 
     3320static void vid_show_help(void) 
     3321{ 
     3322#if PJSUA_HAS_VIDEO 
     3323    puts("+=============================================================================+"); 
     3324    puts("|                            Video commands:                                  |"); 
     3325    puts("|                                                                             |"); 
     3326    puts("| vid help                  Show this help screen                             |"); 
     3327    puts("| vid call rx on|off N      Enable/disable video rx for stream N in curr call |"); 
     3328    puts("| vid call tx on|off N      Enable/disable video tx for stream N in curr call |"); 
     3329    puts("| vid call add              Add video stream for current call                 |"); 
     3330    puts("| vid call enable/disable N Enable/disable stream #N in current call          |"); 
     3331    puts("| vid call set-cap N ID     Set capture dev ID for stream #N in current call  |"); 
     3332    puts("| vid dev list              List all video devices                            |"); 
     3333    puts("| vid dev refresh           Refresh video device list                         |"); 
     3334    puts("| vid dev prev on|off ID    Enable/disable preview for specified device ID    |"); 
     3335    puts("| vid codec list            List video codecs                                 |"); 
     3336    puts("| vid codec prio PT PRIO    Set codec with pt PT priority to PRIO             |"); 
     3337    puts("| vid win list              List all active video windows                     |"); 
     3338    puts("| vid win show|hide ID      Show/hide the specified video window ID           |"); 
     3339    puts("| vid win move ID X Y       Move window ID to position X,Y                    |"); 
     3340    puts("| vid win resize ID w h     Resize window ID to the specified width, height   |"); 
     3341    puts("+=============================================================================+"); 
     3342#endif 
     3343} 
    32133344 
    32143345/* 
     
    34823613    pj_status_t status; 
    34833614 
    3484     printf("List of codecs:\n"); 
    3485  
     3615    printf("List of audio codecs:\n"); 
    34863616    pjsua_enum_codecs(c, &count); 
    34873617    for (i=0; i<count; ++i) { 
     
    34903620    } 
    34913621 
     3622#if PJSUA_HAS_VIDEO 
    34923623    puts(""); 
    3493     puts("Enter codec id and its new priority " 
    3494          "(e.g. \"speex/16000 200\"), empty to cancel:"); 
     3624    printf("List of video codecs:\n"); 
     3625    pjsua_vid_enum_codecs(c, &count); 
     3626    for (i=0; i<count; ++i) { 
     3627        printf("  %d\t%.*s%s%.*s\n", c[i].priority, 
     3628                                     (int)c[i].codec_id.slen, 
     3629                                     c[i].codec_id.ptr, 
     3630                                     c[i].desc.slen? " - ":"", 
     3631                                     (int)c[i].desc.slen, 
     3632                                     c[i].desc.ptr); 
     3633    } 
     3634#endif 
     3635 
     3636    puts(""); 
     3637    puts("Enter codec id and its new priority (e.g. \"speex/16000 200\", ""\"H263 200\"),"); 
     3638    puts("or empty to cancel."); 
    34953639 
    34963640    printf("Codec name (\"*\" for all) and priority: "); 
     
    35183662    status = pjsua_codec_set_priority(pj_cstr(&id, codec),  
    35193663                                      (pj_uint8_t)new_prio); 
     3664#if PJSUA_HAS_VIDEO 
     3665    if (status != PJ_SUCCESS) { 
     3666        status = pjsua_vid_codec_set_priority(pj_cstr(&id, codec),  
     3667                                              (pj_uint8_t)new_prio); 
     3668    } 
     3669#endif 
    35203670    if (status != PJ_SUCCESS) 
    35213671        pjsua_perror(THIS_FILE, "Error setting codec priority", status); 
    35223672} 
     3673 
     3674 
     3675#if PJSUA_HAS_VIDEO 
     3676static void vid_print_dev(int id, const pjmedia_vid_dev_info *vdi, 
     3677                          const char *title) 
     3678{ 
     3679    char capnames[120]; 
     3680    char formats[120]; 
     3681    const char *dirname; 
     3682    unsigned i; 
     3683 
     3684    if (vdi->dir == PJMEDIA_DIR_CAPTURE_RENDER) { 
     3685        dirname = "capture, render"; 
     3686    } else if (vdi->dir == PJMEDIA_DIR_CAPTURE) { 
     3687        dirname = "capture"; 
     3688    } else { 
     3689        dirname = "render"; 
     3690    } 
     3691 
     3692 
     3693    capnames[0] = '\0'; 
     3694    for (i=0; i<sizeof(int)*8 && (1 << i) < PJMEDIA_VID_DEV_CAP_MAX; ++i) { 
     3695        if (vdi->caps & (1 << i)) { 
     3696            const char *capname = pjmedia_vid_dev_cap_name(1 << i, NULL); 
     3697            if (capname) { 
     3698                if (*capnames) 
     3699                    strcat(capnames, ", "); 
     3700                strncat(capnames, capname, 
     3701                        sizeof(capnames)-strlen(capnames)-1); 
     3702            } 
     3703        } 
     3704    } 
     3705 
     3706    formats[0] = '\0'; 
     3707    for (i=0; i<vdi->fmt_cnt; ++i) { 
     3708        const pjmedia_video_format_info *vfi = 
     3709                pjmedia_get_video_format_info(NULL, vdi->fmt[i].id); 
     3710        if (vfi) { 
     3711            if (*formats) 
     3712                strcat(formats, ", "); 
     3713            strncat(formats, vfi->name, sizeof(formats)-strlen(formats)-1); 
     3714        } 
     3715    } 
     3716 
     3717    PJ_LOG(3,(THIS_FILE, "%3d %s [%s][%s] %s", id, vdi->name, vdi->driver, 
     3718              dirname, title)); 
     3719    PJ_LOG(3,(THIS_FILE, "    Supported capabilities: %s", capnames)); 
     3720    PJ_LOG(3,(THIS_FILE, "    Supported formats: %s", formats)); 
     3721} 
     3722 
     3723static void vid_list_devs(void) 
     3724{ 
     3725    unsigned i, count; 
     3726    pjmedia_vid_dev_info vdi; 
     3727    pj_status_t status; 
     3728 
     3729    PJ_LOG(3,(THIS_FILE, "Video device list:")); 
     3730    count = pjsua_vid_dev_count(); 
     3731    if (count == 0) { 
     3732        PJ_LOG(3,(THIS_FILE, " - no device detected -")); 
     3733        return; 
     3734    } else { 
     3735        PJ_LOG(3,(THIS_FILE, "%d device(s) detected:", count)); 
     3736    } 
     3737 
     3738    status = pjsua_vid_dev_get_info(PJMEDIA_VID_DEFAULT_RENDER_DEV, &vdi); 
     3739    if (status == PJ_SUCCESS) 
     3740        vid_print_dev(PJMEDIA_VID_DEFAULT_RENDER_DEV, &vdi, 
     3741                      "(default renderer device)"); 
     3742 
     3743    status = pjsua_vid_dev_get_info(PJMEDIA_VID_DEFAULT_CAPTURE_DEV, &vdi); 
     3744    if (status == PJ_SUCCESS) 
     3745        vid_print_dev(PJMEDIA_VID_DEFAULT_CAPTURE_DEV, &vdi, 
     3746                      "(default capture device)"); 
     3747 
     3748    for (i=0; i<count; ++i) { 
     3749        status = pjsua_vid_dev_get_info(i, &vdi); 
     3750        if (status == PJ_SUCCESS) 
     3751            vid_print_dev(i, &vdi, ""); 
     3752    } 
     3753} 
     3754 
     3755static void vid_handle_menu(char *menuin) 
     3756{ 
     3757    char *argv[8]; 
     3758    int argc = 0; 
     3759 
     3760    /* Tokenize */ 
     3761    argv[argc] = strtok(menuin, " \t\r\n"); 
     3762    while (argv[argc] && *argv[argc]) { 
     3763        argc++; 
     3764        argv[argc] = strtok(NULL, " \t\r\n"); 
     3765    } 
     3766 
     3767    if (strcmp(argv[1], "help")==0 || argc == 1) { 
     3768        vid_show_help(); 
     3769    } else if (strcmp(argv[1], "call")==0) { 
     3770        pjsua_call_vid_strm_op_param param; 
     3771 
     3772        if (argc == 5 && strcmp(argv[2], "rx")==0) { 
     3773            pjsua_stream_info si; 
     3774            pj_bool_t on = (strcmp(argv[3], "on") == 0); 
     3775 
     3776            param.med_idx = atoi(argv[4]); 
     3777            if (pjsua_call_get_stream_info(current_call, param.med_idx, &si) || 
     3778                si.type != PJMEDIA_TYPE_VIDEO) 
     3779            { 
     3780                PJ_PERROR(1,(THIS_FILE, PJ_EINVAL, "Invalid stream")); 
     3781                return; 
     3782            } 
     3783 
     3784            if (on) param.dir = (si.info.vid.dir | PJMEDIA_DIR_DECODING); 
     3785            else param.dir = (si.info.vid.dir & PJMEDIA_DIR_ENCODING); 
     3786 
     3787            pjsua_call_set_vid_strm(current_call, PJSUA_CALL_VID_STRM_CHANGE_DIR, &param); 
     3788        } 
     3789        else if (argc == 5 && strcmp(argv[2], "tx")==0) { 
     3790            pj_bool_t on = (strcmp(argv[3], "on") == 0); 
     3791            pjsua_call_vid_strm_op op = on? PJSUA_CALL_VID_STRM_START_TRANSMIT : 
     3792                                            PJSUA_CALL_VID_STRM_STOP_TRANSMIT; 
     3793 
     3794            param.med_idx = atoi(argv[4]); 
     3795 
     3796            pjsua_call_set_vid_strm(current_call, op, &param); 
     3797        } 
     3798        else if (argc == 3 && strcmp(argv[2], "add")==0) { 
     3799            pjsua_call_set_vid_strm(current_call, PJSUA_CALL_VID_STRM_ADD, NULL); 
     3800        } 
     3801        else if (argc >= 3 &&  
     3802                 (strcmp(argv[2], "disable")==0 || strcmp(argv[2], "enable")==0)) 
     3803        { 
     3804            pj_bool_t enable = (strcmp(argv[2], "enable") == 0); 
     3805            pjsua_call_vid_strm_op op = enable? PJSUA_CALL_VID_STRM_CHANGE_DIR : 
     3806                                                PJSUA_CALL_VID_STRM_REMOVE; 
     3807 
     3808            param.med_idx = argc >= 4? atoi(argv[3]) : -1; 
     3809            param.dir = PJMEDIA_DIR_ENCODING_DECODING; 
     3810            pjsua_call_set_vid_strm(current_call, op, &param); 
     3811        } 
     3812        else if (argc >= 3 && strcmp(argv[2], "set-cap")==0) { 
     3813            param.med_idx = argc >= 4? atoi(argv[3]) : -1; 
     3814            param.cap_dev = argc >= 5? atoi(argv[4]) : PJMEDIA_VID_DEFAULT_CAPTURE_DEV; 
     3815            pjsua_call_set_vid_strm(current_call, PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV, &param); 
     3816        } else 
     3817            goto on_error; 
     3818    } else if (argc >= 3 && strcmp(argv[1], "dev")==0) { 
     3819        if (strcmp(argv[2], "list")==0) { 
     3820            vid_list_devs(); 
     3821        } else if (strcmp(argv[2], "refresh")==0) { 
     3822            pjmedia_vid_dev_refresh(); 
     3823        } else if (strcmp(argv[2], "prev")==0) { 
     3824            if (argc != 5) { 
     3825                goto on_error; 
     3826            } else { 
     3827                pj_bool_t on = (strcmp(argv[3], "on") == 0); 
     3828                int dev_id = atoi(argv[4]); 
     3829                if (on) { 
     3830                    pjsua_vid_preview_start(dev_id, NULL); 
     3831                } else { 
     3832                    pjsua_vid_preview_stop(dev_id); 
     3833                } 
     3834            } 
     3835        } else 
     3836            goto on_error; 
     3837    } else if (strcmp(argv[1], "win")==0) { 
     3838        if (argc==3 && strcmp(argv[2], "list")==0) { 
     3839            pjsua_vid_win_id wids[PJSUA_MAX_VID_WINS]; 
     3840            unsigned i, cnt = PJ_ARRAY_SIZE(wids); 
     3841 
     3842            pjsua_vid_enum_wins(wids, &cnt); 
     3843 
     3844            PJ_LOG(3,(THIS_FILE, "Found %d video windows:", cnt)); 
     3845            PJ_LOG(3,(THIS_FILE, "WID show    pos       size")); 
     3846            PJ_LOG(3,(THIS_FILE, "------------------------------")); 
     3847            for (i = 0; i < cnt; ++i) { 
     3848                pjsua_vid_win_info wi; 
     3849                pjsua_vid_win_get_info(wids[i], &wi); 
     3850                PJ_LOG(3,(THIS_FILE, "%3d   %c  (%d,%d)  %dx%d", 
     3851                          wids[i], (wi.show?'Y':'N'), wi.pos.x, wi.pos.y, 
     3852                          wi.size.w, wi.size.h)); 
     3853            } 
     3854        } else if (argc==4 && (strcmp(argv[2], "show")==0 || 
     3855                               strcmp(argv[2], "hide")==0)) 
     3856        { 
     3857            pj_bool_t show = (strcmp(argv[2], "show")==0); 
     3858            pjsua_vid_win_id wid = atoi(argv[3]); 
     3859            pjsua_vid_win_set_show(wid, show); 
     3860        } else if (argc==6 && strcmp(argv[2], "move")==0) { 
     3861            pjsua_vid_win_id wid = atoi(argv[3]); 
     3862            pjmedia_coord pos; 
     3863 
     3864            pos.x = atoi(argv[4]); 
     3865            pos.y = atoi(argv[5]); 
     3866            pjsua_vid_win_set_pos(wid, &pos); 
     3867        } else if (argc==6 && strcmp(argv[2], "resize")==0) { 
     3868            pjsua_vid_win_id wid = atoi(argv[3]); 
     3869            pjmedia_rect_size size; 
     3870 
     3871            size.w = atoi(argv[4]); 
     3872            size.h = atoi(argv[5]); 
     3873            pjsua_vid_win_set_size(wid, &size); 
     3874        } else 
     3875            goto on_error; 
     3876    } else if (strcmp(argv[1], "codec")==0) { 
     3877        pjmedia_vid_codec_info ci[PJMEDIA_CODEC_MGR_MAX_CODECS]; 
     3878        unsigned prio[PJMEDIA_CODEC_MGR_MAX_CODECS]; 
     3879        unsigned count = PJMEDIA_CODEC_MGR_MAX_CODECS; 
     3880        pj_status_t status; 
     3881 
     3882        if (argc==3 && strcmp(argv[2], "list")==0) { 
     3883            status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, ci, prio); 
     3884            if (status != PJ_SUCCESS) { 
     3885                PJ_PERROR(1,(THIS_FILE, status, "Error enumerating codecs")); 
     3886            } else { 
     3887                unsigned i; 
     3888                PJ_LOG(3,(THIS_FILE, "Found %d video codecs:", count)); 
     3889                PJ_LOG(3,(THIS_FILE, " PT  Prio  Name")); 
     3890                PJ_LOG(3,(THIS_FILE, "-------------------------")); 
     3891                for (i=0; i<count; ++i) { 
     3892                    PJ_LOG(3,(THIS_FILE, "% 3d % 3d  %.*s", ci[i].pt, prio[i], 
     3893                              (int)ci[i].encoding_name.slen, 
     3894                              ci[i].encoding_name.ptr)); 
     3895                } 
     3896            } 
     3897        } else if (argc==5 && strcmp(argv[2], "prio")==0) { 
     3898            int pt = atoi(argv[3]); 
     3899            int prio = atoi(argv[4]); 
     3900            const pjmedia_vid_codec_info *pci; 
     3901 
     3902            status = pjmedia_vid_codec_mgr_get_codec_info(NULL, pt, &pci); 
     3903            if (status != PJ_SUCCESS) { 
     3904                PJ_PERROR(1,(THIS_FILE, status, "Unable to find codec")); 
     3905            } else { 
     3906                char codec_id[40]; 
     3907                if (pjmedia_vid_codec_info_to_id(pci, codec_id, 
     3908                                                 sizeof(codec_id)) == NULL) 
     3909                { 
     3910                    PJ_PERROR(1,(THIS_FILE, status, "Unable to get codec id")); 
     3911                } else { 
     3912                    pj_str_t cid = pj_str(codec_id); 
     3913                    status = pjsua_vid_codec_set_priority(&cid, 
     3914                                                          (pj_uint8_t)prio); 
     3915                } 
     3916            } 
     3917 
     3918        } else 
     3919            goto on_error; 
     3920    } else 
     3921        goto on_error; 
     3922 
     3923    return; 
     3924 
     3925on_error: 
     3926    PJ_LOG(1,(THIS_FILE, "Invalid command, use 'vid help'")); 
     3927} 
     3928 
     3929#endif /* PJSUA_HAS_VIDEO */ 
    35233930 
    35243931 
     
    38934300                acc_cfg.cred_info[0].data = pj_str(passwd); 
    38944301 
     4302                acc_cfg.rtp_cfg = app_config.rtp_cfg; 
     4303 
    38954304                status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL); 
    38964305                if (status != PJ_SUCCESS) { 
     
    39504359 
    39514360        case 'v': 
    3952             /* 
    3953              * Send re-INVITE (to release hold, etc). 
    3954              */ 
     4361#if PJSUA_HAS_VIDEO 
     4362            if (menuin[1]=='i' && menuin[2]=='d' && menuin[3]==' ') { 
     4363 
     4364                vid_handle_menu(menuin); 
     4365 
     4366            } else 
     4367#endif 
    39554368            if (current_call != -1) { 
    3956                  
     4369                /* 
     4370                 * re-INVITE 
     4371                 */ 
    39574372                pjsua_call_reinvite(current_call, PJ_TRUE, NULL); 
    39584373 
     
    45124927} 
    45134928 
     4929/* 
     4930 * A simple registrar, invoked by default_mod_on_rx_request() 
     4931 */ 
     4932static void simple_registrar(pjsip_rx_data *rdata) 
     4933{ 
     4934    pjsip_tx_data *tdata; 
     4935    const pjsip_expires_hdr *exp; 
     4936    const pjsip_hdr *h; 
     4937    unsigned cnt = 0; 
     4938    pjsip_generic_string_hdr *srv; 
     4939    pj_status_t status; 
     4940 
     4941    status = pjsip_endpt_create_response(pjsua_get_pjsip_endpt(), 
     4942                                 rdata, 200, NULL, &tdata); 
     4943    if (status != PJ_SUCCESS) 
     4944    return; 
     4945 
     4946    exp = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL); 
     4947 
     4948    h = rdata->msg_info.msg->hdr.next; 
     4949    while (h != &rdata->msg_info.msg->hdr) { 
     4950    if (h->type == PJSIP_H_CONTACT) { 
     4951    const pjsip_contact_hdr *c = (const pjsip_contact_hdr*)h; 
     4952    int e = c->expires; 
     4953 
     4954    if (e < 0) { 
     4955        if (exp) 
     4956            e = exp->ivalue; 
     4957        else 
     4958            e = 3600; 
     4959    } 
     4960 
     4961    if (e > 0) { 
     4962        pjsip_contact_hdr *nc = pjsip_hdr_clone(tdata->pool, h); 
     4963        nc->expires = e; 
     4964        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)nc); 
     4965        ++cnt; 
     4966    } 
     4967    } 
     4968    h = h->next; 
     4969    } 
     4970 
     4971    srv = pjsip_generic_string_hdr_create(tdata->pool, NULL, NULL); 
     4972    srv->name = pj_str("Server"); 
     4973    srv->hvalue = pj_str("pjsua simple registrar"); 
     4974    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)srv); 
     4975 
     4976    pjsip_endpt_send_response2(pjsua_get_pjsip_endpt(), 
     4977                       rdata, tdata, NULL, NULL); 
     4978} 
     4979 
     4980 
     4981 
    45144982/***************************************************************************** 
    45154983 * A simple module to handle otherwise unhandled request. We will register 
     
    45254993 
    45264994    /* Don't respond to ACK! */ 
    4527     if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,  
     4995    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, 
    45284996                         &pjsip_ack_method) == 0) 
    45294997        return PJ_TRUE; 
     4998 
     4999    /* Simple registrar */ 
     5000    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, 
     5001                         &pjsip_register_method) == 0) 
     5002    { 
     5003        simple_registrar(rdata); 
     5004        return PJ_TRUE; 
     5005    } 
    45305006 
    45315007    /* Create basic response. */ 
     
    46525128    app_config.cfg.cb.on_transport_state = &on_transport_state; 
    46535129    app_config.cfg.cb.on_ice_transport_error = &on_ice_transport_error; 
     5130    app_config.cfg.cb.on_snd_dev_operation = &on_snd_dev_operation; 
     5131    app_config.cfg.cb.on_call_media_event = &on_call_media_event; 
    46545132    app_config.log_cfg.cb = log_cb; 
    46555133 
     
    49305408    /* Add accounts */ 
    49315409    for (i=0; i<app_config.acc_cnt; ++i) { 
     5410        app_config.acc_cfg[i].rtp_cfg = app_config.rtp_cfg; 
    49325411        status = pjsua_acc_add(&app_config.acc_cfg[i], PJ_TRUE, NULL); 
    49335412        if (status != PJ_SUCCESS) 
     
    49465425    for (i=0; i<app_config.codec_dis_cnt; ++i) { 
    49475426        pjsua_codec_set_priority(&app_config.codec_dis[i],PJMEDIA_CODEC_PRIO_DISABLED); 
     5427#if PJSUA_HAS_VIDEO 
     5428        pjsua_vid_codec_set_priority(&app_config.codec_dis[i],PJMEDIA_CODEC_PRIO_DISABLED); 
     5429#endif 
    49485430    } 
    49495431 
     
    49525434        pjsua_codec_set_priority(&app_config.codec_arg[i], 
    49535435                                 (pj_uint8_t)(PJMEDIA_CODEC_PRIO_NORMAL+i+9)); 
     5436#if PJSUA_HAS_VIDEO 
     5437        pjsua_vid_codec_set_priority(&app_config.codec_arg[i], 
     5438                                     (pj_uint8_t)(PJMEDIA_CODEC_PRIO_NORMAL+i+9)); 
     5439#endif 
    49545440    } 
    49555441 
     
    49615447    if (app_config.ipv6) 
    49625448        status = create_ipv6_media_transports(); 
     5449  #if DISABLED_FOR_TICKET_1185 
    49635450    else 
    49645451        status = pjsua_media_transports_create(&app_config.rtp_cfg); 
     5452  #endif 
    49655453#endif 
    49665454    if (status != PJ_SUCCESS) 
     
    49845472            goto on_error; 
    49855473    } 
     5474 
     5475#if PJSUA_HAS_VIDEO 
     5476    if (app_config.vcapture_dev != PJSUA_INVALID_ID || 
     5477        app_config.vrender_dev  != PJSUA_INVALID_ID)  
     5478    { 
     5479        //status = pjsua_vid_set_dev(app_config.vcapture_dev, 
     5480        //                         app_config.vrender_dev); 
     5481        PJ_TODO(vid_implement_pjsua_vid_set_dev); 
     5482        if (status != PJ_SUCCESS) 
     5483            goto on_error; 
     5484    } 
     5485#endif 
    49865486 
    49875487    return PJ_SUCCESS; 
     
    52975797    } 
    52985798 
     5799#if DISABLED_FOR_TICKET_1185 
    52995800    return pjsua_media_transports_attach(tp, i, PJ_TRUE); 
    5300 } 
    5301  
     5801#else 
     5802    return PJ_ENOTSUP; 
     5803#endif 
     5804} 
     5805 
Note: See TracChangeset for help on using the changeset viewer.