Changeset 3457
- Timestamp:
- Mar 17, 2011 4:34:43 AM (14 years ago)
- Location:
- pjproject/branches/projects/2.0-dev
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/2.0-dev/build.mak.in
r3393 r3457 59 59 @ac_build_mak_vars@ 60 60 61 # 62 # Video 63 # Note: there are duplicated macros in pjmedia/os-auto.mak.in (and that's not 64 # good! 65 66 # SDL flags 67 SDL_CFLAGS = @ac_sdl_cflags@ 68 SDL_LDFLAGS = @ac_sdl_ldflags@ 69 70 # FFMPEG dlags 71 FFMPEG_CFLAGS = @ac_ffmpeg_cflags@ 72 FFMPEG_LDFLAGS = @ac_ffmpeg_ldflags@ 73 74 # Video4Linux2 75 V4L2_CFLAGS = @ac_v4l2_cflags@ 76 V4L2_LDFLAGS = @ac_v4l2_ldflags@ 77 78 # QT 79 AC_PJMEDIA_VIDEO_HAS_QT = @ac_pjmedia_video_has_qt@ 80 QT_CFLAGS = @ac_qt_cflags@ 81 82 # iOS 83 IOS_CFLAGS = @ac_ios_cflags@ 84 85 # PJMEDIA features exclusion 86 PJ_VIDEO_CFLAGS += $(SDL_CFLAGS) $(FFMPEG_CFLAGS) $(V4L2_CFLAGS) $(QT_CFLAGS) \ 87 $(IOS_CFLAGS) 88 PJ_VIDEO_LDFLAGS += $(SDL_LDFLAGS) $(FFMPEG_LDFLAGS) $(V4L2_LDFLAGS) 89 90 61 91 # CFLAGS, LDFLAGS, and LIBS to be used by applications 62 92 export PJDIR := @ac_pjdir@ … … 65 95 export APP_CFLAGS := -DPJ_AUTOCONF=1\ 66 96 @CFLAGS@\ 97 $(PJ_VIDEO_CFLAGS) \ 67 98 -I$(PJDIR)/pjlib/include\ 68 99 -I$(PJDIR)/pjlib-util/include\ … … 77 108 -L$(PJDIR)/pjsip/lib\ 78 109 -L$(PJDIR)/third_party/lib\ 110 $(PJ_VIDEO_LDFLAGS) \ 79 111 @LDFLAGS@ 80 112 export APP_LDLIBS := -lpjsua-$(TARGET_NAME)\ -
pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/transport.h
r3392 r3457 484 484 /** Transport's "virtual" function table. */ 485 485 pjmedia_transport_op *op; 486 487 /** Application/user data */ 488 void *user_data; 486 489 }; 487 490 -
pjproject/branches/projects/2.0-dev/pjsip-apps/src/pjsua/pjsua_app.c
r3372 r3457 268 268 269 269 puts (""); 270 puts (" MediaOptions:");270 puts ("Audio Options:"); 271 271 puts (" --add-codec=name Manually add codec (default is to enable all)"); 272 272 puts (" --dis-codec=name Disable codec (can be specified multiple times)"); … … 302 302 puts (" --no-tones Disable audible tones"); 303 303 puts (" --jb-max-size Specify jitter buffer maximum size, in frames (default=-1)"); 304 puts (" --extra-audio Add one more audio stream"); 305 306 puts (""); 307 puts ("Video Options:"); 308 puts (" --video Enable video"); 304 309 305 310 puts (""); … … 541 546 OPT_AUTO_UPDATE_NAT,OPT_USE_COMPACT_FORM,OPT_DIS_CODEC, 542 547 OPT_NO_FORCE_LR, 543 OPT_TIMER, OPT_TIMER_SE, OPT_TIMER_MIN_SE 548 OPT_TIMER, OPT_TIMER_SE, OPT_TIMER_MIN_SE, 549 OPT_VIDEO, OPT_EXTRA_AUDIO 544 550 }; 545 551 struct pj_getopt_option long_options[] = { … … 660 666 { "timer-min-se", 1, 0, OPT_TIMER_MIN_SE}, 661 667 { "outb-rid", 1, 0, OPT_OUTB_RID}, 668 { "video", 0, 0, OPT_VIDEO}, 669 { "extra-audio",0, 0, OPT_EXTRA_AUDIO}, 662 670 { NULL, 0, 0, 0} 663 671 }; … … 1416 1424 cfg->udp_cfg.qos_params.flags = PJ_QOS_PARAM_HAS_DSCP; 1417 1425 cfg->udp_cfg.qos_params.dscp_val = 0x18; 1426 break; 1427 case OPT_VIDEO: 1428 ++cur_acc->max_video_cnt; 1429 break; 1430 case OPT_EXTRA_AUDIO: 1431 ++cur_acc->max_audio_cnt; 1418 1432 break; 1419 1433 default: … … 1661 1675 if (acc_cfg->mwi_enabled) 1662 1676 pj_strcat2(result, "--mwi\n"); 1677 1678 /* Video & extra audio */ 1679 for (i=0; i<acc_cfg->max_video_cnt; ++i) { 1680 pj_strcat2(result, "--video\n"); 1681 } 1682 for (i=1; i<acc_cfg->max_audio_cnt; ++i) { 1683 pj_strcat2(result, "--extra-audio\n"); 1684 } 1663 1685 } 1664 1686 … … 3892 3914 acc_cfg.cred_info[0].data = pj_str(passwd); 3893 3915 3916 acc_cfg.rtp_cfg = app_config.rtp_cfg; 3917 3894 3918 status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL); 3895 3919 if (status != PJ_SUCCESS) { … … 4929 4953 /* Add accounts */ 4930 4954 for (i=0; i<app_config.acc_cnt; ++i) { 4955 app_config.acc_cfg[i].rtp_cfg = app_config.rtp_cfg; 4931 4956 status = pjsua_acc_add(&app_config.acc_cfg[i], PJ_TRUE, NULL); 4932 4957 if (status != PJ_SUCCESS) … … 4960 4985 if (app_config.ipv6) 4961 4986 status = create_ipv6_media_transports(); 4987 #if DISABLED_FOR_TICKET_1185 4962 4988 else 4963 4989 status = pjsua_media_transports_create(&app_config.rtp_cfg); 4990 #endif 4964 4991 #endif 4965 4992 if (status != PJ_SUCCESS) … … 5296 5323 } 5297 5324 5325 #if DISABLED_FOR_TICKET_1185 5298 5326 return pjsua_media_transports_attach(tp, i, PJ_TRUE); 5299 } 5300 5327 #else 5328 return PJ_ENOTSUP; 5329 #endif 5330 } 5331 -
pjproject/branches/projects/2.0-dev/pjsip/build/Makefile
r3319 r3457 77 77 pjsua_acc.o pjsua_call.o pjsua_core.o \ 78 78 pjsua_im.o pjsua_media.o pjsua_pres.o 79 export PJSUA_LIB_CFLAGS += $(_CFLAGS) 79 export PJSUA_LIB_CFLAGS += $(_CFLAGS) $(PJ_VIDEO_CFLAGS) 80 80 81 81 -
pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua.h
r3366 r3457 251 251 #define PJSUA_INVALID_ID (-1) 252 252 253 /** Disabled features temporarily for media reorganization */ 254 #define DISABLED_FOR_TICKET_1185 0 255 253 256 /** Call identification */ 254 257 typedef int pjsua_call_id; … … 282 285 # define PJSUA_ACC_MAX_PROXIES 8 283 286 #endif 284 285 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)286 287 287 288 /** … … 304 305 #endif 305 306 306 #endif307 308 307 /** 309 308 * Controls whether PJSUA-LIB should add ICE media feature tag … … 325 324 # define PJSUA_ACQUIRE_CALL_TIMEOUT 2000 326 325 #endif 326 327 328 /** 329 * This enumeration represents pjsua state. 330 */ 331 typedef enum pjsua_state 332 { 333 /** 334 * The library has not been initialized. 335 */ 336 PJSUA_STATE_NULL, 337 338 /** 339 * After pjsua_create() is called but before pjsua_init() is called. 340 */ 341 PJSUA_STATE_CREATED, 342 343 /** 344 * After pjsua_init() is called but before pjsua_start() is called. 345 */ 346 PJSUA_STATE_INIT, 347 348 /** 349 * After pjsua_start() is called but before everything is running. 350 */ 351 PJSUA_STATE_STARTING, 352 353 /** 354 * After pjsua_start() is called and before pjsua_destroy() is called. 355 */ 356 PJSUA_STATE_RUNNING, 357 358 /** 359 * After pjsua_destroy() is called but before the function returns. 360 */ 361 PJSUA_STATE_CLOSING 362 363 } pjsua_state; 327 364 328 365 … … 484 521 * 485 522 * @param call_id Call identification. 486 * @param s ess Media session for the call.523 * @param strm Media stream. 487 524 * @param stream_idx Stream index in the media session. 488 525 * @param p_port On input, it specifies the media port of the … … 492 529 */ 493 530 void (*on_stream_created)(pjsua_call_id call_id, 494 pjmedia_s ession *sess,531 pjmedia_stream *strm, 495 532 unsigned stream_idx, 496 533 pjmedia_port **p_port); … … 501 538 * 502 539 * @param call_id Call identification. 503 * @param s ess Media session for the call.540 * @param strm Media stream. 504 541 * @param stream_idx Stream index in the media session. 505 542 */ 506 543 void (*on_stream_destroyed)(pjsua_call_id call_id, 507 pjmedia_s ession *sess,544 pjmedia_stream *strm, 508 545 unsigned stream_idx); 509 546 … … 1155 1192 pj_str_t user_agent; 1156 1193 1157 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)1158 1194 /** 1159 1195 * Specify default value of secure media transport usage. … … 1185 1221 1186 1222 /** 1187 * Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose 1223 * Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose 1188 1224 * duplicated media in SDP offer, i.e: unsecured and secured version. 1189 * Otherwise, the SDP media will be composed as unsecured media but 1225 * Otherwise, the SDP media will be composed as unsecured media but 1190 1226 * with SDP "crypto" attribute. 1191 1227 * … … 1193 1229 */ 1194 1230 pj_bool_t srtp_optional_dup_offer; 1195 #endif1196 1231 1197 1232 /** … … 1351 1386 */ 1352 1387 PJ_DECL(pj_status_t) pjsua_destroy(void); 1388 1389 1390 /** 1391 * Retrieve pjsua state. 1392 * 1393 * @return pjsua state. 1394 */ 1395 PJ_DECL(pjsua_state) pjsua_get_state(void); 1353 1396 1354 1397 … … 2094 2137 #endif 2095 2138 2096 2097 2139 /** 2098 2140 * This structure describes account configuration to be specified when … … 2385 2427 pj_str_t ka_data; 2386 2428 2387 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 2429 /** 2430 * Maximum number of simultaneous active audio streams to be allowed 2431 * for calls on this account. Setting this to zero will disable audio 2432 * in calls on this account. 2433 * 2434 * Default: 1 2435 */ 2436 unsigned max_audio_cnt; 2437 2438 /** 2439 * Maximum number of simultaneous active video streams to be allowed 2440 * for calls on this account. Setting this to zero will disable video 2441 * in calls on this account. 2442 * 2443 * Default: 0 2444 */ 2445 unsigned max_video_cnt; 2446 2447 /** 2448 * Media transport config. 2449 */ 2450 pjsua_transport_config rtp_cfg; 2451 2388 2452 /** 2389 2453 * Specify whether secure media transport should be used for this account. … … 2409 2473 2410 2474 /** 2411 * Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose 2475 * Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose 2412 2476 * duplicated media in SDP offer, i.e: unsecured and secured version. 2413 * Otherwise, the SDP media will be composed as unsecured media but 2477 * Otherwise, the SDP media will be composed as unsecured media but 2414 2478 * with SDP "crypto" attribute. 2415 2479 * … … 2417 2481 */ 2418 2482 pj_bool_t srtp_optional_dup_offer; 2419 #endif2420 2483 2421 2484 /** … … 2921 2984 typedef enum pjsua_call_media_status 2922 2985 { 2923 /** Call currently has no media */ 2986 /** 2987 * Call currently has no media, or the media is not used. 2988 */ 2924 2989 PJSUA_CALL_MEDIA_NONE, 2925 2990 2926 /** The media is active */ 2991 /** 2992 * The media is active 2993 */ 2927 2994 PJSUA_CALL_MEDIA_ACTIVE, 2928 2995 2929 /** The media is currently put on hold by local endpoint */ 2996 /** 2997 * The media is currently put on hold by local endpoint 2998 */ 2930 2999 PJSUA_CALL_MEDIA_LOCAL_HOLD, 2931 3000 2932 /** The media is currently put on hold by remote endpoint */ 3001 /** 3002 * The media is currently put on hold by remote endpoint 3003 */ 2933 3004 PJSUA_CALL_MEDIA_REMOTE_HOLD, 2934 3005 2935 /** The media has reported error (e.g. ICE negotiation) */ 3006 /** 3007 * The media has reported error (e.g. ICE negotiation) 3008 */ 2936 3009 PJSUA_CALL_MEDIA_ERROR 2937 3010 … … 2983 3056 pjsua_call_media_status media_status; 2984 3057 2985 /** Media direction */ 3058 /** Number of active audio streams in this call */ 3059 unsigned audio_cnt; 3060 3061 /** Media direction of the first audio stream. */ 2986 3062 pjmedia_dir media_dir; 2987 3063 2988 /** The conference port number for the call*/3064 /** The conference port number for the first audio stream. */ 2989 3065 pjsua_conf_port_id conf_slot; 3066 3067 /** Array of audio media stream information */ 3068 struct 3069 { 3070 /** Media index in SDP. */ 3071 unsigned index; 3072 3073 /** Call media status. */ 3074 pjsua_call_media_status media_status; 3075 3076 /** Media direction. */ 3077 pjmedia_dir media_dir; 3078 3079 /** The conference port number for the call. */ 3080 pjsua_conf_port_id conf_slot; 3081 3082 } audio[4]; 2990 3083 2991 3084 /** Up-to-date call connected duration (zero when call is not … … 3083 3176 3084 3177 3178 #if DISABLED_FOR_TICKET_1185 3085 3179 /** 3086 3180 * Retrieve the media session associated with this call. Note that the media … … 3096 3190 PJ_DECL(pjmedia_session*) pjsua_call_get_media_session(pjsua_call_id call_id); 3097 3191 3098 3099 3192 /** 3100 3193 * Retrieve the media transport instance that is used for this call. … … 3107 3200 */ 3108 3201 PJ_DECL(pjmedia_transport*) pjsua_call_get_media_transport(pjsua_call_id cid); 3109 3202 #endif /* DISABLED_FOR_TICKET_1185 */ 3110 3203 3111 3204 /** … … 4883 4976 const pjmedia_codec_param *param); 4884 4977 4885 4886 4887 4978 #if DISABLED_FOR_TICKET_1185 4888 4979 /** 4889 4980 * Create UDP media transports for all the calls. This function creates … … 4917 5008 unsigned count, 4918 5009 pj_bool_t auto_delete); 5010 #endif 4919 5011 4920 5012 -
pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua_internal.h
r3374 r3457 44 44 } pjsua_med_tp_st; 45 45 46 /** Forward decl of pjsua call */ 47 typedef struct pjsua_call pjsua_call; 48 49 /** 50 * Call's media stream. 51 */ 52 typedef struct pjsua_call_media 53 { 54 pjsua_call *call; /**< Parent call. */ 55 pjmedia_type type; /**< Media type. */ 56 unsigned idx; /**< This media index in parent call. */ 57 pjsua_call_media_status state; /**< Media state. */ 58 pjmedia_dir dir; /**< Media direction. */ 59 60 /** The stream */ 61 union { 62 /** Audio stream */ 63 struct { 64 pjmedia_stream *stream; /**< The media session. */ 65 int conf_slot; /**< Slot # in conference bridge. */ 66 } a; 67 68 /** Video stream */ 69 struct { 70 } v; 71 72 } strm; 73 74 pj_uint32_t ssrc; /**< RTP SSRC */ 75 pj_uint32_t rtp_tx_ts; /**< Initial RTP timestamp for sender. */ 76 pj_uint16_t rtp_tx_seq;/**< Initial RTP sequence for sender. */ 77 pj_uint8_t rtp_tx_seq_ts_set; 78 /**< Bitmask flags if initial RTP sequence 79 and/or timestamp for sender are set. 80 bit 0/LSB : sequence flag 81 bit 1 : timestamp flag */ 82 83 pjmedia_transport *tp; /**< Current media transport (can be 0) */ 84 pj_status_t tp_ready; /**< Media transport status. */ 85 pjmedia_transport *tp_orig; /**< Original media transport */ 86 pj_bool_t tp_auto_del; /**< May delete media transport */ 87 pjsua_med_tp_st tp_st; /**< Media transport state */ 88 pj_sockaddr rtp_addr; /**< Current RTP source address 89 (used to update ICE default 90 address) */ 91 pjmedia_srtp_use rem_srtp_use; /**< Remote's SRTP usage policy. */ 92 } pjsua_call_media; 93 94 /** 95 * Maximum number of SDP "m=" lines to be supported. 96 */ 97 #define PJSUA_MAX_CALL_MEDIA PJMEDIA_MAX_SDP_MEDIA 98 46 99 /** 47 100 * Structure to be attached to invite dialog. … … 49 102 * by accessing dlg->mod_data[pjsua.mod.id]. 50 103 */ 51 typedefstruct pjsua_call104 struct pjsua_call 52 105 { 53 106 unsigned index; /**< Index in pjsua array. */ … … 64 117 pjsua_call_hold_type call_hold_type; /**< How to do call hold. */ 65 118 pj_bool_t local_hold;/**< Flag for call-hold by local. */ 66 pjsua_call_media_status media_st;/**< Media state. */ 67 pjmedia_dir media_dir; /**< Media direction. */ 68 pjmedia_session *session; /**< The media session. */ 69 int audio_idx; /**< Index of m=audio in SDP. */ 70 pj_uint32_t ssrc; /**< RTP SSRC */ 71 pj_uint32_t rtp_tx_ts; /**< Initial RTP timestamp for sender. */ 72 pj_uint16_t rtp_tx_seq;/**< Initial RTP sequence for sender. */ 73 pj_uint8_t rtp_tx_seq_ts_set; 74 /**< Bitmask flags if initial RTP sequence 75 and/or timestamp for sender are set. 76 bit 0/LSB : sequence flag 77 bit 1 : timestamp flag */ 78 int conf_slot; /**< Slot # in conference bridge. */ 119 120 unsigned med_cnt; /**< Number of media in SDP. */ 121 pjsua_call_media media[PJSUA_MAX_CALL_MEDIA]; /**< Array of media */ 122 unsigned audio_idx; /**< Selected audio media. */ 123 79 124 pjsip_evsub *xfer_sub; /**< Xfer server subscription, if this 80 125 call was triggered by xfer. */ 81 pjmedia_transport *med_tp; /**< Current media transport. */82 pj_status_t med_tp_ready;/**< Media transport status. */83 pjmedia_transport *med_orig; /**< Original media transport */84 pj_bool_t med_tp_auto_del; /**< May delete media transport */85 pjsua_med_tp_st med_tp_st; /**< Media transport state */86 pj_sockaddr med_rtp_addr; /**< Current RTP source address87 (used to update ICE default88 address) */89 126 pj_stun_nat_type rem_nat_type; /**< NAT type of remote endpoint. */ 90 pjmedia_srtp_use rem_srtp_use; /**< Remote's SRTP usage policy. */91 127 92 128 char last_text_buf_[128]; /**< Buffer for last_text. */ … … 100 136 contains multiple codecs. */ 101 137 102 } pjsua_call;138 }; 103 139 104 140 … … 271 307 pj_pool_t *pool; /**< pjsua's private pool. */ 272 308 pj_mutex_t *mutex; /**< Mutex protection for this data */ 309 pjsua_state state; /**< Library state. */ 273 310 274 311 /* Logging: */ … … 402 439 #define PJSUA_UNLOCK() 403 440 #endif 441 442 /* Core */ 443 void pjsua_set_state(pjsua_state new_state); 404 444 405 445 /****** -
pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_acc.c
r3377 r3457 119 119 pjsip_auth_clt_pref_dup(pool, &dst->auth_pref, &src->auth_pref); 120 120 121 dst->ka_interval = src->ka_interval; 121 pjsua_transport_config_dup(pool, &dst->rtp_cfg, &src->rtp_cfg); 122 122 123 pj_strdup(pool, &dst->ka_data, &src->ka_data); 123 124 } -
pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_call.c
r3374 r3457 102 102 { 103 103 pjsua_call *call = &pjsua_var.calls[id]; 104 104 unsigned i; 105 106 pj_bzero(call, sizeof(*call)); 105 107 call->index = id; 106 call->inv = NULL;107 call->user_data = NULL;108 call->session = NULL;109 call->audio_idx = -1;110 call->ssrc = pj_rand();111 call->rtp_tx_seq = 0;112 call->rtp_tx_ts = 0;113 call->rtp_tx_seq_ts_set = 0;114 call->xfer_sub = NULL;115 call->last_code = (pjsip_status_code) 0;116 call->conf_slot = PJSUA_INVALID_ID;117 108 call->last_text.ptr = call->last_text_buf_; 118 call->last_text.slen = 0; 119 call->conn_time.sec = 0; 120 call->conn_time.msec = 0; 121 call->res_time.sec = 0; 122 call->res_time.msec = 0; 123 call->rem_nat_type = PJ_STUN_NAT_TYPE_UNKNOWN; 124 call->rem_srtp_use = PJMEDIA_SRTP_DISABLED; 125 call->local_hold = PJ_FALSE; 126 pj_bzero(&call->lock_codec, sizeof(call->lock_codec)); 109 for (i=0; i<PJ_ARRAY_SIZE(call->media); ++i) { 110 pjsua_call_media *call_med = &call->media[i]; 111 call_med->ssrc = pj_rand(); 112 call_med->strm.a.conf_slot = PJSUA_INVALID_ID; 113 call_med->call = call; 114 call_med->idx = i; 115 call_med->tp_auto_del = PJ_TRUE; 116 } 127 117 } 128 118 … … 824 814 status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS, 825 815 call->secure_level, 826 rdata->tp_info.pool, offer, 816 rdata->tp_info.pool, 817 offer, 827 818 &sip_err_code); 828 819 if (status != PJ_SUCCESS) { … … 1119 1110 PJ_DEF(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id) 1120 1111 { 1112 pjsua_call *call = &pjsua_var.calls[call_id]; 1121 1113 PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 1122 1114 PJ_EINVAL); 1123 return pjsua_var.calls[call_id].session != NULL; 1124 } 1125 1126 1115 return call->audio_idx >= 0 && call->media[call->audio_idx].strm.a.stream; 1116 } 1117 1118 1119 #if DISABLED_FOR_TICKET_1185 1127 1120 /* 1128 1121 * Retrieve the media session associated with this call. … … 1143 1136 PJ_ASSERT_RETURN(cid>=0 && cid<(int)pjsua_var.ua_cfg.max_calls, 1144 1137 NULL); 1145 return pjsua_var.calls[cid]. med_tp;1146 } 1147 1138 return pjsua_var.calls[cid].tp; 1139 } 1140 #endif /* Removed in 2.0 */ 1148 1141 1149 1142 /* Acquire lock to the specified call_id */ … … 1239 1232 return PJSUA_INVALID_ID; 1240 1233 1241 port_id = call-> conf_slot;1234 port_id = call->media[call->audio_idx].strm.a.conf_slot; 1242 1235 1243 1236 pjsip_dlg_dec_lock(dlg); … … 1256 1249 pjsua_call *call; 1257 1250 pjsip_dialog *dlg; 1251 unsigned mi; 1258 1252 pj_status_t status; 1259 1253 … … 1330 1324 } 1331 1325 1332 /* media status and dir */ 1333 info->media_status = call->media_st; 1334 info->media_dir = call->media_dir; 1335 1326 /* Build array of media status and dir */ 1327 info->audio_cnt = 0; 1328 for (mi=0; mi < call->med_cnt && 1329 info->audio_cnt < PJ_ARRAY_SIZE(info->audio); ++mi) 1330 { 1331 pjsua_call_media *call_med = &call->media[mi]; 1332 if (call_med->type != PJMEDIA_TYPE_AUDIO) 1333 continue; 1334 info->audio[info->audio_cnt].index = mi; 1335 info->audio[info->audio_cnt].media_status = call_med->state; 1336 info->audio[info->audio_cnt].media_dir = call_med->dir; 1337 info->audio[info->audio_cnt].conf_slot = call_med->strm.a.conf_slot; 1338 ++info->audio_cnt; 1339 } 1340 1341 if (info->audio_cnt) { 1342 info->media_status = info->audio[0].media_status; 1343 info->media_dir = info->audio[0].media_dir; 1344 } 1336 1345 1337 1346 /* conference slot number */ 1338 info->conf_slot = call-> conf_slot;1347 info->conf_slot = call->media[call->audio_idx].strm.a.conf_slot; 1339 1348 1340 1349 /* calculate duration */ … … 1960 1969 return status; 1961 1970 1962 if (! call->session) {1971 if (!pjsua_call_has_media(call_id)) { 1963 1972 PJ_LOG(3,(THIS_FILE, "Media is not established yet!")); 1964 1973 pjsip_dlg_dec_lock(dlg); … … 1966 1975 } 1967 1976 1968 status = pjmedia_session_dial_dtmf( call->session, 0, digits); 1977 status = pjmedia_stream_dial_dtmf( 1978 call->media[call->audio_idx].strm.a.stream, digits); 1969 1979 1970 1980 pjsip_dlg_dec_lock(dlg); … … 2191 2201 char *p = buf, *end = buf+maxlen; 2192 2202 int len; 2193 pjmedia_session_info info; 2194 pjmedia_session *session = call->session; 2195 pjmedia_transport_info tp_info; 2196 2197 pjmedia_transport_info_init(&tp_info); 2198 2199 pjmedia_transport_get_info(call->med_tp, &tp_info); 2200 pjmedia_session_get_info(session, &info); 2201 2202 for (i=0; i<info.stream_cnt; ++i) { 2203 2204 for (i=0; i<call->med_cnt; ++i) { 2205 pjsua_call_media *call_med = &call->media[i]; 2206 pjmedia_stream_info info; 2207 pjmedia_stream *stream = call_med->strm.a.stream; 2208 pjmedia_transport_info tp_info; 2203 2209 pjmedia_rtcp_stat stat; 2204 2210 char rem_addr_buf[80]; … … 2209 2215 pj_time_val media_duration, now; 2210 2216 2211 pjmedia_session_get_stream_stat(session, i, &stat); 2217 /* Check if the stream is deactivated */ 2218 if (call_med->tp == NULL || stream == NULL) { 2219 const char *media_type_str; 2220 2221 switch (call_med->type) { 2222 case PJMEDIA_TYPE_AUDIO: 2223 media_type_str = "audio"; 2224 break; 2225 case PJMEDIA_TYPE_VIDEO: 2226 media_type_str = "video"; 2227 break; 2228 case PJMEDIA_TYPE_APPLICATION: 2229 media_type_str = "application"; 2230 break; 2231 default: 2232 media_type_str = "unknown"; 2233 break; 2234 } 2235 len = pj_ansi_snprintf(p, end-p, 2236 "%s #%d m=%s deactivated\n", 2237 indent, i, media_type_str); 2238 if (len < 1 || len > end-p) { 2239 *p = '\0'; 2240 return; 2241 } 2242 2243 p += len; 2244 continue; 2245 } 2246 2247 pjmedia_transport_info_init(&tp_info); 2248 pjmedia_transport_get_info(call_med->tp, &tp_info); 2249 2250 pjmedia_stream_get_info(stream, &info); 2251 pjmedia_stream_get_stat(stream, &stat); 2252 2212 2253 // rem_addr will contain actual address of RTP originator, instead of 2213 2254 // remote RTP address specified by stream which is fetched from the SDP. … … 2223 2264 } 2224 2265 2225 if (call ->media_dir == PJMEDIA_DIR_NONE) {2266 if (call_med->dir == PJMEDIA_DIR_NONE) { 2226 2267 /* To handle when the stream that is currently being paused 2227 2268 * (http://trac.pjsip.org/repos/ticket/1079) 2228 2269 */ 2229 2270 dir = "inactive"; 2230 } else if (info. stream_info[i].dir == PJMEDIA_DIR_ENCODING)2271 } else if (info.dir == PJMEDIA_DIR_ENCODING) 2231 2272 dir = "sendonly"; 2232 else if (info. stream_info[i].dir == PJMEDIA_DIR_DECODING)2273 else if (info.dir == PJMEDIA_DIR_DECODING) 2233 2274 dir = "recvonly"; 2234 else if (info. stream_info[i].dir == PJMEDIA_DIR_ENCODING_DECODING)2275 else if (info.dir == PJMEDIA_DIR_ENCODING_DECODING) 2235 2276 dir = "sendrecv"; 2236 2277 else … … 2238 2279 2239 2280 2240 len = pj_ansi_snprintf( buf, end-p,2281 len = pj_ansi_snprintf(p, end-p, 2241 2282 "%s #%d %.*s @%dKHz, %s, peer=%s", 2242 2283 indent, i, 2243 (int)info. stream_info[i].fmt.encoding_name.slen,2244 info. stream_info[i].fmt.encoding_name.ptr,2245 info. stream_info[i].fmt.clock_rate / 1000,2284 (int)info.fmt.encoding_name.slen, 2285 info.fmt.encoding_name.ptr, 2286 info.fmt.clock_rate / 1000, 2246 2287 dir, 2247 2288 rem_addr); … … 2294 2335 #endif 2295 2336 "%s", 2296 indent, info. stream_info[i].fmt.pt,2337 indent, info.fmt.pt, 2297 2338 last_update, 2298 2339 indent, … … 2371 2412 "%s jitter : %7.3f %7.3f %7.3f %7.3f %7.3f%s", 2372 2413 indent, 2373 info.stream_info[i].tx_pt, 2374 info.stream_info[i].param->info.frm_ptime * 2375 info.stream_info[i].param->setting.frm_per_pkt, 2414 info.tx_pt, 2415 info.param->info.frm_ptime * info.param->setting.frm_per_pkt, 2376 2416 last_update, 2377 2417 … … 2416 2456 2417 2457 len = pj_ansi_snprintf(p, end-p, 2418 "%s RTT msec : %7.3f %7.3f %7.3f %7.3f %7.3f",2458 "%s RTT msec : %7.3f %7.3f %7.3f %7.3f %7.3f", 2419 2459 indent, 2420 2460 stat.rtt.min / 1000.0, … … 2471 2511 } 2472 2512 2473 clock_rate = info. stream_info[i].fmt.clock_rate;2513 clock_rate = info.fmt.clock_rate; 2474 2514 2475 2515 len = pj_ansi_snprintf(p, end-p, "\n%s Extended reports:", indent); … … 2944 2984 2945 2985 /* Get and ICE SRTP status */ 2986 #if DISABLED_FOR_TICKET_1185 2946 2987 pjmedia_transport_info_init(&tp_info); 2947 pjmedia_transport_get_info(call-> med_tp, &tp_info);2988 pjmedia_transport_get_info(call->tp, &tp_info); 2948 2989 if (tp_info.specific_info_cnt > 0) { 2949 2990 unsigned i; … … 2984 3025 } 2985 3026 } 3027 #endif /* DISABLED_FOR_TICKET_1185 */ 2986 3028 2987 3029 /* Dump session statistics */ 2988 if (with_media && call->session)3030 if (with_media && pjsua_call_has_media(call_id)) 2989 3031 dump_media_session(indent, p, end-p, call); 2990 3032 … … 3064 3106 const pjmedia_sdp_media *ref_m; 3065 3107 pjmedia_sdp_media *m; 3108 pjsua_call_media *call_med = &call->media[call->audio_idx]; 3066 3109 unsigned i, codec_cnt = 0; 3067 3110 pj_bool_t rem_can_update; … … 3098 3141 3099 3142 /* Verify if media is deactivated */ 3100 if (call ->media_st== PJSUA_CALL_MEDIA_NONE ||3101 call->media_st== PJSUA_CALL_MEDIA_ERROR ||3102 call->media_dir == PJMEDIA_DIR_NONE)3143 if (call_med->state == PJSUA_CALL_MEDIA_NONE || 3144 call_med->state == PJSUA_CALL_MEDIA_ERROR || 3145 call_med->dir == PJMEDIA_DIR_NONE) 3103 3146 { 3104 3147 return PJ_EINVALIDOP; … … 3190 3233 const pjmedia_sdp_media *rem_m, *loc_m; 3191 3234 unsigned codec_cnt=0, i; 3235 pjsua_call_media *call_med = &call->media[call->audio_idx]; 3192 3236 pj_time_val delay = {0, 0}; 3193 3237 const pj_str_t st_update = {"UPDATE", 6}; … … 3207 3251 3208 3252 /* Skip this if the media is inactive or error */ 3209 if (call ->media_st== PJSUA_CALL_MEDIA_NONE ||3210 call->media_st== PJSUA_CALL_MEDIA_ERROR ||3211 call->media_dir == PJMEDIA_DIR_NONE)3253 if (call_med->state == PJSUA_CALL_MEDIA_NONE || 3254 call_med->state == PJSUA_CALL_MEDIA_ERROR || 3255 call_med->dir == PJMEDIA_DIR_NONE) 3212 3256 { 3213 3257 return PJ_SUCCESS; … … 3525 3569 3526 3570 /* Add SDP in 488 status */ 3527 if (call && call->med_tp && tdata->msg->type==PJSIP_RESPONSE_MSG && 3571 #if DISABLED_FOR_TICKET_1185 3572 if (call && call->tp && tdata->msg->type==PJSIP_RESPONSE_MSG && 3528 3573 code==PJSIP_SC_NOT_ACCEPTABLE_HERE) 3529 3574 { … … 3540 3585 } 3541 3586 } 3587 #endif 3542 3588 3543 3589 pjsip_inv_send_msg(inv, tdata); … … 3655 3701 */ 3656 3702 /* http://trac.pjsip.org/repos/ticket/880 3657 if (call-> media_dir != PJMEDIA_DIR_ENCODING) {3703 if (call->dir != PJMEDIA_DIR_ENCODING) { 3658 3704 */ 3659 3705 /* https://trac.pjsip.org/repos/ticket/1142: … … 3695 3741 pjmedia_sdp_media_remove_all_attr(m, "inactive"); 3696 3742 3697 if (call->media _dir & PJMEDIA_DIR_ENCODING) {3743 if (call->media[call->audio_idx].dir & PJMEDIA_DIR_ENCODING) { 3698 3744 /* Add sendonly attribute */ 3699 3745 attr = pjmedia_sdp_attr_create(pool, "sendonly", NULL); -
pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_core.c
r3366 r3457 104 104 cfg->force_lr = PJ_TRUE; 105 105 cfg->enable_unsolicited_mwi = PJ_TRUE; 106 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)107 106 cfg->use_srtp = PJSUA_DEFAULT_USE_SRTP; 108 107 cfg->srtp_secure_signaling = PJSUA_DEFAULT_SRTP_SECURE_SIGNALING; 109 #endif110 108 cfg->hangup_forked_call = PJ_TRUE; 111 109 … … 177 175 cfg->ka_interval = 15; 178 176 cfg->ka_data = pj_str("\r\n"); 179 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 177 cfg->max_audio_cnt = 1; 178 pjsua_transport_config_default(&cfg->rtp_cfg); 180 179 cfg->use_srtp = pjsua_var.ua_cfg.use_srtp; 181 180 cfg->srtp_secure_signaling = pjsua_var.ua_cfg.srtp_secure_signaling; 182 181 cfg->srtp_optional_dup_offer = pjsua_var.ua_cfg.srtp_optional_dup_offer; 183 #endif184 182 cfg->reg_retry_interval = PJSUA_REG_RETRY_INTERVAL; 185 183 cfg->contact_rewrite_method = PJSUA_CONTACT_REWRITE_METHOD; … … 224 222 } 225 223 226 227 224 /***************************************************************************** 228 225 * This is a very simple PJSIP module, whose sole purpose is to display … … 379 376 380 377 /* Get media socket info, make sure transport is ready */ 378 #if DISABLED_FOR_TICKET_1185 381 379 if (pjsua_var.calls[0].med_tp) { 382 380 pjmedia_transport_info_init(&tpinfo); … … 390 388 } 391 389 } 392 393 /* Send response statelessly */ 390 #endif 391 392 /* Send response */ 394 393 pjsip_get_response_addr(tdata->pool, rdata, &res_addr); 395 394 status = pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, tdata, NULL, NULL); … … 660 659 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 661 660 661 pjsua_set_state(PJSUA_STATE_CREATED); 662 662 663 663 return PJ_SUCCESS; … … 919 919 pj_get_version(), PJ_OS_NAME)); 920 920 921 pjsua_set_state(PJSUA_STATE_INIT); 922 921 923 return PJ_SUCCESS; 922 924 … … 1276 1278 int i; /* Must be signed */ 1277 1279 1280 if (pjsua_var.state > PJSUA_STATE_NULL && 1281 pjsua_var.state < PJSUA_STATE_CLOSING) 1282 { 1283 pjsua_set_state(PJSUA_STATE_CLOSING); 1284 } 1285 1278 1286 /* Signal threads to quit: */ 1279 1287 pjsua_var.thread_quit_flag = 1; … … 1453 1461 pj_bzero(&pjsua_var, sizeof(pjsua_var)); 1454 1462 1463 pjsua_set_state(PJSUA_STATE_NULL); 1464 1455 1465 /* Done. */ 1456 1466 return PJ_SUCCESS; 1457 1467 } 1458 1468 1469 void pjsua_set_state(pjsua_state new_state) 1470 { 1471 const char *state_name[] = { 1472 "NULL", 1473 "CREATED", 1474 "INIT", 1475 "STARTING", 1476 "RUNNING", 1477 "CLOSING" 1478 }; 1479 pjsua_state old_state = pjsua_var.state; 1480 1481 pjsua_var.state = new_state; 1482 PJ_LOG(4,(THIS_FILE, "PJSUA state changed: %s --> %s", 1483 state_name[old_state], state_name[new_state])); 1484 } 1485 1486 /* Get state */ 1487 PJ_DEF(pjsua_state) pjsua_get_state(void) 1488 { 1489 return pjsua_var.state; 1490 } 1459 1491 1460 1492 /** … … 1469 1501 pj_status_t status; 1470 1502 1503 pjsua_set_state(PJSUA_STATE_STARTING); 1504 1471 1505 status = pjsua_call_subsys_start(); 1472 1506 if (status != PJ_SUCCESS) … … 1480 1514 if (status != PJ_SUCCESS) 1481 1515 return status; 1516 1517 pjsua_set_state(PJSUA_STATE_RUNNING); 1482 1518 1483 1519 return PJ_SUCCESS; … … 2564 2600 2565 2601 PJ_LOG(3,(THIS_FILE, "Dumping media transports:")); 2602 #if DISABLED_FOR_TICKET_1185 2566 2603 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 2567 2604 pjsua_call *call = &pjsua_var.calls[i]; … … 2580 2617 sizeof(addr_buf), 3))); 2581 2618 } 2619 #endif 2582 2620 2583 2621 pjsip_tsx_layer_dump(detail); -
pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_media.c
r3392 r3457 275 275 #endif /* PJMEDIA_HAS_L16_CODEC */ 276 276 277 #if PJMEDIA_HAS_VIDEO 278 status = pjmedia_video_format_mgr_create(pjsua_var.pool, 64, 0, NULL); 279 if (status != PJ_SUCCESS) { 280 pjsua_perror(THIS_FILE, "Error creating PJMEDIA video format manager", 281 status); 282 return status; 283 } 284 285 status = pjmedia_converter_mgr_create(pjsua_var.pool, NULL); 286 if (status != PJ_SUCCESS) { 287 pjsua_perror(THIS_FILE, "Error creating PJMEDIA converter manager", 288 status); 289 return status; 290 } 291 292 status = pjmedia_vid_codec_mgr_create(pjsua_var.pool, NULL); 293 if (status != PJ_SUCCESS) { 294 pjsua_perror(THIS_FILE, "Error creating PJMEDIA video codec manager", 295 status); 296 return status; 297 } 298 299 status = pjmedia_vid_subsys_init(&pjsua_var.cp.factory); 300 if (status != PJ_SUCCESS) { 301 pjsua_perror(THIS_FILE, "Error creating PJMEDIA video subsystem", 302 status); 303 return status; 304 } 305 #endif 306 307 #if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_FFMPEG_CODEC 308 /* Init ffmpeg video codecs */ 309 status = pjmedia_codec_ffmpeg_init(NULL, &pjsua_var.cp.factory); 310 if (status != PJ_SUCCESS) { 311 pjsua_perror(THIS_FILE, "Error initializing ffmpeg library", 312 status); 313 return status; 314 } 315 #endif 277 316 278 317 /* Save additional conference bridge parameters for future … … 339 378 340 379 341 /*342 * Create RTP and RTCP socket pair, and possibly resolve their public343 * address via STUN.344 */345 static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,346 pjmedia_sock_info *skinfo)347 {348 enum {349 RTP_RETRY = 100350 };351 int i;352 pj_sockaddr_in bound_addr;353 pj_sockaddr_in mapped_addr[2];354 pj_status_t status = PJ_SUCCESS;355 char addr_buf[PJ_INET6_ADDRSTRLEN+2];356 pj_sock_t sock[2];357 358 /* Make sure STUN server resolution has completed */359 status = resolve_stun_server(PJ_TRUE);360 if (status != PJ_SUCCESS) {361 pjsua_perror(THIS_FILE, "Error resolving STUN server", status);362 return status;363 }364 365 if (next_rtp_port == 0)366 next_rtp_port = (pj_uint16_t)cfg->port;367 368 for (i=0; i<2; ++i)369 sock[i] = PJ_INVALID_SOCKET;370 371 bound_addr.sin_addr.s_addr = PJ_INADDR_ANY;372 if (cfg->bound_addr.slen) {373 status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr);374 if (status != PJ_SUCCESS) {375 pjsua_perror(THIS_FILE, "Unable to resolve transport bind address",376 status);377 return status;378 }379 }380 381 /* Loop retry to bind RTP and RTCP sockets. */382 for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) {383 384 /* Create RTP socket. */385 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]);386 if (status != PJ_SUCCESS) {387 pjsua_perror(THIS_FILE, "socket() error", status);388 return status;389 }390 391 /* Apply QoS to RTP socket, if specified */392 status = pj_sock_apply_qos2(sock[0], cfg->qos_type,393 &cfg->qos_params,394 2, THIS_FILE, "RTP socket");395 396 /* Bind RTP socket */397 status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr),398 next_rtp_port);399 if (status != PJ_SUCCESS) {400 pj_sock_close(sock[0]);401 sock[0] = PJ_INVALID_SOCKET;402 continue;403 }404 405 /* Create RTCP socket. */406 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]);407 if (status != PJ_SUCCESS) {408 pjsua_perror(THIS_FILE, "socket() error", status);409 pj_sock_close(sock[0]);410 return status;411 }412 413 /* Apply QoS to RTCP socket, if specified */414 status = pj_sock_apply_qos2(sock[1], cfg->qos_type,415 &cfg->qos_params,416 2, THIS_FILE, "RTCP socket");417 418 /* Bind RTCP socket */419 status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr),420 (pj_uint16_t)(next_rtp_port+1));421 if (status != PJ_SUCCESS) {422 pj_sock_close(sock[0]);423 sock[0] = PJ_INVALID_SOCKET;424 425 pj_sock_close(sock[1]);426 sock[1] = PJ_INVALID_SOCKET;427 continue;428 }429 430 /*431 * If we're configured to use STUN, then find out the mapped address,432 * and make sure that the mapped RTCP port is adjacent with the RTP.433 */434 if (pjsua_var.stun_srv.addr.sa_family != 0) {435 char ip_addr[32];436 pj_str_t stun_srv;437 438 pj_ansi_strcpy(ip_addr,439 pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr));440 stun_srv = pj_str(ip_addr);441 442 status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock,443 &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),444 &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),445 mapped_addr);446 if (status != PJ_SUCCESS) {447 pjsua_perror(THIS_FILE, "STUN resolve error", status);448 goto on_error;449 }450 451 #if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT452 if (pj_ntohs(mapped_addr[1].sin_port) ==453 pj_ntohs(mapped_addr[0].sin_port)+1)454 {455 /* Success! */456 break;457 }458 459 pj_sock_close(sock[0]);460 sock[0] = PJ_INVALID_SOCKET;461 462 pj_sock_close(sock[1]);463 sock[1] = PJ_INVALID_SOCKET;464 #else465 if (pj_ntohs(mapped_addr[1].sin_port) !=466 pj_ntohs(mapped_addr[0].sin_port)+1)467 {468 PJ_LOG(4,(THIS_FILE,469 "Note: STUN mapped RTCP port %d is not adjacent"470 " to RTP port %d",471 pj_ntohs(mapped_addr[1].sin_port),472 pj_ntohs(mapped_addr[0].sin_port)));473 }474 /* Success! */475 break;476 #endif477 478 } else if (cfg->public_addr.slen) {479 480 status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr,481 (pj_uint16_t)next_rtp_port);482 if (status != PJ_SUCCESS)483 goto on_error;484 485 status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr,486 (pj_uint16_t)(next_rtp_port+1));487 if (status != PJ_SUCCESS)488 goto on_error;489 490 break;491 492 } else {493 494 if (bound_addr.sin_addr.s_addr == 0) {495 pj_sockaddr addr;496 497 /* Get local IP address. */498 status = pj_gethostip(pj_AF_INET(), &addr);499 if (status != PJ_SUCCESS)500 goto on_error;501 502 bound_addr.sin_addr.s_addr = addr.ipv4.sin_addr.s_addr;503 }504 505 for (i=0; i<2; ++i) {506 pj_sockaddr_in_init(&mapped_addr[i], NULL, 0);507 mapped_addr[i].sin_addr.s_addr = bound_addr.sin_addr.s_addr;508 }509 510 mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port);511 mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(next_rtp_port+1));512 break;513 }514 }515 516 if (sock[0] == PJ_INVALID_SOCKET) {517 PJ_LOG(1,(THIS_FILE,518 "Unable to find appropriate RTP/RTCP ports combination"));519 goto on_error;520 }521 522 523 skinfo->rtp_sock = sock[0];524 pj_memcpy(&skinfo->rtp_addr_name,525 &mapped_addr[0], sizeof(pj_sockaddr_in));526 527 skinfo->rtcp_sock = sock[1];528 pj_memcpy(&skinfo->rtcp_addr_name,529 &mapped_addr[1], sizeof(pj_sockaddr_in));530 531 PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s",532 pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf,533 sizeof(addr_buf), 3)));534 PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s",535 pj_sockaddr_print(&skinfo->rtcp_addr_name, addr_buf,536 sizeof(addr_buf), 3)));537 538 next_rtp_port += 2;539 return PJ_SUCCESS;540 541 on_error:542 for (i=0; i<2; ++i) {543 if (sock[i] != PJ_INVALID_SOCKET)544 pj_sock_close(sock[i]);545 }546 return status;547 }548 549 380 /* Check if sound device is idle. */ 550 381 static void check_snd_dev_idle() … … 579 410 * there is no active call. 580 411 */ 581 if ((pjsua_var.snd_port!=NULL || pjsua_var.null_snd!=NULL) && 412 if ((pjsua_var.snd_port!=NULL || pjsua_var.null_snd!=NULL) && 582 413 pjsua_var.snd_idle_timer.id == PJ_FALSE && 583 414 pjmedia_conf_get_connect_count(pjsua_var.mconf) == 0 && … … 591 422 592 423 pjsua_var.snd_idle_timer.id = PJ_TRUE; 593 pjsip_endpt_schedule_timer(pjsua_var.endpt, &pjsua_var.snd_idle_timer, 424 pjsip_endpt_schedule_timer(pjsua_var.endpt, &pjsua_var.snd_idle_timer, 594 425 &delay); 595 426 } … … 605 436 PJSUA_LOCK(); 606 437 if (entry->id) { 607 PJ_LOG(4,(THIS_FILE,"Closing sound device after idle for %d seconds", 438 PJ_LOG(4,(THIS_FILE,"Closing sound device after idle for %d seconds", 608 439 pjsua_var.media_cfg.snd_auto_close_time)); 609 440 … … 623 454 pj_status_t status; 624 455 456 #if DISABLED_FOR_TICKET_1185 625 457 /* Create media for calls, if none is specified */ 626 if (pjsua_var.calls[0].med _tp == NULL) {458 if (pjsua_var.calls[0].media[0].tp == NULL) { 627 459 pjsua_transport_config transport_cfg; 628 460 … … 635 467 return status; 636 468 } 637 638 pj_timer_entry_init(&pjsua_var.snd_idle_timer, PJ_FALSE, NULL, 469 #endif 470 471 pj_timer_entry_init(&pjsua_var.snd_idle_timer, PJ_FALSE, NULL, 639 472 &close_snd_timer_cb); 640 473 641 474 /* Perform NAT detection */ 642 pjsua_detect_nat_type(); 475 status = pjsua_detect_nat_type(); 476 if (status != PJ_SUCCESS) { 477 PJ_PERROR(1,(THIS_FILE, status, "NAT type detection failed")); 478 } 643 479 644 480 return PJ_SUCCESS; … … 685 521 /* Close media transports */ 686 522 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 687 if (pjsua_var.calls[i].med_tp_st != PJSUA_MED_TP_IDLE) { 688 pjsua_media_channel_deinit(i); 689 } 690 if (pjsua_var.calls[i].med_tp && pjsua_var.calls[i].med_tp_auto_del) { 691 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 692 } 693 pjsua_var.calls[i].med_tp = NULL; 523 unsigned strm_idx; 524 pjsua_call *call = &pjsua_var.calls[i]; 525 for (strm_idx=0; strm_idx<call->med_cnt; ++strm_idx) { 526 pjsua_call_media *call_med = &call->media[strm_idx]; 527 if (call_med->tp_st != PJSUA_MED_TP_IDLE) { 528 pjsua_media_channel_deinit(i); 529 } 530 if (call_med->tp && call_med->tp_auto_del) { 531 pjmedia_transport_close(call_med->tp); 532 } 533 call_med->tp = NULL; 534 } 694 535 } 695 536 696 537 /* Destroy media endpoint. */ 697 538 if (pjsua_var.med_endpt) { 539 540 /* Videodev */ 541 # if PJMEDIA_HAS_VIDEO 542 pjmedia_vid_subsys_shutdown(); 543 # endif 544 545 /* ffmpeg */ 546 # if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_FFMPEG_CODEC 547 pjmedia_codec_ffmpeg_deinit(); 548 # endif 698 549 699 550 /* Shutdown all codecs: */ … … 745 596 } 746 597 747 598 /* 599 * Create RTP and RTCP socket pair, and possibly resolve their public 600 * address via STUN. 601 */ 602 static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg, 603 pjmedia_sock_info *skinfo) 604 { 605 enum { 606 RTP_RETRY = 100 607 }; 608 int i; 609 pj_sockaddr_in bound_addr; 610 pj_sockaddr_in mapped_addr[2]; 611 pj_status_t status = PJ_SUCCESS; 612 char addr_buf[PJ_INET6_ADDRSTRLEN+2]; 613 pj_sock_t sock[2]; 614 615 /* Make sure STUN server resolution has completed */ 616 status = resolve_stun_server(PJ_TRUE); 617 if (status != PJ_SUCCESS) { 618 pjsua_perror(THIS_FILE, "Error resolving STUN server", status); 619 return status; 620 } 621 622 if (next_rtp_port == 0) 623 next_rtp_port = (pj_uint16_t)cfg->port; 624 625 if (next_rtp_port == 0) 626 next_rtp_port = (pj_uint16_t)40000; 627 628 for (i=0; i<2; ++i) 629 sock[i] = PJ_INVALID_SOCKET; 630 631 bound_addr.sin_addr.s_addr = PJ_INADDR_ANY; 632 if (cfg->bound_addr.slen) { 633 status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr); 634 if (status != PJ_SUCCESS) { 635 pjsua_perror(THIS_FILE, "Unable to resolve transport bind address", 636 status); 637 return status; 638 } 639 } 640 641 /* Loop retry to bind RTP and RTCP sockets. */ 642 for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) { 643 644 /* Create RTP socket. */ 645 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]); 646 if (status != PJ_SUCCESS) { 647 pjsua_perror(THIS_FILE, "socket() error", status); 648 return status; 649 } 650 651 /* Apply QoS to RTP socket, if specified */ 652 status = pj_sock_apply_qos2(sock[0], cfg->qos_type, 653 &cfg->qos_params, 654 2, THIS_FILE, "RTP socket"); 655 656 /* Bind RTP socket */ 657 status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr), 658 next_rtp_port); 659 if (status != PJ_SUCCESS) { 660 pj_sock_close(sock[0]); 661 sock[0] = PJ_INVALID_SOCKET; 662 continue; 663 } 664 665 /* Create RTCP socket. */ 666 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]); 667 if (status != PJ_SUCCESS) { 668 pjsua_perror(THIS_FILE, "socket() error", status); 669 pj_sock_close(sock[0]); 670 return status; 671 } 672 673 /* Apply QoS to RTCP socket, if specified */ 674 status = pj_sock_apply_qos2(sock[1], cfg->qos_type, 675 &cfg->qos_params, 676 2, THIS_FILE, "RTCP socket"); 677 678 /* Bind RTCP socket */ 679 status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr), 680 (pj_uint16_t)(next_rtp_port+1)); 681 if (status != PJ_SUCCESS) { 682 pj_sock_close(sock[0]); 683 sock[0] = PJ_INVALID_SOCKET; 684 685 pj_sock_close(sock[1]); 686 sock[1] = PJ_INVALID_SOCKET; 687 continue; 688 } 689 690 /* 691 * If we're configured to use STUN, then find out the mapped address, 692 * and make sure that the mapped RTCP port is adjacent with the RTP. 693 */ 694 if (pjsua_var.stun_srv.addr.sa_family != 0) { 695 char ip_addr[32]; 696 pj_str_t stun_srv; 697 698 pj_ansi_strcpy(ip_addr, 699 pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr)); 700 stun_srv = pj_str(ip_addr); 701 702 status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock, 703 &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 704 &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), 705 mapped_addr); 706 if (status != PJ_SUCCESS) { 707 pjsua_perror(THIS_FILE, "STUN resolve error", status); 708 goto on_error; 709 } 710 711 #if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT 712 if (pj_ntohs(mapped_addr[1].sin_port) == 713 pj_ntohs(mapped_addr[0].sin_port)+1) 714 { 715 /* Success! */ 716 break; 717 } 718 719 pj_sock_close(sock[0]); 720 sock[0] = PJ_INVALID_SOCKET; 721 722 pj_sock_close(sock[1]); 723 sock[1] = PJ_INVALID_SOCKET; 724 #else 725 if (pj_ntohs(mapped_addr[1].sin_port) != 726 pj_ntohs(mapped_addr[0].sin_port)+1) 727 { 728 PJ_LOG(4,(THIS_FILE, 729 "Note: STUN mapped RTCP port %d is not adjacent" 730 " to RTP port %d", 731 pj_ntohs(mapped_addr[1].sin_port), 732 pj_ntohs(mapped_addr[0].sin_port))); 733 } 734 /* Success! */ 735 break; 736 #endif 737 738 } else if (cfg->public_addr.slen) { 739 740 status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr, 741 (pj_uint16_t)next_rtp_port); 742 if (status != PJ_SUCCESS) 743 goto on_error; 744 745 status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr, 746 (pj_uint16_t)(next_rtp_port+1)); 747 if (status != PJ_SUCCESS) 748 goto on_error; 749 750 break; 751 752 } else { 753 754 if (bound_addr.sin_addr.s_addr == 0) { 755 pj_sockaddr addr; 756 757 /* Get local IP address. */ 758 status = pj_gethostip(pj_AF_INET(), &addr); 759 if (status != PJ_SUCCESS) 760 goto on_error; 761 762 bound_addr.sin_addr.s_addr = addr.ipv4.sin_addr.s_addr; 763 } 764 765 for (i=0; i<2; ++i) { 766 pj_sockaddr_in_init(&mapped_addr[i], NULL, 0); 767 mapped_addr[i].sin_addr.s_addr = bound_addr.sin_addr.s_addr; 768 } 769 770 mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port); 771 mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(next_rtp_port+1)); 772 break; 773 } 774 } 775 776 if (sock[0] == PJ_INVALID_SOCKET) { 777 PJ_LOG(1,(THIS_FILE, 778 "Unable to find appropriate RTP/RTCP ports combination")); 779 goto on_error; 780 } 781 782 783 skinfo->rtp_sock = sock[0]; 784 pj_memcpy(&skinfo->rtp_addr_name, 785 &mapped_addr[0], sizeof(pj_sockaddr_in)); 786 787 skinfo->rtcp_sock = sock[1]; 788 pj_memcpy(&skinfo->rtcp_addr_name, 789 &mapped_addr[1], sizeof(pj_sockaddr_in)); 790 791 PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s", 792 pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf, 793 sizeof(addr_buf), 3))); 794 PJ_LOG(4,(THIS_FILE, "RTCP socket reachable at %s", 795 pj_sockaddr_print(&skinfo->rtcp_addr_name, addr_buf, 796 sizeof(addr_buf), 3))); 797 798 next_rtp_port += 2; 799 return PJ_SUCCESS; 800 801 on_error: 802 for (i=0; i<2; ++i) { 803 if (sock[i] != PJ_INVALID_SOCKET) 804 pj_sock_close(sock[i]); 805 } 806 return status; 807 } 808 809 /* Create normal UDP media transports */ 810 static pj_status_t create_udp_media_transport(const pjsua_transport_config *cfg, 811 pjsua_call_media *call_med) 812 { 813 pjmedia_sock_info skinfo; 814 pj_status_t status; 815 816 status = create_rtp_rtcp_sock(cfg, &skinfo); 817 if (status != PJ_SUCCESS) { 818 pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket", 819 status); 820 goto on_error; 821 } 822 823 status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL, 824 &skinfo, 0, &call_med->tp); 825 if (status != PJ_SUCCESS) { 826 pjsua_perror(THIS_FILE, "Unable to create media transport", 827 status); 828 goto on_error; 829 } 830 831 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING, 832 pjsua_var.media_cfg.tx_drop_pct); 833 834 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING, 835 pjsua_var.media_cfg.rx_drop_pct); 836 837 return PJ_SUCCESS; 838 839 on_error: 840 if (call_med->tp) 841 pjmedia_transport_close(call_med->tp); 842 843 return status; 844 } 845 846 #if DISABLED_FOR_TICKET_1185 748 847 /* Create normal UDP media transports */ 749 848 static pj_status_t create_udp_media_transports(pjsua_transport_config *cfg) 750 849 { 751 850 unsigned i; 752 pjmedia_sock_info skinfo;753 851 pj_status_t status; 754 852 755 /* Create each media transport */ 756 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 757 758 status = create_rtp_rtcp_sock(cfg, &skinfo); 759 if (status != PJ_SUCCESS) { 760 pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket", 761 status); 762 goto on_error; 763 } 764 765 status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL, 766 &skinfo, 0, 767 &pjsua_var.calls[i].med_tp); 768 if (status != PJ_SUCCESS) { 769 pjsua_perror(THIS_FILE, "Unable to create media transport", 770 status); 771 goto on_error; 772 } 773 774 pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 775 PJMEDIA_DIR_ENCODING, 776 pjsua_var.media_cfg.tx_drop_pct); 777 778 pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 779 PJMEDIA_DIR_DECODING, 780 pjsua_var.media_cfg.rx_drop_pct); 781 853 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 854 pjsua_call *call = &pjsua_var.calls[i]; 855 unsigned strm_idx; 856 857 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 858 pjsua_call_media *call_med = &call->media[strm_idx]; 859 860 status = create_udp_media_transport(cfg, &call_med->tp); 861 if (status != PJ_SUCCESS) 862 goto on_error; 863 } 782 864 } 783 865 … … 785 867 786 868 on_error: 787 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 788 if (pjsua_var.calls[i].med_tp != NULL) { 789 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 790 pjsua_var.calls[i].med_tp = NULL; 791 } 792 } 793 869 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 870 pjsua_call *call = &pjsua_var.calls[i]; 871 unsigned strm_idx; 872 873 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 874 pjsua_call_media *call_med = &call->media[strm_idx]; 875 876 if (call_med->tp) { 877 pjmedia_transport_close(call_med->tp); 878 call_med->tp = NULL; 879 } 880 } 881 } 794 882 return status; 795 883 } 796 884 #endif 797 885 798 886 /* This callback is called when ICE negotiation completes */ … … 801 889 pj_status_t result) 802 890 { 803 unsigned id; 804 pj_bool_t found = PJ_FALSE; 805 806 /* Find call which has this media transport */ 807 808 PJSUA_LOCK(); 809 810 for (id=0; id<pjsua_var.ua_cfg.max_calls; ++id) { 811 if (pjsua_var.calls[id].med_tp == tp || 812 pjsua_var.calls[id].med_orig == tp) 813 { 814 found = PJ_TRUE; 815 break; 816 } 817 } 818 819 PJSUA_UNLOCK(); 820 821 if (!found) 891 pjsua_call_media *call_med = (pjsua_call_media*)tp->user_data; 892 893 if (!call_med) 822 894 return; 823 895 824 896 switch (op) { 825 897 case PJ_ICE_STRANS_OP_INIT: 826 pjsua_var.calls[id].med_tp_ready = result;898 call_med->tp_ready = result; 827 899 break; 828 900 case PJ_ICE_STRANS_OP_NEGOTIATION: 829 901 if (result != PJ_SUCCESS) { 830 pjsua_var.calls[id].media_st= PJSUA_CALL_MEDIA_ERROR;831 pjsua_var.calls[id].media_dir = PJMEDIA_DIR_NONE;832 833 if ( pjsua_var.ua_cfg.cb.on_call_media_state) {834 pjsua_var.ua_cfg.cb.on_call_media_state( id);902 call_med->state = PJSUA_CALL_MEDIA_ERROR; 903 call_med->dir = PJMEDIA_DIR_NONE; 904 905 if (call_med->call && pjsua_var.ua_cfg.cb.on_call_media_state) { 906 pjsua_var.ua_cfg.cb.on_call_media_state(call_med->call->index); 835 907 } 836 } else {908 } else if (call_med->call) { 837 909 /* Send UPDATE if default transport address is different than 838 910 * what was advertised (ticket #881) … … 854 926 if (ii && ii->role==PJ_ICE_SESS_ROLE_CONTROLLING && 855 927 pj_sockaddr_cmp(&tpinfo.sock_info.rtp_addr_name, 856 & pjsua_var.calls[id].med_rtp_addr))928 &call_med->rtp_addr)) 857 929 { 858 930 pj_bool_t use_update; … … 861 933 pjsip_dialog *dlg; 862 934 863 dlg = pjsua_var.calls[id].inv->dlg;935 dlg = call_med->call->inv->dlg; 864 936 support_update = pjsip_dlg_remote_has_cap(dlg, PJSIP_H_ALLOW, 865 937 NULL, &STR_UPDATE); … … 868 940 PJ_LOG(4,(THIS_FILE, 869 941 "ICE default transport address has changed for " 870 "call %d, sending %s", id,942 "call %d, sending %s", call_med->call->index, 871 943 (use_update ? "UPDATE" : "re-INVITE"))); 872 944 873 945 if (use_update) 874 pjsua_call_update( id, 0, NULL);946 pjsua_call_update(call_med->call->index, 0, NULL); 875 947 else 876 pjsua_call_reinvite( id, 0, NULL);948 pjsua_call_reinvite(call_med->call->index, 0, NULL); 877 949 } 878 950 } … … 881 953 if (result != PJ_SUCCESS) { 882 954 PJ_PERROR(4,(THIS_FILE, result, 883 "ICE keep alive failure for transport %d", id)); 955 "ICE keep alive failure for transport %d:%d", 956 call_med->call->index, call_med->idx)); 884 957 } 885 958 if (pjsua_var.ua_cfg.cb.on_ice_transport_error) { 959 pjsua_call_id id = call_med->call->index; 886 960 (*pjsua_var.ua_cfg.cb.on_ice_transport_error)(id, op, result, 887 961 NULL); … … 919 993 920 994 /* Create ICE media transports (when ice is enabled) */ 921 static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg) 995 static pj_status_t create_ice_media_transport( 996 const pjsua_transport_config *cfg, 997 pjsua_call_media *call_med) 922 998 { 923 999 char stunip[PJ_INET6_ADDRSTRLEN]; 924 1000 pj_ice_strans_cfg ice_cfg; 925 unsigned i; 1001 pjmedia_ice_cb ice_cb; 1002 char name[32]; 1003 unsigned comp_cnt; 926 1004 pj_status_t status; 927 1005 … … 980 1058 } 981 1059 982 /* Create each media transport */ 983 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 984 pjmedia_ice_cb ice_cb; 985 char name[32]; 986 unsigned comp_cnt; 987 988 pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb)); 989 ice_cb.on_ice_complete = &on_ice_complete; 990 pj_ansi_snprintf(name, sizeof(name), "icetp%02d", i); 991 pjsua_var.calls[i].med_tp_ready = PJ_EPENDING; 992 993 comp_cnt = 1; 994 if (PJMEDIA_ADVERTISE_RTCP && !pjsua_var.media_cfg.ice_no_rtcp) 995 ++comp_cnt; 996 997 status = pjmedia_ice_create(pjsua_var.med_endpt, name, comp_cnt, 998 &ice_cfg, &ice_cb, 999 &pjsua_var.calls[i].med_tp); 1000 if (status != PJ_SUCCESS) { 1001 pjsua_perror(THIS_FILE, "Unable to create ICE media transport", 1002 status); 1003 goto on_error; 1004 } 1005 1006 /* Wait until transport is initialized, or time out */ 1007 PJSUA_UNLOCK(); 1008 while (pjsua_var.calls[i].med_tp_ready == PJ_EPENDING) { 1009 pjsua_handle_events(100); 1010 } 1011 PJSUA_LOCK(); 1012 if (pjsua_var.calls[i].med_tp_ready != PJ_SUCCESS) { 1013 pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 1014 pjsua_var.calls[i].med_tp_ready); 1015 status = pjsua_var.calls[i].med_tp_ready; 1016 goto on_error; 1017 } 1018 1019 pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 1020 PJMEDIA_DIR_ENCODING, 1021 pjsua_var.media_cfg.tx_drop_pct); 1022 1023 pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp, 1024 PJMEDIA_DIR_DECODING, 1025 pjsua_var.media_cfg.rx_drop_pct); 1026 } 1060 pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb)); 1061 ice_cb.on_ice_complete = &on_ice_complete; 1062 pj_ansi_snprintf(name, sizeof(name), "icetp%02d", call_med->idx); 1063 call_med->tp_ready = PJ_EPENDING; 1064 1065 comp_cnt = 1; 1066 if (PJMEDIA_ADVERTISE_RTCP && !pjsua_var.media_cfg.ice_no_rtcp) 1067 ++comp_cnt; 1068 1069 status = pjmedia_ice_create(pjsua_var.med_endpt, name, comp_cnt, 1070 &ice_cfg, &ice_cb, &call_med->tp); 1071 if (status != PJ_SUCCESS) { 1072 pjsua_perror(THIS_FILE, "Unable to create ICE media transport", 1073 status); 1074 goto on_error; 1075 } 1076 1077 /* Wait until transport is initialized, or time out */ 1078 PJSUA_UNLOCK(); 1079 while (call_med->tp_ready == PJ_EPENDING) { 1080 pjsua_handle_events(100); 1081 } 1082 PJSUA_LOCK(); 1083 if (call_med->tp_ready != PJ_SUCCESS) { 1084 pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 1085 call_med->tp_ready); 1086 status = call_med->tp_ready; 1087 goto on_error; 1088 } 1089 1090 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_ENCODING, 1091 pjsua_var.media_cfg.tx_drop_pct); 1092 1093 pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING, 1094 pjsua_var.media_cfg.rx_drop_pct); 1027 1095 1028 1096 return PJ_SUCCESS; 1029 1097 1030 1098 on_error: 1031 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 1032 if (pjsua_var.calls[i].med_tp != NULL) { 1033 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 1034 pjsua_var.calls[i].med_tp = NULL; 1035 } 1099 if (call_med->tp != NULL) { 1100 pjmedia_transport_close(call_med->tp); 1101 call_med->tp = NULL; 1036 1102 } 1037 1103 … … 1039 1105 } 1040 1106 1041 1042 /* 1043 * Create UDP media transports for all the calls. This function creates 1107 #if DISABLED_FOR_TICKET_1185 1108 /* Create ICE media transports (when ice is enabled) */ 1109 static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg) 1110 { 1111 unsigned i; 1112 pj_status_t status; 1113 1114 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 1115 pjsua_call *call = &pjsua_var.calls[i]; 1116 unsigned strm_idx; 1117 1118 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 1119 pjsua_call_media *call_med = &call->media[strm_idx]; 1120 1121 status = create_ice_media_transport(cfg, call_med); 1122 if (status != PJ_SUCCESS) 1123 goto on_error; 1124 } 1125 } 1126 1127 return PJ_SUCCESS; 1128 1129 on_error: 1130 for (i=0; i < pjsua_var.ua_cfg.max_calls; ++i) { 1131 pjsua_call *call = &pjsua_var.calls[i]; 1132 unsigned strm_idx; 1133 1134 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 1135 pjsua_call_media *call_med = &call->media[strm_idx]; 1136 1137 if (call_med->tp) { 1138 pjmedia_transport_close(call_med->tp); 1139 call_med->tp = NULL; 1140 } 1141 } 1142 } 1143 return status; 1144 } 1145 #endif 1146 1147 #if DISABLED_FOR_TICKET_1185 1148 /* 1149 * Create media transports for all the calls. This function creates 1044 1150 * one UDP media transport for each call. 1045 1151 */ … … 1059 1165 /* Delete existing media transports */ 1060 1166 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 1061 if (pjsua_var.calls[i].med_tp != NULL && 1062 pjsua_var.calls[i].med_tp_auto_del) 1063 { 1064 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 1065 pjsua_var.calls[i].med_tp = NULL; 1066 pjsua_var.calls[i].med_orig = NULL; 1167 pjsua_call *call = &pjsua_var.calls[i]; 1168 unsigned strm_idx; 1169 1170 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 1171 pjsua_call_media *call_med = &call->media[strm_idx]; 1172 1173 if (call_med->tp && call_med->tp_auto_del) { 1174 pjmedia_transport_close(call_med->tp); 1175 call_med->tp = NULL; 1176 call_med->tp_orig = NULL; 1177 } 1067 1178 } 1068 1179 } … … 1080 1191 /* Set media transport auto_delete to True */ 1081 1192 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 1082 pjsua_var.calls[i].med_tp_auto_del = PJ_TRUE; 1193 pjsua_call *call = &pjsua_var.calls[i]; 1194 unsigned strm_idx; 1195 1196 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 1197 pjsua_call_media *call_med = &call->media[strm_idx]; 1198 1199 call_med->tp_auto_del = PJ_TRUE; 1200 } 1083 1201 } 1084 1202 … … 1101 1219 /* Assign the media transports */ 1102 1220 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { 1103 if (pjsua_var.calls[i].med_tp != NULL && 1104 pjsua_var.calls[i].med_tp_auto_del) 1105 { 1106 pjmedia_transport_close(pjsua_var.calls[i].med_tp); 1107 } 1108 1109 pjsua_var.calls[i].med_tp = tp[i].transport; 1110 pjsua_var.calls[i].med_tp_auto_del = auto_delete; 1221 pjsua_call *call = &pjsua_var.calls[i]; 1222 unsigned strm_idx; 1223 1224 for (strm_idx=0; strm_idx < call->med_cnt; ++strm_idx) { 1225 pjsua_call_media *call_med = &call->media[strm_idx]; 1226 1227 if (call_med->tp && call_med->tp_auto_del) { 1228 pjmedia_transport_close(call_med->tp); 1229 call_med->tp = NULL; 1230 call_med->tp_orig = NULL; 1231 } 1232 } 1233 1234 PJ_TODO(remove_pjsua_media_transports_attach); 1235 1236 call->media[0].tp = tp[i].transport; 1237 call->media[0].tp_auto_del = auto_delete; 1111 1238 } 1112 1239 1113 1240 return PJ_SUCCESS; 1114 1241 } 1115 1116 1117 static int find_audio_index(const pjmedia_sdp_session *sdp, 1118 pj_bool_t prefer_srtp) 1242 #endif 1243 1244 /* Go through the list of media in the SDP, find acceptable media, and 1245 * sort them based on the "quality" of the media, and store the indexes 1246 * in the specified array. Media with the best quality will be listed 1247 * first in the array. The quality factors considered currently is 1248 * encryption. 1249 */ 1250 static void sort_media(const pjmedia_sdp_session *sdp, 1251 const pj_str_t *type, 1252 pjmedia_srtp_use use_srtp, 1253 pj_uint8_t midx[], 1254 unsigned *p_count) 1119 1255 { 1120 1256 unsigned i; 1121 int audio_idx = -1; 1122 1123 for (i=0; i<sdp->media_count; ++i) { 1257 unsigned count = 0; 1258 int score[PJSUA_MAX_CALL_MEDIA]; 1259 1260 pj_assert(*p_count >= PJSUA_MAX_CALL_MEDIA); 1261 1262 *p_count = 0; 1263 pj_bzero(score, sizeof(score)); 1264 1265 /* Score each media */ 1266 for (i=0; i<sdp->media_count && count<PJSUA_MAX_CALL_MEDIA; ++i) { 1124 1267 const pjmedia_sdp_media *m = sdp->media[i]; 1125 1268 1126 /* Skip if media is not audio */ 1127 if (pj_stricmp2(&m->desc.media, "audio") != 0) 1269 /* Skip different media */ 1270 if (pj_stricmp(&m->desc.media, type) != 0) { 1271 score[count++] = -22000; 1128 1272 continue; 1129 1130 /* Skip if media is disabled */ 1273 } 1274 1275 /* Supported transports */ 1276 if (pj_stricmp2(&m->desc.transport, "RTP/SAVP")==0) { 1277 switch (use_srtp) { 1278 case PJMEDIA_SRTP_MANDATORY: 1279 case PJMEDIA_SRTP_OPTIONAL: 1280 ++score[i]; 1281 break; 1282 case PJMEDIA_SRTP_DISABLED: 1283 --score[i]; 1284 break; 1285 } 1286 } else if (pj_stricmp2(&m->desc.transport, "RTP/AVP")==0) { 1287 switch (use_srtp) { 1288 case PJMEDIA_SRTP_MANDATORY: 1289 --score[i]; 1290 break; 1291 case PJMEDIA_SRTP_OPTIONAL: 1292 /* No change in score */ 1293 break; 1294 case PJMEDIA_SRTP_DISABLED: 1295 ++score[i]; 1296 break; 1297 } 1298 } else { 1299 score[i] -= 10; 1300 } 1301 1302 /* Is media disabled? */ 1131 1303 if (m->desc.port == 0) 1132 continue; 1133 1134 /* Skip if transport is not supported */ 1135 if (pj_stricmp2(&m->desc.transport, "RTP/AVP") != 0 && 1136 pj_stricmp2(&m->desc.transport, "RTP/SAVP") != 0) 1137 { 1138 continue; 1139 } 1140 1141 if (audio_idx == -1) { 1142 audio_idx = i; 1304 score[i] -= 10; 1305 1306 /* Is media inactive? */ 1307 if (pjmedia_sdp_media_find_attr2(m, "inactive", NULL)) 1308 score[i] -= 10; 1309 1310 ++count; 1311 } 1312 1313 /* Created sorted list based on quality */ 1314 for (i=0; i<count; ++i) { 1315 unsigned j; 1316 int best = 0; 1317 1318 for (j=1; j<count; ++j) { 1319 if (score[j] > score[best]) 1320 best = j; 1321 } 1322 /* Don't put media with negative score, that media is unacceptable 1323 * for us. 1324 */ 1325 if (score[best] >= 0) { 1326 midx[*p_count] = (pj_uint8_t)best; 1327 (*p_count)++; 1328 } 1329 1330 score[best] = -22000; 1331 1332 } 1333 } 1334 1335 /* Initialize the media line */ 1336 static pj_status_t pjsua_call_media_init(pjsua_call_media *call_med, 1337 pjmedia_type type, 1338 const pjsua_transport_config *tcfg, 1339 int security_level, 1340 int *sip_err_code) 1341 { 1342 pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id]; 1343 pj_status_t status; 1344 1345 /* 1346 * Note: this function may be called when the media already exists 1347 * (e.g. in reinvites, updates, etc.) 1348 */ 1349 call_med->type = type; 1350 1351 /* Create the media transport for initial call. This is blocking for now */ 1352 if (call_med->tp == NULL) { 1353 if (pjsua_var.media_cfg.enable_ice) { 1354 status = create_ice_media_transport(tcfg, call_med); 1143 1355 } else { 1144 /* We've found multiple candidates. This could happen 1145 * e.g. when remote is offering both RTP/SAVP and RTP/AVP, 1146 * or when remote for some reason offers two audio. 1147 */ 1148 1149 if (prefer_srtp && 1150 pj_stricmp2(&m->desc.transport, "RTP/SAVP")==0) 1151 { 1152 /* Prefer RTP/SAVP when our media transport is SRTP */ 1153 audio_idx = i; 1154 break; 1155 } else if (!prefer_srtp && 1156 pj_stricmp2(&m->desc.transport, "RTP/AVP")==0) 1157 { 1158 /* Prefer RTP/AVP when our media transport is NOT SRTP */ 1159 audio_idx = i; 1356 status = create_udp_media_transport(tcfg, call_med); 1357 } 1358 1359 if (status != PJ_SUCCESS) { 1360 PJ_PERROR(1,(THIS_FILE, status, "Error creating media transport")); 1361 return status; 1362 } 1363 } 1364 1365 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1366 /* This function may be called when SRTP transport already exists 1367 * (e.g: in re-invite, update), don't need to destroy/re-create. 1368 */ 1369 if (!call_med->tp_orig || call_med->tp == call_med->tp_orig) { 1370 pjmedia_srtp_setting srtp_opt; 1371 pjmedia_transport *srtp = NULL; 1372 1373 /* Check if SRTP requires secure signaling */ 1374 if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 1375 if (security_level < acc->cfg.srtp_secure_signaling) { 1376 if (sip_err_code) 1377 *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1378 status = PJSIP_ESESSIONINSECURE; 1379 goto on_error; 1160 1380 } 1161 1381 } 1162 } 1163 1164 return audio_idx; 1165 } 1166 1382 1383 /* Always create SRTP adapter */ 1384 pjmedia_srtp_setting_default(&srtp_opt); 1385 srtp_opt.close_member_tp = PJ_FALSE; 1386 /* If media session has been ever established, let's use remote's 1387 * preference in SRTP usage policy, especially when it is stricter. 1388 */ 1389 if (call_med->rem_srtp_use > acc->cfg.use_srtp) 1390 srtp_opt.use = call_med->rem_srtp_use; 1391 else 1392 srtp_opt.use = acc->cfg.use_srtp; 1393 1394 status = pjmedia_transport_srtp_create(pjsua_var.med_endpt, 1395 call_med->tp, 1396 &srtp_opt, &srtp); 1397 if (status != PJ_SUCCESS) { 1398 if (sip_err_code) 1399 *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 1400 goto on_error; 1401 } 1402 1403 /* Set SRTP as current media transport */ 1404 call_med->tp_orig = call_med->tp; 1405 call_med->tp = srtp; 1406 } 1407 #else 1408 call->tp_orig = call->tp; 1409 PJ_UNUSED_ARG(security_level); 1410 #endif 1411 1412 return PJ_SUCCESS; 1413 1414 on_error: 1415 if (call_med->tp) { 1416 pjmedia_transport_close(call_med->tp); 1417 call_med->tp = NULL; 1418 } 1419 return status; 1420 } 1167 1421 1168 1422 pj_status_t pjsua_media_channel_init(pjsua_call_id call_id, … … 1173 1427 int *sip_err_code) 1174 1428 { 1429 const pj_str_t STR_AUDIO = { "audio", 5 }; 1430 const pj_str_t STR_VIDEO = { "video", 5 }; 1175 1431 pjsua_call *call = &pjsua_var.calls[call_id]; 1432 pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 1433 pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA]; 1434 unsigned maudcnt = PJ_ARRAY_SIZE(maudidx); 1435 pj_uint8_t mvididx[PJSUA_MAX_CALL_MEDIA]; 1436 unsigned mvidcnt = PJ_ARRAY_SIZE(mvididx); 1437 pjmedia_type media_types[PJSUA_MAX_CALL_MEDIA]; 1438 unsigned mi; 1176 1439 pj_status_t status; 1177 1440 1178 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)1179 pjsua_acc *acc = &pjsua_var.acc[call->acc_id];1180 pjmedia_srtp_setting srtp_opt;1181 pjmedia_transport *srtp = NULL;1182 #endif1183 1184 1441 PJ_UNUSED_ARG(role); 1185 1442 1443 if (pjsua_get_state() != PJSUA_STATE_RUNNING) 1444 return PJ_EBUSY; 1445 1446 #if DISABLED_FOR_TICKET_1185 1186 1447 /* Return error if media transport has not been created yet 1187 1448 * (e.g. application is starting) 1188 1449 */ 1189 if (call->med_tp == NULL) { 1190 if (sip_err_code) 1191 *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 1192 return PJ_EBUSY; 1193 } 1194 1195 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1196 /* This function may be called when SRTP transport already exists 1197 * (e.g: in re-invite, update), don't need to destroy/re-create. 1198 */ 1199 if (!call->med_orig || call->med_tp == call->med_orig) { 1200 1201 /* Check if SRTP requires secure signaling */ 1202 if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) { 1203 if (security_level < acc->cfg.srtp_secure_signaling) { 1204 if (sip_err_code) 1205 *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1206 return PJSIP_ESESSIONINSECURE; 1207 } 1208 } 1209 1210 /* Always create SRTP adapter */ 1211 pjmedia_srtp_setting_default(&srtp_opt); 1212 srtp_opt.close_member_tp = PJ_FALSE; 1213 /* If media session has been ever established, let's use remote's 1214 * preference in SRTP usage policy, especially when it is stricter. 1215 */ 1216 if (call->rem_srtp_use > acc->cfg.use_srtp) 1217 srtp_opt.use = call->rem_srtp_use; 1218 else 1219 srtp_opt.use = acc->cfg.use_srtp; 1220 1221 status = pjmedia_transport_srtp_create(pjsua_var.med_endpt, 1222 call->med_tp, 1223 &srtp_opt, &srtp); 1224 if (status != PJ_SUCCESS) { 1225 if (sip_err_code) 1226 *sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; 1227 return status; 1228 } 1229 1230 /* Set SRTP as current media transport */ 1231 call->med_orig = call->med_tp; 1232 call->med_tp = srtp; 1233 } 1234 #else 1235 call->med_orig = call->med_tp; 1236 PJ_UNUSED_ARG(security_level); 1450 for (i=0; i<call->med_cnt; ++i) { 1451 if (call->media[i].tp == NULL) { 1452 return PJ_EBUSY; 1453 } 1454 } 1237 1455 #endif 1238 1456 1239 /* Find out which media line in SDP that we support. If we are offerer, 1240 * audio will be initialized at index 0 in SDP. 1241 */ 1242 if (rem_sdp == NULL) { 1243 call->audio_idx = 0; 1244 } 1245 /* Otherwise find out the candidate audio media line in SDP */ 1246 else { 1247 pj_bool_t srtp_active; 1248 1249 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1250 srtp_active = acc->cfg.use_srtp; 1251 #else 1252 srtp_active = PJ_FALSE; 1253 #endif 1254 1255 /* Media count must have been checked */ 1256 pj_assert(rem_sdp->media_count != 0); 1257 1258 call->audio_idx = find_audio_index(rem_sdp, srtp_active); 1259 } 1260 1261 /* Reject offer if we couldn't find a good m=audio line in offer */ 1262 if (call->audio_idx < 0) { 1457 if (rem_sdp) { 1458 sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp, 1459 maudidx, &maudcnt); 1460 1461 if (maudcnt==0) { 1462 /* Expecting audio in the offer */ 1463 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 1464 pjsua_media_channel_deinit(call_id); 1465 return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE); 1466 } 1467 1468 sort_media(rem_sdp, &STR_VIDEO, acc->cfg.use_srtp, 1469 mvididx, &mvidcnt); 1470 mvidcnt = (mvidcnt < acc->cfg.max_video_cnt) ? 1471 mvidcnt : acc->cfg.max_video_cnt; 1472 1473 } else { 1474 maudcnt = acc->cfg.max_audio_cnt; 1475 for (mi=0; mi<maudcnt; ++mi) { 1476 maudidx[mi] = mi; 1477 media_types[mi] = PJMEDIA_TYPE_AUDIO; 1478 } 1479 mvidcnt = acc->cfg.max_video_cnt; 1480 for (mi=0; mi<mvidcnt; ++mi) { 1481 media_types[maudcnt + mi] = PJMEDIA_TYPE_VIDEO; 1482 } 1483 } 1484 1485 call->med_cnt = maudcnt + mvidcnt; 1486 1487 if (call->med_cnt == 0) { 1488 /* Expecting at least one media */ 1263 1489 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 1264 1490 pjsua_media_channel_deinit(call_id); … … 1266 1492 } 1267 1493 1268 PJ_LOG(4,(THIS_FILE, "Media index %d selected for call %d", 1494 /* Initialize each media line */ 1495 for (mi=0; mi < call->med_cnt; ++mi) { 1496 pjsua_call_media *call_med = &call->media[mi]; 1497 pj_bool_t enabled = PJ_FALSE; 1498 pjmedia_type media_type = PJMEDIA_TYPE_NONE; 1499 1500 if (rem_sdp) { 1501 if (!pj_stricmp(&rem_sdp->media[mi]->desc.media, &STR_AUDIO)) { 1502 media_type = PJMEDIA_TYPE_AUDIO; 1503 if (pj_memchr(maudidx, mi, maudcnt * sizeof(maudidx[0]))) { 1504 enabled = PJ_TRUE; 1505 } 1506 } 1507 else if (!pj_stricmp(&rem_sdp->media[mi]->desc.media, &STR_VIDEO)) { 1508 media_type = PJMEDIA_TYPE_VIDEO; 1509 if (pj_memchr(mvididx, mi, mvidcnt * sizeof(mvididx[0]))) { 1510 enabled = PJ_TRUE; 1511 } 1512 } 1513 1514 } else { 1515 enabled = PJ_TRUE; 1516 media_type = media_types[mi]; 1517 } 1518 1519 if (enabled) { 1520 status = pjsua_call_media_init(call_med, media_type, 1521 &acc->cfg.rtp_cfg, 1522 security_level, sip_err_code); 1523 if (status != PJ_SUCCESS) { 1524 pjsua_media_channel_deinit(call_id); 1525 return status; 1526 } 1527 } else { 1528 /* By convention, the media is inactive if transport is NULL */ 1529 if (call_med->tp) { 1530 pjmedia_transport_close(call_med->tp); 1531 call_med->tp = NULL; 1532 } 1533 } 1534 } 1535 1536 call->audio_idx = maudidx[0]; 1537 1538 PJ_LOG(4,(THIS_FILE, "Media index %d selected for audio call %d", 1269 1539 call->audio_idx, call->index)); 1270 1540 1271 /* Create the media transport */ 1272 status = pjmedia_transport_media_create(call->med_tp, tmp_pool, 0, 1273 rem_sdp, call->audio_idx); 1274 if (status != PJ_SUCCESS) { 1275 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1276 pjsua_media_channel_deinit(call_id); 1277 return status; 1278 } 1279 1280 call->med_tp_st = PJSUA_MED_TP_INIT; 1541 /* Tell the media transport of a new offer/answer session */ 1542 for (mi=0; mi < call->med_cnt; ++mi) { 1543 pjsua_call_media *call_med = &call->media[mi]; 1544 1545 /* Note: tp may be NULL if this media line is inactive */ 1546 if (call_med->tp) { 1547 status = pjmedia_transport_media_create(call_med->tp, 1548 tmp_pool, 0, 1549 rem_sdp, mi); 1550 if (status != PJ_SUCCESS) { 1551 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1552 pjsua_media_channel_deinit(call_id); 1553 return status; 1554 } 1555 1556 call_med->tp_st = PJSUA_MED_TP_INIT; 1557 } 1558 } 1559 1281 1560 return PJ_SUCCESS; 1282 1561 } … … 1286 1565 const pjmedia_sdp_session *rem_sdp, 1287 1566 pjmedia_sdp_session **p_sdp, 1288 int *sip_status_code) 1289 { 1290 enum { MAX_MEDIA = 1 }; 1567 int *sip_err_code) 1568 { 1569 const pj_str_t STR_AUDIO = { "audio", 5 }; 1570 enum { MAX_MEDIA = PJSUA_MAX_CALL_MEDIA }; 1291 1571 pjmedia_sdp_session *sdp; 1292 pj media_transport_info tpinfo;1572 pj_sockaddr origin; 1293 1573 pjsua_call *call = &pjsua_var.calls[call_id]; 1574 pjsua_acc *acc = &pjsua_var.acc[call->acc_id]; 1294 1575 pjmedia_sdp_neg_state sdp_neg_state = PJMEDIA_SDP_NEG_STATE_NULL; 1576 unsigned mi; 1295 1577 pj_status_t status; 1296 1578 1297 /* Return error if media transport has not been created yet 1298 * (e.g. application is starting) 1579 if (pjsua_get_state() != PJSUA_STATE_RUNNING) 1580 return PJ_EBUSY; 1581 1582 if (rem_sdp) { 1583 pj_uint8_t maudidx[PJSUA_MAX_CALL_MEDIA]; 1584 unsigned maudcnt = PJ_ARRAY_SIZE(maudidx); 1585 1586 sort_media(rem_sdp, &STR_AUDIO, acc->cfg.use_srtp, 1587 maudidx, &maudcnt); 1588 1589 if (maudcnt==0) { 1590 /* Expecting audio in the offer */ 1591 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 1592 pjsua_media_channel_deinit(call_id); 1593 return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE); 1594 } 1595 1596 call->audio_idx = maudidx[0]; 1597 } else { 1598 /* Audio is first in our offer, by convention */ 1599 call->audio_idx = 0; 1600 } 1601 1602 /* Create media if it's not created. This could happen when call is 1603 * currently on-hold (with the old style hold) 1299 1604 */ 1300 if (call->med_tp == NULL) { 1301 return PJ_EBUSY; 1302 } 1303 1304 if (rem_sdp && rem_sdp->media_count != 0) { 1305 pj_bool_t srtp_active; 1306 1307 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1308 srtp_active = pjsua_var.acc[call->acc_id].cfg.use_srtp; 1309 #else 1310 srtp_active = PJ_FALSE; 1311 #endif 1312 1313 call->audio_idx = find_audio_index(rem_sdp, srtp_active); 1314 if (call->audio_idx == -1) { 1315 /* No audio in the offer. We can't accept this */ 1316 PJ_LOG(4,(THIS_FILE, 1317 "Unable to accept SDP offer without audio for call %d", 1318 call_id)); 1319 return PJMEDIA_SDP_EINMEDIA; 1320 } 1321 } 1322 1323 /* Media index must have been determined before */ 1324 pj_assert(call->audio_idx != -1); 1325 1326 /* Create media if it's not created. This could happen when call is 1327 * currently on-hold 1328 */ 1329 if (call->med_tp_st == PJSUA_MED_TP_IDLE) { 1605 if (call->media[call->audio_idx].tp == NULL) { 1330 1606 pjsip_role_e role; 1331 1607 role = (rem_sdp ? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC); 1332 1608 status = pjsua_media_channel_init(call_id, role, call->secure_level, 1333 pool, rem_sdp, sip_ status_code);1609 pool, rem_sdp, sip_err_code); 1334 1610 if (status != PJ_SUCCESS) 1335 1611 return status; … … 1340 1616 sdp_neg_state = pjmedia_sdp_neg_get_state(call->inv->neg); 1341 1617 1342 /* Get media socket info */ 1343 pjmedia_transport_info_init(&tpinfo); 1344 pjmedia_transport_get_info(call->med_tp, &tpinfo); 1345 1346 /* Create SDP */ 1347 status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, MAX_MEDIA, 1348 &tpinfo.sock_info, &sdp); 1349 if (status != PJ_SUCCESS) { 1350 if (sip_status_code) *sip_status_code = 500; 1618 /* Get one address to use in the origin field */ 1619 pj_bzero(&origin, sizeof(origin)); 1620 for (mi=0; mi<call->med_cnt; ++mi) { 1621 pjmedia_transport_info tpinfo; 1622 1623 if (call->media[mi].tp == NULL) 1624 continue; 1625 1626 pjmedia_transport_info_init(&tpinfo); 1627 pjmedia_transport_get_info(call->media[mi].tp, &tpinfo); 1628 pj_sockaddr_cp(&origin, &tpinfo.sock_info.rtp_addr_name); 1629 break; 1630 } 1631 1632 /* Create the base (blank) SDP */ 1633 status = pjmedia_endpt_create_base_sdp(pjsua_var.med_endpt, pool, NULL, 1634 &origin, &sdp); 1635 if (status != PJ_SUCCESS) 1351 1636 return status; 1352 } 1353 1354 /* If we're answering or updating the session with a new offer, 1355 * and the selected media is not the first media 1356 * in SDP, then fill in the unselected media with with zero port. 1357 * Otherwise we'll crash in transport_encode_sdp() because the media 1358 * lines are not aligned between offer and answer. 1359 */ 1360 if (call->audio_idx != 0 && 1361 (rem_sdp || sdp_neg_state==PJMEDIA_SDP_NEG_STATE_DONE)) 1362 { 1363 unsigned i; 1364 const pjmedia_sdp_session *ref_sdp = rem_sdp; 1365 1366 if (!ref_sdp) { 1367 /* We are updating session with a new offer */ 1368 status = pjmedia_sdp_neg_get_active_local(call->inv->neg, 1369 &ref_sdp); 1370 pj_assert(status == PJ_SUCCESS); 1371 } 1372 1373 for (i=0; i<ref_sdp->media_count; ++i) { 1374 const pjmedia_sdp_media *ref_m = ref_sdp->media[i]; 1375 pjmedia_sdp_media *m; 1376 1377 if ((int)i == call->audio_idx) 1378 continue; 1379 1380 m = pjmedia_sdp_media_clone_deactivate(pool, ref_m); 1381 if (i==sdp->media_count) 1382 sdp->media[sdp->media_count++] = m; 1383 else { 1384 pj_array_insert(sdp->media, sizeof(sdp->media[0]), 1385 sdp->media_count, i, &m); 1386 ++sdp->media_count; 1637 1638 /* Process each media line */ 1639 for (mi=0; mi<call->med_cnt; ++mi) { 1640 pjsua_call_media *call_med = &call->media[mi]; 1641 pjmedia_sdp_media *m = NULL; 1642 pjmedia_transport_info tpinfo; 1643 1644 if (call_med->tp == NULL) { 1645 /* 1646 * This media is deactivated. Just create a valid SDP with zero 1647 * port. 1648 */ 1649 m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); 1650 m->desc.transport = pj_str("RTP/AVP"); 1651 m->desc.fmt_count = 1; 1652 m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn); 1653 m->conn->net_type = pj_str("IN"); 1654 m->conn->addr_type = pj_str("IP4"); 1655 m->conn->addr = pj_str("127.0.0.1"); 1656 1657 switch (call_med->type) { 1658 case PJMEDIA_TYPE_AUDIO: 1659 m->desc.media = pj_str("audio"); 1660 m->desc.fmt[0] = pj_str("0"); 1661 break; 1662 case PJMEDIA_TYPE_VIDEO: 1663 m->desc.media = pj_str("video"); 1664 m->desc.fmt[0] = pj_str("31"); 1665 break; 1666 default: 1667 if (rem_sdp && mi < rem_sdp->media_count) { 1668 pj_strdup(pool, &m->desc.media, 1669 &rem_sdp->media[mi]->desc.media); 1670 pj_strdup(pool, &m->desc.fmt[0], 1671 &rem_sdp->media[mi]->desc.fmt[0]); 1672 } else { 1673 pj_assert(!"Invalid call_med media type"); 1674 return PJ_EBUG; 1675 } 1387 1676 } 1677 1678 sdp->media[sdp->media_count++] = m; 1679 continue; 1680 } 1681 1682 /* Get transport address info */ 1683 pjmedia_transport_info_init(&tpinfo); 1684 pjmedia_transport_get_info(call_med->tp, &tpinfo); 1685 1686 /* Ask pjmedia endpoint to create SDP media line */ 1687 switch (call_med->type) { 1688 case PJMEDIA_TYPE_AUDIO: 1689 status = pjmedia_endpt_create_audio_sdp(pjsua_var.med_endpt, pool, 1690 &tpinfo.sock_info, 0, &m); 1691 break; 1692 case PJMEDIA_TYPE_VIDEO: 1693 status = pjmedia_endpt_create_video_sdp(pjsua_var.med_endpt, pool, 1694 &tpinfo.sock_info, 0, &m); 1695 break; 1696 default: 1697 pj_assert(!"Invalid call_med media type"); 1698 return PJ_EBUG; 1699 } 1700 1701 if (status != PJ_SUCCESS) 1702 return status; 1703 1704 sdp->media[sdp->media_count++] = m; 1705 1706 /* Give to transport */ 1707 status = pjmedia_transport_encode_sdp(call_med->tp, pool, 1708 sdp, rem_sdp, mi); 1709 if (status != PJ_SUCCESS) { 1710 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 1711 return status; 1388 1712 } 1389 1713 } … … 1413 1737 } 1414 1738 1415 /* Give the SDP to media transport */ 1416 status = pjmedia_transport_encode_sdp(call->med_tp, pool, sdp, rem_sdp, 1417 call->audio_idx); 1418 if (status != PJ_SUCCESS) { 1419 if (sip_status_code) *sip_status_code = PJSIP_SC_NOT_ACCEPTABLE; 1420 return status; 1421 } 1422 1423 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1739 1740 #if DISABLED_FOR_TICKET_1185 && defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) 1424 1741 /* Check if SRTP is in optional mode and configured to use duplicated 1425 1742 * media, i.e: secured and unsecured version, in the SDP offer. … … 1434 1751 pjmedia_sdp_media *m = sdp->media[i]; 1435 1752 1436 /* Check if this media is unsecured but has SDP "crypto" 1753 /* Check if this media is unsecured but has SDP "crypto" 1437 1754 * attribute. 1438 1755 */ … … 1440 1757 pjmedia_sdp_media_find_attr2(m, "crypto", NULL) != NULL) 1441 1758 { 1442 if (i == (unsigned)call->audio_idx && 1759 if (i == (unsigned)call->audio_idx && 1443 1760 sdp_neg_state == PJMEDIA_SDP_NEG_STATE_DONE) 1444 1761 { … … 1463 1780 /* Insert the new media before the unsecured media */ 1464 1781 if (sdp->media_count < PJMEDIA_MAX_SDP_MEDIA) { 1465 pj_array_insert(sdp->media, sizeof(new_m), 1782 pj_array_insert(sdp->media, sizeof(new_m), 1466 1783 sdp->media_count, i, &new_m); 1467 1784 ++sdp->media_count; … … 1474 1791 #endif 1475 1792 1476 /* Update currently advertised RTP source address */1477 pj_memcpy(&call->med_rtp_addr, &tpinfo.sock_info.rtp_addr_name,1478 sizeof(pj_sockaddr));1479 1480 1793 *p_sdp = sdp; 1481 1794 return PJ_SUCCESS; … … 1486 1799 { 1487 1800 pjsua_call *call = &pjsua_var.calls[call_id]; 1488 1489 if (call->conf_slot != PJSUA_INVALID_ID) { 1490 if (pjsua_var.mconf) { 1491 pjsua_conf_remove_port(call->conf_slot); 1492 } 1493 call->conf_slot = PJSUA_INVALID_ID; 1494 } 1495 1496 if (call->session) { 1497 pjmedia_rtcp_stat stat; 1498 1499 if ((call->media_dir & PJMEDIA_DIR_ENCODING) && 1500 (pjmedia_session_get_stream_stat(call->session, 0, &stat) 1501 == PJ_SUCCESS)) 1801 unsigned mi; 1802 1803 for (mi=0; mi<call->med_cnt; ++mi) { 1804 pjsua_call_media *call_med = &call->media[mi]; 1805 1806 if (call_med->type == PJMEDIA_TYPE_AUDIO) { 1807 pjmedia_stream *strm = call_med->strm.a.stream; 1808 pjmedia_rtcp_stat stat; 1809 1810 if (strm) { 1811 if (call_med->strm.a.conf_slot != PJSUA_INVALID_ID) { 1812 if (pjsua_var.mconf) { 1813 pjsua_conf_remove_port(call_med->strm.a.conf_slot); 1814 } 1815 call_med->strm.a.conf_slot = PJSUA_INVALID_ID; 1816 } 1817 1818 if ((call_med->dir & PJMEDIA_DIR_ENCODING) && 1819 (pjmedia_stream_get_stat(strm, &stat) == PJ_SUCCESS)) 1820 { 1821 /* Save RTP timestamp & sequence, so when media session is 1822 * restarted, those values will be restored as the initial 1823 * RTP timestamp & sequence of the new media session. So in 1824 * the same call session, RTP timestamp and sequence are 1825 * guaranteed to be contigue. 1826 */ 1827 call_med->rtp_tx_seq_ts_set = 1 | (1 << 1); 1828 call_med->rtp_tx_seq = stat.rtp_tx_last_seq; 1829 call_med->rtp_tx_ts = stat.rtp_tx_last_ts; 1830 } 1831 1832 if (pjsua_var.ua_cfg.cb.on_stream_destroyed) { 1833 pjsua_var.ua_cfg.cb.on_stream_destroyed(call_id, strm, mi); 1834 } 1835 1836 pjmedia_stream_destroy(strm); 1837 call_med->strm.a.stream = NULL; 1838 1839 PJ_LOG(4,(THIS_FILE, "Media session call%02d:%d is destroyed", 1840 call_id, mi)); 1841 } 1842 } 1843 call_med->state = PJSUA_CALL_MEDIA_NONE; 1844 } 1845 } 1846 1847 pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id) 1848 { 1849 pjsua_call *call = &pjsua_var.calls[call_id]; 1850 unsigned mi; 1851 1852 stop_media_session(call_id); 1853 1854 for (mi=0; mi<call->med_cnt; ++mi) { 1855 pjsua_call_media *call_med = &call->media[mi]; 1856 1857 if (call_med->tp_st != PJSUA_MED_TP_IDLE) { 1858 pjmedia_transport_media_stop(call_med->tp); 1859 call_med->tp_st = PJSUA_MED_TP_IDLE; 1860 } 1861 1862 if (call_med->tp_orig && call_med->tp && 1863 call_med->tp != call_med->tp_orig) 1502 1864 { 1503 /* Save RTP timestamp & sequence, so when media session is 1504 * restarted, those values will be restored as the initial 1505 * RTP timestamp & sequence of the new media session. So in 1506 * the same call session, RTP timestamp and sequence are 1507 * guaranteed to be contigue. 1508 */ 1509 call->rtp_tx_seq_ts_set = 1 | (1 << 1); 1510 call->rtp_tx_seq = stat.rtp_tx_last_seq; 1511 call->rtp_tx_ts = stat.rtp_tx_last_ts; 1512 } 1513 1514 if (pjsua_var.ua_cfg.cb.on_stream_destroyed) { 1515 pjsua_var.ua_cfg.cb.on_stream_destroyed(call_id, call->session, 0); 1516 } 1517 1518 pjmedia_session_destroy(call->session); 1519 call->session = NULL; 1520 1521 PJ_LOG(4,(THIS_FILE, "Media session for call %d is destroyed", 1522 call_id)); 1523 1524 } 1525 1526 call->media_st = PJSUA_CALL_MEDIA_NONE; 1527 } 1528 1529 pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id) 1530 { 1531 pjsua_call *call = &pjsua_var.calls[call_id]; 1532 1533 stop_media_session(call_id); 1534 1535 if (call->med_tp_st != PJSUA_MED_TP_IDLE) { 1536 pjmedia_transport_media_stop(call->med_tp); 1537 call->med_tp_st = PJSUA_MED_TP_IDLE; 1538 } 1539 1540 if (call->med_orig && call->med_tp && call->med_tp != call->med_orig) { 1541 pjmedia_transport_close(call->med_tp); 1542 call->med_tp = call->med_orig; 1865 pjmedia_transport_close(call_med->tp); 1866 call_med->tp = call_med->tp_orig; 1867 } 1543 1868 } 1544 1869 … … 1570 1895 1571 1896 1572 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 1573 const pjmedia_sdp_session *local_sdp, 1574 const pjmedia_sdp_session *remote_sdp) 1575 { 1576 int prev_media_st = 0; 1577 pjsua_call *call = &pjsua_var.calls[call_id]; 1578 pjmedia_session_info sess_info; 1579 pjmedia_stream_info *si = NULL; 1897 static pj_status_t audio_channel_update(pjsua_call_media *call_med, 1898 pj_pool_t *tmp_pool, 1899 const pjmedia_sdp_session *local_sdp, 1900 const pjmedia_sdp_session *remote_sdp) 1901 { 1902 pjsua_call *call = call_med->call; 1903 pjmedia_stream_info the_si, *si = &the_si; 1580 1904 pjmedia_port *media_port; 1905 unsigned strm_idx = call_med->idx; 1581 1906 pj_status_t status; 1582 1583 if (!pjsua_var.med_endpt) { 1584 /* We're being shutdown */ 1585 return PJ_EBUSY; 1586 } 1587 1588 /* Destroy existing media session, if any. */ 1589 prev_media_st = call->media_st; 1590 stop_media_session(call->index); 1591 1592 /* Create media session info based on SDP parameters. 1593 */ 1594 status = pjmedia_session_info_from_sdp( call->inv->pool_prov, 1595 pjsua_var.med_endpt, 1596 PJMEDIA_MAX_SDP_MEDIA, &sess_info, 1597 local_sdp, remote_sdp); 1907 1908 status = pjmedia_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt, 1909 local_sdp, remote_sdp, strm_idx); 1598 1910 if (status != PJ_SUCCESS) 1599 1911 return status; 1600 1912 1601 /* Update audio index from the negotiated SDP */1602 call->audio_idx = find_audio_index(local_sdp, PJ_TRUE);1603 1604 /* Find which session is audio */1605 PJ_ASSERT_RETURN(call->audio_idx != -1, PJ_EBUG);1606 PJ_ASSERT_RETURN(call->audio_idx < (int)sess_info.stream_cnt, PJ_EBUG);1607 si = &sess_info.stream_info[call->audio_idx];1608 1609 /* Reset session info with only one media stream */1610 sess_info.stream_cnt = 1;1611 if (si != &sess_info.stream_info[0]) {1612 pj_memcpy(&sess_info.stream_info[0], si, sizeof(pjmedia_stream_info));1613 si = &sess_info.stream_info[0];1614 }1615 1616 1913 /* Check if no media is active */ 1617 if (sess_info.stream_cnt == 0 || si->dir == PJMEDIA_DIR_NONE) 1618 { 1914 if (si->dir == PJMEDIA_DIR_NONE) { 1619 1915 /* Call media state */ 1620 call ->media_st= PJSUA_CALL_MEDIA_NONE;1916 call_med->state = PJSUA_CALL_MEDIA_NONE; 1621 1917 1622 1918 /* Call media direction */ 1623 call->media_dir = PJMEDIA_DIR_NONE; 1624 1625 /* Don't stop transport because we need to transmit keep-alives, and 1626 * also to prevent restarting ICE negotiation. See 1627 * http://trac.pjsip.org/repos/ticket/1094 1628 */ 1629 #if 0 1630 /* Shutdown transport's session */ 1631 pjmedia_transport_media_stop(call->med_tp); 1632 call->med_tp_st = PJSUA_MED_TP_IDLE; 1633 1634 /* No need because we need keepalive? */ 1635 1636 /* Close upper entry of transport stack */ 1637 if (call->med_orig && (call->med_tp != call->med_orig)) { 1638 pjmedia_transport_close(call->med_tp); 1639 call->med_tp = call->med_orig; 1640 } 1641 #endif 1919 call_med->dir = PJMEDIA_DIR_NONE; 1642 1920 1643 1921 } else { … … 1645 1923 1646 1924 /* Start/restart media transport */ 1647 status = pjmedia_transport_media_start(call->med_tp, 1648 call->inv->pool_prov, 1649 local_sdp, remote_sdp, 1650 call->audio_idx); 1925 status = pjmedia_transport_media_start(call_med->tp, 1926 tmp_pool, local_sdp, 1927 remote_sdp, strm_idx); 1651 1928 if (status != PJ_SUCCESS) 1652 1929 return status; 1653 1930 1654 call ->med_tp_st = PJSUA_MED_TP_RUNNING;1931 call_med->tp_st = PJSUA_MED_TP_RUNNING; 1655 1932 1656 1933 /* Get remote SRTP usage policy */ 1657 1934 pjmedia_transport_info_init(&tp_info); 1658 pjmedia_transport_get_info(call ->med_tp, &tp_info);1935 pjmedia_transport_get_info(call_med->tp, &tp_info); 1659 1936 if (tp_info.specific_info_cnt > 0) { 1660 1937 unsigned i; … … 1665 1942 (pjmedia_srtp_info*) tp_info.spc_info[i].buffer; 1666 1943 1667 call ->rem_srtp_use = srtp_info->peer_use;1944 call_med->rem_srtp_use = srtp_info->peer_use; 1668 1945 break; 1669 1946 } … … 1694 1971 1695 1972 /* Set SSRC */ 1696 si->ssrc = call ->ssrc;1973 si->ssrc = call_med->ssrc; 1697 1974 1698 1975 /* Set RTP timestamp & sequence, normally these value are intialized … … 1701 1978 * contigue. 1702 1979 */ 1703 si->rtp_ts = call ->rtp_tx_ts;1704 si->rtp_seq = call ->rtp_tx_seq;1705 si->rtp_seq_ts_set = call ->rtp_tx_seq_ts_set;1980 si->rtp_ts = call_med->rtp_tx_ts; 1981 si->rtp_seq = call_med->rtp_tx_seq; 1982 si->rtp_seq_ts_set = call_med->rtp_tx_seq_ts_set; 1706 1983 1707 1984 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0 … … 1711 1988 1712 1989 /* Create session based on session info. */ 1713 status = pjmedia_session_create( pjsua_var.med_endpt, &sess_info, 1714 &call->med_tp, 1715 call, &call->session ); 1990 status = pjmedia_stream_create(pjsua_var.med_endpt, NULL, si, 1991 call_med->tp, NULL, 1992 &call_med->strm.a.stream); 1993 if (status != PJ_SUCCESS) { 1994 return status; 1995 } 1996 1997 /* Start stream */ 1998 status = pjmedia_stream_start(call_med->strm.a.stream); 1716 1999 if (status != PJ_SUCCESS) { 1717 2000 return status; … … 1722 2005 */ 1723 2006 if (pjsua_var.ua_cfg.cb.on_dtmf_digit) { 1724 pjmedia_s ession_set_dtmf_callback(call->session, 0,1725 &dtmf_callback,1726 2007 pjmedia_stream_set_dtmf_callback(call_med->strm.a.stream, 2008 &dtmf_callback, 2009 (void*)(long)(call->index)); 1727 2010 } 1728 2011 … … 1730 2013 * We need the port interface to add to the conference bridge. 1731 2014 */ 1732 pjmedia_s ession_get_port(call->session, 0, &media_port);2015 pjmedia_stream_get_port(call_med->strm.a.stream, &media_port); 1733 2016 1734 2017 /* Notify application about stream creation. … … 1737 2020 */ 1738 2021 if (pjsua_var.ua_cfg.cb.on_stream_created) { 1739 pjsua_var.ua_cfg.cb.on_stream_created(call_id, call->session, 1740 0, &media_port); 2022 pjsua_var.ua_cfg.cb.on_stream_created(call->index, 2023 call_med->strm.a.stream, 2024 strm_idx, &media_port); 1741 2025 } 1742 2026 … … 1759 2043 media_port, 1760 2044 &port_name, 1761 (unsigned*)&call->conf_slot); 2045 (unsigned*) 2046 &call_med->strm.a.conf_slot); 1762 2047 if (status != PJ_SUCCESS) { 1763 2048 return status; … … 1766 2051 1767 2052 /* Call media direction */ 1768 call ->media_dir = si->dir;2053 call_med->dir = si->dir; 1769 2054 1770 2055 /* Call media state */ 1771 2056 if (call->local_hold) 1772 call ->media_st= PJSUA_CALL_MEDIA_LOCAL_HOLD;1773 else if (call ->media_dir == PJMEDIA_DIR_DECODING)1774 call ->media_st= PJSUA_CALL_MEDIA_REMOTE_HOLD;2057 call_med->state = PJSUA_CALL_MEDIA_LOCAL_HOLD; 2058 else if (call_med->dir == PJMEDIA_DIR_DECODING) 2059 call_med->state = PJSUA_CALL_MEDIA_REMOTE_HOLD; 1775 2060 else 1776 call ->media_st= PJSUA_CALL_MEDIA_ACTIVE;2061 call_med->state = PJSUA_CALL_MEDIA_ACTIVE; 1777 2062 } 1778 2063 … … 1781 2066 char info[80]; 1782 2067 int info_len = 0; 1783 unsigned i; 1784 1785 for (i=0; i<sess_info.stream_cnt; ++i) { 1786 int len; 1787 const char *dir; 1788 pjmedia_stream_info *strm_info = &sess_info.stream_info[i]; 1789 1790 switch (strm_info->dir) { 1791 case PJMEDIA_DIR_NONE: 1792 dir = "inactive"; 1793 break; 1794 case PJMEDIA_DIR_ENCODING: 1795 dir = "sendonly"; 1796 break; 1797 case PJMEDIA_DIR_DECODING: 1798 dir = "recvonly"; 1799 break; 1800 case PJMEDIA_DIR_ENCODING_DECODING: 1801 dir = "sendrecv"; 1802 break; 1803 default: 1804 dir = "unknown"; 1805 break; 2068 int len; 2069 const char *dir; 2070 2071 switch (si->dir) { 2072 case PJMEDIA_DIR_NONE: 2073 dir = "inactive"; 2074 break; 2075 case PJMEDIA_DIR_ENCODING: 2076 dir = "sendonly"; 2077 break; 2078 case PJMEDIA_DIR_DECODING: 2079 dir = "recvonly"; 2080 break; 2081 case PJMEDIA_DIR_ENCODING_DECODING: 2082 dir = "sendrecv"; 2083 break; 2084 default: 2085 dir = "unknown"; 2086 break; 2087 } 2088 len = pj_ansi_sprintf( info+info_len, 2089 ", stream #%d: %.*s (%s)", strm_idx, 2090 (int)si->fmt.encoding_name.slen, 2091 si->fmt.encoding_name.ptr, 2092 dir); 2093 if (len > 0) 2094 info_len += len; 2095 PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 2096 } 2097 2098 return PJ_SUCCESS; 2099 } 2100 2101 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 2102 const pjmedia_sdp_session *local_sdp, 2103 const pjmedia_sdp_session *remote_sdp) 2104 { 2105 pjsua_call *call = &pjsua_var.calls[call_id]; 2106 pj_pool_t *tmp_pool = call->inv->pool_prov; 2107 unsigned mi; 2108 pj_status_t status; 2109 2110 if (pjsua_get_state() != PJSUA_STATE_RUNNING) 2111 return PJ_EBUSY; 2112 2113 /* Destroy existing media session, if any. */ 2114 stop_media_session(call->index); 2115 2116 /* Reset audio_idx first */ 2117 call->audio_idx = -1; 2118 2119 /* Process each media stream */ 2120 for (mi=0; mi < call->med_cnt; ++mi) { 2121 pjsua_call_media *call_med = &call->media[mi]; 2122 2123 if (mi > local_sdp->media_count || 2124 mi > remote_sdp->media_count) 2125 { 2126 /* Something is wrong */ 2127 PJ_LOG(1,(THIS_FILE, "Error updating media for call %d: " 2128 "invalid media index %d in SDP", call_id, mi)); 2129 return PJMEDIA_SDP_EINSDP; 2130 } 2131 2132 switch (call_med->type) { 2133 case PJMEDIA_TYPE_AUDIO: 2134 status = audio_channel_update(call_med, tmp_pool, 2135 local_sdp, remote_sdp); 2136 if (call->audio_idx==-1 && status==PJ_SUCCESS && 2137 call_med->strm.a.stream) 2138 { 2139 call->audio_idx = mi; 1806 2140 } 1807 len = pj_ansi_sprintf( info+info_len, 1808 ", stream #%d: %.*s (%s)", i, 1809 (int)strm_info->fmt.encoding_name.slen, 1810 strm_info->fmt.encoding_name.ptr, 1811 dir); 1812 if (len > 0) 1813 info_len += len; 1814 } 1815 PJ_LOG(4,(THIS_FILE,"Media updates%s", info)); 2141 break; 2142 case PJMEDIA_TYPE_VIDEO: 2143 PJ_LOG(4,(THIS_FILE, "-x-x-x-x- Updating video for stream %d", mi)); 2144 break; 2145 default: 2146 break; 2147 } 2148 2149 if (status != PJ_SUCCESS) { 2150 PJ_PERROR(1,(THIS_FILE, status, "Error updating media call%02:%d", 2151 call_id, mi)); 2152 } 1816 2153 } 1817 2154
Note: See TracChangeset
for help on using the changeset viewer.